diff options
Diffstat (limited to 'support/texlab/src/link')
-rw-r--r-- | support/texlab/src/link/latex_import.rs | 99 | ||||
-rw-r--r-- | support/texlab/src/link/latex_include.rs | 137 | ||||
-rw-r--r-- | support/texlab/src/link/mod.rs | 25 |
3 files changed, 177 insertions, 84 deletions
diff --git a/support/texlab/src/link/latex_import.rs b/support/texlab/src/link/latex_import.rs new file mode 100644 index 0000000000..494a72b481 --- /dev/null +++ b/support/texlab/src/link/latex_import.rs @@ -0,0 +1,99 @@ +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{DocumentLink, DocumentLinkParams}, + syntax::{latex, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] +pub struct LatexImportLinkProvider; + +#[async_trait] +impl FeatureProvider for LatexImportLinkProvider { + type Params = DocumentLinkParams; + type Output = Vec<DocumentLink>; + + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + if let DocumentContent::Latex(table) = &req.current().content { + table + .imports + .iter() + .flat_map(|import| Self::resolve(req, table, import)) + .collect() + } else { + Vec::new() + } + } +} + +impl LatexImportLinkProvider { + fn resolve( + req: &FeatureRequest<DocumentLinkParams>, + table: &latex::SymbolTable, + import: &latex::Import, + ) -> Vec<DocumentLink> { + let mut links = Vec::new(); + let file = import.file(&table); + for target in &import.targets { + if let Some(link) = req.snapshot().find(target).map(|doc| DocumentLink { + range: file.range(), + target: doc.uri.clone().into(), + tooltip: None, + }) { + links.push(link); + break; + } + } + links + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + feature::FeatureTester, + protocol::{Range, RangeExt}, + }; + + #[tokio::test] + async fn empty_latex_document_command() { + let actual_links = FeatureTester::new() + .file("main.tex", "") + .main("main.tex") + .test_link(LatexImportLinkProvider) + .await; + + assert!(actual_links.is_empty()); + } + + #[tokio::test] + async fn empty_bibtex_document_command() { + let actual_links = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .test_link(LatexImportLinkProvider) + .await; + + assert!(actual_links.is_empty()); + } + + #[tokio::test] + async fn has_links() { + let actual_links = FeatureTester::new() + .file("foo.tex", r#"\import{bar/}{baz}"#) + .file("bar/baz.tex", r#""#) + .main("foo.tex") + .test_link(LatexImportLinkProvider) + .await; + + let expected_links = vec![DocumentLink { + range: Range::new_simple(0, 14, 0, 17), + target: FeatureTester::uri("bar/baz.tex").into(), + tooltip: None, + }]; + + assert_eq!(actual_links, expected_links); + } +} diff --git a/support/texlab/src/link/latex_include.rs b/support/texlab/src/link/latex_include.rs index 0cc6c36364..5f4f592f14 100644 --- a/support/texlab/src/link/latex_include.rs +++ b/support/texlab/src/link/latex_include.rs @@ -1,49 +1,49 @@ -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{DocumentLink, DocumentLinkParams}; +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{DocumentLink, DocumentLinkParams}, + syntax::{latex, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct LatexIncludeLinkProvider; +#[async_trait] impl FeatureProvider for LatexIncludeLinkProvider { type Params = DocumentLinkParams; type Output = Vec<DocumentLink>; - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<DocumentLinkParams>, - ) -> Vec<DocumentLink> { - if let SyntaxTree::Latex(tree) = &request.document().tree { - return tree + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + if let DocumentContent::Latex(table) = &req.current().content { + table .includes .iter() - .flat_map(|include| Self::resolve(request, include)) - .collect(); + .flat_map(|include| Self::resolve(req, table, include)) + .collect() + } else { + Vec::new() } - Vec::new() } } impl LatexIncludeLinkProvider { fn resolve( - request: &FeatureRequest<DocumentLinkParams>, - include: &LatexInclude, + req: &FeatureRequest<DocumentLinkParams>, + table: &latex::SymbolTable, + include: &latex::Include, ) -> Vec<DocumentLink> { let mut links = Vec::new(); - let paths = include.paths(); + let paths = include.paths(&table); for (i, targets) in include.all_targets.iter().enumerate() { for target in targets { - if let Some(link) = request - .workspace() - .find(target) - .map(|document| DocumentLink { - range: paths[i].range(), - target: document.uri.clone().into(), - }) - { + if let Some(link) = req.snapshot().find(target).map(|doc| DocumentLink { + range: paths[i].range(), + target: doc.uri.clone().into(), + tooltip: None, + }) { links.push(link); + break; } } } @@ -54,57 +54,48 @@ impl LatexIncludeLinkProvider { #[cfg(test)] mod tests { use super::*; - use crate::range::RangeExt; - use lsp_types::{Position, Range}; + use crate::{ + feature::FeatureTester, + protocol::{Range, RangeExt}, + }; + + #[tokio::test] + async fn empty_latex_document_command() { + let actual_links = FeatureTester::new() + .file("main.tex", "") + .main("main.tex") + .test_link(LatexIncludeLinkProvider) + .await; - #[test] - fn test_has_links() { - let links = test_feature( - LatexIncludeLinkProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file("foo.tex", "\\input{bar.tex}"), - FeatureSpec::file("bar.tex", ""), - ], - main_file: "foo.tex", - position: Position::new(0, 15), - ..FeatureSpec::default() - }, - ); - assert_eq!( - links, - vec![DocumentLink { - range: Range::new_simple(0, 7, 0, 14), - target: FeatureSpec::uri("bar.tex"), - }] - ); + assert!(actual_links.is_empty()); } - #[test] - fn test_no_links_latex() { - let links = test_feature( - LatexIncludeLinkProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "")], - main_file: "foo.tex", - position: Position::new(0, 15), - ..FeatureSpec::default() - }, - ); - assert!(links.is_empty()); + #[tokio::test] + async fn empty_bibtex_document_command() { + let actual_links = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .test_link(LatexIncludeLinkProvider) + .await; + + assert!(actual_links.is_empty()); } - #[test] - fn test_no_links_bibtex() { - let links = test_feature( - LatexIncludeLinkProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "")], - main_file: "foo.bib", - position: Position::new(0, 15), - ..FeatureSpec::default() - }, - ); - assert!(links.is_empty()); + #[tokio::test] + async fn has_links() { + let actual_links = FeatureTester::new() + .file("foo.tex", r#"\input{bar.tex}"#) + .file("bar.tex", r#""#) + .main("foo.tex") + .test_link(LatexIncludeLinkProvider) + .await; + + let expected_links = vec![DocumentLink { + range: Range::new_simple(0, 7, 0, 14), + target: FeatureTester::uri("bar.tex").into(), + tooltip: None, + }]; + + assert_eq!(actual_links, expected_links); } } diff --git a/support/texlab/src/link/mod.rs b/support/texlab/src/link/mod.rs index 33d5556332..934975f060 100644 --- a/support/texlab/src/link/mod.rs +++ b/support/texlab/src/link/mod.rs @@ -1,9 +1,12 @@ +mod latex_import; mod latex_include; -use crate::link::latex_include::LatexIncludeLinkProvider; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{DocumentLink, DocumentLinkParams}; +use self::{latex_import::LatexImportLinkProvider, latex_include::LatexIncludeLinkProvider}; +use crate::{ + feature::{ConcatProvider, FeatureProvider, FeatureRequest}, + protocol::{DocumentLink, DocumentLinkParams}, +}; +use async_trait::async_trait; pub struct LinkProvider { provider: ConcatProvider<DocumentLinkParams, DocumentLink>, @@ -12,7 +15,10 @@ pub struct LinkProvider { impl LinkProvider { pub fn new() -> Self { Self { - provider: ConcatProvider::new(vec![Box::new(LatexIncludeLinkProvider)]), + provider: ConcatProvider::new(vec![ + Box::new(LatexImportLinkProvider), + Box::new(LatexIncludeLinkProvider), + ]), } } } @@ -23,15 +29,12 @@ impl Default for LinkProvider { } } +#[async_trait] impl FeatureProvider for LinkProvider { type Params = DocumentLinkParams; type Output = Vec<DocumentLink>; - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<DocumentLinkParams>, - ) -> Vec<DocumentLink> { - self.provider.execute(request).await + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + self.provider.execute(req).await } } |