mirror of https://github.com/helix-editor/helix
feat: add typable command to get injection layer for current range
parent
99d16170dc
commit
d451077978
|
@ -30,43 +30,20 @@ pub fn get_injected_tokens(
|
|||
start: usize,
|
||||
end: usize,
|
||||
) -> (Option<Vec<String>>, Option<Vec<BlockCommentToken>>) {
|
||||
let mut best_fit = None;
|
||||
let mut min_gap = usize::MAX;
|
||||
|
||||
// Find the injection with the most tightly encompassing range.
|
||||
if let Some(syntax) = &syntax {
|
||||
for (layer_id, layer) in &syntax.layers {
|
||||
for ts_range in &layer.ranges {
|
||||
let is_encompassing = ts_range.start_byte <= start && ts_range.end_byte >= end;
|
||||
if is_encompassing {
|
||||
let this_gap = ts_range.end_byte - ts_range.start_byte;
|
||||
if this_gap < min_gap
|
||||
// ignore the "comment" language family
|
||||
// as that would mean we can't uncomment anything, or
|
||||
// the comments would be incorrect.
|
||||
//
|
||||
// Since uncommenting would attempt to use the comment
|
||||
// language's non-existing comment tokens
|
||||
// TODO: add this as a language configuration key?
|
||||
&& !matches!(syntax.layer_config(layer_id).language_name.as_ref(), "jsdoc" | "comment")
|
||||
{
|
||||
best_fit = Some(layer_id);
|
||||
min_gap = this_gap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(best_fit) = best_fit {
|
||||
let config = syntax.layer_config(best_fit);
|
||||
return (
|
||||
config.comment_tokens.clone(),
|
||||
config.block_comment_tokens.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(None, None)
|
||||
syntax
|
||||
.and_then(|syntax| {
|
||||
syntax
|
||||
.injection_for_range(start, end)
|
||||
.map(|language_id| syntax.layer_config(language_id))
|
||||
.map(|config| {
|
||||
(
|
||||
config.comment_tokens.clone(),
|
||||
config.block_comment_tokens.clone(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Given text, a comment token, and a set of line indices, returns the following:
|
||||
|
|
|
@ -1437,6 +1437,37 @@ impl Syntax {
|
|||
Arc::clone(&loader.language_configs[language_id])
|
||||
}
|
||||
|
||||
/// For a given range in the document, get the most tightly encompassing
|
||||
/// injection layer corresponding to that range.
|
||||
pub fn injection_for_range(&self, from: usize, to: usize) -> Option<LayerId> {
|
||||
let mut best_fit = None;
|
||||
let mut min_gap = usize::MAX;
|
||||
|
||||
for (layer_id, layer) in &self.layers {
|
||||
for ts_range in &layer.ranges {
|
||||
let is_encompassing = ts_range.start_byte <= from && ts_range.end_byte >= to;
|
||||
if is_encompassing {
|
||||
let this_gap = ts_range.end_byte - ts_range.start_byte;
|
||||
if this_gap < min_gap
|
||||
// ignore the "comment" language family
|
||||
// as that would mean we can't uncomment anything, or
|
||||
// the comments would be incorrect.
|
||||
//
|
||||
// Since uncommenting would attempt to use the comment
|
||||
// language's non-existing comment tokens
|
||||
// TODO: add this as a language configuration key?
|
||||
&& !matches!(self.layer_config(layer_id).language_name.as_ref(), "jsdoc" | "comment")
|
||||
{
|
||||
best_fit = Some(layer_id);
|
||||
min_gap = this_gap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best_fit
|
||||
}
|
||||
|
||||
pub fn tree(&self) -> &Tree {
|
||||
self.layers[self.root].tree()
|
||||
}
|
||||
|
|
|
@ -1604,6 +1604,33 @@ fn tree_sitter_scopes(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn tree_sitter_injection(
|
||||
cx: &mut compositor::Context,
|
||||
_args: &[Cow<str>],
|
||||
event: PromptEvent,
|
||||
) -> anyhow::Result<()> {
|
||||
if event != PromptEvent::Validate {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (view, doc) = current!(cx.editor);
|
||||
|
||||
let syntax = doc
|
||||
.syntax()
|
||||
.context("No tree-sitter grammar found for this file.")?;
|
||||
|
||||
let range = doc.selection(view.id).primary();
|
||||
|
||||
let language_name = syntax
|
||||
.injection_for_range(range.from(), range.to())
|
||||
.map(|language_id| syntax.layer_config(language_id).language_name.clone())
|
||||
.context("No injection layer found for the current range.")?;
|
||||
|
||||
cx.editor.set_status(language_name);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tree_sitter_highlight_name(
|
||||
cx: &mut compositor::Context,
|
||||
_args: Args,
|
||||
|
@ -3134,6 +3161,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
|||
..Signature::DEFAULT
|
||||
},
|
||||
},
|
||||
TypableCommand {
|
||||
name: "tree-sitter-injection",
|
||||
aliases: &[],
|
||||
doc: "Display injected language for the primary range.",
|
||||
fun: tree_sitter_injection,
|
||||
signature: CommandSignature::none(),
|
||||
},
|
||||
TypableCommand {
|
||||
name: "debug-start",
|
||||
aliases: &["dbg"],
|
||||
|
|
Loading…
Reference in New Issue