summaryrefslogtreecommitdiff
path: root/support/texlab/src/folding
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/folding')
-rw-r--r--support/texlab/src/folding/bibtex_decl.rs159
-rw-r--r--support/texlab/src/folding/bibtex_declaration.rs160
-rw-r--r--support/texlab/src/folding/latex_env.rs80
-rw-r--r--support/texlab/src/folding/latex_environment.rs74
-rw-r--r--support/texlab/src/folding/latex_section.rs145
-rw-r--r--support/texlab/src/folding/mod.rs28
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 = &sections[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
}
}