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