diff options
-rw-r--r-- | crates/ra_ide/src/completion/complete_scope.rs | 107 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 16 |
2 files changed, 120 insertions, 3 deletions
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs index 81d3cc1b6..82842e7e3 100644 --- a/crates/ra_ide/src/completion/complete_scope.rs +++ b/crates/ra_ide/src/completion/complete_scope.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use crate::completion::{CompletionContext, Completions}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | 4 | ||
5 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | 5 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { |
6 | if !ctx.is_trivial_path { | 6 | if !ctx.is_trivial_path && !ctx.is_pat_binding_and_path { |
7 | return; | 7 | return; |
8 | } | 8 | } |
9 | 9 | ||
@@ -21,6 +21,111 @@ mod tests { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn nested_bind_pat_and_path() { | ||
25 | assert_debug_snapshot!( | ||
26 | do_reference_completion( | ||
27 | r" | ||
28 | enum First { | ||
29 | A, | ||
30 | B, | ||
31 | } | ||
32 | enum Second { | ||
33 | A(First), | ||
34 | B(First), | ||
35 | } | ||
36 | fn quux(x: Option<Option<Second>>>) { | ||
37 | match x { | ||
38 | None => (), | ||
39 | Some(Some(Second(Fi<|>))) => (), | ||
40 | } | ||
41 | } | ||
42 | " | ||
43 | ), | ||
44 | @r###" | ||
45 | [ | ||
46 | CompletionItem { | ||
47 | label: "First", | ||
48 | source_range: [363; 365), | ||
49 | delete: [363; 365), | ||
50 | insert: "First", | ||
51 | kind: Enum, | ||
52 | }, | ||
53 | CompletionItem { | ||
54 | label: "Second", | ||
55 | source_range: [363; 365), | ||
56 | delete: [363; 365), | ||
57 | insert: "Second", | ||
58 | kind: Enum, | ||
59 | }, | ||
60 | CompletionItem { | ||
61 | label: "quux(…)", | ||
62 | source_range: [363; 365), | ||
63 | delete: [363; 365), | ||
64 | insert: "quux(${1:x})$0", | ||
65 | kind: Function, | ||
66 | lookup: "quux", | ||
67 | detail: "fn quux(x: Option<Option<Second>>)", | ||
68 | }, | ||
69 | ] | ||
70 | "### | ||
71 | ); | ||
72 | } | ||
73 | |||
74 | #[test] | ||
75 | fn bind_pat_and_path() { | ||
76 | assert_debug_snapshot!( | ||
77 | do_reference_completion( | ||
78 | r" | ||
79 | enum Enum { | ||
80 | A, | ||
81 | B, | ||
82 | } | ||
83 | fn quux(x: Option<Enum>) { | ||
84 | match x { | ||
85 | None => (), | ||
86 | Some(en<|>) => (), | ||
87 | } | ||
88 | } | ||
89 | " | ||
90 | ), | ||
91 | @r###" | ||
92 | [ | ||
93 | CompletionItem { | ||
94 | label: "Enum", | ||
95 | source_range: [231; 233), | ||
96 | delete: [231; 233), | ||
97 | insert: "Enum", | ||
98 | kind: Enum, | ||
99 | }, | ||
100 | CompletionItem { | ||
101 | label: "None", | ||
102 | source_range: [231; 233), | ||
103 | delete: [231; 233), | ||
104 | insert: "None", | ||
105 | kind: Binding, | ||
106 | }, | ||
107 | CompletionItem { | ||
108 | label: "quux(…)", | ||
109 | source_range: [231; 233), | ||
110 | delete: [231; 233), | ||
111 | insert: "quux(${1:x})$0", | ||
112 | kind: Function, | ||
113 | lookup: "quux", | ||
114 | detail: "fn quux(x: Option<Enum>)", | ||
115 | }, | ||
116 | CompletionItem { | ||
117 | label: "x", | ||
118 | source_range: [231; 233), | ||
119 | delete: [231; 233), | ||
120 | insert: "x", | ||
121 | kind: Binding, | ||
122 | }, | ||
123 | ] | ||
124 | "### | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | #[test] | ||
24 | fn completes_bindings_from_let() { | 129 | fn completes_bindings_from_let() { |
25 | assert_debug_snapshot!( | 130 | assert_debug_snapshot!( |
26 | do_reference_completion( | 131 | do_reference_completion( |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 54589a2a8..d867ff6b2 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -36,6 +36,9 @@ pub(crate) struct CompletionContext<'a> { | |||
36 | /// If a name-binding or reference to a const in a pattern. | 36 | /// If a name-binding or reference to a const in a pattern. |
37 | /// Irrefutable patterns (like let) are excluded. | 37 | /// Irrefutable patterns (like let) are excluded. |
38 | pub(super) is_pat_binding: bool, | 38 | pub(super) is_pat_binding: bool, |
39 | // A bind battern which may also be part of a path. | ||
40 | // if let Some(En<|>) = Some(Enum::A) | ||
41 | pub(super) is_pat_binding_and_path: bool, | ||
39 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 42 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
40 | pub(super) is_trivial_path: bool, | 43 | pub(super) is_trivial_path: bool, |
41 | /// If not a trivial path, the prefix (qualifier). | 44 | /// If not a trivial path, the prefix (qualifier). |
@@ -95,6 +98,7 @@ impl<'a> CompletionContext<'a> { | |||
95 | impl_def: None, | 98 | impl_def: None, |
96 | is_param: false, | 99 | is_param: false, |
97 | is_pat_binding: false, | 100 | is_pat_binding: false, |
101 | is_pat_binding_and_path: false, | ||
98 | is_trivial_path: false, | 102 | is_trivial_path: false, |
99 | path_prefix: None, | 103 | path_prefix: None, |
100 | after_if: false, | 104 | after_if: false, |
@@ -186,12 +190,20 @@ impl<'a> CompletionContext<'a> { | |||
186 | // suggest declaration names, see `CompletionKind::Magic`. | 190 | // suggest declaration names, see `CompletionKind::Magic`. |
187 | if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) { | 191 | if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) { |
188 | if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { | 192 | if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { |
189 | let parent = bind_pat.syntax().parent(); | 193 | let mut parent = bind_pat.syntax().parent(); |
190 | if parent.clone().and_then(ast::MatchArm::cast).is_some() | 194 | if parent.clone().and_then(ast::MatchArm::cast).is_some() |
191 | || parent.and_then(ast::Condition::cast).is_some() | 195 | || parent.clone().and_then(ast::Condition::cast).is_some() |
192 | { | 196 | { |
193 | self.is_pat_binding = true; | 197 | self.is_pat_binding = true; |
194 | } | 198 | } |
199 | |||
200 | while let Some(_) = parent.clone().and_then(ast::TupleStructPat::cast) { | ||
201 | parent = parent.and_then(|p| p.parent()); | ||
202 | if parent.clone().and_then(ast::MatchArm::cast).is_some() { | ||
203 | self.is_pat_binding_and_path = true; | ||
204 | break; | ||
205 | } | ||
206 | } | ||
195 | } | 207 | } |
196 | if is_node::<ast::Param>(name.syntax()) { | 208 | if is_node::<ast::Param>(name.syntax()) { |
197 | self.is_param = true; | 209 | self.is_param = true; |