summaryrefslogtreecommitdiff
path: root/support/texlab/src/definition/latex_label.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/definition/latex_label.rs')
-rw-r--r--support/texlab/src/definition/latex_label.rs192
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);
}
}