1 use cancellation::CancellationToken;
2 use lsp_types::{Hover, HoverContents, HoverParams};
3 
4 use crate::{
5     component_db::COMPONENT_DATABASE, features::cursor::CursorContext, syntax::latex, LineIndexExt,
6 };
7 
find_component_hover( context: &CursorContext<HoverParams>, token: &CancellationToken, ) -> Option<Hover>8 pub fn find_component_hover(
9     context: &CursorContext<HoverParams>,
10     token: &CancellationToken,
11 ) -> Option<Hover> {
12     let main_document = context.request.main_document();
13     let data = main_document.data.as_latex()?;
14     for link in &data.extras.explicit_links {
15         if token.is_canceled() {
16             break;
17         }
18 
19         if matches!(
20             link.kind,
21             latex::ExplicitLinkKind::Package | latex::ExplicitLinkKind::Class
22         ) && link.stem_range.contains_inclusive(context.offset)
23         {
24             let docs = COMPONENT_DATABASE.documentation(&link.stem)?;
25             return Some(Hover {
26                 contents: HoverContents::Markup(docs),
27                 range: Some(main_document.line_index.line_col_lsp_range(link.stem_range)),
28             });
29         }
30     }
31     None
32 }
33 
34 #[cfg(test)]
35 mod tests {
36     use lsp_types::Range;
37 
38     use crate::{features::testing::FeatureTester, RangeExt};
39 
40     use super::*;
41 
42     #[test]
test_empty_latex_document()43     fn test_empty_latex_document() {
44         let request = FeatureTester::builder()
45             .files(vec![("main.tex", "")])
46             .main("main.tex")
47             .line(0)
48             .character(0)
49             .build()
50             .hover();
51 
52         let context = CursorContext::new(request);
53         let actual_hover = find_component_hover(&context, CancellationToken::none());
54 
55         assert_eq!(actual_hover, None);
56     }
57 
58     #[test]
test_empty_bibtex_document()59     fn test_empty_bibtex_document() {
60         let request = FeatureTester::builder()
61             .files(vec![("main.bib", "")])
62             .main("main.bib")
63             .line(0)
64             .character(0)
65             .build()
66             .hover();
67 
68         let context = CursorContext::new(request);
69         let actual_hover = find_component_hover(&context, CancellationToken::none());
70 
71         assert_eq!(actual_hover, None);
72     }
73 
74     #[test]
test_known_package()75     fn test_known_package() {
76         let request = FeatureTester::builder()
77             .files(vec![("main.tex", r#"\usepackage{amsmath}"#)])
78             .main("main.tex")
79             .line(0)
80             .character(15)
81             .build()
82             .hover();
83 
84         let context = CursorContext::new(request);
85         let actual_hover = find_component_hover(&context, CancellationToken::none()).unwrap();
86 
87         assert_eq!(actual_hover.range.unwrap(), Range::new_simple(0, 12, 0, 19));
88     }
89 
90     #[test]
test_unknown_class()91     fn test_unknown_class() {
92         let request = FeatureTester::builder()
93             .files(vec![("main.tex", r#"\documentclass{abcdefghijklmnop}"#)])
94             .main("main.tex")
95             .line(0)
96             .character(20)
97             .build()
98             .hover();
99 
100         let context = CursorContext::new(request);
101         let actual_hover = find_component_hover(&context, CancellationToken::none());
102 
103         assert_eq!(actual_hover, None);
104     }
105 }
106