diff options
Diffstat (limited to 'support/texlab/src/folding')
-rw-r--r-- | support/texlab/src/folding/bibtex_decl.rs | 159 | ||||
-rw-r--r-- | support/texlab/src/folding/bibtex_declaration.rs | 160 | ||||
-rw-r--r-- | support/texlab/src/folding/latex_env.rs | 80 | ||||
-rw-r--r-- | support/texlab/src/folding/latex_environment.rs | 74 | ||||
-rw-r--r-- | support/texlab/src/folding/latex_section.rs | 145 | ||||
-rw-r--r-- | support/texlab/src/folding/mod.rs | 28 |
6 files changed, 331 insertions, 315 deletions
diff --git a/support/texlab/src/folding/bibtex_decl.rs b/support/texlab/src/folding/bibtex_decl.rs new file mode 100644 index 0000000000..f0ffa787e1 --- /dev/null +++ b/support/texlab/src/folding/bibtex_decl.rs @@ -0,0 +1,159 @@ +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{FoldingRange, FoldingRangeKind, FoldingRangeParams}, + syntax::{bibtex, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; +use petgraph::graph::NodeIndex; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] +pub struct BibtexDeclarationFoldingProvider; + +#[async_trait] +impl FeatureProvider for BibtexDeclarationFoldingProvider { + type Params = FoldingRangeParams; + type Output = Vec<FoldingRange>; + + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + if let DocumentContent::Bibtex(tree) = &req.current().content { + tree.children(tree.root) + .filter_map(|decl| Self::fold(tree, decl)) + .collect() + } else { + Vec::new() + } + } +} + +impl BibtexDeclarationFoldingProvider { + fn fold(tree: &bibtex::Tree, decl: NodeIndex) -> Option<FoldingRange> { + let (ty, right) = match &tree.graph[decl] { + bibtex::Node::Preamble(preamble) => (Some(&preamble.ty), preamble.right.as_ref()), + bibtex::Node::String(string) => (Some(&string.ty), string.right.as_ref()), + bibtex::Node::Entry(entry) => (Some(&entry.ty), entry.right.as_ref()), + bibtex::Node::Root(_) + | bibtex::Node::Comment(_) + | bibtex::Node::Field(_) + | bibtex::Node::Word(_) + | bibtex::Node::Command(_) + | bibtex::Node::QuotedContent(_) + | bibtex::Node::BracedContent(_) + | bibtex::Node::Concat(_) => (None, None), + }; + + Some(FoldingRange { + start_line: ty?.start().line, + start_character: Some(ty?.start().character), + end_line: right?.end().line, + end_character: Some(right?.end().character), + kind: Some(FoldingRangeKind::Region), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::feature::FeatureTester; + use indoc::indoc; + + #[tokio::test] + async fn preamble() { + let actual_foldings = FeatureTester::new() + .file("main.bib", r#"@preamble{"foo"}"#) + .main("main.bib") + .test_folding(BibtexDeclarationFoldingProvider) + .await; + + let expected_foldings = vec![FoldingRange { + start_line: 0, + start_character: Some(0), + end_line: 0, + end_character: Some(16), + kind: Some(FoldingRangeKind::Region), + }]; + + assert_eq!(actual_foldings, expected_foldings); + } + + #[tokio::test] + async fn string() { + let actual_foldings = FeatureTester::new() + .file("main.bib", r#"@string{foo = "bar"}"#) + .main("main.bib") + .test_folding(BibtexDeclarationFoldingProvider) + .await; + + let expected_foldings = vec![FoldingRange { + start_line: 0, + start_character: Some(0), + end_line: 0, + end_character: Some(20), + kind: Some(FoldingRangeKind::Region), + }]; + + assert_eq!(actual_foldings, expected_foldings); + } + + #[tokio::test] + async fn entry() { + let actual_foldings = FeatureTester::new() + .file( + "main.bib", + indoc!( + r#" + @article{foo, + bar = baz + } + "# + ), + ) + .main("main.bib") + .test_folding(BibtexDeclarationFoldingProvider) + .await; + + let expected_foldings = vec![FoldingRange { + start_line: 0, + start_character: Some(0), + end_line: 2, + end_character: Some(1), + kind: Some(FoldingRangeKind::Region), + }]; + + assert_eq!(actual_foldings, expected_foldings); + } + + #[tokio::test] + async fn comment() { + let actual_foldings = FeatureTester::new() + .file("main.bib", "foo") + .main("main.bib") + .test_folding(BibtexDeclarationFoldingProvider) + .await; + + assert!(actual_foldings.is_empty()); + } + + #[tokio::test] + async fn entry_invalid() { + let actual_foldings = FeatureTester::new() + .file("main.bib", "@article{foo,") + .main("main.bib") + .test_folding(BibtexDeclarationFoldingProvider) + .await; + + assert!(actual_foldings.is_empty()); + } + + #[tokio::test] + async fn latex() { + let actual_foldings = FeatureTester::new() + .file("main.tex", "foo") + .main("main.tex") + .test_folding(BibtexDeclarationFoldingProvider) + .await; + + assert!(actual_foldings.is_empty()); + } +} diff --git a/support/texlab/src/folding/bibtex_declaration.rs b/support/texlab/src/folding/bibtex_declaration.rs deleted file mode 100644 index cea17daa7d..0000000000 --- a/support/texlab/src/folding/bibtex_declaration.rs +++ /dev/null @@ -1,160 +0,0 @@ -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{FoldingRange, FoldingRangeKind, FoldingRangeParams}; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct BibtexDeclarationFoldingProvider; - -impl FeatureProvider for BibtexDeclarationFoldingProvider { - type Params = FoldingRangeParams; - type Output = Vec<FoldingRange>; - - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<FoldingRangeParams>, - ) -> Vec<FoldingRange> { - if let SyntaxTree::Bibtex(tree) = &request.document().tree { - tree.root.children.iter().flat_map(Self::fold).collect() - } else { - Vec::new() - } - } -} - -impl BibtexDeclarationFoldingProvider { - fn fold(declaration: &BibtexDeclaration) -> Option<FoldingRange> { - let ty = match declaration { - BibtexDeclaration::Comment(_) => None, - BibtexDeclaration::Preamble(preamble) => Some(&preamble.ty), - BibtexDeclaration::String(string) => Some(&string.ty), - BibtexDeclaration::Entry(entry) => Some(&entry.ty), - }?; - - let right = match declaration { - BibtexDeclaration::Comment(_) => None, - BibtexDeclaration::Preamble(preamble) => preamble.right.as_ref(), - BibtexDeclaration::String(string) => string.right.as_ref(), - BibtexDeclaration::Entry(entry) => entry.right.as_ref(), - }?; - - Some(FoldingRange { - start_line: ty.range().start.line, - start_character: Some(ty.range().start.character), - end_line: right.range().start.line, - end_character: Some(right.range().start.character), - kind: Some(FoldingRangeKind::Region), - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_preamble() { - let foldings = test_feature( - BibtexDeclarationFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "\n@preamble{\"foo\"}")], - main_file: "foo.bib", - ..FeatureSpec::default() - }, - ); - assert_eq!( - foldings, - vec![FoldingRange { - start_line: 1, - start_character: Some(0), - end_line: 1, - end_character: Some(15), - kind: Some(FoldingRangeKind::Region), - }] - ); - } - - #[test] - fn test_string() { - let foldings = test_feature( - BibtexDeclarationFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "@string{foo = \"bar\"}")], - main_file: "foo.bib", - ..FeatureSpec::default() - }, - ); - assert_eq!( - foldings, - vec![FoldingRange { - start_line: 0, - start_character: Some(0), - end_line: 0, - end_character: Some(19), - kind: Some(FoldingRangeKind::Region), - }] - ); - } - - #[test] - fn test_entry() { - let foldings = test_feature( - BibtexDeclarationFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "@article{foo, bar = baz\n}")], - main_file: "foo.bib", - ..FeatureSpec::default() - }, - ); - assert_eq!( - foldings, - vec![FoldingRange { - start_line: 0, - start_character: Some(0), - end_line: 1, - end_character: Some(0), - kind: Some(FoldingRangeKind::Region), - }] - ); - } - - #[test] - fn test_comment() { - let foldings = test_feature( - BibtexDeclarationFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "foo")], - main_file: "foo.bib", - ..FeatureSpec::default() - }, - ); - assert!(foldings.is_empty()); - } - - #[test] - fn test_entry_invalid() { - let foldings = test_feature( - BibtexDeclarationFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "@article{foo,")], - main_file: "foo.bib", - ..FeatureSpec::default() - }, - ); - assert!(foldings.is_empty()); - } - - #[test] - fn test_latex() { - let foldings = test_feature( - BibtexDeclarationFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "")], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert!(foldings.is_empty()); - } -} diff --git a/support/texlab/src/folding/latex_env.rs b/support/texlab/src/folding/latex_env.rs new file mode 100644 index 0000000000..ced2567b41 --- /dev/null +++ b/support/texlab/src/folding/latex_env.rs @@ -0,0 +1,80 @@ +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{FoldingRange, FoldingRangeKind, FoldingRangeParams}, + syntax::SyntaxNode, + workspace::DocumentContent, +}; +use async_trait::async_trait; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] +pub struct LatexEnvironmentFoldingProvider; + +#[async_trait] +impl FeatureProvider for LatexEnvironmentFoldingProvider { + type Params = FoldingRangeParams; + type Output = Vec<FoldingRange>; + + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + let mut foldings = Vec::new(); + if let DocumentContent::Latex(table) = &req.current().content { + for env in &table.environments { + let left_node = &table[env.left.parent]; + let right_node = &table[env.right.parent]; + let folding = FoldingRange { + start_line: left_node.end().line, + start_character: Some(left_node.end().character), + end_line: right_node.start().line, + end_character: Some(right_node.start().character), + kind: Some(FoldingRangeKind::Region), + }; + foldings.push(folding); + } + } + foldings + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::feature::FeatureTester; + use indoc::indoc; + + #[tokio::test] + async fn multiline() { + let actual_foldings = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \begin{foo} + \end{foo} + "# + ), + ) + .main("main.tex") + .test_folding(LatexEnvironmentFoldingProvider) + .await; + + let expected_foldings = vec![FoldingRange { + start_line: 0, + start_character: Some(11), + end_line: 1, + end_character: Some(0), + kind: Some(FoldingRangeKind::Region), + }]; + + assert_eq!(actual_foldings, expected_foldings); + } + + #[tokio::test] + async fn bibtex() { + let actual_foldings = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .test_folding(LatexEnvironmentFoldingProvider) + .await; + + assert!(actual_foldings.is_empty()); + } +} diff --git a/support/texlab/src/folding/latex_environment.rs b/support/texlab/src/folding/latex_environment.rs deleted file mode 100644 index 853ece7a09..0000000000 --- a/support/texlab/src/folding/latex_environment.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{FoldingRange, FoldingRangeKind, FoldingRangeParams}; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct LatexEnvironmentFoldingProvider; - -impl FeatureProvider for LatexEnvironmentFoldingProvider { - type Params = FoldingRangeParams; - type Output = Vec<FoldingRange>; - - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<FoldingRangeParams>, - ) -> Vec<FoldingRange> { - let mut foldings = Vec::new(); - if let SyntaxTree::Latex(tree) = &request.document().tree { - for environment in &tree.env.environments { - let start = environment.left.command.end(); - let end = environment.right.command.start(); - foldings.push(FoldingRange { - start_line: start.line, - start_character: Some(start.character), - end_line: end.line, - end_character: Some(end.character), - kind: Some(FoldingRangeKind::Region), - }) - } - } - foldings - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_multiline() { - let foldings = test_feature( - LatexEnvironmentFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\begin{foo}\n\\end{foo}")], - main_file: "foo.tex", - ..FeatureSpec::default() - }, - ); - assert_eq!( - foldings, - vec![FoldingRange { - start_line: 0, - start_character: Some(11), - end_line: 1, - end_character: Some(0), - kind: Some(FoldingRangeKind::Region), - }] - ); - } - - #[test] - fn test_bibtex() { - let foldings = test_feature( - LatexEnvironmentFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "@article{foo, bar = baz}")], - main_file: "foo.bib", - ..FeatureSpec::default() - }, - ); - assert!(foldings.is_empty()); - } -} diff --git a/support/texlab/src/folding/latex_section.rs b/support/texlab/src/folding/latex_section.rs index ca7b8387be..a37efe1a7a 100644 --- a/support/texlab/src/folding/latex_section.rs +++ b/support/texlab/src/folding/latex_section.rs @@ -1,36 +1,37 @@ -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{FoldingRange, FoldingRangeKind, FoldingRangeParams}; +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{FoldingRange, FoldingRangeKind, FoldingRangeParams}, + syntax::SyntaxNode, + workspace::DocumentContent, +}; +use async_trait::async_trait; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct LatexSectionFoldingProvider; +#[async_trait] impl FeatureProvider for LatexSectionFoldingProvider { type Params = FoldingRangeParams; type Output = Vec<FoldingRange>; - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<FoldingRangeParams>, - ) -> Vec<FoldingRange> { + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { let mut foldings = Vec::new(); - if let SyntaxTree::Latex(tree) = &request.document().tree { - let sections = &tree.structure.sections; + if let DocumentContent::Latex(table) = &req.current().content { + let sections = &table.sections; for i in 0..sections.len() { let current = §ions[i]; - let next = sections + if let Some(next) = sections .iter() .skip(i + 1) - .find(|sec| current.level >= sec.level); - - if let Some(next) = next { - if next.command.start().line > 0 { + .find(|sec| current.level >= sec.level) + { + let next_node = &table[next.parent]; + if next_node.start().line > 0 { + let current_node = &table[current.parent]; let folding = FoldingRange { - start_line: current.command.end().line, - start_character: Some(current.command.end().character), - end_line: next.command.start().line - 1, + start_line: current_node.end().line, + start_character: Some(current_node.end().character), + end_line: next_node.start().line - 1, end_character: Some(0), kind: Some(FoldingRangeKind::Region), }; @@ -46,55 +47,65 @@ impl FeatureProvider for LatexSectionFoldingProvider { #[cfg(test)] mod tests { use super::*; + use crate::feature::FeatureTester; + use indoc::indoc; - #[test] - fn test_nesting() { - let foldings = test_feature( - LatexSectionFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\section{Foo}\nfoo\n\\subsection{Bar}\nbar\n\\section{Baz}\nbaz\n\\section{Qux}")], - main_file: "foo.tex", - ..FeatureSpec::default() - } - ); - assert_eq!( - foldings, - vec![ - FoldingRange { - start_line: 0, - start_character: Some(13), - end_line: 3, - end_character: Some(0), - kind: Some(FoldingRangeKind::Region), - }, - FoldingRange { - start_line: 2, - start_character: Some(16), - end_line: 3, - end_character: Some(0), - kind: Some(FoldingRangeKind::Region), - }, - FoldingRange { - start_line: 4, - start_character: Some(13), - end_line: 5, - end_character: Some(0), - kind: Some(FoldingRangeKind::Region), - } - ] - ); - } + #[tokio::test] + async fn nested() { + let actual_foldings = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \section{Foo} + foo + \subsection{Bar} + bar + \section{Baz} + baz + \section{Qux} + "# + ), + ) + .main("main.tex") + .test_folding(LatexSectionFoldingProvider) + .await; - #[test] - fn test_bibtex() { - let foldings = test_feature( - LatexSectionFoldingProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "@article{foo, bar = baz}")], - main_file: "foo.bib", - ..FeatureSpec::default() + let expected_foldings = vec![ + FoldingRange { + start_line: 0, + start_character: Some(13), + end_line: 3, + end_character: Some(0), + kind: Some(FoldingRangeKind::Region), + }, + FoldingRange { + start_line: 2, + start_character: Some(16), + end_line: 3, + end_character: Some(0), + kind: Some(FoldingRangeKind::Region), }, - ); - assert!(foldings.is_empty()); + FoldingRange { + start_line: 4, + start_character: Some(13), + end_line: 5, + end_character: Some(0), + kind: Some(FoldingRangeKind::Region), + }, + ]; + + assert_eq!(actual_foldings, expected_foldings); + } + + #[tokio::test] + async fn bibtex() { + let actual_foldings = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .test_folding(LatexSectionFoldingProvider) + .await; + + assert!(actual_foldings.is_empty()); } } diff --git a/support/texlab/src/folding/mod.rs b/support/texlab/src/folding/mod.rs index 52c8149a31..448e3d26fc 100644 --- a/support/texlab/src/folding/mod.rs +++ b/support/texlab/src/folding/mod.rs @@ -1,13 +1,16 @@ -mod bibtex_declaration; -mod latex_environment; +mod bibtex_decl; +mod latex_env; mod latex_section; -use self::bibtex_declaration::BibtexDeclarationFoldingProvider; -use self::latex_environment::LatexEnvironmentFoldingProvider; -use self::latex_section::LatexSectionFoldingProvider; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{FoldingRange, FoldingRangeParams}; +use self::{ + bibtex_decl::BibtexDeclarationFoldingProvider, latex_env::LatexEnvironmentFoldingProvider, + latex_section::LatexSectionFoldingProvider, +}; +use crate::{ + feature::{ConcatProvider, FeatureProvider, FeatureRequest}, + protocol::{FoldingRange, FoldingRangeParams}, +}; +use async_trait::async_trait; pub struct FoldingProvider { provider: ConcatProvider<FoldingRangeParams, FoldingRange>, @@ -31,15 +34,12 @@ impl Default for FoldingProvider { } } +#[async_trait] impl FeatureProvider for FoldingProvider { type Params = FoldingRangeParams; type Output = Vec<FoldingRange>; - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<FoldingRangeParams>, - ) -> Vec<FoldingRange> { - self.provider.execute(request).await + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + self.provider.execute(req).await } } |