diff options
author | Norbert Preining <norbert@preining.info> | 2020-05-28 03:03:21 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2020-05-28 03:03:21 +0000 |
commit | 745892fbddea56040139108277e728b53fd8fc11 (patch) | |
tree | 15e55e299b38fccdabce8364f1fbf4f02ef37994 /support/texlab/src/definition/latex_label.rs | |
parent | 195ca7e0c377d83455867bdd8e409d4e1cf024ea (diff) |
CTAN sync 202005280303
Diffstat (limited to 'support/texlab/src/definition/latex_label.rs')
-rw-r--r-- | support/texlab/src/definition/latex_label.rs | 192 |
1 files changed, 103 insertions, 89 deletions
diff --git a/support/texlab/src/definition/latex_label.rs b/support/texlab/src/definition/latex_label.rs index 8d1a415749..5318982ccd 100644 --- a/support/texlab/src/definition/latex_label.rs +++ b/support/texlab/src/definition/latex_label.rs @@ -1,26 +1,40 @@ -use crate::range::RangeExt; -use crate::symbol::build_section_tree; -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{LocationLink, TextDocumentPositionParams}; -use std::sync::Arc; +use crate::{ + feature::{DocumentView, FeatureProvider, FeatureRequest}, + outline::{Outline, OutlineContext, OutlineContextItem}, + protocol::{LocationLink, Options, RangeExt, TextDocumentPositionParams}, + symbol::build_section_tree, + syntax::{latex, LatexLabelKind, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; +use std::{path::Path, sync::Arc}; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct LatexLabelDefinitionProvider; +#[async_trait] impl FeatureProvider for LatexLabelDefinitionProvider { 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() { - let workspace = Arc::clone(&request.view.workspace); - let view = DocumentView::new(workspace, Arc::clone(&document)); - Self::find_definitions(&view, &reference, &mut links); + if let Some(reference) = Self::find_reference(req) { + for doc in req.related() { + let snapshot = Arc::clone(&req.view.snapshot); + let view = DocumentView::analyze( + snapshot, + Arc::clone(&doc), + &req.options, + &req.current_dir, + ); + Self::find_definitions( + &view, + &req.options, + &req.current_dir, + &reference, + &mut links, + ); } } links @@ -28,18 +42,32 @@ impl FeatureProvider for LatexLabelDefinitionProvider { } impl LatexLabelDefinitionProvider { + fn find_reference(req: &FeatureRequest<TextDocumentPositionParams>) -> Option<&latex::Token> { + if let DocumentContent::Latex(table) = &req.current().content { + table + .labels + .iter() + .flat_map(|label| label.names(&table)) + .find(|label| label.range().contains(req.params.position)) + } else { + None + } + } + fn find_definitions( view: &DocumentView, - reference: &LatexToken, + options: &Options, + current_dir: &Path, + reference: &latex::Token, links: &mut Vec<LocationLink>, ) { - if let SyntaxTree::Latex(tree) = &view.document.tree { - let outline = Outline::from(view); - let section_tree = build_section_tree(view, tree); - for label in &tree.structure.labels { + if let DocumentContent::Latex(table) = &view.current.content { + let outline = Outline::analyze(view, options, current_dir); + let section_tree = build_section_tree(view, table, options, current_dir); + for label in &table.labels { if label.kind == LatexLabelKind::Definition { - let context = OutlineContext::parse(view, label, &outline); - for name in label.names() { + let context = OutlineContext::parse(view, &outline, *label); + for name in label.names(&table) { if name.text() == reference.text() { let target_range = if let Some(OutlineContextItem::Section { .. }) = context.as_ref().map(|ctx| &ctx.item) @@ -53,9 +81,10 @@ impl LatexLabelDefinitionProvider { links.push(LocationLink { origin_selection_range: Some(reference.range()), - target_uri: view.document.uri.clone().into(), - target_range: target_range.unwrap_or_else(|| label.range()), - target_selection_range: label.range(), + target_uri: view.current.uri.clone().into(), + target_range: target_range + .unwrap_or_else(|| table[label.parent].range()), + target_selection_range: table[label.parent].range(), }); } } @@ -63,79 +92,64 @@ impl LatexLabelDefinitionProvider { } } } - - fn find_reference(request: &FeatureRequest<TextDocumentPositionParams>) -> Option<&LatexToken> { - if let SyntaxTree::Latex(tree) = &request.document().tree { - tree.structure - .labels - .iter() - .flat_map(LatexLabel::names) - .find(|label| label.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; - #[test] - fn test_has_definition() { - let links = test_feature( - LatexLabelDefinitionProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file("foo.tex", "\\label{foo}"), - FeatureSpec::file( - "bar.tex", - "\\begin{a}\\begin{b}\\label{foo}\\end{b}\\end{a}\n\\input{baz.tex}", - ), - FeatureSpec::file("baz.tex", "\\ref{foo}"), - ], - main_file: "baz.tex", - position: Position::new(0, 5), - ..FeatureSpec::default() - }, - ); - assert_eq!( - links, - vec![LocationLink { - origin_selection_range: Some(Range::new_simple(0, 5, 0, 8)), - target_uri: FeatureSpec::uri("bar.tex"), - target_range: Range::new_simple(0, 18, 0, 29), - target_selection_range: Range::new_simple(0, 18, 0, 29) - }] - ); + #[tokio::test] + async fn empty_latex_document() { + let actual_links = FeatureTester::new() + .file("main.tex", "") + .main("main.tex") + .position(0, 0) + .test_position(LatexLabelDefinitionProvider) + .await; + + assert!(actual_links.is_empty()); } - #[test] - fn test_no_definition_latex() { - let links = test_feature( - LatexLabelDefinitionProvider, - 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(LatexLabelDefinitionProvider) + .await; + + assert!(actual_links.is_empty()); } - #[test] - fn test_no_definition_bibtex() { - let links = test_feature( - LatexLabelDefinitionProvider, - 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 unknown_context() { + let actual_links = FeatureTester::new() + .file("foo.tex", r#"\label{foo}"#) + .file( + "bar.tex", + indoc!( + r#" + \begin{a}\begin{b}\label{foo}\end{b}\end{a} + \input{baz.tex} + "# + ), + ) + .file("baz.tex", r#"\ref{foo}"#) + .main("baz.tex") + .position(0, 5) + .test_position(LatexLabelDefinitionProvider) + .await; + + let expected_links = vec![LocationLink { + origin_selection_range: Some(Range::new_simple(0, 5, 0, 8)), + target_uri: FeatureTester::uri("bar.tex").into(), + target_range: Range::new_simple(0, 18, 0, 29), + target_selection_range: Range::new_simple(0, 18, 0, 29), + }]; + + assert_eq!(actual_links, expected_links); } } |