diff options
5 files changed, 59 insertions, 48 deletions
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs index 270e96df0..6000106d0 100644 --- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs +++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs | |||
@@ -41,7 +41,7 @@ mod tests { | |||
41 | @r###" | 41 | @r###" |
42 | [ | 42 | [ |
43 | CompletionItem { | 43 | CompletionItem { |
44 | label: "foo!", | 44 | label: "foo!(…)", |
45 | source_range: [46; 46), | 45 | source_range: [46; 46), |
46 | delete: [46; 46), | 46 | delete: [46; 46), |
47 | insert: "foo!($0)", | 47 | insert: "foo!($0)", |
@@ -81,7 +81,7 @@ mod tests { | |||
81 | @r###" | 81 | @r###" |
82 | [ | 82 | [ |
83 | CompletionItem { | 83 | CompletionItem { |
84 | label: "vec!", | 84 | label: "vec![…]", |
85 | source_range: [280; 280), | 85 | source_range: [280; 280), |
86 | delete: [280; 280), | 86 | delete: [280; 280), |
87 | insert: "vec![$0]", | 87 | insert: "vec![$0]", |
@@ -118,7 +118,7 @@ mod tests { | |||
118 | @r###" | 118 | @r###" |
119 | [ | 119 | [ |
120 | CompletionItem { | 120 | CompletionItem { |
121 | label: "foo!", | 121 | label: "foo! {…}", |
122 | source_range: [163; 163), | 122 | source_range: [163; 163), |
123 | delete: [163; 163), | 123 | delete: [163; 163), |
124 | insert: "foo! {$0}", | 124 | insert: "foo! {$0}", |
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs index a8b4ce114..218829b10 100644 --- a/crates/ra_ide/src/completion/complete_pattern.rs +++ b/crates/ra_ide/src/completion/complete_pattern.rs | |||
@@ -125,7 +125,7 @@ mod tests { | |||
125 | kind: Enum, | 125 | kind: Enum, |
126 | }, | 126 | }, |
127 | CompletionItem { | 127 | CompletionItem { |
128 | label: "m!", | 128 | label: "m!(…)", |
129 | source_range: [151; 151), | 129 | source_range: [151; 151), |
130 | delete: [151; 151), | 130 | delete: [151; 151), |
131 | insert: "m!($0)", | 131 | insert: "m!($0)", |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index d98523406..9f795e441 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -869,7 +869,7 @@ mod tests { | |||
869 | @r###" | 869 | @r###" |
870 | [ | 870 | [ |
871 | CompletionItem { | 871 | CompletionItem { |
872 | label: "foo!", | 872 | label: "foo!(…)", |
873 | source_range: [179; 179), | 873 | source_range: [179; 179), |
874 | delete: [179; 179), | 874 | delete: [179; 179), |
875 | insert: "foo!($0)", | 875 | insert: "foo!($0)", |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index ad00154a3..638f86eda 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -733,7 +733,7 @@ mod tests { | |||
733 | @r###" | 733 | @r###" |
734 | [ | 734 | [ |
735 | CompletionItem { | 735 | CompletionItem { |
736 | label: "bar!", | 736 | label: "bar!(…)", |
737 | source_range: [252; 252), | 737 | source_range: [252; 252), |
738 | delete: [252; 252), | 738 | delete: [252; 252), |
739 | insert: "bar!($0)", | 739 | insert: "bar!($0)", |
@@ -741,7 +741,7 @@ mod tests { | |||
741 | detail: "macro_rules! bar", | 741 | detail: "macro_rules! bar", |
742 | }, | 742 | }, |
743 | CompletionItem { | 743 | CompletionItem { |
744 | label: "baz!", | 744 | label: "baz!(…)", |
745 | source_range: [252; 252), | 745 | source_range: [252; 252), |
746 | delete: [252; 252), | 746 | delete: [252; 252), |
747 | insert: "baz!($0)", | 747 | insert: "baz!($0)", |
@@ -749,7 +749,7 @@ mod tests { | |||
749 | detail: "#[macro_export]\nmacro_rules! baz", | 749 | detail: "#[macro_export]\nmacro_rules! baz", |
750 | }, | 750 | }, |
751 | CompletionItem { | 751 | CompletionItem { |
752 | label: "foo!", | 752 | label: "foo!(…)", |
753 | source_range: [252; 252), | 753 | source_range: [252; 252), |
754 | delete: [252; 252), | 754 | delete: [252; 252), |
755 | insert: "foo!($0)", | 755 | insert: "foo!($0)", |
@@ -802,7 +802,7 @@ mod tests { | |||
802 | @r###" | 802 | @r###" |
803 | [ | 803 | [ |
804 | CompletionItem { | 804 | CompletionItem { |
805 | label: "foo!", | 805 | label: "foo!(…)", |
806 | source_range: [49; 49), | 806 | source_range: [49; 49), |
807 | delete: [49; 49), | 807 | delete: [49; 49), |
808 | insert: "foo!($0)", | 808 | insert: "foo!($0)", |
@@ -841,7 +841,7 @@ mod tests { | |||
841 | @r###" | 841 | @r###" |
842 | [ | 842 | [ |
843 | CompletionItem { | 843 | CompletionItem { |
844 | label: "foo!", | 844 | label: "foo!(…)", |
845 | source_range: [57; 57), | 845 | source_range: [57; 57), |
846 | delete: [57; 57), | 846 | delete: [57; 57), |
847 | insert: "foo!($0)", | 847 | insert: "foo!($0)", |
@@ -880,7 +880,7 @@ mod tests { | |||
880 | @r###" | 880 | @r###" |
881 | [ | 881 | [ |
882 | CompletionItem { | 882 | CompletionItem { |
883 | label: "foo!", | 883 | label: "foo!(…)", |
884 | source_range: [50; 50), | 884 | source_range: [50; 50), |
885 | delete: [50; 50), | 885 | delete: [50; 50), |
886 | insert: "foo!($0)", | 886 | insert: "foo!($0)", |
@@ -953,7 +953,7 @@ mod tests { | |||
953 | @r###" | 953 | @r###" |
954 | [ | 954 | [ |
955 | CompletionItem { | 955 | CompletionItem { |
956 | label: "m!", | 956 | label: "m!(…)", |
957 | source_range: [145; 145), | 957 | source_range: [145; 145), |
958 | delete: [145; 145), | 958 | delete: [145; 145), |
959 | insert: "m!($0)", | 959 | insert: "m!($0)", |
@@ -1006,7 +1006,7 @@ mod tests { | |||
1006 | @r###" | 1006 | @r###" |
1007 | [ | 1007 | [ |
1008 | CompletionItem { | 1008 | CompletionItem { |
1009 | label: "m!", | 1009 | label: "m!(…)", |
1010 | source_range: [145; 146), | 1010 | source_range: [145; 146), |
1011 | delete: [145; 146), | 1011 | delete: [145; 146), |
1012 | insert: "m!($0)", | 1012 | insert: "m!($0)", |
@@ -1059,7 +1059,7 @@ mod tests { | |||
1059 | @r###" | 1059 | @r###" |
1060 | [ | 1060 | [ |
1061 | CompletionItem { | 1061 | CompletionItem { |
1062 | label: "m!", | 1062 | label: "m!(…)", |
1063 | source_range: [145; 146), | 1063 | source_range: [145; 146), |
1064 | delete: [145; 146), | 1064 | delete: [145; 146), |
1065 | insert: "m!($0)", | 1065 | insert: "m!($0)", |
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; |