aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
authorSteffen Lyngbaek <[email protected]>2020-03-10 01:10:25 +0000
committerSteffen Lyngbaek <[email protected]>2020-03-19 21:12:00 +0000
commitb6d6277362366e7ddd2b355d83227041d8b6fa12 (patch)
treefd90520d229f62aa44d1cfb817c3bf49b8566956 /crates/ra_ide/src/completion
parent1ba03c6995015b3143a417ed07437f0c9028a97d (diff)
Completition for type name? #3418
Iterate through TupleStructPat's until a MatchArm if one exists. Store in a new is_pat_bind_and_path bool and allow the `complete_scope` to find matches. Added some tests to ensure it works in simple and nested cases.
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs107
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs16
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 @@
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
4 4
5pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { 5pub(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;