diff options
Diffstat (limited to 'support/texlab/src/features/hover/string_ref.rs')
-rw-r--r-- | support/texlab/src/features/hover/string_ref.rs | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/support/texlab/src/features/hover/string_ref.rs b/support/texlab/src/features/hover/string_ref.rs new file mode 100644 index 0000000000..f6e7f1c873 --- /dev/null +++ b/support/texlab/src/features/hover/string_ref.rs @@ -0,0 +1,141 @@ +use cancellation::CancellationToken; +use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent, MarkupKind}; + +use crate::{ + features::cursor::CursorContext, + syntax::{bibtex, CstNode}, + LineIndexExt, +}; + +pub fn find_string_reference_hover( + context: &CursorContext<HoverParams>, + cancellation_token: &CancellationToken, +) -> Option<Hover> { + let main_document = context.request.main_document(); + let data = main_document.data.as_bibtex()?; + + let name = context + .cursor + .as_bibtex() + .filter(|token| token.kind() == bibtex::WORD) + .filter(|name| matches!(name.parent().kind(), bibtex::TOKEN | bibtex::STRING))?; + + for string in data.root.children().filter_map(bibtex::String::cast) { + if cancellation_token.is_canceled() { + return None; + } + + if string.name().filter(|n| n.text() == name.text()).is_some() { + let value = string.value()?.syntax().text().to_string(); + return Some(Hover { + range: Some( + main_document + .line_index + .line_col_lsp_range(name.text_range()), + ), + contents: HoverContents::Markup(MarkupContent { + kind: MarkupKind::PlainText, + value, + }), + }); + } + } + + None +} + +#[cfg(test)] +mod tests { + use indoc::indoc; + 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() + .hover(); + + let context = CursorContext::new(request); + let actual_hover = find_string_reference_hover(&context, CancellationToken::none()); + + assert_eq!(actual_hover, None); + } + + #[test] + fn test_empty_bibtex_document() { + let request = FeatureTester::builder() + .files(vec![("main.bib", "")]) + .main("main.bib") + .line(0) + .character(0) + .build() + .hover(); + + let context = CursorContext::new(request); + let actual_hover = find_string_reference_hover(&context, CancellationToken::none()); + + assert_eq!(actual_hover, None); + } + + #[test] + fn test_inside_reference() { + let request = FeatureTester::builder() + .files(vec![( + "main.bib", + indoc! { r#" + @string{foo = "Foo"} + @string{bar = "Bar"} + @article{baz, author = bar} + "# }, + )]) + .main("main.bib") + .line(2) + .character(24) + .build() + .hover(); + + let context = CursorContext::new(request); + let actual_hover = + find_string_reference_hover(&context, CancellationToken::none()).unwrap(); + + let expected_hover = Hover { + contents: HoverContents::Markup(MarkupContent { + kind: MarkupKind::PlainText, + value: "\"Bar\"".into(), + }), + range: Some(Range::new_simple(2, 23, 2, 26)), + }; + + assert_eq!(actual_hover, expected_hover); + } + + #[test] + fn test_inside_field() { + let request = FeatureTester::builder() + .files(vec![( + "main.bib", + indoc! { r#" + @string{foo = "Foo"} + @string{bar = "Bar"} + @article{baz, author = bar} + "# }, + )]) + .main("main.bib") + .line(2) + .character(20) + .build() + .hover(); + + let context = CursorContext::new(request); + let actual_hover = find_string_reference_hover(&context, CancellationToken::none()); + assert_eq!(actual_hover, None); + } +} |