aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin DeLorey <[email protected]>2020-02-05 04:04:57 +0000
committerKevin DeLorey <[email protected]>2020-02-05 04:04:57 +0000
commitfc46ed81ee54d342d83e428ca74cbb0083547251 (patch)
tree4f81d8e27f25abf0eb133f260f1829a3ee52f3d2
parent698ff91c1309b189ca0f08e3d62d219305ae5f46 (diff)
Add detection for a user already starting a fn impl and still providing completion.
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs162
-rw-r--r--crates/ra_ide/src/completion/presentation.rs33
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 @@
1use crate::completion::{CompletionContext, Completions}; 1use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionKind, CompletionItemKind};
2 2
3use ast::{ NameOwner }; 3use ast::{ NameOwner };
4use hir::{ self, db::HirDatabase }; 4use hir::{ self, db::HirDatabase };
5 5
6use ra_syntax::{ ast, ast::AstNode }; 6use ra_syntax::{ SyntaxKind, ast, ast::AstNode, TextRange };
7 7
8pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 8pub(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
156pub(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)]
126mod tests { 191mod 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(&macro_name) { 134 for (idx, s) in docs.match_indices(&macro_name) {