tinymist_query/syntax/
index.rs

1use std::str::FromStr;
2
3use rustc_hash::FxHashSet;
4use tinymist_world::package::PackageSpec;
5
6use crate::{adt::interner::Interned, prelude::*};
7
8/// The information for the index.
9#[derive(Default)]
10pub struct IndexInfo {
11    /// The paths in the source.
12    pub(crate) paths: FxHashSet<Interned<str>>,
13    /// The packages in the source.
14    pub(crate) packages: FxHashSet<PackageSpec>,
15    /// The identifiers in the source.
16    pub(crate) identifiers: FxHashSet<Interned<str>>,
17}
18
19/// Gets the index information for the source.
20#[typst_macros::time(span = src.root().span())]
21#[comemo::memoize]
22pub fn get_index_info(src: &Source) -> Arc<IndexInfo> {
23    let root = src.root();
24    let mut worker = IndexWorker {
25        info: IndexInfo::default(),
26    };
27    worker.visit(root);
28    Arc::new(worker.info)
29}
30
31/// The worker for the index.
32struct IndexWorker {
33    info: IndexInfo,
34}
35
36impl IndexWorker {
37    /// Visits the node.
38    fn visit(&mut self, node: &SyntaxNode) {
39        match node.cast::<ast::Expr>() {
40            Some(ast::Expr::Str(path_str)) => {
41                if path_str.to_untyped().text().len() > 65536 {
42                    // skip long strings
43                    return;
44                }
45                let path_str = path_str.get();
46
47                if path_str.starts_with('@') {
48                    let pkg_spec = PackageSpec::from_str(&path_str).ok();
49                    if let Some(pkg_spec) = pkg_spec {
50                        self.info.identifiers.insert(pkg_spec.name.clone().into());
51                        self.info.packages.insert(pkg_spec);
52                    }
53                    return;
54                }
55                let path = Path::new(path_str.as_str());
56                let name = path.file_name().unwrap_or_default().to_str();
57                if let Some(name) = name {
58                    self.info.paths.insert(name.into());
59                }
60            }
61            Some(ast::Expr::MathIdent(ident)) => {
62                self.info.identifiers.insert(ident.get().into());
63            }
64            Some(ast::Expr::Ident(ident)) => {
65                self.info.identifiers.insert(ident.get().into());
66            }
67            _ => {}
68        }
69
70        for child in node.children() {
71            self.visit(child);
72        }
73    }
74}