aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/presentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r--crates/ra_ide/src/completion/presentation.rs79
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(&macro_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(), &macro_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
390fn 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(&macro_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)]
408mod tests { 419mod tests {
409 use insta::assert_debug_snapshot; 420 use insta::assert_debug_snapshot;