tinymist_query/
document_symbol.rs1use crate::{
2 SyntaxRequest,
3 prelude::*,
4 syntax::{LexicalHierarchy, LexicalScopeKind, get_lexical_hierarchy},
5};
6
7#[derive(Debug, Clone)]
20pub struct DocumentSymbolRequest {
21 pub path: PathBuf,
23}
24
25impl SyntaxRequest for DocumentSymbolRequest {
26 type Response = DocumentSymbolResponse;
27
28 fn request(
29 self,
30 source: &Source,
31 position_encoding: PositionEncoding,
32 ) -> Option<Self::Response> {
33 let hierarchy = get_lexical_hierarchy(source, LexicalScopeKind::Symbol)?;
34 let symbols = symbols_in_hierarchy(&hierarchy, source, position_encoding);
35 Some(DocumentSymbolResponse::Nested(symbols))
36 }
37}
38
39#[allow(deprecated)]
40fn symbols_in_hierarchy(
41 hierarchy: &[LexicalHierarchy],
42 source: &Source,
43 position_encoding: PositionEncoding,
44) -> Vec<DocumentSymbol> {
45 hierarchy
46 .iter()
47 .filter(|hierarchy| hierarchy.info.kind.is_valid_lsp_symbol())
48 .map(|hierarchy| {
49 let range = to_lsp_range(hierarchy.info.range.clone(), source, position_encoding);
50
51 DocumentSymbol {
52 name: hierarchy.info.name.to_string(),
53 detail: None,
54 kind: hierarchy.info.kind.clone().into(),
55 tags: None,
56 deprecated: None,
57 range,
58 selection_range: range,
59 children: hierarchy
60 .children
61 .as_ref()
62 .map(|ch| symbols_in_hierarchy(ch, source, position_encoding)),
63 }
64 })
65 .collect()
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::tests::*;
72
73 #[test]
74 fn test() {
75 snapshot_testing("document_symbols", &|ctx, path| {
76 let request = DocumentSymbolRequest { path: path.clone() };
77
78 let source = ctx.source_by_path(&path).unwrap();
79
80 let result = request.request(&source, PositionEncoding::Utf16);
81 assert_snapshot!(JsonRepr::new_redacted(result.unwrap(), &REDACT_LOC));
82 });
83 }
84}