summaryrefslogtreecommitdiff
path: root/support/texlab/src/link
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/link')
-rw-r--r--support/texlab/src/link/latex_import.rs99
-rw-r--r--support/texlab/src/link/latex_include.rs137
-rw-r--r--support/texlab/src/link/mod.rs25
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
}
}