From 745892fbddea56040139108277e728b53fd8fc11 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 28 May 2020 03:03:21 +0000 Subject: CTAN sync 202005280303 --- support/texlab/src/symbol/latex_section/mod.rs | 781 +++++++++++++------------ 1 file changed, 409 insertions(+), 372 deletions(-) (limited to 'support/texlab/src/symbol/latex_section/mod.rs') diff --git a/support/texlab/src/symbol/latex_section/mod.rs b/support/texlab/src/symbol/latex_section/mod.rs index f6fe2aede9..fc81695b50 100644 --- a/support/texlab/src/symbol/latex_section/mod.rs +++ b/support/texlab/src/symbol/latex_section/mod.rs @@ -3,38 +3,57 @@ mod equation; mod float; mod theorem; -use super::{LatexSymbol, LatexSymbolKind}; -use crate::range::RangeExt; -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::*; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +use super::types::{LatexSymbol, LatexSymbolKind}; +use crate::{ + feature::{DocumentView, FeatureProvider, FeatureRequest}, + outline::{Outline, OutlineContext, OutlineContextItem}, + protocol::{DocumentSymbolParams, Options, Position, Range, RangeExt}, + syntax::{latex, CharStream, LatexLabelKind, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; +use std::path::Path; + +fn label_name(table: &latex::SymbolTable, label: Option<&latex::Label>) -> Option { + label.map(|label| label.names(&table)[0].text().to_owned()) +} + +fn selection_range( + table: &latex::SymbolTable, + full_range: Range, + label: Option<&latex::Label>, +) -> Range { + label + .map(|label| table[label.parent].range()) + .unwrap_or(full_range) +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct LatexSectionSymbolProvider; +#[async_trait] impl FeatureProvider for LatexSectionSymbolProvider { type Params = DocumentSymbolParams; type Output = Vec; - #[boxed] - async fn execute<'a>(&'a self, request: &'a FeatureRequest) -> Self::Output { + async fn execute<'a>(&'a self, req: &'a FeatureRequest) -> Self::Output { let mut symbols = Vec::new(); - if let SyntaxTree::Latex(tree) = &request.document().tree { - let mut section_tree = build_section_tree(&request.view, tree); - for symbol in enumeration::symbols(&request.view, tree) { + if let DocumentContent::Latex(table) = &req.current().content { + let mut section_tree = + build_section_tree(&req.view, table, &req.options, &req.current_dir); + for symbol in enumeration::symbols(&req.view, table) { section_tree.insert_symbol(&symbol); } - for symbol in equation::symbols(&request.view, tree) { + for symbol in equation::symbols(&req.view, table) { section_tree.insert_symbol(&symbol); } - for symbol in float::symbols(&request.view, tree) { + for symbol in float::symbols(&req.view, table) { section_tree.insert_symbol(&symbol); } - for symbol in theorem::symbols(&request.view, tree) { + for symbol in theorem::symbols(&req.view, table) { section_tree.insert_symbol(&symbol); } @@ -52,33 +71,36 @@ impl FeatureProvider for LatexSectionSymbolProvider { pub fn build_section_tree<'a>( view: &'a DocumentView, - tree: &'a LatexSyntaxTree, + table: &'a latex::SymbolTable, + options: &'a Options, + current_dir: &'a Path, ) -> LatexSectionTree<'a> { - let mut section_tree = LatexSectionTree::from(tree); - section_tree.set_full_text(&view.document.text); - let end_position = compute_end_position(tree, &view.document.text); - LatexSectionNode::set_full_range(&mut section_tree.children, end_position); - let outline = Outline::from(view); + let mut section_tree = LatexSectionTree::from(table); + section_tree.set_full_text(&view.current.text); + let end_position = compute_end_position(table, &view.current.text); + LatexSectionNode::set_full_range(&mut section_tree.children, table, end_position); + let outline = Outline::analyze(view, options, current_dir); for child in &mut section_tree.children { - child.set_label(tree, view, &outline); + child.set_label(view, &outline); } section_tree } -fn compute_end_position(tree: &LatexSyntaxTree, text: &str) -> Position { +fn compute_end_position(table: &latex::SymbolTable, text: &str) -> Position { let mut stream = CharStream::new(text); while stream.next().is_some() {} - tree.env + table .environments .iter() - .find(|env| env.left.name().map(LatexToken::text) == Some("document")) - .map(|env| env.right.start()) + .find(|env| env.left.name(&table).map(latex::Token::text) == Some("document")) + .map(|env| table[env.right.parent].start()) .unwrap_or(stream.current_position) } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, Clone)] pub struct LatexSectionNode<'a> { - pub section: &'a LatexSection, + pub table: &'a latex::SymbolTable, + pub section: &'a latex::Section, pub full_range: Range, full_text: &'a str, label: Option, @@ -88,8 +110,9 @@ pub struct LatexSectionNode<'a> { } impl<'a> LatexSectionNode<'a> { - fn new(section: &'a LatexSection) -> Self { + fn new(table: &'a latex::SymbolTable, section: &'a latex::Section) -> Self { Self { + table, section, full_range: Range::default(), full_text: "", @@ -108,37 +131,45 @@ impl<'a> LatexSectionNode<'a> { } fn name(&self) -> String { - self.section - .extract_text(self.full_text) - .unwrap_or_else(|| "Unknown".to_owned()) + self.table + .print_group_content( + self.section.parent, + latex::GroupKind::Group, + self.section.arg_index, + ) + .unwrap_or_else(|| "Unknown".into()) } - fn set_full_range(children: &mut Vec, end_position: Position) { + fn set_full_range( + children: &mut Vec, + table: &latex::SymbolTable, + end_position: Position, + ) { for i in 0..children.len() { let current_end = children .get(i + 1) - .map(|next| next.section.start()) + .map(|next| table[next.section.parent].start()) .unwrap_or(end_position); let mut current = &mut children[i]; - current.full_range = Range::new(current.section.start(), current_end); - Self::set_full_range(&mut current.children, current_end); + current.full_range = Range::new(table[current.section.parent].start(), current_end); + Self::set_full_range(&mut current.children, table, current_end); } } - fn set_label(&mut self, tree: &LatexSyntaxTree, view: &DocumentView, outline: &Outline) { - if let Some(label) = tree - .structure + fn set_label(&mut self, view: &DocumentView, outline: &Outline) { + if let Some(label) = self + .table .labels .iter() .filter(|label| label.kind == LatexLabelKind::Definition) - .find(|label| self.full_range.contains(label.start())) + .find(|label| self.full_range.contains(self.table[label.parent].start())) { - if let Some(ctx) = OutlineContext::parse(view, label, outline) { + if let Some(ctx) = OutlineContext::parse(view, outline, *label) { let mut is_section = false; if let OutlineContextItem::Section { text, .. } = &ctx.item { if self.name() == *text { - for name in label.names() { + for name in label.names(&self.table) { self.label = Some(name.text().to_owned()); } @@ -153,21 +184,25 @@ impl<'a> LatexSectionNode<'a> { } for child in &mut self.children { - child.set_label(tree, view, outline); + child.set_label(view, outline); } } - fn insert_section(nodes: &mut Vec, section: &'a LatexSection) { + fn insert_section( + nodes: &mut Vec, + table: &'a latex::SymbolTable, + section: &'a latex::Section, + ) { match nodes.last_mut() { Some(parent) => { if parent.section.level < section.level { - Self::insert_section(&mut parent.children, section); + Self::insert_section(&mut parent.children, table, section); } else { - nodes.push(LatexSectionNode::new(section)); + nodes.push(LatexSectionNode::new(table, section)); } } None => { - nodes.push(LatexSectionNode::new(section)); + nodes.push(LatexSectionNode::new(table, section)); } } } @@ -223,13 +258,13 @@ impl<'a> Into for LatexSectionNode<'a> { kind: LatexSymbolKind::Section, deprecated: false, full_range: self.full_range, - selection_range: self.section.range(), + selection_range: self.table[self.section.parent].range(), children, } } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, Clone)] pub struct LatexSectionTree<'a> { symbols: Vec, children: Vec>, @@ -269,366 +304,368 @@ impl<'a> LatexSectionTree<'a> { } } -impl<'a> From<&'a LatexSyntaxTree> for LatexSectionTree<'a> { - fn from(tree: &'a LatexSyntaxTree) -> Self { +impl<'a> From<&'a latex::SymbolTable> for LatexSectionTree<'a> { + fn from(table: &'a latex::SymbolTable) -> Self { let mut root = Self::new(); - for section in &tree.structure.sections { - LatexSectionNode::insert_section(&mut root.children, section); + for section in &table.sections { + LatexSectionNode::insert_section(&mut root.children, table, section); } root } } -pub fn label_name(label: Option<&LatexLabel>) -> Option { - label.map(|label| label.names()[0].text().to_owned()) -} - -pub fn selection_range(full_range: Range, label: Option<&LatexLabel>) -> Range { - label.map(|label| label.range()).unwrap_or(full_range) -} - #[cfg(test)] mod tests { use super::*; - use crate::range::RangeExt; - - #[test] - fn test_subsection() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file( - "foo.tex", - "\\section{Foo}\n\\subsection{Bar}\\label{sec:bar}\n\\subsection{Baz}\n\\section{Qux}", - ), - FeatureSpec::file( - "foo.aux", - "\\newlabel{sec:bar}{{\\relax 2.1}{4}{Bar\\relax }{figure.caption.4}{}}" - ), - ], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![ - LatexSymbol { - name: "Foo".into(), - label: None, - kind: LatexSymbolKind::Section, - deprecated: false, - full_range: Range::new_simple(0, 0, 3, 0), - selection_range: Range::new_simple(0, 0, 0, 13), - children: vec![ - LatexSymbol { - name: "2.1 Bar".into(), - label: Some("sec:bar".into()), - kind: LatexSymbolKind::Section, - deprecated: false, - full_range: Range::new_simple(1, 0, 2, 0), - selection_range: Range::new_simple(1, 0, 1, 16), - children: Vec::new(), - }, - LatexSymbol { - name: "Baz".into(), - label: None, - kind: LatexSymbolKind::Section, - deprecated: false, - full_range: Range::new_simple(2, 0, 3, 0), - selection_range: Range::new_simple(2, 0, 2, 16), - children: Vec::new(), - }, - ], - }, - LatexSymbol { - name: "Qux".into(), - label: None, - kind: LatexSymbolKind::Section, - deprecated: false, - full_range: Range::new_simple(3, 0, 3, 13), - selection_range: Range::new_simple(3, 0, 3, 13), - children: Vec::new(), - } - ] - ); + use crate::feature::FeatureTester; + use indoc::indoc; + + #[tokio::test] + async fn empty_latex_document() { + let actual_symbols = FeatureTester::new() + .file("main.tex", "") + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + assert!(actual_symbols.is_empty()); } - #[test] - fn test_section_inside_document_environment() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\begin{document}\\section{Foo}\\relax\n\\end{document}", - )], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { + #[tokio::test] + async fn empty_bibtex_document() { + let actual_symbols = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .test_symbol(LatexSectionSymbolProvider) + .await; + + assert!(actual_symbols.is_empty()); + } + + #[tokio::test] + async fn subsection() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \section{Foo} + \subsection{Bar}\label{sec:bar} + \subsection{Baz} + \section{Qux} + "# + ), + ) + .file( + "main.aux", + r#"\newlabel{sec:bar}{{\relax 2.1}{4}{Bar\relax }{figure.caption.4}{}}"#, + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![ + LatexSymbol { name: "Foo".into(), label: None, kind: LatexSymbolKind::Section, deprecated: false, - full_range: Range::new_simple(0, 16, 1, 0), - selection_range: Range::new_simple(0, 16, 0, 29), - children: Vec::new() - }] - ); - } - - #[test] - fn test_enumeration() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\section{Foo}\n\\begin{enumerate}\n\\end{enumerate}", - )], - main_file: "foo.tex", - ..FeatureSpec::default() + full_range: Range::new_simple(0, 0, 3, 0), + selection_range: Range::new_simple(0, 0, 0, 13), + children: vec![ + LatexSymbol { + name: "2.1 Bar".into(), + label: Some("sec:bar".into()), + kind: LatexSymbolKind::Section, + deprecated: false, + full_range: Range::new_simple(1, 0, 2, 0), + selection_range: Range::new_simple(1, 0, 1, 16), + children: Vec::new(), + }, + LatexSymbol { + name: "Baz".into(), + label: None, + kind: LatexSymbolKind::Section, + deprecated: false, + full_range: Range::new_simple(2, 0, 3, 0), + selection_range: Range::new_simple(2, 0, 2, 16), + children: Vec::new(), + }, + ], }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Foo".into(), + LatexSymbol { + name: "Qux".into(), label: None, kind: LatexSymbolKind::Section, deprecated: false, - full_range: Range::new_simple(0, 0, 2, 15), - selection_range: Range::new_simple(0, 0, 0, 13), - children: vec![LatexSymbol { - name: "Enumerate".into(), - label: None, - kind: LatexSymbolKind::Enumeration, - deprecated: false, - full_range: Range::new_simple(1, 0, 2, 15), - selection_range: Range::new_simple(1, 0, 2, 15), - children: Vec::new(), - },], - },] - ); + full_range: Range::new_simple(3, 0, 3, 13), + selection_range: Range::new_simple(3, 0, 3, 13), + children: Vec::new(), + }, + ]; + + assert_eq!(actual_symbols, expected_symbols); } - #[test] - fn test_equation() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\[Foo\\]\n\\begin{equation}\\label{eq:foo}\\end{equation}", - )], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![ - LatexSymbol { - name: "Equation".into(), - label: None, - kind: LatexSymbolKind::Equation, - deprecated: false, - full_range: Range::new_simple(0, 0, 0, 7), - selection_range: Range::new_simple(0, 0, 0, 7), - children: Vec::new(), - }, - LatexSymbol { - name: "Equation".into(), - label: Some("eq:foo".into()), - kind: LatexSymbolKind::Equation, - deprecated: false, - full_range: Range::new_simple(1, 0, 1, 44), - selection_range: Range::new_simple(1, 16, 1, 30), - children: Vec::new(), - }, - ] - ); + #[tokio::test] + async fn section_inside_document_environment() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \begin{document}\section{Foo}\relax + \end{document} + "# + ), + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Foo".into(), + label: None, + kind: LatexSymbolKind::Section, + deprecated: false, + full_range: Range::new_simple(0, 16, 1, 0), + selection_range: Range::new_simple(0, 16, 0, 29), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); } - #[test] - fn test_equation_number() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file("foo.tex", "\\[\\label{eq:foo}\\]"), - FeatureSpec::file( - "foo.aux", - "\\newlabel{eq:foo}{{\\relax 2.1}{4}{Bar\\relax }{figure.caption.4}{}}", - ), - ], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Equation (2.1)".into(), - label: Some("eq:foo".into()), - kind: LatexSymbolKind::Equation, + #[tokio::test] + async fn enumeration() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \section{Foo} + \begin{enumerate} + \end{enumerate} + "# + ), + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Foo".into(), + label: None, + kind: LatexSymbolKind::Section, + deprecated: false, + full_range: Range::new_simple(0, 0, 2, 15), + selection_range: Range::new_simple(0, 0, 0, 13), + children: vec![LatexSymbol { + name: "Enumerate".into(), + label: None, + kind: LatexSymbolKind::Enumeration, deprecated: false, - full_range: Range::new_simple(0, 0, 0, 18), - selection_range: Range::new_simple(0, 2, 0, 16), + full_range: Range::new_simple(1, 0, 2, 15), + selection_range: Range::new_simple(1, 0, 2, 15), children: Vec::new(), - },] - ); + }], + }]; + + assert_eq!(actual_symbols, expected_symbols); } - #[test] - fn test_table() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\begin{table}\\caption{Foo}\\end{table}", - )], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Table: Foo".into(), + #[tokio::test] + async fn equation() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \[Foo\] + \begin{equation}\label{eq:foo}\end{equation} + "# + ), + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![ + LatexSymbol { + name: "Equation".into(), label: None, - kind: LatexSymbolKind::Table, + kind: LatexSymbolKind::Equation, deprecated: false, - full_range: Range::new_simple(0, 0, 0, 37), - selection_range: Range::new_simple(0, 0, 0, 37), + full_range: Range::new_simple(0, 0, 0, 7), + selection_range: Range::new_simple(0, 0, 0, 7), children: Vec::new(), - },] - ); - } - - #[test] - fn test_figure_number() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file( - "foo.tex", - "\\begin{figure}\\caption{Foo}\\label{fig:foo}\\end{figure}", - ), - FeatureSpec::file( - "foo.aux", - "\\newlabel{fig:foo}{{\\relax 2.1}{4}{Bar\\relax }{figure.caption.4}{}}", - ), - ], - main_file: "foo.tex", - ..FeatureSpec::default() }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Figure 2.1: Foo".into(), - label: Some("fig:foo".into()), - kind: LatexSymbolKind::Figure, + LatexSymbol { + name: "Equation".into(), + label: Some("eq:foo".into()), + kind: LatexSymbolKind::Equation, deprecated: false, - full_range: Range::new_simple(0, 0, 0, 54), - selection_range: Range::new_simple(0, 27, 0, 42), + full_range: Range::new_simple(1, 0, 1, 44), + selection_range: Range::new_simple(1, 16, 1, 30), children: Vec::new(), - },] - ); + }, + ]; + + assert_eq!(actual_symbols, expected_symbols); } - #[test] - fn test_lemma() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\newtheorem{lemma}{Lemma}\\begin{lemma}\\end{lemma}", - )], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Lemma".into(), - label: None, - kind: LatexSymbolKind::Theorem, - deprecated: false, - full_range: Range::new_simple(0, 25, 0, 49), - selection_range: Range::new_simple(0, 25, 0, 49), - children: Vec::new(), - },] - ); + #[tokio::test] + async fn equation_number() { + let actual_symbols = FeatureTester::new() + .file("main.tex", r#"\[\label{eq:foo}\]"#) + .file( + "main.aux", + r#"\newlabel{eq:foo}{{\relax 2.1}{4}{Bar\relax }{figure.caption.4}{}}"#, + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Equation (2.1)".into(), + label: Some("eq:foo".into()), + kind: LatexSymbolKind::Equation, + deprecated: false, + full_range: Range::new_simple(0, 0, 0, 18), + selection_range: Range::new_simple(0, 2, 0, 16), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); } - #[test] - fn test_lemma_number() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file( - "foo.tex", - "\\newtheorem{lemma}{Lemma}\n\\begin{lemma}\\label{thm:foo}\\end{lemma}", - ), - FeatureSpec::file( - "foo.aux", - "\\newlabel{thm:foo}{{\\relax 2.1}{4}{Bar\\relax }{figure.caption.4}{}}", - ), - ], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Lemma 2.1".into(), - label: Some("thm:foo".into()), - kind: LatexSymbolKind::Theorem, - deprecated: false, - full_range: Range::new_simple(1, 0, 1, 39), - selection_range: Range::new_simple(1, 13, 1, 28), - children: Vec::new(), - },] - ); + #[tokio::test] + async fn table() { + let actual_symbols = FeatureTester::new() + .file("main.tex", r#"\begin{table}\caption{Foo}\end{table}"#) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Table: Foo".into(), + label: None, + kind: LatexSymbolKind::Table, + deprecated: false, + full_range: Range::new_simple(0, 0, 0, 37), + selection_range: Range::new_simple(0, 0, 0, 37), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); } - #[test] - fn test_lemma_description() { - let symbols = test_feature( - LatexSectionSymbolProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\newtheorem{lemma}{Lemma}\\begin{lemma}[Foo]\\end{lemma}", - )], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - symbols, - vec![LatexSymbol { - name: "Lemma (Foo)".into(), - label: None, - kind: LatexSymbolKind::Theorem, - deprecated: false, - full_range: Range::new_simple(0, 25, 0, 54), - selection_range: Range::new_simple(0, 25, 0, 54), - children: Vec::new(), - },] - ); + #[tokio::test] + async fn figure_number() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + r#"\begin{figure}\caption{Foo}\label{fig:foo}\end{figure}"#, + ) + .file( + "main.aux", + r#"\newlabel{fig:foo}{{\relax 2.1}{4}{Bar\relax }{figure.caption.4}{}}"#, + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Figure 2.1: Foo".into(), + label: Some("fig:foo".into()), + kind: LatexSymbolKind::Figure, + deprecated: false, + full_range: Range::new_simple(0, 0, 0, 54), + selection_range: Range::new_simple(0, 27, 0, 42), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); + } + + #[tokio::test] + async fn lemma() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + r#"\newtheorem{lemma}{Lemma}\begin{lemma}\end{lemma}"#, + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Lemma".into(), + label: None, + kind: LatexSymbolKind::Theorem, + deprecated: false, + full_range: Range::new_simple(0, 25, 0, 49), + selection_range: Range::new_simple(0, 25, 0, 49), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); + } + + #[tokio::test] + async fn lemma_number() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \newtheorem{lemma}{Lemma} + \begin{lemma}\label{thm:foo}\end{lemma} + "# + ), + ) + .file( + "main.aux", + r#"\newlabel{thm:foo}{{\relax 2.1}{4}{Bar\relax }{figure.caption.4}{}}"#, + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Lemma 2.1".into(), + label: Some("thm:foo".into()), + kind: LatexSymbolKind::Theorem, + deprecated: false, + full_range: Range::new_simple(1, 0, 1, 39), + selection_range: Range::new_simple(1, 13, 1, 28), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); + } + + #[tokio::test] + async fn lemma_description() { + let actual_symbols = FeatureTester::new() + .file( + "main.tex", + r#"\newtheorem{lemma}{Lemma}\begin{lemma}[Foo]\end{lemma}"#, + ) + .main("main.tex") + .test_symbol(LatexSectionSymbolProvider) + .await; + + let expected_symbols = vec![LatexSymbol { + name: "Lemma (Foo)".into(), + label: None, + kind: LatexSymbolKind::Theorem, + deprecated: false, + full_range: Range::new_simple(0, 25, 0, 54), + selection_range: Range::new_simple(0, 25, 0, 54), + children: Vec::new(), + }]; + + assert_eq!(actual_symbols, expected_symbols); } } -- cgit v1.2.3