tinymist_query/analysis/completion/
mode.rs1use super::*;
4impl CompletionPair<'_, '_, '_> {
5 pub fn complete_comments(&mut self) -> bool {
7 let text = self.cursor.leaf.get().text();
8 if (text == "///" || text == "/// ")
10 && let Some(hash_node) = self.cursor.leaf.next_leaf()
12 && let Some(let_node) = hash_node.next_leaf()
14 && let Some(let_closure) = let_node.next_leaf()
15 && matches!(let_closure.parent_kind(), Some(SyntaxKind::Closure))
16 && let Some(closure) = let_closure.parent()
17 && let Some(closure) = closure.cast::<ast::Expr>()
18 && let ast::Expr::Closure(c) = closure
19 {
20 let rng = self.cursor.leaf.offset()..hash_node.offset();
22 let text_between = &self.cursor.source.text()[rng];
23 let mut line_count = 0;
24 for ch in text_between.chars() {
25 if ch == '\n' {
26 line_count += 1;
27 }
28 if line_count > 1 {
29 return false;
30 }
31 }
32
33 let mut doc_snippet: String = if text == "///" {
34 " $0\n///".to_string()
35 } else {
36 "$0\n///".to_string()
37 };
38 let mut i = 0;
39 for param in c.params().children() {
40 let param: &EcoString = match param {
42 Param::Pos(p) => match p {
43 ast::Pattern::Normal(ast::Expr::Ident(ident)) => ident.get(),
44 _ => &"_".into(),
45 },
46 Param::Named(n) => n.name().get(),
47 Param::Spread(s) => {
48 if let Some(ident) = s.sink_ident() {
49 &eco_format!("{}", ident.get())
50 } else {
51 &EcoString::new()
52 }
53 }
54 };
55 log::info!("param: {param}, index: {i}");
56 doc_snippet += &format!("\n/// - {param} (${}): ${}", i + 1, i + 2);
57 i += 2;
58 }
59 doc_snippet += &format!("\n/// -> ${}", i + 1);
60 self.push_completion(Completion {
61 label: "Document function".into(),
62 apply: Some(doc_snippet.into()),
63 ..Completion::default()
64 });
65 }
66
67 true
68 }
69
70 pub fn complete_markup(&mut self) -> bool {
72 let parent_raw =
73 node_ancestors(&self.cursor.leaf).find(|node| matches!(node.kind(), SyntaxKind::Raw));
74
75 if let Some(prev) = self.cursor.leaf.prev_leaf()
77 && matches!(prev.kind(), SyntaxKind::Eq | SyntaxKind::Arrow)
78 && matches!(
79 prev.parent_kind(),
80 Some(SyntaxKind::LetBinding | SyntaxKind::Closure)
81 )
82 {
83 self.cursor.from = self.cursor.cursor;
84 self.code_completions(false);
85 return true;
86 }
87
88 if let Some(prev) = self.cursor.leaf.prev_leaf()
90 && prev.kind() == SyntaxKind::Context
91 {
92 self.cursor.from = self.cursor.cursor;
93 self.code_completions(false);
94 return true;
95 }
96
97 if let Some(parent_raw) = parent_raw {
99 let mut s = Scanner::new(self.cursor.text);
100 s.jump(parent_raw.offset());
101 if s.eat_if("```") {
102 s.eat_while('`');
103 let start = s.cursor();
104 if s.eat_if(is_id_start) {
105 s.eat_while(is_id_continue);
106 }
107 if s.cursor() == self.cursor.cursor {
108 self.cursor.from = start;
109 self.raw_completions();
110 }
111 return true;
112 }
113 }
114
115 if !is_triggered_by_punc(self.worker.trigger_character) && self.worker.explicit {
117 self.cursor.from = self.cursor.cursor;
118 self.snippet_completions(Some(InterpretMode::Markup), None);
119 return true;
120 }
121
122 false
123 }
124
125 pub fn complete_math(&mut self) -> bool {
127 if !is_triggered_by_punc(self.worker.trigger_character)
129 && matches!(
130 self.cursor.leaf.kind(),
131 SyntaxKind::Text | SyntaxKind::MathIdent | SyntaxKind::MathText
132 )
133 {
134 self.cursor.from = self.cursor.leaf.offset();
135 self.scope_completions(true);
136 self.snippet_completions(Some(InterpretMode::Math), None);
137 return true;
138 }
139
140 if !is_triggered_by_punc(self.worker.trigger_character) && self.worker.explicit {
142 self.cursor.from = self.cursor.cursor;
143 self.scope_completions(true);
144 self.snippet_completions(Some(InterpretMode::Math), None);
145 return true;
146 }
147
148 false
149 }
150
151 pub fn complete_code(&mut self) -> bool {
153 if self.cursor.leaf.kind() == SyntaxKind::Hash {
155 self.cursor.from = self.cursor.cursor;
156 self.code_completions(true);
157
158 return true;
159 }
160
161 if self.cursor.leaf.kind() == SyntaxKind::Ident {
163 self.cursor.from = self.cursor.leaf.offset();
164 self.code_completions(is_hash_expr(&self.cursor.leaf));
165 return true;
166 }
167
168 if let Some(prev) = self.cursor.leaf.prev_leaf()
170 && prev.kind() == SyntaxKind::Context
171 {
172 self.cursor.from = self.cursor.cursor;
173 self.code_completions(false);
174 return true;
175 }
176
177 if self.cursor.leaf.kind() == SyntaxKind::Ident
179 && !matches!(
180 self.cursor.leaf.parent_kind(),
181 Some(SyntaxKind::FieldAccess)
182 )
183 {
184 self.cursor.from = self.cursor.leaf.offset();
185 self.code_completions(false);
186 return true;
187 }
188
189 if self.cursor.leaf.kind().is_trivia()
193 || (matches!(
194 self.cursor.leaf.kind(),
195 SyntaxKind::LeftParen | SyntaxKind::LeftBrace
196 ) || (matches!(self.cursor.leaf.kind(), SyntaxKind::Colon)
197 && self.cursor.leaf.parent_kind() == Some(SyntaxKind::ShowRule)))
198 {
199 self.cursor.from = self.cursor.cursor;
200 self.code_completions(false);
201 return true;
202 }
203
204 false
205 }
206
207 fn code_completions(&mut self, hash: bool) {
209 self.scope_completions(true);
213
214 self.snippet_completions(Some(InterpretMode::Code), None);
215
216 if !hash {
217 self.snippet_completion(
218 "function",
219 "(${params}) => ${output}",
220 "Creates an unnamed function.",
221 );
222 }
223 }
224}