diff options
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 79 |
1 files changed, 45 insertions, 34 deletions
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 5e2b8b920..6a6ddc7bd 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -133,29 +133,6 @@ impl Completions { | |||
133 | completion_item.kind(kind).set_documentation(docs).add_to(self) | 133 | completion_item.kind(kind).set_documentation(docs).add_to(self) |
134 | } | 134 | } |
135 | 135 | ||
136 | fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { | ||
137 | let mut votes = [0, 0, 0]; | ||
138 | for (idx, s) in docs.match_indices(¯o_name) { | ||
139 | let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); | ||
140 | // Ensure to match the full word | ||
141 | if after.starts_with('!') | ||
142 | && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric()) | ||
143 | { | ||
144 | // It may have spaces before the braces like `foo! {}` | ||
145 | match after[1..].chars().find(|&c| !c.is_whitespace()) { | ||
146 | Some('{') => votes[0] += 1, | ||
147 | Some('[') => votes[1] += 1, | ||
148 | Some('(') => votes[2] += 1, | ||
149 | _ => {} | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | // Insert a space before `{}`. | ||
155 | // We prefer the last one when some votes equal. | ||
156 | *votes.iter().zip(&[" {$0}", "[$0]", "($0)"]).max_by_key(|&(&vote, _)| vote).unwrap().1 | ||
157 | } | ||
158 | |||
159 | pub(crate) fn add_macro( | 136 | pub(crate) fn add_macro( |
160 | &mut self, | 137 | &mut self, |
161 | ctx: &CompletionContext, | 138 | ctx: &CompletionContext, |
@@ -177,21 +154,27 @@ impl Completions { | |||
177 | let detail = macro_label(&ast_node); | 154 | let detail = macro_label(&ast_node); |
178 | 155 | ||
179 | let docs = macro_.docs(ctx.db); | 156 | let docs = macro_.docs(ctx.db); |
180 | let macro_declaration = format!("{}!", name); | ||
181 | 157 | ||
182 | let mut builder = | 158 | let mut builder = CompletionItem::new( |
183 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) | 159 | CompletionKind::Reference, |
184 | .kind(CompletionItemKind::Macro) | 160 | ctx.source_range(), |
185 | .set_documentation(docs.clone()) | 161 | &format!("{}!", name), |
186 | .set_deprecated(is_deprecated(macro_, ctx.db)) | 162 | ) |
187 | .detail(detail); | 163 | .kind(CompletionItemKind::Macro) |
164 | .set_documentation(docs.clone()) | ||
165 | .set_deprecated(is_deprecated(macro_, ctx.db)) | ||
166 | .detail(detail); | ||
188 | 167 | ||
168 | let needs_bang = ctx.use_item_syntax.is_none() && !ctx.is_macro_call; | ||
189 | builder = match ctx.config.snippet_cap { | 169 | builder = match ctx.config.snippet_cap { |
190 | Some(cap) if ctx.use_item_syntax.is_none() && !ctx.is_macro_call => { | 170 | Some(cap) if needs_bang => { |
191 | let macro_braces_to_insert = | 171 | let docs = docs.as_ref().map_or("", |s| s.as_str()); |
192 | self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); | 172 | let (bra, ket) = guess_macro_braces(&name, docs); |
193 | builder.insert_snippet(cap, macro_declaration + macro_braces_to_insert) | 173 | builder |
174 | .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket)) | ||
175 | .label(format!("{}!{}…{}", name, bra, ket)) | ||
194 | } | 176 | } |
177 | None if needs_bang => builder.insert_text(format!("{}!", name)), | ||
195 | _ => { | 178 | _ => { |
196 | tested_by!(dont_insert_macro_call_parens_unncessary); | 179 | tested_by!(dont_insert_macro_call_parens_unncessary); |
197 | builder.insert_text(name) | 180 | builder.insert_text(name) |
@@ -404,6 +387,34 @@ fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool { | |||
404 | node.attrs(db).by_key("deprecated").exists() | 387 | node.attrs(db).by_key("deprecated").exists() |
405 | } | 388 | } |
406 | 389 | ||
390 | fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) { | ||
391 | let mut votes = [0, 0, 0]; | ||
392 | for (idx, s) in docs.match_indices(¯o_name) { | ||
393 | let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); | ||
394 | // Ensure to match the full word | ||
395 | if after.starts_with('!') | ||
396 | && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric()) | ||
397 | { | ||
398 | // It may have spaces before the braces like `foo! {}` | ||
399 | match after[1..].chars().find(|&c| !c.is_whitespace()) { | ||
400 | Some('{') => votes[0] += 1, | ||
401 | Some('[') => votes[1] += 1, | ||
402 | Some('(') => votes[2] += 1, | ||
403 | _ => {} | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
408 | // Insert a space before `{}`. | ||
409 | // We prefer the last one when some votes equal. | ||
410 | let (_vote, (bra, ket)) = votes | ||
411 | .iter() | ||
412 | .zip(&[(" {", "}"), ("[", "]"), ("(", ")")]) | ||
413 | .max_by_key(|&(&vote, _)| vote) | ||
414 | .unwrap(); | ||
415 | (*bra, *ket) | ||
416 | } | ||
417 | |||
407 | #[cfg(test)] | 418 | #[cfg(test)] |
408 | mod tests { | 419 | mod tests { |
409 | use insta::assert_debug_snapshot; | 420 | use insta::assert_debug_snapshot; |