aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion/complete_keyword.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/completion/complete_keyword.rs')
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs164
1 files changed, 46 insertions, 118 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs
index d350f06ce..3fbf36313 100644
--- a/crates/ra_ide_api/src/completion/complete_keyword.rs
+++ b/crates/ra_ide_api/src/completion/complete_keyword.rs
@@ -11,36 +11,33 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
11 // complete keyword "crate" in use stmt 11 // complete keyword "crate" in use stmt
12 match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) { 12 match (ctx.use_item_syntax.as_ref(), ctx.path_prefix.as_ref()) {
13 (Some(_), None) => { 13 (Some(_), None) => {
14 CompletionItem::new(CompletionKind::Keyword, "crate") 14 CompletionItem::new(CompletionKind::Keyword, ctx, "crate")
15 .kind(CompletionItemKind::Keyword) 15 .kind(CompletionItemKind::Keyword)
16 .lookup_by("crate") 16 .insert_text("crate::")
17 .snippet("crate::")
18 .add_to(acc); 17 .add_to(acc);
19 CompletionItem::new(CompletionKind::Keyword, "self") 18 CompletionItem::new(CompletionKind::Keyword, ctx, "self")
20 .kind(CompletionItemKind::Keyword) 19 .kind(CompletionItemKind::Keyword)
21 .lookup_by("self")
22 .add_to(acc); 20 .add_to(acc);
23 CompletionItem::new(CompletionKind::Keyword, "super") 21 CompletionItem::new(CompletionKind::Keyword, ctx, "super")
24 .kind(CompletionItemKind::Keyword) 22 .kind(CompletionItemKind::Keyword)
25 .lookup_by("super") 23 .insert_text("super::")
26 .add_to(acc); 24 .add_to(acc);
27 } 25 }
28 (Some(_), Some(_)) => { 26 (Some(_), Some(_)) => {
29 CompletionItem::new(CompletionKind::Keyword, "self") 27 CompletionItem::new(CompletionKind::Keyword, ctx, "self")
30 .kind(CompletionItemKind::Keyword) 28 .kind(CompletionItemKind::Keyword)
31 .lookup_by("self")
32 .add_to(acc); 29 .add_to(acc);
33 CompletionItem::new(CompletionKind::Keyword, "super") 30 CompletionItem::new(CompletionKind::Keyword, ctx, "super")
34 .kind(CompletionItemKind::Keyword) 31 .kind(CompletionItemKind::Keyword)
35 .lookup_by("super") 32 .insert_text("super::")
36 .add_to(acc); 33 .add_to(acc);
37 } 34 }
38 _ => {} 35 _ => {}
39 } 36 }
40} 37}
41 38
42fn keyword(kw: &str, snippet: &str) -> CompletionItem { 39fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
43 CompletionItem::new(CompletionKind::Keyword, kw) 40 CompletionItem::new(CompletionKind::Keyword, ctx, kw)
44 .kind(CompletionItemKind::Keyword) 41 .kind(CompletionItemKind::Keyword)
45 .snippet(snippet) 42 .snippet(snippet)
46 .build() 43 .build()
@@ -55,25 +52,25 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
55 Some(it) => it, 52 Some(it) => it,
56 None => return, 53 None => return,
57 }; 54 };
58 acc.add(keyword("if", "if $0 {}")); 55 acc.add(keyword(ctx, "if", "if $0 {}"));
59 acc.add(keyword("match", "match $0 {}")); 56 acc.add(keyword(ctx, "match", "match $0 {}"));
60 acc.add(keyword("while", "while $0 {}")); 57 acc.add(keyword(ctx, "while", "while $0 {}"));
61 acc.add(keyword("loop", "loop {$0}")); 58 acc.add(keyword(ctx, "loop", "loop {$0}"));
62 59
63 if ctx.after_if { 60 if ctx.after_if {
64 acc.add(keyword("else", "else {$0}")); 61 acc.add(keyword(ctx, "else", "else {$0}"));
65 acc.add(keyword("else if", "else if $0 {}")); 62 acc.add(keyword(ctx, "else if", "else if $0 {}"));
66 } 63 }
67 if is_in_loop_body(ctx.leaf) { 64 if is_in_loop_body(ctx.leaf) {
68 if ctx.can_be_stmt { 65 if ctx.can_be_stmt {
69 acc.add(keyword("continue", "continue;")); 66 acc.add(keyword(ctx, "continue", "continue;"));
70 acc.add(keyword("break", "break;")); 67 acc.add(keyword(ctx, "break", "break;"));
71 } else { 68 } else {
72 acc.add(keyword("continue", "continue")); 69 acc.add(keyword(ctx, "continue", "continue"));
73 acc.add(keyword("break", "break")); 70 acc.add(keyword(ctx, "break", "break"));
74 } 71 }
75 } 72 }
76 acc.add_all(complete_return(fn_def, ctx.can_be_stmt)); 73 acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt));
77} 74}
78 75
79fn is_in_loop_body(leaf: &SyntaxNode) -> bool { 76fn is_in_loop_body(leaf: &SyntaxNode) -> bool {
@@ -95,78 +92,69 @@ fn is_in_loop_body(leaf: &SyntaxNode) -> bool {
95 false 92 false
96} 93}
97 94
98fn complete_return(fn_def: &ast::FnDef, can_be_stmt: bool) -> Option<CompletionItem> { 95fn complete_return(
96 ctx: &CompletionContext,
97 fn_def: &ast::FnDef,
98 can_be_stmt: bool,
99) -> Option<CompletionItem> {
99 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { 100 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
100 (true, true) => "return $0;", 101 (true, true) => "return $0;",
101 (true, false) => "return;", 102 (true, false) => "return;",
102 (false, true) => "return $0", 103 (false, true) => "return $0",
103 (false, false) => "return", 104 (false, false) => "return",
104 }; 105 };
105 Some(keyword("return", snip)) 106 Some(keyword(ctx, "return", snip))
106} 107}
107 108
108#[cfg(test)] 109#[cfg(test)]
109mod tests { 110mod tests {
110 use crate::completion::{CompletionKind, check_completion}; 111 use crate::completion::CompletionKind;
111 fn check_keyword_completion(code: &str, expected_completions: &str) { 112 use crate::completion::completion_item::check_completion;
112 check_completion(code, expected_completions, CompletionKind::Keyword); 113
114 fn check_keyword_completion(name: &str, code: &str) {
115 check_completion(name, code, CompletionKind::Keyword);
113 } 116 }
114 117
115 #[test] 118 #[test]
116 fn completes_keywords_in_use_stmt() { 119 fn completes_keywords_in_use_stmt() {
117 check_keyword_completion( 120 check_keyword_completion(
121 "keywords_in_use_stmt1",
118 r" 122 r"
119 use <|> 123 use <|>
120 ", 124 ",
121 r#"
122 crate "crate" "crate::"
123 self "self"
124 super "super"
125 "#,
126 ); 125 );
127 126
128 check_keyword_completion( 127 check_keyword_completion(
128 "keywords_in_use_stmt2",
129 r" 129 r"
130 use a::<|> 130 use a::<|>
131 ", 131 ",
132 r#"
133 self "self"
134 super "super"
135 "#,
136 ); 132 );
137 133
138 check_keyword_completion( 134 check_keyword_completion(
135 "keywords_in_use_stmt3",
139 r" 136 r"
140 use a::{b, <|>} 137 use a::{b, <|>}
141 ", 138 ",
142 r#"
143 self "self"
144 super "super"
145 "#,
146 ); 139 );
147 } 140 }
148 141
149 #[test] 142 #[test]
150 fn completes_various_keywords_in_function() { 143 fn completes_various_keywords_in_function() {
151 check_keyword_completion( 144 check_keyword_completion(
145 "keywords_in_function1",
152 r" 146 r"
153 fn quux() { 147 fn quux() {
154 <|> 148 <|>
155 } 149 }
156 ", 150 ",
157 r#"
158 if "if $0 {}"
159 match "match $0 {}"
160 while "while $0 {}"
161 loop "loop {$0}"
162 return "return;"
163 "#,
164 ); 151 );
165 } 152 }
166 153
167 #[test] 154 #[test]
168 fn completes_else_after_if() { 155 fn completes_else_after_if() {
169 check_keyword_completion( 156 check_keyword_completion(
157 "keywords_in_function2",
170 r" 158 r"
171 fn quux() { 159 fn quux() {
172 if true { 160 if true {
@@ -174,55 +162,35 @@ mod tests {
174 } <|> 162 } <|>
175 } 163 }
176 ", 164 ",
177 r#"
178 if "if $0 {}"
179 match "match $0 {}"
180 while "while $0 {}"
181 loop "loop {$0}"
182 else "else {$0}"
183 else if "else if $0 {}"
184 return "return;"
185 "#,
186 ); 165 );
187 } 166 }
188 167
189 #[test] 168 #[test]
190 fn test_completion_return_value() { 169 fn test_completion_return_value() {
191 check_keyword_completion( 170 check_keyword_completion(
171 "keywords_in_function3",
192 r" 172 r"
193 fn quux() -> i32 { 173 fn quux() -> i32 {
194 <|> 174 <|>
195 92 175 92
196 } 176 }
197 ", 177 ",
198 r#"
199 if "if $0 {}"
200 match "match $0 {}"
201 while "while $0 {}"
202 loop "loop {$0}"
203 return "return $0;"
204 "#,
205 ); 178 );
206 check_keyword_completion( 179 check_keyword_completion(
180 "keywords_in_function4",
207 r" 181 r"
208 fn quux() { 182 fn quux() {
209 <|> 183 <|>
210 92 184 92
211 } 185 }
212 ", 186 ",
213 r#"
214 if "if $0 {}"
215 match "match $0 {}"
216 while "while $0 {}"
217 loop "loop {$0}"
218 return "return;"
219 "#,
220 ); 187 );
221 } 188 }
222 189
223 #[test] 190 #[test]
224 fn dont_add_semi_after_return_if_not_a_statement() { 191 fn dont_add_semi_after_return_if_not_a_statement() {
225 check_keyword_completion( 192 check_keyword_completion(
193 "dont_add_semi_after_return_if_not_a_statement",
226 r" 194 r"
227 fn quux() -> i32 { 195 fn quux() -> i32 {
228 match () { 196 match () {
@@ -230,19 +198,13 @@ mod tests {
230 } 198 }
231 } 199 }
232 ", 200 ",
233 r#"
234 if "if $0 {}"
235 match "match $0 {}"
236 while "while $0 {}"
237 loop "loop {$0}"
238 return "return $0"
239 "#,
240 ); 201 );
241 } 202 }
242 203
243 #[test] 204 #[test]
244 fn last_return_in_block_has_semi() { 205 fn last_return_in_block_has_semi() {
245 check_keyword_completion( 206 check_keyword_completion(
207 "last_return_in_block_has_semi1",
246 r" 208 r"
247 fn quux() -> i32 { 209 fn quux() -> i32 {
248 if condition { 210 if condition {
@@ -250,15 +212,9 @@ mod tests {
250 } 212 }
251 } 213 }
252 ", 214 ",
253 r#"
254 if "if $0 {}"
255 match "match $0 {}"
256 while "while $0 {}"
257 loop "loop {$0}"
258 return "return $0;"
259 "#,
260 ); 215 );
261 check_keyword_completion( 216 check_keyword_completion(
217 "last_return_in_block_has_semi2",
262 r" 218 r"
263 fn quux() -> i32 { 219 fn quux() -> i32 {
264 if condition { 220 if condition {
@@ -268,54 +224,35 @@ mod tests {
268 x 224 x
269 } 225 }
270 ", 226 ",
271 r#"
272 if "if $0 {}"
273 match "match $0 {}"
274 while "while $0 {}"
275 loop "loop {$0}"
276 return "return $0;"
277 "#,
278 ); 227 );
279 } 228 }
280 229
281 #[test] 230 #[test]
282 fn completes_break_and_continue_in_loops() { 231 fn completes_break_and_continue_in_loops() {
283 check_keyword_completion( 232 check_keyword_completion(
233 "completes_break_and_continue_in_loops1",
284 r" 234 r"
285 fn quux() -> i32 { 235 fn quux() -> i32 {
286 loop { <|> } 236 loop { <|> }
287 } 237 }
288 ", 238 ",
289 r#"
290 if "if $0 {}"
291 match "match $0 {}"
292 while "while $0 {}"
293 loop "loop {$0}"
294 continue "continue;"
295 break "break;"
296 return "return $0;"
297 "#,
298 ); 239 );
240
299 // No completion: lambda isolates control flow 241 // No completion: lambda isolates control flow
300 check_keyword_completion( 242 check_keyword_completion(
243 "completes_break_and_continue_in_loops2",
301 r" 244 r"
302 fn quux() -> i32 { 245 fn quux() -> i32 {
303 loop { || { <|> } } 246 loop { || { <|> } }
304 } 247 }
305 ", 248 ",
306 r#"
307 if "if $0 {}"
308 match "match $0 {}"
309 while "while $0 {}"
310 loop "loop {$0}"
311 return "return $0;"
312 "#,
313 ); 249 );
314 } 250 }
315 251
316 #[test] 252 #[test]
317 fn no_semi_after_break_continue_in_expr() { 253 fn no_semi_after_break_continue_in_expr() {
318 check_keyword_completion( 254 check_keyword_completion(
255 "no_semi_after_break_continue_in_expr",
319 r" 256 r"
320 fn f() { 257 fn f() {
321 loop { 258 loop {
@@ -325,15 +262,6 @@ mod tests {
325 } 262 }
326 } 263 }
327 ", 264 ",
328 r#"
329 if "if $0 {}"
330 match "match $0 {}"
331 while "while $0 {}"
332 loop "loop {$0}"
333 continue "continue"
334 break "break"
335 return "return"
336 "#,
337 ) 265 )
338 } 266 }
339} 267}