php_lsp/analysis/
document_highlight.rs1use tower_lsp::lsp_types::{DocumentHighlight, DocumentHighlightKind, Position, Range};
2
3use crate::document::ast::ParsedDoc;
4use crate::navigation::walk::{collect_var_refs_in_scope, refs_in_stmts};
5use crate::text::word_at_position;
6
7pub fn document_highlights(
12 source: &str,
13 doc: &ParsedDoc,
14 position: Position,
15) -> Vec<DocumentHighlight> {
16 let word = match word_at_position(source, position) {
17 Some(w) => w,
18 None => return vec![],
19 };
20
21 let word_utf16_len: u32 = word.chars().map(|c| c.len_utf16() as u32).sum();
22 let sv = doc.view();
23
24 if word.starts_with('$') {
25 let bare = word.trim_start_matches('$');
26 let byte_off = sv.byte_of_position(position) as usize;
27 let mut var_spans = Vec::new();
28 collect_var_refs_in_scope(&doc.program().stmts, bare, byte_off, &mut var_spans);
29 var_spans
30 .into_iter()
31 .map(|(span, kind)| {
32 let start = sv.position_of(span.start);
33 let end = Position {
34 line: start.line,
35 character: start.character + word_utf16_len,
36 };
37 DocumentHighlight {
38 range: Range { start, end },
39 kind: Some(kind),
40 }
41 })
42 .collect()
43 } else {
44 let mut spans = Vec::new();
52 refs_in_stmts(doc.source(), &doc.program().stmts, &word, &mut spans);
53 spans
54 .into_iter()
55 .map(|span| {
56 let start = sv.position_of(span.start);
57 let end = Position {
58 line: start.line,
59 character: start.character + word_utf16_len,
60 };
61 DocumentHighlight {
62 range: Range { start, end },
63 kind: Some(DocumentHighlightKind::TEXT),
64 }
65 })
66 .collect()
67 }
68}