Add tree-sitter-highlight-name command (#8170)
* adds treesitter-highlight-name command * commit documentation changes * moves the get_highlight_name function into core/syntax * rename get_highlight_name function to get_highlight_for_node_at_position * addresses pr comments: moves fn into helper fn, simplifies a lot * commit updated documentation changes * changes scope method to return &str so that callers can decide whether or not to own
This commit is contained in:
parent
528a5e3aff
commit
b959162ceb
3 changed files with 91 additions and 0 deletions
|
@ -55,6 +55,7 @@
|
||||||
| `:lsp-restart` | Restarts the language servers used by the current doc |
|
| `:lsp-restart` | Restarts the language servers used by the current doc |
|
||||||
| `:lsp-stop` | Stops the language servers that are used by the current doc |
|
| `:lsp-stop` | Stops the language servers that are used by the current doc |
|
||||||
| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
|
| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
|
||||||
|
| `:tree-sitter-highlight-name` | Display name of tree-sitter highlight scope under the cursor. |
|
||||||
| `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. |
|
| `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. |
|
||||||
| `:debug-remote`, `:dbg-tcp` | Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters. |
|
| `:debug-remote`, `:dbg-tcp` | Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters. |
|
||||||
| `:debug-eval` | Evaluate expression in current debug context. |
|
| `:debug-eval` | Evaluate expression in current debug context. |
|
||||||
|
|
|
@ -1527,6 +1527,84 @@ fn tree_sitter_scopes(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tree_sitter_highlight_name(
|
||||||
|
cx: &mut compositor::Context,
|
||||||
|
_args: &[Cow<str>],
|
||||||
|
event: PromptEvent,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
fn find_highlight_at_cursor(
|
||||||
|
cx: &mut compositor::Context<'_>,
|
||||||
|
) -> Option<helix_core::syntax::Highlight> {
|
||||||
|
use helix_core::syntax::HighlightEvent;
|
||||||
|
|
||||||
|
let (view, doc) = current!(cx.editor);
|
||||||
|
let syntax = doc.syntax()?;
|
||||||
|
let text = doc.text().slice(..);
|
||||||
|
let cursor = doc.selection(view.id).primary().cursor(text);
|
||||||
|
let byte = text.char_to_byte(cursor);
|
||||||
|
let node = syntax
|
||||||
|
.tree()
|
||||||
|
.root_node()
|
||||||
|
.descendant_for_byte_range(byte, byte)?;
|
||||||
|
// Query the same range as the one used in syntax highlighting.
|
||||||
|
let range = {
|
||||||
|
// Calculate viewport byte ranges:
|
||||||
|
let row = text.char_to_line(view.offset.anchor.min(text.len_chars()));
|
||||||
|
// Saturating subs to make it inclusive zero indexing.
|
||||||
|
let last_line = text.len_lines().saturating_sub(1);
|
||||||
|
let height = view.inner_area(doc).height;
|
||||||
|
let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
|
||||||
|
let start = text.line_to_byte(row.min(last_line));
|
||||||
|
let end = text.line_to_byte(last_visible_line + 1);
|
||||||
|
|
||||||
|
start..end
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut highlight = None;
|
||||||
|
|
||||||
|
for event in syntax.highlight_iter(text, Some(range), None) {
|
||||||
|
match event.unwrap() {
|
||||||
|
HighlightEvent::Source { start, end }
|
||||||
|
if start == node.start_byte() && end == node.end_byte() =>
|
||||||
|
{
|
||||||
|
return highlight;
|
||||||
|
}
|
||||||
|
HighlightEvent::HighlightStart(hl) => {
|
||||||
|
highlight = Some(hl);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
if event != PromptEvent::Validate {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(highlight) = find_highlight_at_cursor(cx) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let content = cx.editor.theme.scope(highlight.0).to_string();
|
||||||
|
|
||||||
|
let callback = async move {
|
||||||
|
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
||||||
|
move |editor: &mut Editor, compositor: &mut Compositor| {
|
||||||
|
let content = ui::Markdown::new(content, editor.syn_loader.clone());
|
||||||
|
let popup = Popup::new("hover", content).auto_close(true);
|
||||||
|
compositor.replace_or_push("hover", popup);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
Ok(call)
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.jobs.callback(callback);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn vsplit(
|
fn vsplit(
|
||||||
cx: &mut compositor::Context,
|
cx: &mut compositor::Context,
|
||||||
args: &[Cow<str>],
|
args: &[Cow<str>],
|
||||||
|
@ -2703,6 +2781,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
||||||
fun: tree_sitter_scopes,
|
fun: tree_sitter_scopes,
|
||||||
signature: CommandSignature::none(),
|
signature: CommandSignature::none(),
|
||||||
},
|
},
|
||||||
|
TypableCommand {
|
||||||
|
name: "tree-sitter-highlight-name",
|
||||||
|
aliases: &[],
|
||||||
|
doc: "Display name of tree-sitter highlight scope under the cursor.",
|
||||||
|
fun: tree_sitter_highlight_name,
|
||||||
|
signature: CommandSignature::none(),
|
||||||
|
},
|
||||||
TypableCommand {
|
TypableCommand {
|
||||||
name: "debug-start",
|
name: "debug-start",
|
||||||
aliases: &["dbg"],
|
aliases: &["dbg"],
|
||||||
|
|
|
@ -297,6 +297,11 @@ impl Theme {
|
||||||
self.highlights[index]
|
self.highlights[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn scope(&self, index: usize) -> &str {
|
||||||
|
&self.scopes[index]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue