mirror of https://github.com/helix-editor/helix
feat(core): add `tree-sitter-breadcrumbs` command
Using this command, the user will be able to see a popup showing all parent lines for cursor. This is good to get context on the editor on big files. This implementation is not ideal, as breadcrumbs should maybe appear all the time, but is a simple hack to suppress the need for the time being.pull/13492/head
parent
63a1a94d92
commit
c54f886b15
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, collections::HashMap, iter};
|
||||
use std::{borrow::Cow, collections::BTreeMap, collections::HashMap, iter};
|
||||
|
||||
use helix_stdx::rope::RopeSliceExt;
|
||||
use tree_sitter::{Query, QueryCursor, QueryPredicateArg};
|
||||
|
@ -1040,6 +1040,41 @@ pub fn get_scopes(syntax: Option<&Syntax>, text: RopeSlice, pos: usize) -> Vec<&
|
|||
scopes
|
||||
}
|
||||
|
||||
pub fn get_breadcrumbs(syntax: Option<&Syntax>, text: RopeSlice, pos: usize) -> Vec<String> {
|
||||
let mut breadcrumb_set: BTreeMap<usize, String> = BTreeMap::new();
|
||||
if let Some(syntax) = syntax {
|
||||
let pos = text.char_to_byte(pos);
|
||||
let mut node = match syntax
|
||||
.tree()
|
||||
.root_node()
|
||||
.descendant_for_byte_range(pos, pos)
|
||||
{
|
||||
Some(node) => node,
|
||||
None => return vec![],
|
||||
};
|
||||
|
||||
while let Some(parent) = node.parent() {
|
||||
if node.is_extra() {
|
||||
continue;
|
||||
}
|
||||
if node.is_named() {
|
||||
let line_idx = text.byte_to_line(parent.start_byte());
|
||||
let line: String = text.line(line_idx).into();
|
||||
breadcrumb_set.insert(line_idx, format!("{}: {}", line_idx + 1, line.trim_end()));
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
let breadcrumbs: Vec<String> = breadcrumb_set
|
||||
.into_iter()
|
||||
.map(|(_k, v)| v.into())
|
||||
// Remove the `source_code` node
|
||||
.skip(1)
|
||||
.collect();
|
||||
breadcrumbs
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1667,6 +1667,43 @@ fn tree_sitter_scopes(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn tree_sitter_breadcrumbs(
|
||||
cx: &mut compositor::Context,
|
||||
_args: Args,
|
||||
event: PromptEvent,
|
||||
) -> anyhow::Result<()> {
|
||||
if event != PromptEvent::Validate {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (view, doc) = current!(cx.editor);
|
||||
let text = doc.text().slice(..);
|
||||
|
||||
let pos = doc.selection(view.id).primary().cursor(text);
|
||||
let breadcrumbs = indent::get_breadcrumbs(doc.syntax(), text, pos);
|
||||
let language = match doc.language_config() {
|
||||
Some(l) => &l.language_id,
|
||||
None => "txt",
|
||||
};
|
||||
|
||||
let contents = format!("```{}\n{}\n```\n", language, breadcrumbs.join("\n"));
|
||||
|
||||
let callback = async move {
|
||||
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
||||
move |editor: &mut Editor, compositor: &mut Compositor| {
|
||||
let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
|
||||
let popup = Popup::new("hover", contents).auto_close(true);
|
||||
compositor.replace_or_push("hover", popup);
|
||||
},
|
||||
));
|
||||
Ok(call)
|
||||
};
|
||||
|
||||
cx.jobs.callback(callback);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tree_sitter_highlight_name(
|
||||
cx: &mut compositor::Context,
|
||||
_args: Args,
|
||||
|
@ -3195,6 +3232,17 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
|||
..Signature::DEFAULT
|
||||
},
|
||||
},
|
||||
TypableCommand {
|
||||
name: "tree-sitter-breadcrumbs",
|
||||
aliases: &["breadcrumbs", "bread"],
|
||||
doc: "Display lines of parents to reach the token under the cursor. Useful to know where you are in the program.",
|
||||
fun: tree_sitter_breadcrumbs,
|
||||
completer: CommandCompleter::none(),
|
||||
signature: Signature {
|
||||
positionals: (0, Some(0)),
|
||||
..Signature::DEFAULT
|
||||
},
|
||||
},
|
||||
TypableCommand {
|
||||
name: "tree-sitter-highlight-name",
|
||||
aliases: &[],
|
||||
|
|
Loading…
Reference in New Issue