diff options
Diffstat (limited to 'crates/libeditor/src/completion.rs')
-rw-r--r-- | crates/libeditor/src/completion.rs | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs index c6ce62661..2756e472a 100644 --- a/crates/libeditor/src/completion.rs +++ b/crates/libeditor/src/completion.rs | |||
@@ -8,7 +8,7 @@ use libsyntax2::{ | |||
8 | 8 | ||
9 | use { | 9 | use { |
10 | AtomEdit, find_node_at_offset, | 10 | AtomEdit, find_node_at_offset, |
11 | scope::FnScopes, | 11 | scope::{FnScopes, ModuleScope}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | #[derive(Debug)] | 14 | #[derive(Debug)] |
@@ -24,18 +24,27 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI | |||
24 | file.incremental_reparse(&edit)? | 24 | file.incremental_reparse(&edit)? |
25 | }; | 25 | }; |
26 | let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?; | 26 | let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?; |
27 | let fn_def = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next()?; | 27 | let mut res = Vec::new(); |
28 | let scopes = FnScopes::new(fn_def); | 28 | if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() { |
29 | Some(complete(name_ref, &scopes)) | 29 | let scopes = FnScopes::new(fn_def); |
30 | complete_fn(name_ref, &scopes, &mut res); | ||
31 | } | ||
32 | if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() { | ||
33 | let scope = ModuleScope::new(root); | ||
34 | res.extend( | ||
35 | scope.entries().iter() | ||
36 | .map(|entry| CompletionItem { name: entry.name().to_string() }) | ||
37 | ) | ||
38 | } | ||
39 | Some(res) | ||
30 | } | 40 | } |
31 | 41 | ||
32 | fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec<CompletionItem> { | 42 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { |
33 | scopes.scope_chain(name_ref.syntax()) | 43 | acc.extend( |
34 | .flat_map(|scope| scopes.entries(scope).iter()) | 44 | scopes.scope_chain(name_ref.syntax()) |
35 | .map(|entry| CompletionItem { | 45 | .flat_map(|scope| scopes.entries(scope).iter()) |
36 | name: entry.name().to_string() | 46 | .map(|entry| CompletionItem { name: entry.name().to_string() }) |
37 | }) | 47 | ) |
38 | .collect() | ||
39 | } | 48 | } |
40 | 49 | ||
41 | #[cfg(test)] | 50 | #[cfg(test)] |
@@ -59,7 +68,8 @@ mod tests { | |||
59 | let z = (); | 68 | let z = (); |
60 | } | 69 | } |
61 | ", r#"[CompletionItem { name: "y" }, | 70 | ", r#"[CompletionItem { name: "y" }, |
62 | CompletionItem { name: "x" }]"#); | 71 | CompletionItem { name: "x" }, |
72 | CompletionItem { name: "quux" }]"#); | ||
63 | } | 73 | } |
64 | 74 | ||
65 | #[test] | 75 | #[test] |
@@ -75,7 +85,8 @@ mod tests { | |||
75 | } | 85 | } |
76 | } | 86 | } |
77 | ", r#"[CompletionItem { name: "b" }, | 87 | ", r#"[CompletionItem { name: "b" }, |
78 | CompletionItem { name: "a" }]"#); | 88 | CompletionItem { name: "a" }, |
89 | CompletionItem { name: "quux" }]"#); | ||
79 | } | 90 | } |
80 | 91 | ||
81 | #[test] | 92 | #[test] |
@@ -86,6 +97,20 @@ mod tests { | |||
86 | <|> | 97 | <|> |
87 | } | 98 | } |
88 | } | 99 | } |
89 | ", r#"[CompletionItem { name: "x" }]"#); | 100 | ", r#"[CompletionItem { name: "x" }, |
101 | CompletionItem { name: "quux" }]"#); | ||
102 | } | ||
103 | |||
104 | #[test] | ||
105 | fn test_completion_mod_scope() { | ||
106 | do_check(r" | ||
107 | struct Foo; | ||
108 | enum Baz {} | ||
109 | fn quux() { | ||
110 | <|> | ||
111 | } | ||
112 | ", r#"[CompletionItem { name: "Foo" }, | ||
113 | CompletionItem { name: "Baz" }, | ||
114 | CompletionItem { name: "quux" }]"#); | ||
90 | } | 115 | } |
91 | } | 116 | } |