diff options
author | Norbert Preining <norbert@preining.info> | 2021-05-23 03:00:39 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-05-23 03:00:39 +0000 |
commit | f1261b349e875b842745b63258c3e338cb1fe3bf (patch) | |
tree | b5d402b3e80818cde2c079a42249f3dcb9732247 /support/texlab/src/features/reference/entry.rs | |
parent | 58aa1ac09b1d9e4769d0a0661cf12e2b2db41b14 (diff) |
CTAN sync 202105230300
Diffstat (limited to 'support/texlab/src/features/reference/entry.rs')
-rw-r--r-- | support/texlab/src/features/reference/entry.rs | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/support/texlab/src/features/reference/entry.rs b/support/texlab/src/features/reference/entry.rs new file mode 100644 index 0000000000..fbbcbdb4cc --- /dev/null +++ b/support/texlab/src/features/reference/entry.rs @@ -0,0 +1,198 @@ +use cancellation::CancellationToken; +use lsp_types::{Location, ReferenceParams}; + +use crate::{ + features::cursor::CursorContext, + syntax::{bibtex, latex, CstNode}, + DocumentData, LineIndexExt, +}; + +pub fn find_entry_references( + context: &CursorContext<ReferenceParams>, + cancellation_token: &CancellationToken, + references: &mut Vec<Location>, +) -> Option<()> { + let (key_text, _) = context + .find_citation_key_word() + .or_else(|| context.find_citation_key_command()) + .or_else(|| context.find_entry_key())?; + + for document in &context.request.subset.documents { + cancellation_token.result().ok()?; + + match &document.data { + DocumentData::Latex(data) => { + data.root + .descendants() + .filter_map(latex::Citation::cast) + .filter_map(|citation| citation.key_list()) + .flat_map(|keys| keys.words()) + .filter(|key| key.text() == key_text) + .map(|key| document.line_index.line_col_lsp_range(key.text_range())) + .for_each(|range| { + references.push(Location::new(document.uri.as_ref().clone().into(), range)); + }); + } + DocumentData::Bibtex(data) if context.request.params.context.include_declaration => { + data.root + .children() + .filter_map(bibtex::Entry::cast) + .filter_map(|entry| entry.key()) + .filter(|key| key.text() == key_text) + .map(|key| document.line_index.line_col_lsp_range(key.text_range())) + .for_each(|range| { + references.push(Location::new(document.uri.as_ref().clone().into(), range)); + }); + } + DocumentData::Bibtex(_) | DocumentData::BuildLog(_) => {} + } + } + Some(()) +} + +#[cfg(test)] +mod tests { + use lsp_types::Range; + + use crate::{features::testing::FeatureTester, RangeExt}; + + use super::*; + + #[test] + fn test_empty_latex_document() { + let request = FeatureTester::builder() + .files(vec![("main.tex", "")]) + .main("main.tex") + .line(0) + .character(0) + .build() + .reference(); + + let mut actual_references = Vec::new(); + let context = CursorContext::new(request); + find_entry_references(&context, CancellationToken::none(), &mut actual_references); + + assert!(actual_references.is_empty()); + } + + #[test] + fn test_empty_bibtex_document() { + let request = FeatureTester::builder() + .files(vec![("main.bib", "")]) + .main("main.bib") + .line(0) + .character(0) + .build() + .reference(); + + let mut actual_references = Vec::new(); + let context = CursorContext::new(request); + find_entry_references(&context, CancellationToken::none(), &mut actual_references); + + assert!(actual_references.is_empty()); + } + + #[test] + fn test_definition() { + let tester = FeatureTester::builder() + .files(vec![ + ("foo.bib", r#"@article{foo,}"#), + ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#), + ]) + .main("foo.bib") + .line(0) + .character(11) + .build(); + let uri = tester.uri("bar.tex"); + let mut actual_references = Vec::new(); + + let request = tester.reference(); + let context = CursorContext::new(request); + find_entry_references(&context, CancellationToken::none(), &mut actual_references); + + let expected_references = vec![Location::new( + uri.as_ref().clone().into(), + Range::new_simple(0, 6, 0, 9), + )]; + assert_eq!(actual_references, expected_references); + } + + #[test] + fn test_definition_include_declaration() { + let tester = FeatureTester::builder() + .files(vec![ + ("foo.bib", r#"@article{foo,}"#), + ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#), + ]) + .main("foo.bib") + .line(0) + .character(11) + .include_declaration(true) + .build(); + let uri1 = tester.uri("foo.bib"); + let uri2 = tester.uri("bar.tex"); + let mut actual_references = Vec::new(); + + let request = tester.reference(); + let context = CursorContext::new(request); + find_entry_references(&context, CancellationToken::none(), &mut actual_references); + + let expected_references = vec![ + Location::new(uri1.as_ref().clone().into(), Range::new_simple(0, 9, 0, 12)), + Location::new(uri2.as_ref().clone().into(), Range::new_simple(0, 6, 0, 9)), + ]; + assert_eq!(actual_references, expected_references); + } + + #[test] + fn test_reference() { + let tester = FeatureTester::builder() + .files(vec![ + ("foo.bib", r#"@article{foo,}"#), + ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#), + ]) + .main("bar.tex") + .line(0) + .character(8) + .build(); + let uri = tester.uri("bar.tex"); + let mut actual_references = Vec::new(); + + let request = tester.reference(); + let context = CursorContext::new(request); + find_entry_references(&context, CancellationToken::none(), &mut actual_references); + + let expected_references = vec![Location::new( + uri.as_ref().clone().into(), + Range::new_simple(0, 6, 0, 9), + )]; + assert_eq!(actual_references, expected_references); + } + + #[test] + fn test_reference_include_declaration() { + let tester = FeatureTester::builder() + .files(vec![ + ("foo.bib", r#"@article{foo,}"#), + ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#), + ]) + .main("bar.tex") + .line(0) + .character(6) + .include_declaration(true) + .build(); + let uri1 = tester.uri("foo.bib"); + let uri2 = tester.uri("bar.tex"); + let mut actual_references = Vec::new(); + + let request = tester.reference(); + let context = CursorContext::new(request); + find_entry_references(&context, CancellationToken::none(), &mut actual_references); + + let expected_references = vec![ + Location::new(uri2.as_ref().clone().into(), Range::new_simple(0, 6, 0, 9)), + Location::new(uri1.as_ref().clone().into(), Range::new_simple(0, 9, 0, 12)), + ]; + assert_eq!(actual_references, expected_references); + } +} |