diff options
author | Kevin DeLorey <[email protected]> | 2020-02-05 04:04:57 +0000 |
---|---|---|
committer | Kevin DeLorey <[email protected]> | 2020-02-05 04:04:57 +0000 |
commit | fc46ed81ee54d342d83e428ca74cbb0083547251 (patch) | |
tree | 4f81d8e27f25abf0eb133f260f1829a3ee52f3d2 /crates | |
parent | 698ff91c1309b189ca0f08e3d62d219305ae5f46 (diff) |
Add detection for a user already starting a fn impl and still providing completion.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 162 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 33 |
2 files changed, 157 insertions, 38 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 |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 0689013ba..97475fc0b 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -129,39 +129,6 @@ impl Completions { | |||
129 | self.add_function_with_name(ctx, None, func) | 129 | self.add_function_with_name(ctx, None, func) |
130 | } | 130 | } |
131 | 131 | ||
132 | pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: &hir::Function) { | ||
133 | use crate::display::FunctionSignature; | ||
134 | |||
135 | let display = FunctionSignature::from_hir(ctx.db, func.clone()); | ||
136 | |||
137 | let func_name = func.name(ctx.db); | ||
138 | |||
139 | let mut builder = CompletionItem::new( | ||
140 | CompletionKind::Reference, | ||
141 | ctx.source_range(), | ||
142 | format!("fn {}()", func_name.to_string())) | ||
143 | .set_documentation(func.docs(ctx.db)); | ||
144 | |||
145 | let completion_kind = if func.has_self_param(ctx.db) { | ||
146 | CompletionItemKind::Method | ||
147 | } else { | ||
148 | CompletionItemKind::Function | ||
149 | }; | ||
150 | |||
151 | let snippet = { | ||
152 | let mut s = format!("{}", display); | ||
153 | s.push_str(" { $0}"); | ||
154 | s | ||
155 | }; | ||
156 | |||
157 | builder = builder | ||
158 | .insert_text(snippet) | ||
159 | .kind(completion_kind) | ||
160 | .lookup_by(func_name.to_string()); | ||
161 | |||
162 | self.add(builder.build()); | ||
163 | } | ||
164 | |||
165 | fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { | 132 | fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { |
166 | let mut votes = [0, 0, 0]; | 133 | let mut votes = [0, 0, 0]; |
167 | for (idx, s) in docs.match_indices(¯o_name) { | 134 | for (idx, s) in docs.match_indices(¯o_name) { |