summaryrefslogtreecommitdiff
path: root/support/texlab/src/definition/bibtex_string.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/definition/bibtex_string.rs')
-rw-r--r--support/texlab/src/definition/bibtex_string.rs225
1 files changed, 132 insertions, 93 deletions
diff --git a/support/texlab/src/definition/bibtex_string.rs b/support/texlab/src/definition/bibtex_string.rs
index 0e4f643153..a1fe5132c0 100644
--- a/support/texlab/src/definition/bibtex_string.rs
+++ b/support/texlab/src/definition/bibtex_string.rs
@@ -1,20 +1,23 @@
-use crate::syntax::*;
-use crate::workspace::*;
-use futures_boxed::boxed;
-use lsp_types::{LocationLink, Position, TextDocumentPositionParams};
+use crate::{
+ feature::{FeatureProvider, FeatureRequest},
+ protocol::{LocationLink, Position, TextDocumentPositionParams, Uri},
+ syntax::{bibtex, SyntaxNode},
+ workspace::DocumentContent,
+};
+use async_trait::async_trait;
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct BibtexStringDefinitionProvider;
+#[async_trait]
impl FeatureProvider for BibtexStringDefinitionProvider {
type Params = TextDocumentPositionParams;
type Output = Vec<LocationLink>;
- #[boxed]
- async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
- if let SyntaxTree::Bibtex(tree) = &request.document().tree {
- if let Some(reference) = Self::find_reference(tree, request.params.position) {
- return Self::find_definitions(&request.view.document.uri, tree, reference);
+ async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
+ if let DocumentContent::Bibtex(tree) = &req.current().content {
+ if let Some(reference) = Self::find_reference(tree, req.params.position) {
+ return Self::find_definitions(&req.current().uri, tree, reference);
}
}
Vec::new()
@@ -22,31 +25,36 @@ impl FeatureProvider for BibtexStringDefinitionProvider {
}
impl BibtexStringDefinitionProvider {
- fn find_reference(tree: &BibtexSyntaxTree, position: Position) -> Option<&BibtexToken> {
- let mut nodes = tree.find(position);
+ fn find_reference(tree: &bibtex::Tree, pos: Position) -> Option<&bibtex::Token> {
+ let mut nodes = tree.find(pos);
nodes.reverse();
- match (&nodes[0], &nodes.get(1)) {
- (BibtexNode::Word(word), Some(BibtexNode::Field(_)))
- | (BibtexNode::Word(word), Some(BibtexNode::Concat(_))) => Some(&word.token),
+ match (
+ &tree.graph[nodes[0]],
+ nodes.get(1).map(|node| &tree.graph[*node]),
+ ) {
+ (bibtex::Node::Word(word), Some(bibtex::Node::Field(_)))
+ | (bibtex::Node::Word(word), Some(bibtex::Node::Concat(_))) => Some(&word.token),
_ => None,
}
}
fn find_definitions(
uri: &Uri,
- tree: &BibtexSyntaxTree,
- reference: &BibtexToken,
+ tree: &bibtex::Tree,
+ reference: &bibtex::Token,
) -> Vec<LocationLink> {
let mut links = Vec::new();
- for string in tree.strings() {
- if let Some(name) = &string.name {
- if name.text() == reference.text() {
- links.push(LocationLink {
- origin_selection_range: Some(reference.range()),
- target_uri: uri.clone().into(),
- target_range: string.range(),
- target_selection_range: name.range(),
- });
+ for node in tree.children(tree.root) {
+ if let Some(string) = tree.as_string(node) {
+ if let Some(name) = &string.name {
+ if name.text() == reference.text() {
+ links.push(LocationLink {
+ origin_selection_range: Some(reference.range()),
+ target_uri: uri.clone().into(),
+ target_range: string.range(),
+ target_selection_range: name.range(),
+ });
+ }
}
}
}
@@ -57,76 +65,107 @@ impl BibtexStringDefinitionProvider {
#[cfg(test)]
mod tests {
use super::*;
- use crate::range::RangeExt;
- use lsp_types::{Position, Range};
-
- #[test]
- fn test_simple() {
- let links = test_feature(
- BibtexStringDefinitionProvider,
- FeatureSpec {
- files: vec![FeatureSpec::file(
- "foo.bib",
- "@string{foo = {bar}}\n@article{bar, author = foo}",
- )],
- main_file: "foo.bib",
- position: Position::new(1, 24),
- ..FeatureSpec::default()
- },
- );
-
- assert_eq!(
- links,
- vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(1, 23, 1, 26)),
- target_uri: FeatureSpec::uri("foo.bib"),
- target_range: Range::new_simple(0, 0, 0, 20),
- target_selection_range: Range::new_simple(0, 8, 0, 11)
- }]
- );
+ use crate::{
+ feature::FeatureTester,
+ protocol::{Range, RangeExt},
+ };
+ 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(BibtexStringDefinitionProvider)
+ .await;
+
+ assert!(actual_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(BibtexStringDefinitionProvider)
+ .await;
+
+ assert!(actual_links.is_empty());
+ }
+
+ #[tokio::test]
+ async fn simple() {
+ let actual_links = FeatureTester::new()
+ .file(
+ "main.bib",
+ indoc!(
+ r#"
+ @string{foo = {bar}}
+ @article{bar, author = foo}
+ "#
+ ),
+ )
+ .main("main.bib")
+ .position(1, 24)
+ .test_position(BibtexStringDefinitionProvider)
+ .await;
+
+ let expected_links = vec![LocationLink {
+ origin_selection_range: Some(Range::new_simple(1, 23, 1, 26)),
+ target_uri: FeatureTester::uri("main.bib").into(),
+ target_range: Range::new_simple(0, 0, 0, 20),
+ target_selection_range: Range::new_simple(0, 8, 0, 11),
+ }];
+
+ assert_eq!(actual_links, expected_links);
}
- #[test]
- fn test_concat() {
- let links = test_feature(
- BibtexStringDefinitionProvider,
- FeatureSpec {
- files: vec![FeatureSpec::file(
- "foo.bib",
- "@string{foo = {bar}}\n@article{bar, author = foo # \"bar\"}",
- )],
- main_file: "foo.bib",
- position: Position::new(1, 24),
- ..FeatureSpec::default()
- },
- );
-
- assert_eq!(
- links,
- vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(1, 23, 1, 26)),
- target_uri: FeatureSpec::uri("foo.bib"),
- target_range: Range::new_simple(0, 0, 0, 20),
- target_selection_range: Range::new_simple(0, 8, 0, 11)
- }]
- );
+ #[tokio::test]
+ async fn concat() {
+ let actual_links = FeatureTester::new()
+ .file(
+ "main.bib",
+ indoc!(
+ r#"
+ @string{foo = {bar}}
+ @article{bar, author = foo # "bar"}
+ "#
+ ),
+ )
+ .main("main.bib")
+ .position(1, 24)
+ .test_position(BibtexStringDefinitionProvider)
+ .await;
+
+ let expected_links = vec![LocationLink {
+ origin_selection_range: Some(Range::new_simple(1, 23, 1, 26)),
+ target_uri: FeatureTester::uri("main.bib").into(),
+ target_range: Range::new_simple(0, 0, 0, 20),
+ target_selection_range: Range::new_simple(0, 8, 0, 11),
+ }];
+
+ assert_eq!(actual_links, expected_links);
}
- #[test]
- fn test_field() {
- let links = test_feature(
- BibtexStringDefinitionProvider,
- FeatureSpec {
- files: vec![FeatureSpec::file(
- "foo.bib",
- "@string{foo = {bar}}\n@article{bar, author = foo}",
- )],
- main_file: "foo.bib",
- position: Position::new(1, 18),
- ..FeatureSpec::default()
- },
- );
-
- assert!(links.is_empty());
+ #[tokio::test]
+ async fn field() {
+ let actual_links = FeatureTester::new()
+ .file(
+ "main.bib",
+ indoc!(
+ r#"
+ @string{foo = {bar}}
+ @article{bar, author = foo}
+ "#
+ ),
+ )
+ .main("main.bib")
+ .position(1, 18)
+ .test_position(BibtexStringDefinitionProvider)
+ .await;
+
+ assert!(actual_links.is_empty());
}
}