diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 18:56:49 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 18:56:49 +0000 |
commit | 5a684099e9aa3482b408002030fafe1dcd0fa9a9 (patch) | |
tree | 20e86fbc586b350c336277d2b0886a60f9844de8 /crates/ra_ide_api | |
parent | 67528c4b3943a2027839a25770d079132a9ea130 (diff) | |
parent | d5f6a5f5e29df3005533502b49f78daae314ac5b (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')
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 @@ | |||
1 | mod completion_item; | 1 | mod completion_item; |
2 | mod completion_context; | 2 | mod completion_context; |
3 | mod presentation; | ||
3 | 4 | ||
4 | mod complete_dot; | 5 | mod complete_dot; |
5 | mod complete_struct_literal; | 6 | mod 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)] | ||
27 | use crate::completion::completion_item::{do_completion, check_completion}; | ||
24 | 28 | ||
25 | pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind, InsertTextFormat}; | 29 | pub 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 @@ | |||
1 | use hir::{Ty, AdtDef, Docs}; | 1 | use hir::{Ty, AdtDef}; |
2 | 2 | ||
3 | use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | use 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). |
7 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(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)] |
83 | mod tests { | 60 | mod 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)] |
56 | mod tests { | 56 | mod 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)] |
111 | mod tests { | 111 | mod 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 @@ | |||
1 | use join_to_string::join; | 1 | use hir::Resolution; |
2 | use hir::{Docs, Resolution}; | 2 | use ra_syntax::AstNode; |
3 | use ra_syntax::{AstNode, ast::NameOwner}; | ||
4 | use test_utils::tested_by; | 3 | use test_utils::tested_by; |
5 | 4 | ||
6 | use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}; | 5 | use crate::completion::{Completions, CompletionContext}; |
7 | 6 | ||
8 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | 7 | pub(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)] |
111 | mod tests { | 59 | mod 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)] |
58 | mod tests { | 58 | mod 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 @@ | |||
1 | use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext}; | 1 | use crate::completion::{Completions, CompletionContext}; |
2 | 2 | ||
3 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | 3 | pub(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)] |
17 | mod tests { | 13 | mod 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)] |
38 | mod tests { | 38 | mod 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 @@ | |||
1 | use hir::{Ty, AdtDef, Docs}; | 1 | use hir::{Ty, AdtDef}; |
2 | 2 | ||
3 | use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | use crate::completion::completion_item::CompletionKind; | ||
5 | 4 | ||
6 | /// Complete fields in fields literals. | 5 | /// Complete fields in fields literals. |
7 | pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(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)] |
44 | mod tests { | 35 | mod 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 @@ | |||
1 | use std::fmt; | 1 | use std::fmt; |
2 | 2 | ||
3 | use hir::{Docs, Documentation, PerNs, Resolution}; | 3 | use hir::Documentation; |
4 | use ra_syntax::TextRange; | 4 | use ra_syntax::TextRange; |
5 | use ra_text_edit::{ TextEditBuilder, TextEdit}; | 5 | use ra_text_edit::{TextEditBuilder, TextEdit}; |
6 | use test_utils::tested_by; | ||
7 | |||
8 | use 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 | ||
345 | impl<'a> Into<CompletionItem> for Builder { | 252 | impl<'a> Into<CompletionItem> for Builder { |
@@ -373,21 +280,6 @@ impl Into<Vec<CompletionItem>> for Completions { | |||
373 | } | 280 | } |
374 | } | 281 | } |
375 | 282 | ||
376 | fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> { | ||
377 | let node = function.source(ctx.db).1; | ||
378 | function_label(&node) | ||
379 | } | ||
380 | |||
381 | fn const_item_label(ctx: &CompletionContext, ct: hir::Const) -> String { | ||
382 | let node = ct.source(ctx.db).1; | ||
383 | const_label(&node) | ||
384 | } | ||
385 | |||
386 | fn 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)] |
392 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | 284 | pub(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)] | ||
416 | mod 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. | ||
2 | use join_to_string::join; | ||
3 | use test_utils::tested_by; | ||
4 | use hir::{Docs, PerNs, Resolution}; | ||
5 | use ra_syntax::ast::NameOwner; | ||
6 | |||
7 | use crate::completion::{ | ||
8 | Completions, CompletionKind, CompletionItemKind, CompletionContext, CompletionItem, | ||
9 | function_label, const_label, type_label, | ||
10 | }; | ||
11 | |||
12 | impl 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)] | ||
168 | mod 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 | --- |
2 | created: "2019-02-18T09:22:24.268227065Z" | 2 | created: "2019-02-24T16:33:48.008220694Z" |
3 | creator: [email protected].2 | 3 | creator: [email protected].3 |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: 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 | --- |
2 | created: "2019-02-18T09:22:24.093082839Z" | 2 | created: "2019-02-24T16:33:47.990111169Z" |
3 | creator: [email protected].2 | 3 | creator: [email protected].3 |
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | 4 | source: crates/ra_ide_api/src/completion/completion_item.rs |
5 | expression: kind_completions | 5 | expression: 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" |