aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 18:56:49 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 18:56:49 +0000
commit5a684099e9aa3482b408002030fafe1dcd0fa9a9 (patch)
tree20e86fbc586b350c336277d2b0886a60f9844de8 /crates/ra_ide_api
parent67528c4b3943a2027839a25770d079132a9ea130 (diff)
parentd5f6a5f5e29df3005533502b49f78daae314ac5b (diff)
Merge #893
893: Completion presentation r=matklad a=matklad Just moves completion code around a bit, to keep logic for producing completions and logic for rendering them into completion items separate. Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/completion.rs4
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs36
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs3
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs3
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs93
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs3
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs11
-rw-r--r--crates/ra_ide_api/src/completion/complete_snippet.rs3
-rw-r--r--crates/ra_ide_api/src/completion/complete_struct_literal.rs19
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs192
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs245
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__dont_render_function_parens_if_already_call_assoc_fn.snap6
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__struct_associated_method.snap6
13 files changed, 294 insertions, 330 deletions
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index d92e01bfb..fbfd7e3e7 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -1,5 +1,6 @@
1mod completion_item; 1mod completion_item;
2mod completion_context; 2mod completion_context;
3mod presentation;
3 4
4mod complete_dot; 5mod complete_dot;
5mod complete_struct_literal; 6mod complete_struct_literal;
@@ -20,7 +21,10 @@ use crate::{
20 completion_item::{Completions, CompletionKind}, 21 completion_item::{Completions, CompletionKind},
21 completion_context::CompletionContext, 22 completion_context::CompletionContext,
22 }, 23 },
24
23}; 25};
26#[cfg(test)]
27use crate::completion::completion_item::{do_completion, check_completion};
24 28
25pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind, InsertTextFormat}; 29pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind, InsertTextFormat};
26 30
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 20fa323ce..d5ad2e79f 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -1,7 +1,6 @@
1use hir::{Ty, AdtDef, Docs}; 1use hir::{Ty, AdtDef};
2 2
3use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; 3use crate::completion::{CompletionContext, Completions};
4use crate::completion::completion_item::CompletionKind;
5 4
6/// Complete dot accesses, i.e. fields or methods (currently only fields). 5/// Complete dot accesses, i.e. fields or methods (currently only fields).
7pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
@@ -29,15 +28,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
29 match def_id { 28 match def_id {
30 AdtDef::Struct(s) => { 29 AdtDef::Struct(s) => {
31 for field in s.fields(ctx.db) { 30 for field in s.fields(ctx.db) {
32 CompletionItem::new( 31 acc.add_field(ctx, field, substs);
33 CompletionKind::Reference,
34 ctx.source_range(),
35 field.name(ctx.db).to_string(),
36 )
37 .kind(CompletionItemKind::Field)
38 .detail(field.ty(ctx.db).subst(substs).to_string())
39 .set_documentation(field.docs(ctx.db))
40 .add_to(acc);
41 } 32 }
42 } 33 }
43 34
@@ -47,14 +38,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
47 } 38 }
48 Ty::Tuple(fields) => { 39 Ty::Tuple(fields) => {
49 for (i, ty) in fields.iter().enumerate() { 40 for (i, ty) in fields.iter().enumerate() {
50 CompletionItem::new( 41 acc.add_pos_field(ctx, i, ty);
51 CompletionKind::Reference,
52 ctx.source_range(),
53 i.to_string(),
54 )
55 .kind(CompletionItemKind::Field)
56 .detail(ty.to_string())
57 .add_to(acc);
58 } 42 }
59 } 43 }
60 _ => {} 44 _ => {}
@@ -66,14 +50,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty
66 receiver.iterate_methods(ctx.db, |_ty, func| { 50 receiver.iterate_methods(ctx.db, |_ty, func| {
67 let sig = func.signature(ctx.db); 51 let sig = func.signature(ctx.db);
68 if sig.has_self_param() { 52 if sig.has_self_param() {
69 CompletionItem::new( 53 acc.add_function(ctx, func);
70 CompletionKind::Reference,
71 ctx.source_range(),
72 sig.name().to_string(),
73 )
74 .from_function(ctx, func)
75 .kind(CompletionItemKind::Method)
76 .add_to(acc);
77 } 54 }
78 None::<()> 55 None::<()>
79 }); 56 });
@@ -81,8 +58,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty
81 58
82#[cfg(test)] 59#[cfg(test)]
83mod tests { 60mod tests {
84 use crate::completion::*; 61 use crate::completion::{check_completion, CompletionKind};
85 use crate::completion::completion_item::check_completion;
86 62
87 fn check_ref_completion(name: &str, code: &str) { 63 fn check_ref_completion(name: &str, code: &str) {
88 check_completion(name, code, CompletionKind::Reference); 64 check_completion(name, code, CompletionKind::Reference);
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index 4d6416284..ffdc744b2 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -54,8 +54,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
54 54
55#[cfg(test)] 55#[cfg(test)]
56mod tests { 56mod tests {
57 use crate::completion::*; 57 use crate::completion::{check_completion, CompletionKind};
58 use crate::completion::completion_item::check_completion;
59 58
60 fn check_magic_completion(name: &str, code: &str) { 59 fn check_magic_completion(name: &str, code: &str) {
61 check_completion(name, code, CompletionKind::Magic); 60 check_completion(name, code, CompletionKind::Magic);
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs
index b667381a7..841c0c554 100644
--- a/crates/ra_ide_api/src/completion/complete_keyword.rs
+++ b/crates/ra_ide_api/src/completion/complete_keyword.rs
@@ -109,8 +109,7 @@ fn complete_return(
109 109
110#[cfg(test)] 110#[cfg(test)]
111mod tests { 111mod tests {
112 use crate::completion::CompletionKind; 112 use crate::completion::{check_completion, CompletionKind};
113 use crate::completion::completion_item::check_completion;
114 113
115 fn check_keyword_completion(name: &str, code: &str) { 114 fn check_keyword_completion(name: &str, code: &str) {
116 check_completion(name, code, CompletionKind::Keyword); 115 check_completion(name, code, CompletionKind::Keyword);
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index d337fe970..629a7ee77 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -1,9 +1,8 @@
1use join_to_string::join; 1use hir::Resolution;
2use hir::{Docs, Resolution}; 2use ra_syntax::AstNode;
3use ra_syntax::{AstNode, ast::NameOwner};
4use test_utils::tested_by; 3use test_utils::tested_by;
5 4
6use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}; 5use crate::completion::{Completions, CompletionContext};
7 6
8pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { 7pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
9 let path = match &ctx.path_prefix { 8 let path = match &ctx.path_prefix {
@@ -28,79 +27,28 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
28 } 27 }
29 } 28 }
30 } 29 }
31 30 acc.add_resolution(ctx, name.to_string(), &res.def.map(hir::Resolution::Def));
32 CompletionItem::new(
33 CompletionKind::Reference,
34 ctx.source_range(),
35 name.to_string(),
36 )
37 .from_resolution(ctx, &res.def.map(hir::Resolution::Def))
38 .add_to(acc);
39 } 31 }
40 } 32 }
41 hir::ModuleDef::Enum(e) => { 33 hir::ModuleDef::Enum(e) => {
42 e.variants(ctx.db).into_iter().for_each(|variant| { 34 for variant in e.variants(ctx.db) {
43 if let Some(name) = variant.name(ctx.db) { 35 acc.add_enum_variant(ctx, variant);
44 let detail_types = 36 }
45 variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
46 let detail =
47 join(detail_types).separator(", ").surround_with("(", ")").to_string();
48
49 CompletionItem::new(
50 CompletionKind::Reference,
51 ctx.source_range(),
52 name.to_string(),
53 )
54 .kind(CompletionItemKind::EnumVariant)
55 .set_documentation(variant.docs(ctx.db))
56 .set_detail(Some(detail))
57 .add_to(acc)
58 }
59 });
60 } 37 }
61 hir::ModuleDef::Struct(s) => { 38 hir::ModuleDef::Struct(s) => {
62 let ty = s.ty(ctx.db); 39 let ty = s.ty(ctx.db);
63 ty.iterate_impl_items(ctx.db, |item| match item { 40 ty.iterate_impl_items(ctx.db, |item| {
64 hir::ImplItem::Method(func) => { 41 match item {
65 let sig = func.signature(ctx.db); 42 hir::ImplItem::Method(func) => {
66 if !sig.has_self_param() { 43 let sig = func.signature(ctx.db);
67 CompletionItem::new( 44 if !sig.has_self_param() {
68 CompletionKind::Reference, 45 acc.add_function(ctx, func);
69 ctx.source_range(), 46 }
70 sig.name().to_string(),
71 )
72 .from_function(ctx, func)
73 .kind(CompletionItemKind::Method)
74 .add_to(acc);
75 }
76 None::<()>
77 }
78 hir::ImplItem::Const(ct) => {
79 let source = ct.source(ctx.db);
80 if let Some(name) = source.1.name() {
81 CompletionItem::new(
82 CompletionKind::Reference,
83 ctx.source_range(),
84 name.text().to_string(),
85 )
86 .from_const(ctx, ct)
87 .add_to(acc);
88 }
89 None::<()>
90 }
91 hir::ImplItem::Type(ty) => {
92 let source = ty.source(ctx.db);
93 if let Some(name) = source.1.name() {
94 CompletionItem::new(
95 CompletionKind::Reference,
96 ctx.source_range(),
97 name.text().to_string(),
98 )
99 .from_type(ctx, ty)
100 .add_to(acc);
101 } 47 }
102 None::<()> 48 hir::ImplItem::Const(ct) => acc.add_const(ctx, ct),
49 hir::ImplItem::Type(ty) => acc.add_type(ctx, ty),
103 } 50 }
51 None::<()>
104 }); 52 });
105 } 53 }
106 _ => return, 54 _ => return,
@@ -109,13 +57,10 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
109 57
110#[cfg(test)] 58#[cfg(test)]
111mod tests { 59mod tests {
112 use crate::completion::{
113 CompletionKind,
114 completion_item::{check_completion, do_completion},
115};
116
117 use test_utils::covers; 60 use test_utils::covers;
118 61
62 use crate::completion::{CompletionKind, check_completion, do_completion};
63
119 fn check_reference_completion(code: &str, expected_completions: &str) { 64 fn check_reference_completion(code: &str, expected_completions: &str) {
120 check_completion(code, expected_completions, CompletionKind::Reference); 65 check_completion(code, expected_completions, CompletionKind::Reference);
121 } 66 }
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index ce3d6ed3c..4dfa5f176 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -56,8 +56,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
56 56
57#[cfg(test)] 57#[cfg(test)]
58mod tests { 58mod tests {
59 use crate::completion::completion_item::CompletionKind; 59 use crate::completion::{CompletionKind, check_completion};
60 use crate::completion::completion_item::check_completion;
61 60
62 fn check_snippet_completion(test_name: &str, code: &str) { 61 fn check_snippet_completion(test_name: &str, code: &str) {
63 check_completion(test_name, code, CompletionKind::Postfix); 62 check_completion(test_name, code, CompletionKind::Postfix);
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index eeaf26d93..6146b7bb6 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -1,4 +1,4 @@
1use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext}; 1use crate::completion::{Completions, CompletionContext};
2 2
3pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { 3pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
4 if !ctx.is_trivial_path { 4 if !ctx.is_trivial_path {
@@ -6,17 +6,12 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
6 } 6 }
7 let names = ctx.resolver.all_names(ctx.db); 7 let names = ctx.resolver.all_names(ctx.db);
8 8
9 names.into_iter().for_each(|(name, res)| { 9 names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res));
10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
11 .from_resolution(ctx, &res)
12 .add_to(acc)
13 });
14} 10}
15 11
16#[cfg(test)] 12#[cfg(test)]
17mod tests { 13mod tests {
18 use crate::completion::CompletionKind; 14 use crate::completion::{CompletionKind, check_completion};
19 use crate::completion::completion_item::check_completion;
20 15
21 fn check_reference_completion(name: &str, code: &str) { 16 fn check_reference_completion(name: &str, code: &str) {
22 check_completion(name, code, CompletionKind::Reference); 17 check_completion(name, code, CompletionKind::Reference);
diff --git a/crates/ra_ide_api/src/completion/complete_snippet.rs b/crates/ra_ide_api/src/completion/complete_snippet.rs
index aa3a16fa2..e1df9e625 100644
--- a/crates/ra_ide_api/src/completion/complete_snippet.rs
+++ b/crates/ra_ide_api/src/completion/complete_snippet.rs
@@ -36,8 +36,7 @@ fn ${1:feature}() {
36 36
37#[cfg(test)] 37#[cfg(test)]
38mod tests { 38mod tests {
39 use crate::completion::CompletionKind; 39 use crate::completion::{CompletionKind, check_completion};
40 use crate::completion::completion_item::check_completion;
41 40
42 fn check_snippet_completion(name: &str, code: &str) { 41 fn check_snippet_completion(name: &str, code: &str) {
43 check_completion(name, code, CompletionKind::Snippet); 42 check_completion(name, code, CompletionKind::Snippet);
diff --git a/crates/ra_ide_api/src/completion/complete_struct_literal.rs b/crates/ra_ide_api/src/completion/complete_struct_literal.rs
index f8dd2baad..afb092f59 100644
--- a/crates/ra_ide_api/src/completion/complete_struct_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_struct_literal.rs
@@ -1,7 +1,6 @@
1use hir::{Ty, AdtDef, Docs}; 1use hir::{Ty, AdtDef};
2 2
3use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; 3use crate::completion::{CompletionContext, Completions};
4use crate::completion::completion_item::CompletionKind;
5 4
6/// Complete fields in fields literals. 5/// Complete fields in fields literals.
7pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) {
@@ -23,15 +22,7 @@ pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionCon
23 match adt { 22 match adt {
24 AdtDef::Struct(s) => { 23 AdtDef::Struct(s) => {
25 for field in s.fields(ctx.db) { 24 for field in s.fields(ctx.db) {
26 CompletionItem::new( 25 acc.add_field(ctx, field, substs);
27 CompletionKind::Reference,
28 ctx.source_range(),
29 field.name(ctx.db).to_string(),
30 )
31 .kind(CompletionItemKind::Field)
32 .detail(field.ty(ctx.db).subst(substs).to_string())
33 .set_documentation(field.docs(ctx.db))
34 .add_to(acc);
35 } 26 }
36 } 27 }
37 28
@@ -43,10 +34,10 @@ pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionCon
43#[cfg(test)] 34#[cfg(test)]
44mod tests { 35mod tests {
45 use insta::assert_debug_snapshot_matches; 36 use insta::assert_debug_snapshot_matches;
46 use crate::completion::{CompletionItem, CompletionKind}; 37 use crate::completion::{CompletionItem, CompletionKind, do_completion};
47 38
48 fn complete(code: &str) -> Vec<CompletionItem> { 39 fn complete(code: &str) -> Vec<CompletionItem> {
49 crate::completion::completion_item::do_completion(code, CompletionKind::Reference) 40 do_completion(code, CompletionKind::Reference)
50 } 41 }
51 42
52 #[test] 43 #[test]
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index 95bdd59b4..f515fcc14 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -1,16 +1,8 @@
1use std::fmt; 1use std::fmt;
2 2
3use hir::{Docs, Documentation, PerNs, Resolution}; 3use hir::Documentation;
4use ra_syntax::TextRange; 4use ra_syntax::TextRange;
5use ra_text_edit::{ TextEditBuilder, TextEdit}; 5use ra_text_edit::{TextEditBuilder, TextEdit};
6use test_utils::tested_by;
7
8use crate::completion::{
9 completion_context::CompletionContext,
10 function_label,
11 const_label,
12 type_label
13};
14 6
15/// `CompletionItem` describes a single completion variant in the editor pop-up. 7/// `CompletionItem` describes a single completion variant in the editor pop-up.
16/// It is basically a POD with various properties. To construct a 8/// It is basically a POD with various properties. To construct a
@@ -255,91 +247,6 @@ impl Builder {
255 self.documentation = docs.map(Into::into); 247 self.documentation = docs.map(Into::into);
256 self 248 self
257 } 249 }
258 pub(super) fn from_resolution(
259 mut self,
260 ctx: &CompletionContext,
261 resolution: &PerNs<Resolution>,
262 ) -> Builder {
263 use hir::ModuleDef::*;
264
265 let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
266 let def = match def {
267 None => return self,
268 Some(it) => it,
269 };
270 let (kind, docs) = match def {
271 Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
272 Resolution::Def(Function(func)) => return self.from_function(ctx, *func),
273 Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
274 Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)),
275 Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
276 Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
277 Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
278 Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
279 Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
280 Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
281 Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
282 Resolution::SelfType(..) => (
283 CompletionItemKind::TypeParam, // (does this need its own kind?)
284 None,
285 ),
286 };
287 self.kind = Some(kind);
288 self.documentation = docs;
289
290 self
291 }
292
293 pub(super) fn from_function(
294 mut self,
295 ctx: &CompletionContext,
296 function: hir::Function,
297 ) -> Builder {
298 // If not an import, add parenthesis automatically.
299 if ctx.use_item_syntax.is_none() && !ctx.is_call {
300 tested_by!(inserts_parens_for_function_calls);
301 let sig = function.signature(ctx.db);
302 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 {
303 self.insert_text = Some(format!("{}()$0", self.label));
304 } else {
305 self.insert_text = Some(format!("{}($0)", self.label));
306 }
307 self.insert_text_format = InsertTextFormat::Snippet;
308 }
309
310 if let Some(docs) = function.docs(ctx.db) {
311 self.documentation = Some(docs);
312 }
313
314 if let Some(label) = function_item_label(ctx, function) {
315 self.detail = Some(label);
316 }
317
318 self.kind = Some(CompletionItemKind::Function);
319 self
320 }
321
322 pub(super) fn from_const(mut self, ctx: &CompletionContext, ct: hir::Const) -> Builder {
323 if let Some(docs) = ct.docs(ctx.db) {
324 self.documentation = Some(docs);
325 }
326
327 self.detail = Some(const_item_label(ctx, ct));
328 self.kind = Some(CompletionItemKind::Const);
329
330 self
331 }
332
333 pub(super) fn from_type(mut self, ctx: &CompletionContext, ty: hir::Type) -> Builder {
334 if let Some(docs) = ty.docs(ctx.db) {
335 self.documentation = Some(docs);
336 }
337
338 self.detail = Some(type_item_label(ctx, ty));
339 self.kind = Some(CompletionItemKind::TypeAlias);
340
341 self
342 }
343} 250}
344 251
345impl<'a> Into<CompletionItem> for Builder { 252impl<'a> Into<CompletionItem> for Builder {
@@ -373,21 +280,6 @@ impl Into<Vec<CompletionItem>> for Completions {
373 } 280 }
374} 281}
375 282
376fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
377 let node = function.source(ctx.db).1;
378 function_label(&node)
379}
380
381fn const_item_label(ctx: &CompletionContext, ct: hir::Const) -> String {
382 let node = ct.source(ctx.db).1;
383 const_label(&node)
384}
385
386fn type_item_label(ctx: &CompletionContext, ty: hir::Type) -> String {
387 let node = ty.source(ctx.db).1;
388 type_label(&node)
389}
390
391#[cfg(test)] 283#[cfg(test)]
392pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 284pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
393 use crate::mock_analysis::{single_file_with_position, analysis_and_position}; 285 use crate::mock_analysis::{single_file_with_position, analysis_and_position};
@@ -411,83 +303,3 @@ pub(crate) fn check_completion(test_name: &str, code: &str, kind: CompletionKind
411 let kind_completions = do_completion(code, kind); 303 let kind_completions = do_completion(code, kind);
412 assert_debug_snapshot_matches!(test_name, kind_completions); 304 assert_debug_snapshot_matches!(test_name, kind_completions);
413} 305}
414
415#[cfg(test)]
416mod tests {
417 use test_utils::covers;
418
419 use super::*;
420
421 fn check_reference_completion(code: &str, expected_completions: &str) {
422 check_completion(code, expected_completions, CompletionKind::Reference);
423 }
424
425 #[test]
426 fn inserts_parens_for_function_calls() {
427 covers!(inserts_parens_for_function_calls);
428 check_reference_completion(
429 "inserts_parens_for_function_calls1",
430 r"
431 fn no_args() {}
432 fn main() { no_<|> }
433 ",
434 );
435 check_reference_completion(
436 "inserts_parens_for_function_calls2",
437 r"
438 fn with_args(x: i32, y: String) {}
439 fn main() { with_<|> }
440 ",
441 );
442 check_reference_completion(
443 "inserts_parens_for_function_calls3",
444 r"
445 struct S {}
446 impl S {
447 fn foo(&self) {}
448 }
449 fn bar(s: &S) {
450 s.f<|>
451 }
452 ",
453 )
454 }
455
456 #[test]
457 fn dont_render_function_parens_in_use_item() {
458 check_reference_completion(
459 "dont_render_function_parens_in_use_item",
460 "
461 //- /lib.rs
462 mod m { pub fn foo() {} }
463 use crate::m::f<|>;
464 ",
465 )
466 }
467
468 #[test]
469 fn dont_render_function_parens_if_already_call() {
470 check_reference_completion(
471 "dont_render_function_parens_if_already_call",
472 "
473 //- /lib.rs
474 fn frobnicate() {}
475 fn main() {
476 frob<|>();
477 }
478 ",
479 );
480 check_reference_completion(
481 "dont_render_function_parens_if_already_call_assoc_fn",
482 "
483 //- /lib.rs
484 struct Foo {}
485 impl Foo { fn new() -> Foo {} }
486 fn main() {
487 Foo::ne<|>();
488 }
489 ",
490 )
491 }
492
493}
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
new file mode 100644
index 000000000..6454436c9
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -0,0 +1,245 @@
1//! This modules takes care of rendering various defenitions as completion items.
2use join_to_string::join;
3use test_utils::tested_by;
4use hir::{Docs, PerNs, Resolution};
5use ra_syntax::ast::NameOwner;
6
7use crate::completion::{
8 Completions, CompletionKind, CompletionItemKind, CompletionContext, CompletionItem,
9 function_label, const_label, type_label,
10};
11
12impl Completions {
13 pub(crate) fn add_field(
14 &mut self,
15 ctx: &CompletionContext,
16 field: hir::StructField,
17 substs: &hir::Substs,
18 ) {
19 CompletionItem::new(
20 CompletionKind::Reference,
21 ctx.source_range(),
22 field.name(ctx.db).to_string(),
23 )
24 .kind(CompletionItemKind::Field)
25 .detail(field.ty(ctx.db).subst(substs).to_string())
26 .set_documentation(field.docs(ctx.db))
27 .add_to(self);
28 }
29
30 pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
31 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
32 .kind(CompletionItemKind::Field)
33 .detail(ty.to_string())
34 .add_to(self);
35 }
36
37 pub(crate) fn add_resolution(
38 &mut self,
39 ctx: &CompletionContext,
40 local_name: String,
41 resolution: &PerNs<Resolution>,
42 ) {
43 use hir::ModuleDef::*;
44
45 let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
46 let def = match def {
47 None => {
48 self.add(CompletionItem::new(
49 CompletionKind::Reference,
50 ctx.source_range(),
51 local_name,
52 ));
53 return;
54 }
55 Some(it) => it,
56 };
57 let (kind, docs) = match def {
58 Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
59 Resolution::Def(Function(func)) => {
60 return self.add_function_with_name(ctx, Some(local_name), *func);
61 }
62 Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
63 Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)),
64 Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
65 Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
66 Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
67 Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
68 Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
69 Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
70 Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
71 Resolution::SelfType(..) => (
72 CompletionItemKind::TypeParam, // (does this need its own kind?)
73 None,
74 ),
75 };
76 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
77 .kind(kind)
78 .set_documentation(docs)
79 .add_to(self)
80 }
81
82 pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
83 self.add_function_with_name(ctx, None, func)
84 }
85
86 fn add_function_with_name(
87 &mut self,
88 ctx: &CompletionContext,
89 name: Option<String>,
90 func: hir::Function,
91 ) {
92 let sig = func.signature(ctx.db);
93 let name = name.unwrap_or_else(|| sig.name().to_string());
94 let (_, ast_node) = func.source(ctx.db);
95 let detail = function_label(&ast_node);
96
97 let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name)
98 .kind(if sig.has_self_param() {
99 CompletionItemKind::Method
100 } else {
101 CompletionItemKind::Function
102 })
103 .set_documentation(func.docs(ctx.db))
104 .set_detail(detail);
105 // If not an import, add parenthesis automatically.
106 if ctx.use_item_syntax.is_none() && !ctx.is_call {
107 tested_by!(inserts_parens_for_function_calls);
108 let snippet =
109 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 {
110 format!("{}()$0", sig.name())
111 } else {
112 format!("{}($0)", sig.name())
113 };
114 builder = builder.insert_snippet(snippet);
115 }
116 self.add(builder)
117 }
118
119 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
120 let (_file_id, ast_node) = constant.source(ctx.db);
121 let name = match ast_node.name() {
122 Some(name) => name,
123 _ => return,
124 };
125 let (_, ast_node) = constant.source(ctx.db);
126 let detail = const_label(&ast_node);
127
128 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
129 .kind(CompletionItemKind::Const)
130 .set_documentation(constant.docs(ctx.db))
131 .detail(detail)
132 .add_to(self);
133 }
134
135 pub(crate) fn add_type(&mut self, ctx: &CompletionContext, type_alias: hir::Type) {
136 let (_file_id, type_def) = type_alias.source(ctx.db);
137 let name = match type_def.name() {
138 Some(name) => name,
139 _ => return,
140 };
141 let (_, ast_node) = type_alias.source(ctx.db);
142 let detail = type_label(&ast_node);
143
144 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
145 .kind(CompletionItemKind::TypeAlias)
146 .set_documentation(type_alias.docs(ctx.db))
147 .detail(detail)
148 .add_to(self);
149 }
150
151 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
152 let name = match variant.name(ctx.db) {
153 Some(it) => it,
154 None => return,
155 };
156 let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
157 let detail = join(detail_types).separator(", ").surround_with("(", ")").to_string();
158
159 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
160 .kind(CompletionItemKind::EnumVariant)
161 .set_documentation(variant.docs(ctx.db))
162 .detail(detail)
163 .add_to(self);
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use test_utils::covers;
170
171 use crate::completion::{CompletionKind, check_completion};
172
173 fn check_reference_completion(code: &str, expected_completions: &str) {
174 check_completion(code, expected_completions, CompletionKind::Reference);
175 }
176
177 #[test]
178 fn inserts_parens_for_function_calls() {
179 covers!(inserts_parens_for_function_calls);
180 check_reference_completion(
181 "inserts_parens_for_function_calls1",
182 r"
183 fn no_args() {}
184 fn main() { no_<|> }
185 ",
186 );
187 check_reference_completion(
188 "inserts_parens_for_function_calls2",
189 r"
190 fn with_args(x: i32, y: String) {}
191 fn main() { with_<|> }
192 ",
193 );
194 check_reference_completion(
195 "inserts_parens_for_function_calls3",
196 r"
197 struct S {}
198 impl S {
199 fn foo(&self) {}
200 }
201 fn bar(s: &S) {
202 s.f<|>
203 }
204 ",
205 )
206 }
207
208 #[test]
209 fn dont_render_function_parens_in_use_item() {
210 check_reference_completion(
211 "dont_render_function_parens_in_use_item",
212 "
213 //- /lib.rs
214 mod m { pub fn foo() {} }
215 use crate::m::f<|>;
216 ",
217 )
218 }
219
220 #[test]
221 fn dont_render_function_parens_if_already_call() {
222 check_reference_completion(
223 "dont_render_function_parens_if_already_call",
224 "
225 //- /lib.rs
226 fn frobnicate() {}
227 fn main() {
228 frob<|>();
229 }
230 ",
231 );
232 check_reference_completion(
233 "dont_render_function_parens_if_already_call_assoc_fn",
234 "
235 //- /lib.rs
236 struct Foo {}
237 impl Foo { fn new() -> Foo {} }
238 fn main() {
239 Foo::ne<|>();
240 }
241 ",
242 )
243 }
244
245}
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_render_function_parens_if_already_call_assoc_fn.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_render_function_parens_if_already_call_assoc_fn.snap
index 39fff2cb7..19375ea95 100644
--- a/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_render_function_parens_if_already_call_assoc_fn.snap
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__dont_render_function_parens_if_already_call_assoc_fn.snap
@@ -1,6 +1,6 @@
1--- 1---
2created: "2019-02-18T09:22:24.268227065Z" 2created: "2019-02-24T16:33:48.008220694Z"
3creator: [email protected].2 3creator: [email protected].3
4source: crates/ra_ide_api/src/completion/completion_item.rs 4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions 5expression: kind_completions
6--- 6---
@@ -10,7 +10,7 @@ expression: kind_completions
10 source_range: [67; 69), 10 source_range: [67; 69),
11 delete: [67; 69), 11 delete: [67; 69),
12 insert: "new", 12 insert: "new",
13 kind: Method, 13 kind: Function,
14 detail: "fn new() -> Foo" 14 detail: "fn new() -> Foo"
15 } 15 }
16] 16]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__struct_associated_method.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__struct_associated_method.snap
index 163b325c3..7c69eebeb 100644
--- a/crates/ra_ide_api/src/completion/snapshots/completion_item__struct_associated_method.snap
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__struct_associated_method.snap
@@ -1,6 +1,6 @@
1--- 1---
2created: "2019-02-18T09:22:24.093082839Z" 2created: "2019-02-24T16:33:47.990111169Z"
3creator: [email protected].2 3creator: [email protected].3
4source: crates/ra_ide_api/src/completion/completion_item.rs 4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions 5expression: kind_completions
6--- 6---
@@ -10,7 +10,7 @@ expression: kind_completions
10 source_range: [100; 100), 10 source_range: [100; 100),
11 delete: [100; 100), 11 delete: [100; 100),
12 insert: "m()$0", 12 insert: "m()$0",
13 kind: Method, 13 kind: Function,
14 detail: "fn m()", 14 detail: "fn m()",
15 documentation: Documentation( 15 documentation: Documentation(
16 "An associated method" 16 "An associated method"