aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs62
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs36
2 files changed, 91 insertions, 7 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
index d808b2357..09f743c66 100644
--- a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
@@ -56,6 +56,16 @@ mod tests {
56 do_reference_completion( 56 do_reference_completion(
57 " 57 "
58 //- /main.rs 58 //- /main.rs
59 /// Creates a [`Vec`] containing the arguments.
60 ///
61 /// - Create a [`Vec`] containing a given list of elements:
62 ///
63 /// ```
64 /// let v = vec![1, 2, 3];
65 /// assert_eq!(v[0], 1);
66 /// assert_eq!(v[1], 2);
67 /// assert_eq!(v[2], 3);
68 /// ```
59 macro_rules! vec { 69 macro_rules! vec {
60 () => {} 70 () => {}
61 } 71 }
@@ -68,13 +78,61 @@ mod tests {
68 @r##"[ 78 @r##"[
69 CompletionItem { 79 CompletionItem {
70 label: "vec!", 80 label: "vec!",
71 source_range: [46; 46), 81 source_range: [280; 280),
72 delete: [46; 46), 82 delete: [280; 280),
73 insert: "vec![$0]", 83 insert: "vec![$0]",
74 kind: Macro, 84 kind: Macro,
75 detail: "macro_rules! vec", 85 detail: "macro_rules! vec",
86 documentation: Documentation(
87 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
88 ),
76 }, 89 },
77]"## 90]"##
78 ); 91 );
79 } 92 }
93
94 #[test]
95 fn completes_macros_braces_guessing() {
96 assert_debug_snapshot!(
97 do_reference_completion(
98 "
99 //- /main.rs
100 /// Foo
101 ///
102 /// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
103 /// Call as `let _=foo! { hello world };`
104 macro_rules! foo {
105 () => {}
106 }
107
108 fn main() {
109 <|>
110 }
111 "
112 ),
113 @r###"[
114 CompletionItem {
115 label: "foo!",
116 source_range: [163; 163),
117 delete: [163; 163),
118 insert: "foo! {$0}",
119 kind: Macro,
120 detail: "macro_rules! foo",
121 documentation: Documentation(
122 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
123 ),
124 },
125 CompletionItem {
126 label: "main()",
127 source_range: [163; 163),
128 delete: [163; 163),
129 insert: "main()$0",
130 kind: Function,
131 lookup: "main",
132 detail: "fn main()",
133 },
134]
135 "###
136 );
137 }
80} 138}
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 20242d293..aed4ce6d4 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -131,6 +131,33 @@ impl Completions {
131 self.add_function_with_name(ctx, None, func) 131 self.add_function_with_name(ctx, None, func)
132 } 132 }
133 133
134 fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str {
135 let mut votes = [0, 0, 0];
136 for (idx, s) in docs.match_indices(&macro_name) {
137 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
138 // Ensure to match the full word
139 if after.starts_with("!")
140 && before
141 .chars()
142 .rev()
143 .next()
144 .map_or(true, |c| c != '_' && !c.is_ascii_alphanumeric())
145 {
146 // It may have spaces before the braces like `foo! {}`
147 match after[1..].chars().find(|&c| !c.is_whitespace()) {
148 Some('{') => votes[0] += 1,
149 Some('[') => votes[1] += 1,
150 Some('(') => votes[2] += 1,
151 _ => {}
152 }
153 }
154 }
155
156 // Insert a space before `{}`.
157 // We prefer the last one when some votes equal.
158 *votes.iter().zip(&[" {$0}", "[$0]", "($0)"]).max_by_key(|&(&vote, _)| vote).unwrap().1
159 }
160
134 pub(crate) fn add_macro( 161 pub(crate) fn add_macro(
135 &mut self, 162 &mut self,
136 ctx: &CompletionContext, 163 ctx: &CompletionContext,
@@ -141,10 +168,9 @@ impl Completions {
141 if let Some(name) = name { 168 if let Some(name) = name {
142 let detail = macro_label(&ast_node); 169 let detail = macro_label(&ast_node);
143 170
144 let macro_braces_to_insert = match name.as_str() { 171 let docs = macro_.docs(ctx.db);
145 "vec" => "[$0]", 172 let macro_braces_to_insert =
146 _ => "($0)", 173 self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str()));
147 };
148 let macro_declaration = name + "!"; 174 let macro_declaration = name + "!";
149 175
150 let builder = CompletionItem::new( 176 let builder = CompletionItem::new(
@@ -153,7 +179,7 @@ impl Completions {
153 &macro_declaration, 179 &macro_declaration,
154 ) 180 )
155 .kind(CompletionItemKind::Macro) 181 .kind(CompletionItemKind::Macro)
156 .set_documentation(macro_.docs(ctx.db)) 182 .set_documentation(docs)
157 .detail(detail) 183 .detail(detail)
158 .insert_snippet(macro_declaration + macro_braces_to_insert); 184 .insert_snippet(macro_declaration + macro_braces_to_insert);
159 185