diff options
Diffstat (limited to 'crates/completion')
-rw-r--r-- | crates/completion/src/completions/pattern.rs | 38 | ||||
-rw-r--r-- | crates/completion/src/render.rs | 6 | ||||
-rw-r--r-- | crates/completion/src/render/builder_ext.rs | 1 | ||||
-rw-r--r-- | crates/completion/src/render/enum_variant.rs | 45 | ||||
-rw-r--r-- | crates/completion/src/render/pattern.rs | 80 |
5 files changed, 76 insertions, 94 deletions
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs index ba9921a44..eee31098d 100644 --- a/crates/completion/src/completions/pattern.rs +++ b/crates/completion/src/completions/pattern.rs | |||
@@ -1,7 +1,5 @@ | |||
1 | //! Completes constats and paths in patterns. | 1 | //! Completes constats and paths in patterns. |
2 | 2 | ||
3 | use hir::StructKind; | ||
4 | |||
5 | use crate::{CompletionContext, Completions}; | 3 | use crate::{CompletionContext, Completions}; |
6 | 4 | ||
7 | /// Completes constants and paths in patterns. | 5 | /// Completes constants and paths in patterns. |
@@ -22,11 +20,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
22 | acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone())); | 20 | acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone())); |
23 | true | 21 | true |
24 | } | 22 | } |
25 | hir::ModuleDef::Variant(variant) | 23 | hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => { |
26 | if !ctx.is_irrefutable_pat_binding | ||
27 | // render_resolution already does some pattern completion tricks for tuple variants | ||
28 | && variant.kind(ctx.db) == StructKind::Record => | ||
29 | { | ||
30 | acc.add_variant_pat(ctx, variant.clone(), Some(name.clone())); | 24 | acc.add_variant_pat(ctx, variant.clone(), Some(name.clone())); |
31 | true | 25 | true |
32 | } | 26 | } |
@@ -49,7 +43,10 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
49 | mod tests { | 43 | mod tests { |
50 | use expect_test::{expect, Expect}; | 44 | use expect_test::{expect, Expect}; |
51 | 45 | ||
52 | use crate::{test_utils::completion_list, CompletionKind}; | 46 | use crate::{ |
47 | test_utils::{check_edit, completion_list}, | ||
48 | CompletionKind, | ||
49 | }; | ||
53 | 50 | ||
54 | fn check(ra_fixture: &str, expect: Expect) { | 51 | fn check(ra_fixture: &str, expect: Expect) { |
55 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 52 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
@@ -81,7 +78,7 @@ fn foo() { | |||
81 | en E | 78 | en E |
82 | ct Z | 79 | ct Z |
83 | st Bar | 80 | st Bar |
84 | ev X () | 81 | ev X |
85 | md m | 82 | md m |
86 | "#]], | 83 | "#]], |
87 | ); | 84 | ); |
@@ -238,4 +235,27 @@ fn outer() { | |||
238 | "#]], | 235 | "#]], |
239 | ) | 236 | ) |
240 | } | 237 | } |
238 | |||
239 | #[test] | ||
240 | fn only_shows_ident_completion() { | ||
241 | check_edit( | ||
242 | "Foo", | ||
243 | r#" | ||
244 | struct Foo(i32); | ||
245 | fn main() { | ||
246 | match Foo(92) { | ||
247 | <|>(92) => (), | ||
248 | } | ||
249 | } | ||
250 | "#, | ||
251 | r#" | ||
252 | struct Foo(i32); | ||
253 | fn main() { | ||
254 | match Foo(92) { | ||
255 | Foo(92) => (), | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
241 | } | 261 | } |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 945158d10..1ba7201a1 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -160,6 +160,12 @@ impl<'a> Render<'a> { | |||
160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); |
161 | return Some(item); | 161 | return Some(item); |
162 | } | 162 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | ||
164 | if self.ctx.completion.is_pat_binding_or_const | ||
165 | | self.ctx.completion.is_irrefutable_pat_binding => | ||
166 | { | ||
167 | CompletionItemKind::EnumVariant | ||
168 | } | ||
163 | ScopeDef::ModuleDef(Variant(var)) => { | 169 | ScopeDef::ModuleDef(Variant(var)) => { |
164 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); | 170 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); |
165 | return Some(item); | 171 | return Some(item); |
diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs index ce8718bd5..d053a988b 100644 --- a/crates/completion/src/render/builder_ext.rs +++ b/crates/completion/src/render/builder_ext.rs | |||
@@ -34,7 +34,6 @@ impl Builder { | |||
34 | return false; | 34 | return false; |
35 | } | 35 | } |
36 | if ctx.is_pattern_call { | 36 | if ctx.is_pattern_call { |
37 | mark::hit!(dont_duplicate_pattern_parens); | ||
38 | return false; | 37 | return false; |
39 | } | 38 | } |
40 | if ctx.is_call { | 39 | if ctx.is_call { |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index 7176fd9b3..732e139ec 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -126,50 +126,5 @@ fn main() -> Option<i32> { | |||
126 | } | 126 | } |
127 | "#, | 127 | "#, |
128 | ); | 128 | ); |
129 | check_edit( | ||
130 | "Some", | ||
131 | r#" | ||
132 | enum Option<T> { Some(T), None } | ||
133 | use Option::*; | ||
134 | fn main(value: Option<i32>) { | ||
135 | match value { | ||
136 | Som<|> | ||
137 | } | ||
138 | } | ||
139 | "#, | ||
140 | r#" | ||
141 | enum Option<T> { Some(T), None } | ||
142 | use Option::*; | ||
143 | fn main(value: Option<i32>) { | ||
144 | match value { | ||
145 | Some($0) | ||
146 | } | ||
147 | } | ||
148 | "#, | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn dont_duplicate_pattern_parens() { | ||
154 | mark::check!(dont_duplicate_pattern_parens); | ||
155 | check_edit( | ||
156 | "Var", | ||
157 | r#" | ||
158 | enum E { Var(i32) } | ||
159 | fn main() { | ||
160 | match E::Var(92) { | ||
161 | E::<|>(92) => (), | ||
162 | } | ||
163 | } | ||
164 | "#, | ||
165 | r#" | ||
166 | enum E { Var(i32) } | ||
167 | fn main() { | ||
168 | match E::Var(92) { | ||
169 | E::Var(92) => (), | ||
170 | } | ||
171 | } | ||
172 | "#, | ||
173 | ); | ||
174 | } | 129 | } |
175 | } | 130 | } |
diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs index 073d50a11..a3b6a3cac 100644 --- a/crates/completion/src/render/pattern.rs +++ b/crates/completion/src/render/pattern.rs | |||
@@ -8,6 +8,24 @@ use crate::{ | |||
8 | CompletionItemKind, | 8 | CompletionItemKind, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | fn visible_fields( | ||
12 | ctx: &RenderContext<'_>, | ||
13 | fields: &[hir::Field], | ||
14 | item: impl HasAttrs, | ||
15 | ) -> Option<(Vec<hir::Field>, bool)> { | ||
16 | let module = ctx.completion.scope.module()?; | ||
17 | let n_fields = fields.len(); | ||
18 | let fields = fields | ||
19 | .into_iter() | ||
20 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
21 | .copied() | ||
22 | .collect::<Vec<_>>(); | ||
23 | |||
24 | let fields_omitted = | ||
25 | n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
26 | Some((fields, fields_omitted)) | ||
27 | } | ||
28 | |||
11 | pub(crate) fn render_struct_pat( | 29 | pub(crate) fn render_struct_pat( |
12 | ctx: RenderContext<'_>, | 30 | ctx: RenderContext<'_>, |
13 | strukt: hir::Struct, | 31 | strukt: hir::Struct, |
@@ -15,35 +33,18 @@ pub(crate) fn render_struct_pat( | |||
15 | ) -> Option<CompletionItem> { | 33 | ) -> Option<CompletionItem> { |
16 | let _p = profile::span("render_struct_pat"); | 34 | let _p = profile::span("render_struct_pat"); |
17 | 35 | ||
18 | let module = ctx.completion.scope.module()?; | ||
19 | let fields = strukt.fields(ctx.db()); | 36 | let fields = strukt.fields(ctx.db()); |
20 | let n_fields = fields.len(); | 37 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?; |
21 | let fields = fields | ||
22 | .into_iter() | ||
23 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
24 | .collect::<Vec<_>>(); | ||
25 | 38 | ||
26 | if fields.is_empty() { | 39 | if visible_fields.is_empty() { |
27 | // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields | 40 | // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields |
28 | return None; | 41 | return None; |
29 | } | 42 | } |
30 | let fields_omitted = | ||
31 | n_fields - fields.len() > 0 || strukt.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
32 | 43 | ||
33 | let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); | 44 | let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); |
34 | let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &fields, fields_omitted)?; | 45 | let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?; |
35 | 46 | ||
36 | let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) | 47 | Some(build_completion(ctx, name, pat, strukt)) |
37 | .kind(CompletionItemKind::Binding) | ||
38 | .set_documentation(ctx.docs(strukt)) | ||
39 | .set_deprecated(ctx.is_deprecated(strukt)) | ||
40 | .detail(&pat); | ||
41 | if let Some(snippet_cap) = ctx.snippet_cap() { | ||
42 | completion = completion.insert_snippet(snippet_cap, pat); | ||
43 | } else { | ||
44 | completion = completion.insert_text(pat); | ||
45 | } | ||
46 | Some(completion.build()) | ||
47 | } | 48 | } |
48 | 49 | ||
49 | pub(crate) fn render_variant_pat( | 50 | pub(crate) fn render_variant_pat( |
@@ -53,31 +54,32 @@ pub(crate) fn render_variant_pat( | |||
53 | ) -> Option<CompletionItem> { | 54 | ) -> Option<CompletionItem> { |
54 | let _p = profile::span("render_variant_pat"); | 55 | let _p = profile::span("render_variant_pat"); |
55 | 56 | ||
56 | let module = ctx.completion.scope.module()?; | ||
57 | let fields = variant.fields(ctx.db()); | 57 | let fields = variant.fields(ctx.db()); |
58 | let n_fields = fields.len(); | 58 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?; |
59 | let fields = fields | ||
60 | .into_iter() | ||
61 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
62 | .collect::<Vec<_>>(); | ||
63 | |||
64 | let fields_omitted = | ||
65 | n_fields - fields.len() > 0 || variant.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
66 | 59 | ||
67 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(); | 60 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(); |
68 | let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &fields, fields_omitted)?; | 61 | let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?; |
69 | 62 | ||
70 | let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) | 63 | Some(build_completion(ctx, name, pat, variant)) |
64 | } | ||
65 | |||
66 | fn build_completion( | ||
67 | ctx: RenderContext<'_>, | ||
68 | name: String, | ||
69 | pat: String, | ||
70 | item: impl HasAttrs + Copy, | ||
71 | ) -> CompletionItem { | ||
72 | let completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) | ||
71 | .kind(CompletionItemKind::Binding) | 73 | .kind(CompletionItemKind::Binding) |
72 | .set_documentation(ctx.docs(variant)) | 74 | .set_documentation(ctx.docs(item)) |
73 | .set_deprecated(ctx.is_deprecated(variant)) | 75 | .set_deprecated(ctx.is_deprecated(item)) |
74 | .detail(&pat); | 76 | .detail(&pat); |
75 | if let Some(snippet_cap) = ctx.snippet_cap() { | 77 | let completion = if let Some(snippet_cap) = ctx.snippet_cap() { |
76 | completion = completion.insert_snippet(snippet_cap, pat); | 78 | completion.insert_snippet(snippet_cap, pat) |
77 | } else { | 79 | } else { |
78 | completion = completion.insert_text(pat); | 80 | completion.insert_text(pat) |
79 | } | 81 | }; |
80 | Some(completion.build()) | 82 | completion.build() |
81 | } | 83 | } |
82 | 84 | ||
83 | fn render_pat( | 85 | fn render_pat( |