diff options
Diffstat (limited to 'crates/ra_ide/src/completion/complete_trait_impl.rs')
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 162 |
1 files changed, 157 insertions, 5 deletions
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 52ad7dd9d..c94ebee82 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::completion::{CompletionContext, Completions}; | 1 | use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionKind, CompletionItemKind}; |
2 | 2 | ||
3 | use ast::{ NameOwner }; | 3 | use ast::{ NameOwner }; |
4 | use hir::{ self, db::HirDatabase }; | 4 | use hir::{ self, db::HirDatabase }; |
5 | 5 | ||
6 | use ra_syntax::{ ast, ast::AstNode }; | 6 | use ra_syntax::{ SyntaxKind, ast, ast::AstNode, TextRange }; |
7 | 7 | ||
8 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
9 | let item_list = ast::ItemList::cast(ctx.token.parent()); | 9 | let item_list = ast::ItemList::cast(ctx.token.parent()); |
@@ -24,6 +24,37 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
24 | return; | 24 | return; |
25 | } | 25 | } |
26 | 26 | ||
27 | // for cases where the user has already started writing the function def, navigate | ||
28 | // the previous tokens in order to find the location of that token so that we may | ||
29 | // replace it with our completion. | ||
30 | let start_position = { | ||
31 | let mut prev_token = ctx.token | ||
32 | .prev_token() | ||
33 | .clone(); | ||
34 | |||
35 | while let Some(token) = &prev_token { | ||
36 | match token.kind() { | ||
37 | SyntaxKind::FN_KW => break, | ||
38 | |||
39 | // todo: attempt to find a better way of determining when to stop as | ||
40 | // the following feels sketchy. | ||
41 | SyntaxKind::IMPL_KW | | ||
42 | SyntaxKind::L_CURLY | | ||
43 | SyntaxKind::R_CURLY => { | ||
44 | prev_token = None; | ||
45 | break; | ||
46 | } | ||
47 | _ => {} | ||
48 | } | ||
49 | |||
50 | prev_token = token.prev_token().clone(); | ||
51 | } | ||
52 | |||
53 | prev_token | ||
54 | .map(|t| t.text_range()) | ||
55 | .unwrap_or(ctx.source_range()) | ||
56 | }; | ||
57 | |||
27 | let trait_ = target_trait.unwrap(); | 58 | let trait_ = target_trait.unwrap(); |
28 | 59 | ||
29 | let trait_items = trait_.items(ctx.db); | 60 | let trait_items = trait_.items(ctx.db); |
@@ -97,7 +128,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
97 | 128 | ||
98 | for item in missing_items { | 129 | for item in missing_items { |
99 | match item { | 130 | match item { |
100 | hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), | 131 | hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f, start_position), |
101 | _ => {} | 132 | _ => {} |
102 | } | 133 | } |
103 | } | 134 | } |
@@ -122,6 +153,40 @@ fn resolve_target_trait( | |||
122 | } | 153 | } |
123 | } | 154 | } |
124 | 155 | ||
156 | pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function, start: TextRange) { | ||
157 | use crate::display::FunctionSignature; | ||
158 | |||
159 | let display = FunctionSignature::from_hir(ctx.db, func.clone()); | ||
160 | |||
161 | let func_name = func.name(ctx.db); | ||
162 | |||
163 | let label = if func.params(ctx.db).len() > 0 { | ||
164 | format!("fn {}(..)", func_name.to_string()) | ||
165 | } else { | ||
166 | format!("fn {}()", func_name.to_string()) | ||
167 | }; | ||
168 | |||
169 | let builder = CompletionItem::new(CompletionKind::Reference, start, label); | ||
170 | |||
171 | let completion_kind = if func.has_self_param(ctx.db) { | ||
172 | CompletionItemKind::Method | ||
173 | } else { | ||
174 | CompletionItemKind::Function | ||
175 | }; | ||
176 | |||
177 | let snippet = { | ||
178 | let mut s = format!("{}", display); | ||
179 | s.push_str(" {}"); | ||
180 | s | ||
181 | }; | ||
182 | |||
183 | builder | ||
184 | .insert_text(snippet) | ||
185 | .kind(completion_kind) | ||
186 | .lookup_by(func_name.to_string()) | ||
187 | .add_to(acc); | ||
188 | } | ||
189 | |||
125 | #[cfg(test)] | 190 | #[cfg(test)] |
126 | mod tests { | 191 | mod tests { |
127 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 192 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; |
@@ -152,7 +217,7 @@ mod tests { | |||
152 | label: "fn foo()", | 217 | label: "fn foo()", |
153 | source_range: [138; 138), | 218 | source_range: [138; 138), |
154 | delete: [138; 138), | 219 | delete: [138; 138), |
155 | insert: "fn foo() { $0}", | 220 | insert: "fn foo() {}", |
156 | kind: Function, | 221 | kind: Function, |
157 | lookup: "foo", | 222 | lookup: "foo", |
158 | }, | 223 | }, |
@@ -184,11 +249,98 @@ mod tests { | |||
184 | label: "fn bar()", | 249 | label: "fn bar()", |
185 | source_range: [193; 193), | 250 | source_range: [193; 193), |
186 | delete: [193; 193), | 251 | delete: [193; 193), |
187 | insert: "fn bar() { $0}", | 252 | insert: "fn bar() {}", |
188 | kind: Function, | 253 | kind: Function, |
189 | lookup: "bar", | 254 | lookup: "bar", |
190 | }, | 255 | }, |
191 | ] | 256 | ] |
192 | "###); | 257 | "###); |
193 | } | 258 | } |
259 | |||
260 | #[test] | ||
261 | fn generic_fn() { | ||
262 | let completions = complete( | ||
263 | r" | ||
264 | trait Test { | ||
265 | fn foo<T>(); | ||
266 | } | ||
267 | |||
268 | struct T1; | ||
269 | |||
270 | impl Test for T1 { | ||
271 | <|> | ||
272 | } | ||
273 | ", | ||
274 | ); | ||
275 | assert_debug_snapshot!(completions, @r###" | ||
276 | [ | ||
277 | CompletionItem { | ||
278 | label: "fn foo()", | ||
279 | source_range: [141; 141), | ||
280 | delete: [141; 141), | ||
281 | insert: "fn foo<T>() {}", | ||
282 | kind: Function, | ||
283 | lookup: "foo", | ||
284 | }, | ||
285 | ] | ||
286 | "###); | ||
287 | } | ||
288 | |||
289 | #[test] | ||
290 | fn generic_constrait_fn() { | ||
291 | let completions = complete( | ||
292 | r" | ||
293 | trait Test { | ||
294 | fn foo<T>() where T: Into<String>; | ||
295 | } | ||
296 | |||
297 | struct T1; | ||
298 | |||
299 | impl Test for T1 { | ||
300 | <|> | ||
301 | } | ||
302 | ", | ||
303 | ); | ||
304 | assert_debug_snapshot!(completions, @r###" | ||
305 | [ | ||
306 | CompletionItem { | ||
307 | label: "fn foo()", | ||
308 | source_range: [163; 163), | ||
309 | delete: [163; 163), | ||
310 | insert: "fn foo<T>()\nwhere T: Into<String> {}", | ||
311 | kind: Function, | ||
312 | lookup: "foo", | ||
313 | }, | ||
314 | ] | ||
315 | "###); | ||
316 | } | ||
317 | |||
318 | #[test] | ||
319 | fn start_from_fn_kw() { | ||
320 | let completions = complete( | ||
321 | r" | ||
322 | trait Test { | ||
323 | fn foo(); | ||
324 | } | ||
325 | |||
326 | struct T1; | ||
327 | |||
328 | impl Test for T1 { | ||
329 | fn <|> | ||
330 | } | ||
331 | ", | ||
332 | ); | ||
333 | assert_debug_snapshot!(completions, @r###" | ||
334 | [ | ||
335 | CompletionItem { | ||
336 | label: "fn foo()", | ||
337 | source_range: [138; 140), | ||
338 | delete: [138; 140), | ||
339 | insert: "fn foo() {}", | ||
340 | kind: Function, | ||
341 | lookup: "foo", | ||
342 | }, | ||
343 | ] | ||
344 | "###); | ||
345 | } | ||
194 | } \ No newline at end of file | 346 | } \ No newline at end of file |