diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 65b2dc5f..aed75cbd 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -45,3 +45,4 @@ | `:set-option`, `:set` | Set a config option at runtime | | `:sort` | Sort ranges in selection. | | `:rsort` | Sort ranges in selection in reverse order. | +| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index de4bfa49..6123b7d2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -403,7 +403,6 @@ impl MappableCommand { decrement, "Decrement", record_macro, "Record macro", replay_macro, "Replay macro", - show_subtree, "Show tree-sitter subtree under primary selection", ); } @@ -2766,6 +2765,46 @@ pub mod cmd { Ok(()) } + fn tree_sitter_subtree( + cx: &mut compositor::Context, + _args: &[Cow], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let (view, doc) = current!(cx.editor); + + if let Some(syntax) = doc.syntax() { + let primary_selection = doc.selection(view.id).primary(); + let text = doc.text(); + let from = text.char_to_byte(primary_selection.from()); + let to = text.char_to_byte(primary_selection.to()); + if let Some(selected_node) = syntax + .tree() + .root_node() + .descendant_for_byte_range(from, to) + { + let contents = format!("```tsq\n{}\n```", selected_node.to_sexp()); + + let callback = async move { + let call: job::Callback = + 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); + if let Some(doc_popup) = compositor.find_id("hover") { + *doc_popup = popup; + } else { + compositor.push(Box::new(popup)); + } + }); + Ok(call) + }; + + cx.jobs.callback(callback); + } + } + + Ok(()) + } + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -3082,6 +3121,13 @@ pub mod cmd { fun: sort_reverse, completer: None, }, + TypableCommand { + name: "tree-sitter-subtree", + aliases: &["ts-subtree"], + doc: "Display tree sitter subtree under cursor, primarily for debugging queries.", + fun: tree_sitter_subtree, + completer: None, + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = @@ -6252,33 +6298,3 @@ fn replay_macro(cx: &mut Context) { }, )); } - -fn show_subtree(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - - if let Some(syntax) = doc.syntax() { - let primary_selection = doc.selection(view.id).primary(); - let text = doc.text(); - let from = text.char_to_byte(primary_selection.from()); - let to = text.char_to_byte(primary_selection.to()); - if let Some(selected_node) = syntax - .tree() - .root_node() - .descendant_for_byte_range(from, to) - { - let contents = format!("```tsq\n{}\n```", selected_node.to_sexp()); - - cx.callback = Some(Box::new( - move |compositor: &mut Compositor, cx: &mut compositor::Context| { - let contents = ui::Markdown::new(contents, cx.editor.syn_loader.clone()); - let popup = Popup::new("hover", contents); - if let Some(doc_popup) = compositor.find_id("hover") { - *doc_popup = popup; - } else { - compositor.push(Box::new(popup)); - } - }, - )); - } - } -}