diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 140 |
1 files changed, 84 insertions, 56 deletions
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 400a266a2..b7807ef8e 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -44,48 +44,56 @@ impl Completions { | |||
44 | ) { | 44 | ) { |
45 | use hir::ModuleDef::*; | 45 | use hir::ModuleDef::*; |
46 | 46 | ||
47 | let mut completion_kind = CompletionKind::Reference; | 47 | let completion_kind = match resolution { |
48 | let (kind, docs) = match resolution { | 48 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, |
49 | ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)), | 49 | _ => CompletionKind::Reference, |
50 | }; | ||
51 | |||
52 | let kind = match resolution { | ||
53 | ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, | ||
50 | ScopeDef::ModuleDef(Function(func)) => { | 54 | ScopeDef::ModuleDef(Function(func)) => { |
51 | return self.add_function_with_name(ctx, Some(local_name), *func); | 55 | return self.add_function_with_name(ctx, Some(local_name), *func); |
52 | } | 56 | } |
53 | ScopeDef::ModuleDef(Adt(adt)) => { | 57 | ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, |
54 | return self.add_adt_with_name(ctx, local_name, *adt); | 58 | // FIXME: add CompletionItemKind::Union |
55 | } | 59 | ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, |
56 | ScopeDef::ModuleDef(EnumVariant(it)) => { | 60 | ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, |
57 | (CompletionItemKind::EnumVariant, it.docs(ctx.db)) | 61 | |
58 | } | 62 | ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant, |
59 | ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)), | 63 | ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, |
60 | ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)), | 64 | ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, |
61 | ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)), | 65 | ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, |
62 | ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), | 66 | ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, |
63 | ScopeDef::ModuleDef(BuiltinType(..)) => { | 67 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, |
64 | completion_kind = CompletionKind::BuiltinType; | 68 | ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, |
65 | (CompletionItemKind::BuiltinType, None) | 69 | ScopeDef::LocalBinding(..) => CompletionItemKind::Binding, |
66 | } | 70 | // (does this need its own kind?) |
67 | ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None), | 71 | ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, |
68 | ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None), | ||
69 | ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => ( | ||
70 | CompletionItemKind::TypeParam, // (does this need its own kind?) | ||
71 | None, | ||
72 | ), | ||
73 | ScopeDef::MacroDef(mac) => { | 72 | ScopeDef::MacroDef(mac) => { |
74 | self.add_macro(ctx, Some(local_name), *mac); | 73 | return self.add_macro(ctx, Some(local_name), *mac); |
75 | return; | ||
76 | } | 74 | } |
77 | ScopeDef::Unknown => { | 75 | ScopeDef::Unknown => { |
78 | self.add(CompletionItem::new( | 76 | return self.add(CompletionItem::new( |
79 | CompletionKind::Reference, | 77 | CompletionKind::Reference, |
80 | ctx.source_range(), | 78 | ctx.source_range(), |
81 | local_name, | 79 | local_name, |
82 | )); | 80 | )); |
83 | return; | ||
84 | } | 81 | } |
85 | }; | 82 | }; |
86 | 83 | ||
84 | let docs = match resolution { | ||
85 | ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db), | ||
86 | ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db), | ||
87 | ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db), | ||
88 | ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db), | ||
89 | ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db), | ||
90 | ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db), | ||
91 | ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db), | ||
92 | _ => None, | ||
93 | }; | ||
94 | |||
87 | let mut completion_item = | 95 | let mut completion_item = |
88 | CompletionItem::new(completion_kind, ctx.source_range(), local_name); | 96 | CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); |
89 | if let ScopeDef::LocalBinding(pat_id) = resolution { | 97 | if let ScopeDef::LocalBinding(pat_id) = resolution { |
90 | let ty = ctx | 98 | let ty = ctx |
91 | .analyzer | 99 | .analyzer |
@@ -94,6 +102,25 @@ impl Completions { | |||
94 | .map(|t| t.display(ctx.db).to_string()); | 102 | .map(|t| t.display(ctx.db).to_string()); |
95 | completion_item = completion_item.set_detail(ty); | 103 | completion_item = completion_item.set_detail(ty); |
96 | }; | 104 | }; |
105 | |||
106 | // If not an import, add parenthesis automatically. | ||
107 | if ctx.is_path_type | ||
108 | && !ctx.has_type_args | ||
109 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
110 | { | ||
111 | let generic_def: Option<hir::GenericDef> = match resolution { | ||
112 | ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()), | ||
113 | ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()), | ||
114 | _ => None, | ||
115 | }; | ||
116 | if let Some(def) = generic_def { | ||
117 | if has_non_default_type_params(def, ctx.db) { | ||
118 | tested_by!(inserts_angle_brackets_for_generics); | ||
119 | completion_item = completion_item.insert_snippet(format!("{}<$0>", local_name)); | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
97 | completion_item.kind(kind).set_documentation(docs).add_to(self) | 124 | completion_item.kind(kind).set_documentation(docs).add_to(self) |
98 | } | 125 | } |
99 | 126 | ||
@@ -169,32 +196,6 @@ impl Completions { | |||
169 | self.add(builder) | 196 | self.add(builder) |
170 | } | 197 | } |
171 | 198 | ||
172 | fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) { | ||
173 | let mut builder = | ||
174 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()); | ||
175 | |||
176 | let kind = match adt { | ||
177 | hir::Adt::Struct(_) => CompletionItemKind::Struct, | ||
178 | // FIXME: add CompletionItemKind::Union | ||
179 | hir::Adt::Union(_) => CompletionItemKind::Struct, | ||
180 | hir::Adt::Enum(_) => CompletionItemKind::Enum, | ||
181 | }; | ||
182 | let docs = adt.docs(ctx.db); | ||
183 | |||
184 | // If not an import, add parenthesis automatically. | ||
185 | if ctx.is_path_type | ||
186 | && !ctx.has_type_args | ||
187 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
188 | { | ||
189 | if has_non_default_type_params(adt, ctx.db) { | ||
190 | tested_by!(inserts_angle_brackets_for_generics); | ||
191 | builder = builder.insert_snippet(format!("{}<$0>", name)); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | builder.kind(kind).set_documentation(docs).add_to(self) | ||
196 | } | ||
197 | |||
198 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 199 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
199 | let ast_node = constant.source(ctx.db).ast; | 200 | let ast_node = constant.source(ctx.db).ast; |
200 | let name = match ast_node.name() { | 201 | let name = match ast_node.name() { |
@@ -243,8 +244,8 @@ impl Completions { | |||
243 | } | 244 | } |
244 | } | 245 | } |
245 | 246 | ||
246 | fn has_non_default_type_params(adt: hir::Adt, db: &db::RootDatabase) -> bool { | 247 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { |
247 | let subst = db.generic_defaults(adt.into()); | 248 | let subst = db.generic_defaults(def); |
248 | subst.iter().any(|ty| ty == &Ty::Unknown) | 249 | subst.iter().any(|ty| ty == &Ty::Unknown) |
249 | } | 250 | } |
250 | 251 | ||
@@ -449,6 +450,33 @@ mod tests { | |||
449 | assert_debug_snapshot!( | 450 | assert_debug_snapshot!( |
450 | do_reference_completion( | 451 | do_reference_completion( |
451 | r" | 452 | r" |
453 | type Vec<T> = (T,); | ||
454 | fn foo(xs: Ve<|>) | ||
455 | " | ||
456 | ), | ||
457 | @r###" | ||
458 | [ | ||
459 | CompletionItem { | ||
460 | label: "Vec", | ||
461 | source_range: [64; 66), | ||
462 | delete: [64; 66), | ||
463 | insert: "Vec<$0>", | ||
464 | kind: TypeAlias, | ||
465 | }, | ||
466 | CompletionItem { | ||
467 | label: "foo", | ||
468 | source_range: [64; 66), | ||
469 | delete: [64; 66), | ||
470 | insert: "foo($0)", | ||
471 | kind: Function, | ||
472 | detail: "fn foo(xs: Ve)", | ||
473 | }, | ||
474 | ] | ||
475 | "### | ||
476 | ); | ||
477 | assert_debug_snapshot!( | ||
478 | do_reference_completion( | ||
479 | r" | ||
452 | struct Vec<T = i128> {} | 480 | struct Vec<T = i128> {} |
453 | fn foo(xs: Ve<|>) | 481 | fn foo(xs: Ve<|>) |
454 | " | 482 | " |