tinymist_query/
workspace_label.rs

1use crate::{
2    SemanticRequest,
3    prelude::*,
4    syntax::{
5        LexicalHierarchy, LexicalKind, LexicalScopeKind, LexicalVarKind, get_lexical_hierarchy,
6    },
7};
8
9/// The `workspace/label` request resembles [`workspace/symbol`] request but is
10/// extended for typst cases.
11///
12/// [`workspace/symbol`]: https://microsoft.github.io/language-server-protocol/specification#workspace_symbol
13#[derive(Debug, Clone)]
14pub struct WorkspaceLabelRequest {}
15
16impl SemanticRequest for WorkspaceLabelRequest {
17    type Response = Vec<SymbolInformation>;
18
19    fn request(self, ctx: &mut LocalContext) -> Option<Self::Response> {
20        // todo: let typst.ts expose source
21
22        let mut symbols = vec![];
23
24        for fid in ctx.source_files().clone() {
25            let Ok(source) = ctx.source_by_id(fid) else {
26                continue;
27            };
28            let Ok(uri) = ctx.uri_for_id(fid) else {
29                continue;
30            };
31            let res = get_lexical_hierarchy(&source, LexicalScopeKind::Symbol).map(|hierarchy| {
32                filter_document_labels(&hierarchy, &source, &uri, ctx.position_encoding())
33            });
34
35            if let Some(mut res) = res {
36                symbols.append(&mut res)
37            }
38        }
39
40        Some(symbols)
41    }
42}
43
44#[allow(deprecated)]
45fn filter_document_labels(
46    hierarchy: &[LexicalHierarchy],
47    source: &Source,
48    uri: &Url,
49    position_encoding: PositionEncoding,
50) -> Vec<SymbolInformation> {
51    hierarchy
52        .iter()
53        .flat_map(|hierarchy| {
54            [hierarchy]
55                .into_iter()
56                .chain(hierarchy.children.as_deref().into_iter().flatten())
57        })
58        .flat_map(|hierarchy| {
59            if !matches!(hierarchy.info.kind, LexicalKind::Var(LexicalVarKind::Label)) {
60                return None;
61            }
62
63            let rng = to_lsp_range(hierarchy.info.range.clone(), source, position_encoding);
64
65            Some(SymbolInformation {
66                name: hierarchy.info.name.to_string(),
67                kind: hierarchy.info.kind.clone().into(),
68                tags: None,
69                deprecated: None,
70                location: LspLocation {
71                    uri: uri.clone(),
72                    range: rng,
73                },
74                container_name: None,
75            })
76        })
77        .collect()
78}