diff options
Diffstat (limited to 'support/texlab/crates/commands/src/find_envs.rs')
-rw-r--r-- | support/texlab/crates/commands/src/find_envs.rs | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/support/texlab/crates/commands/src/find_envs.rs b/support/texlab/crates/commands/src/find_envs.rs new file mode 100644 index 0000000000..20b11c9e37 --- /dev/null +++ b/support/texlab/crates/commands/src/find_envs.rs @@ -0,0 +1,65 @@ +use base_db::{semantics::Span, Document, DocumentData}; +use rowan::{ast::AstNode, TextRange, TextSize}; +use syntax::latex; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct EnvironmentMatch { + pub name: Span, + pub full_range: TextRange, +} + +pub fn find_environments(document: &Document, offset: TextSize) -> Vec<EnvironmentMatch> { + let DocumentData::Tex(data) = &document.data else { return Vec::new() }; + + let root = latex::SyntaxNode::new_root(data.green.clone()); + + let Some(token) = root.token_at_offset(offset).right_biased() else { return Vec::new() }; + + let mut results = Vec::new(); + for environment in token + .parent_ancestors() + .filter_map(latex::Environment::cast) + { + let Some(name) = environment + .begin() + .and_then(|begin| begin.name()) + .and_then(|group| group.key()) + .map(|name| Span::from(&name)) else { continue }; + + let full_range = latex::small_range(&environment); + results.push(EnvironmentMatch { name, full_range }); + } + + results.reverse(); + results +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + use test_utils::fixture::Fixture; + + use crate::find_environments; + + #[test] + fn test() { + let fixture = Fixture::parse( + r#" +%! main.tex +\begin{a} + \begin{b} + \begin{c} + | + \end{c} + \end{b} + \begin{d} + \end{d} +\end{a}"#, + ); + + let workspace = fixture.workspace; + let document = workspace.iter().next().unwrap(); + let results = find_environments(&document, fixture.documents[0].cursor.unwrap()); + assert_debug_snapshot!(results); + } +} |