diff options
Diffstat (limited to 'support/texlab/src/definition/latex_citation.rs')
-rw-r--r-- | support/texlab/src/definition/latex_citation.rs | 161 |
1 files changed, 80 insertions, 81 deletions
diff --git a/support/texlab/src/definition/latex_citation.rs b/support/texlab/src/definition/latex_citation.rs index daefa8b2ef..aa93e25fc0 100644 --- a/support/texlab/src/definition/latex_citation.rs +++ b/support/texlab/src/definition/latex_citation.rs @@ -1,22 +1,24 @@ -use crate::range::RangeExt; -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{LocationLink, TextDocumentPositionParams}; +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{LocationLink, RangeExt, TextDocumentPositionParams}, + syntax::{latex, SyntaxNode}, + workspace::{Document, DocumentContent}, +}; +use async_trait::async_trait; #[derive(Debug, PartialEq, Eq, Clone)] pub struct LatexCitationDefinitionProvider; +#[async_trait] impl FeatureProvider for LatexCitationDefinitionProvider { type Params = TextDocumentPositionParams; type Output = Vec<LocationLink>; - #[boxed] - async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output { + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { let mut links = Vec::new(); - if let Some(reference) = Self::find_reference(&request) { - for document in request.related_documents() { - Self::find_definitions(&document, &reference, &mut links); + if let Some(reference) = Self::find_reference(req) { + for doc in req.related() { + Self::find_definitions(&doc, &reference, &mut links); } } links @@ -24,96 +26,93 @@ impl FeatureProvider for LatexCitationDefinitionProvider { } impl LatexCitationDefinitionProvider { - fn find_definitions( - document: &Document, - reference: &LatexToken, - links: &mut Vec<LocationLink>, - ) { - if let SyntaxTree::Bibtex(tree) = &document.tree { - for entry in tree.entries() { + fn find_reference(req: &FeatureRequest<TextDocumentPositionParams>) -> Option<&latex::Token> { + req.current().content.as_latex().and_then(|table| { + table + .citations + .iter() + .flat_map(|citation| citation.keys(&table)) + .find(|key| key.range().contains(req.params.position)) + }) + } + + fn find_definitions(doc: &Document, reference: &latex::Token, links: &mut Vec<LocationLink>) { + if let DocumentContent::Bibtex(tree) = &doc.content { + for entry in tree + .children(tree.root) + .filter_map(|node| tree.as_entry(node)) + { if let Some(key) = &entry.key { if key.text() == reference.text() { - let link = LocationLink { + links.push(LocationLink { origin_selection_range: Some(reference.range()), - target_uri: document.uri.clone().into(), + target_uri: doc.uri.clone().into(), target_range: entry.range(), target_selection_range: key.range(), - }; - links.push(link); + }); } } } } } - - fn find_reference(request: &FeatureRequest<TextDocumentPositionParams>) -> Option<&LatexToken> { - if let SyntaxTree::Latex(tree) = &request.document().tree { - tree.citations - .iter() - .flat_map(LatexCitation::keys) - .find(|key| key.range().contains(request.params.position)) - } else { - None - } - } } #[cfg(test)] mod tests { use super::*; - use lsp_types::{Position, Range}; + use crate::{feature::FeatureTester, protocol::Range}; + use indoc::indoc; + + #[tokio::test] + async fn empty_latex_document() { + let actual_links = FeatureTester::new() + .file("main.tex", "") + .main("main.tex") + .position(0, 0) + .test_position(LatexCitationDefinitionProvider) + .await; - #[test] - fn test_has_definition() { - let links = test_feature( - LatexCitationDefinitionProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file("foo.tex", "\\addbibresource{baz.bib}\n\\cite{foo}"), - FeatureSpec::file("bar.bib", "@article{foo, bar = {baz}}"), - FeatureSpec::file("baz.bib", "@article{foo, bar = {baz}}"), - ], - main_file: "foo.tex", - position: Position::new(1, 6), - ..FeatureSpec::default() - }, - ); - assert_eq!( - links, - vec![LocationLink { - origin_selection_range: Some(Range::new_simple(1, 6, 1, 9)), - target_uri: FeatureSpec::uri("baz.bib"), - target_range: Range::new_simple(0, 0, 0, 26), - target_selection_range: Range::new_simple(0, 9, 0, 12) - }] - ); + assert!(actual_links.is_empty()); } - #[test] - fn test_no_definition_latex() { - let links = test_feature( - LatexCitationDefinitionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "")], - main_file: "foo.tex", - position: Position::new(0, 0), - ..FeatureSpec::default() - }, - ); - assert!(links.is_empty()); + #[tokio::test] + async fn empty_bibtex_document() { + let actual_links = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .position(0, 0) + .test_position(LatexCitationDefinitionProvider) + .await; + + assert!(actual_links.is_empty()); } - #[test] - fn test_no_definition_bibtex() { - let links = test_feature( - LatexCitationDefinitionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "")], - main_file: "foo.bib", - position: Position::new(0, 0), - ..FeatureSpec::default() - }, - ); - assert!(links.is_empty()); + #[tokio::test] + async fn has_definition() { + let actual_links = FeatureTester::new() + .file( + "foo.tex", + indoc!( + r#" + \addbibresource{baz.bib} + \cite{foo} + "# + ), + ) + .file("bar.bib", r#"@article{foo, bar = {baz}}"#) + .file("baz.bib", r#"@article{foo, bar = {baz}}"#) + .main("foo.tex") + .position(1, 6) + .test_position(LatexCitationDefinitionProvider) + .await; + + let exepcted_links = vec![LocationLink { + origin_selection_range: Some(Range::new_simple(1, 6, 1, 9)), + target_uri: FeatureTester::uri("baz.bib").into(), + target_range: Range::new_simple(0, 0, 0, 26), + target_selection_range: Range::new_simple(0, 9, 0, 12), + }]; + + assert_eq!(actual_links, exepcted_links); } } |