diff options
author | Norbert Preining <norbert@preining.info> | 2019-12-03 03:01:24 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-12-03 03:01:24 +0000 |
commit | b8d4bb76703bcb15578e2b23c5d256532180b894 (patch) | |
tree | bedd1df7a00521a2bd986b3c0289d6556a59e39b /support/texlab/src/definition/latex_citation.rs | |
parent | 02e4625a78a5029e8b5dc2a4ec70193b232f497e (diff) |
CTAN sync 201912030301
Diffstat (limited to 'support/texlab/src/definition/latex_citation.rs')
-rw-r--r-- | support/texlab/src/definition/latex_citation.rs | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/support/texlab/src/definition/latex_citation.rs b/support/texlab/src/definition/latex_citation.rs new file mode 100644 index 0000000000..daefa8b2ef --- /dev/null +++ b/support/texlab/src/definition/latex_citation.rs @@ -0,0 +1,119 @@ +use crate::range::RangeExt; +use crate::syntax::*; +use crate::workspace::*; +use futures_boxed::boxed; +use lsp_types::{LocationLink, TextDocumentPositionParams}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct LatexCitationDefinitionProvider; + +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 { + 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); + } + } + links + } +} + +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() { + if let Some(key) = &entry.key { + if key.text() == reference.text() { + let link = LocationLink { + origin_selection_range: Some(reference.range()), + target_uri: document.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}; + + #[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) + }] + ); + } + + #[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()); + } + + #[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()); + } +} |