tinymist_query/analysis/completion/
param.rs

1//! Completion for param items.
2//!
3//! Note, this is used for the completion of parameters on a function's
4//! *definition* instead of the completion of arguments of some *function call*.
5
6use typst_shim::eval::CapturesVisitor;
7
8use super::*;
9impl CompletionPair<'_, '_, '_> {
10    /// Complete parameters.
11    pub fn complete_params(&mut self) -> Option<()> {
12        self.cursor.from = self.cursor.leaf.offset();
13
14        let leaf = self.cursor.leaf.clone();
15        let closure_node = node_ancestors(&leaf).find(|node| node.kind() == SyntaxKind::Closure)?;
16
17        let mut bindings = HashSet::<EcoString>::default();
18
19        let closure_node = closure_node.cast::<ast::Closure>()?;
20
21        // It is common for a function to reference itself in typst.
22        let name = closure_node.name();
23        if let Some(name) = name {
24            bindings.insert(name.get().clone());
25        }
26
27        // Collects all bindings from the parameters.
28        let param_list = closure_node.params();
29        for param in param_list.children() {
30            match param {
31                ast::Param::Pos(pos) => {
32                    for name in pos.bindings() {
33                        bindings.insert(name.get().clone());
34                    }
35                }
36                ast::Param::Named(named) => {
37                    bindings.insert(named.name().get().clone());
38                }
39                ast::Param::Spread(spread) => {
40                    if let Some(ident) = spread.sink_ident() {
41                        bindings.insert(ident.get().clone());
42                    }
43                }
44            }
45        }
46
47        let mut visitor = CapturesVisitor::new(None, typst::foundations::Capturer::Function);
48        visitor.visit(closure_node.body().to_untyped());
49        let captures = visitor.finish();
50
51        // Converts the captures into completions.
52        for (name, bind) in captures.iter() {
53            if !bindings.contains(name) {
54                let docs = "Parametrizes the captured variable.";
55                self.value_completion(Some(name.clone()), bind.read(), false, Some(docs));
56            }
57        }
58
59        Some(())
60    }
61}