diff options
author | Aleksey Kladov <[email protected]> | 2018-09-07 23:35:20 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-09-07 23:35:20 +0100 |
commit | 127814d9a7f62c834c0893ff05e933aac4be89e9 (patch) | |
tree | 412432e0308c8b22b28e3b84776b44b311b283da | |
parent | ff1c82216cc05f2621a301e30ab7a1102dea9d2b (diff) |
nested mod completion
-rw-r--r-- | crates/libeditor/src/completion.rs | 58 | ||||
-rw-r--r-- | crates/libeditor/src/scope/mod_scope.rs | 11 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/generated.rs | 13 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/mod.rs | 24 | ||||
-rw-r--r-- | crates/libsyntax2/src/grammar.ron | 8 |
5 files changed, 68 insertions, 46 deletions
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs index c25b4c217..52df6fd10 100644 --- a/crates/libeditor/src/completion.rs +++ b/crates/libeditor/src/completion.rs | |||
@@ -2,7 +2,7 @@ use std::collections::{HashSet, HashMap}; | |||
2 | 2 | ||
3 | use libsyntax2::{ | 3 | use libsyntax2::{ |
4 | File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, | 4 | File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, |
5 | ast::{self, LoopBodyOwner}, | 5 | ast::{self, LoopBodyOwner, ModuleItemOwner}, |
6 | algo::{ | 6 | algo::{ |
7 | ancestors, | 7 | ancestors, |
8 | visit::{visitor, Visitor, visitor_ctx, VisitorCtx}, | 8 | visit::{visitor, Visitor, visitor_ctx, VisitorCtx}, |
@@ -58,22 +58,34 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi | |||
58 | if !is_node::<ast::Path>(name_ref.syntax()) { | 58 | if !is_node::<ast::Path>(name_ref.syntax()) { |
59 | return; | 59 | return; |
60 | } | 60 | } |
61 | if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() { | 61 | let mut visited_fn = false; |
62 | complete_expr_keywords(&file, fn_def, name_ref, acc); | 62 | for node in ancestors(name_ref.syntax()) { |
63 | let scopes = FnScopes::new(fn_def); | 63 | if let Some(items) = visitor() |
64 | complete_fn(name_ref, &scopes, acc); | 64 | .visit::<ast::Root, _>(|it| Some(it.items())) |
65 | } | 65 | .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) |
66 | if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() { | 66 | .accept(node) { |
67 | let scope = ModuleScope::new(root); | 67 | if let Some(items) = items { |
68 | acc.extend( | 68 | let scope = ModuleScope::new(items); |
69 | scope.entries().iter() | 69 | acc.extend( |
70 | .filter(|entry| entry.syntax() != name_ref.syntax()) | 70 | scope.entries().iter() |
71 | .map(|entry| CompletionItem { | 71 | .filter(|entry| entry.syntax() != name_ref.syntax()) |
72 | label: entry.name().to_string(), | 72 | .map(|entry| CompletionItem { |
73 | lookup: None, | 73 | label: entry.name().to_string(), |
74 | snippet: None, | 74 | lookup: None, |
75 | }) | 75 | snippet: None, |
76 | ); | 76 | }) |
77 | ); | ||
78 | } | ||
79 | break; | ||
80 | |||
81 | } else if !visited_fn { | ||
82 | if let Some(fn_def) = ast::FnDef::cast(node) { | ||
83 | visited_fn = true; | ||
84 | complete_expr_keywords(&file, fn_def, name_ref, acc); | ||
85 | let scopes = FnScopes::new(fn_def); | ||
86 | complete_fn(name_ref, &scopes, acc); | ||
87 | } | ||
88 | } | ||
77 | } | 89 | } |
78 | } | 90 | } |
79 | 91 | ||
@@ -300,6 +312,18 @@ mod tests { | |||
300 | } | 312 | } |
301 | 313 | ||
302 | #[test] | 314 | #[test] |
315 | fn test_completion_mod_scope_nested() { | ||
316 | check_scope_completion(r" | ||
317 | struct Foo; | ||
318 | mod m { | ||
319 | struct Bar; | ||
320 | fn quux() { <|> } | ||
321 | } | ||
322 | ", r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }, | ||
323 | CompletionItem { label: "quux", lookup: None, snippet: None }]"#); | ||
324 | } | ||
325 | |||
326 | #[test] | ||
303 | fn test_complete_type() { | 327 | fn test_complete_type() { |
304 | check_scope_completion(r" | 328 | check_scope_completion(r" |
305 | struct Foo; | 329 | struct Foo; |
diff --git a/crates/libeditor/src/scope/mod_scope.rs b/crates/libeditor/src/scope/mod_scope.rs index 67baa8678..0ec56a206 100644 --- a/crates/libeditor/src/scope/mod_scope.rs +++ b/crates/libeditor/src/scope/mod_scope.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use libsyntax2::{ | 1 | use libsyntax2::{ |
2 | AstNode, SyntaxNode, SyntaxNodeRef, SmolStr, ast | 2 | AstNode, SyntaxNode, SyntaxNodeRef, SmolStr, |
3 | ast::{self, AstChildren}, | ||
3 | }; | 4 | }; |
4 | 5 | ||
5 | pub struct ModuleScope { | 6 | pub struct ModuleScope { |
@@ -16,9 +17,9 @@ enum EntryKind { | |||
16 | } | 17 | } |
17 | 18 | ||
18 | impl ModuleScope { | 19 | impl ModuleScope { |
19 | pub fn new(m: ast::Root) -> ModuleScope { | 20 | pub fn new(items: AstChildren<ast::ModuleItem>) -> ModuleScope { |
20 | let mut entries = Vec::new(); | 21 | let mut entries = Vec::new(); |
21 | for item in m.items() { | 22 | for item in items { |
22 | let entry = match item { | 23 | let entry = match item { |
23 | ast::ModuleItem::StructDef(item) => Entry::new(item), | 24 | ast::ModuleItem::StructDef(item) => Entry::new(item), |
24 | ast::ModuleItem::EnumDef(item) => Entry::new(item), | 25 | ast::ModuleItem::EnumDef(item) => Entry::new(item), |
@@ -85,11 +86,11 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { | |||
85 | #[cfg(test)] | 86 | #[cfg(test)] |
86 | mod tests { | 87 | mod tests { |
87 | use super::*; | 88 | use super::*; |
88 | use libsyntax2::File; | 89 | use libsyntax2::{File, ast::ModuleItemOwner}; |
89 | 90 | ||
90 | fn do_check(code: &str, expected: &[&str]) { | 91 | fn do_check(code: &str, expected: &[&str]) { |
91 | let file = File::parse(&code); | 92 | let file = File::parse(&code); |
92 | let scope = ModuleScope::new(file.ast()); | 93 | let scope = ModuleScope::new(file.ast().items()); |
93 | let actual = scope.entries | 94 | let actual = scope.entries |
94 | .iter() | 95 | .iter() |
95 | .map(|it| it.name()) | 96 | .map(|it| it.name()) |
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index a239f0630..c945c094a 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs | |||
@@ -699,11 +699,8 @@ impl<'a> AstNode<'a> for ItemList<'a> { | |||
699 | } | 699 | } |
700 | 700 | ||
701 | impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {} | 701 | impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {} |
702 | impl<'a> ItemList<'a> { | 702 | impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {} |
703 | pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a { | 703 | impl<'a> ItemList<'a> {} |
704 | super::children(self) | ||
705 | } | ||
706 | } | ||
707 | 704 | ||
708 | // Label | 705 | // Label |
709 | #[derive(Debug, Clone, Copy)] | 706 | #[derive(Debug, Clone, Copy)] |
@@ -979,7 +976,6 @@ impl<'a> AstNode<'a> for Module<'a> { | |||
979 | 976 | ||
980 | impl<'a> ast::NameOwner<'a> for Module<'a> {} | 977 | impl<'a> ast::NameOwner<'a> for Module<'a> {} |
981 | impl<'a> ast::AttrsOwner<'a> for Module<'a> {} | 978 | impl<'a> ast::AttrsOwner<'a> for Module<'a> {} |
982 | impl<'a> ast::FnDefOwner<'a> for Module<'a> {} | ||
983 | impl<'a> Module<'a> {pub fn item_list(self) -> Option<ItemList<'a>> { | 979 | impl<'a> Module<'a> {pub fn item_list(self) -> Option<ItemList<'a>> { |
984 | super::child_opt(self) | 980 | super::child_opt(self) |
985 | } | 981 | } |
@@ -1616,12 +1612,9 @@ impl<'a> AstNode<'a> for Root<'a> { | |||
1616 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | 1612 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } |
1617 | } | 1613 | } |
1618 | 1614 | ||
1615 | impl<'a> ast::ModuleItemOwner<'a> for Root<'a> {} | ||
1619 | impl<'a> ast::FnDefOwner<'a> for Root<'a> {} | 1616 | impl<'a> ast::FnDefOwner<'a> for Root<'a> {} |
1620 | impl<'a> Root<'a> { | 1617 | impl<'a> Root<'a> { |
1621 | pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a { | ||
1622 | super::children(self) | ||
1623 | } | ||
1624 | |||
1625 | pub fn modules(self) -> impl Iterator<Item = Module<'a>> + 'a { | 1618 | pub fn modules(self) -> impl Iterator<Item = Module<'a>> + 'a { |
1626 | super::children(self) | 1619 | super::children(self) |
1627 | } | 1620 | } |
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index 0b6868547..a6da82957 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs | |||
@@ -36,7 +36,13 @@ pub trait ArgListOwner<'a>: AstNode<'a> { | |||
36 | } | 36 | } |
37 | 37 | ||
38 | pub trait FnDefOwner<'a>: AstNode<'a> { | 38 | pub trait FnDefOwner<'a>: AstNode<'a> { |
39 | fn functions(self) -> AstNodeChildren<'a, FnDef<'a>> { | 39 | fn functions(self) -> AstChildren<'a, FnDef<'a>> { |
40 | children(self) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | pub trait ModuleItemOwner<'a>: AstNode<'a> { | ||
45 | fn items(self) -> AstChildren<'a, ModuleItem<'a>> { | ||
40 | children(self) | 46 | children(self) |
41 | } | 47 | } |
42 | } | 48 | } |
@@ -52,7 +58,7 @@ pub trait TypeParamsOwner<'a>: AstNode<'a> { | |||
52 | } | 58 | } |
53 | 59 | ||
54 | pub trait AttrsOwner<'a>: AstNode<'a> { | 60 | pub trait AttrsOwner<'a>: AstNode<'a> { |
55 | fn attrs(self) -> AstNodeChildren<'a, Attr<'a>> { | 61 | fn attrs(self) -> AstChildren<'a, Attr<'a>> { |
56 | children(self) | 62 | children(self) |
57 | } | 63 | } |
58 | } | 64 | } |
@@ -158,7 +164,7 @@ impl<'a> IfExpr<'a> { | |||
158 | pub fn else_branch(self) -> Option<Block<'a>> { | 164 | pub fn else_branch(self) -> Option<Block<'a>> { |
159 | self.blocks().nth(1) | 165 | self.blocks().nth(1) |
160 | } | 166 | } |
161 | fn blocks(self) -> AstNodeChildren<'a, Block<'a>> { | 167 | fn blocks(self) -> AstChildren<'a, Block<'a>> { |
162 | children(self) | 168 | children(self) |
163 | } | 169 | } |
164 | } | 170 | } |
@@ -167,27 +173,27 @@ fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> { | |||
167 | children(parent).next() | 173 | children(parent).next() |
168 | } | 174 | } |
169 | 175 | ||
170 | fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstNodeChildren<'a, C> { | 176 | fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstChildren<'a, C> { |
171 | AstNodeChildren::new(parent.syntax()) | 177 | AstChildren::new(parent.syntax()) |
172 | } | 178 | } |
173 | 179 | ||
174 | 180 | ||
175 | #[derive(Debug)] | 181 | #[derive(Debug)] |
176 | pub struct AstNodeChildren<'a, N> { | 182 | pub struct AstChildren<'a, N> { |
177 | inner: SyntaxNodeChildren<RefRoot<'a>>, | 183 | inner: SyntaxNodeChildren<RefRoot<'a>>, |
178 | ph: PhantomData<N>, | 184 | ph: PhantomData<N>, |
179 | } | 185 | } |
180 | 186 | ||
181 | impl<'a, N> AstNodeChildren<'a, N> { | 187 | impl<'a, N> AstChildren<'a, N> { |
182 | fn new(parent: SyntaxNodeRef<'a>) -> Self { | 188 | fn new(parent: SyntaxNodeRef<'a>) -> Self { |
183 | AstNodeChildren { | 189 | AstChildren { |
184 | inner: parent.children(), | 190 | inner: parent.children(), |
185 | ph: PhantomData, | 191 | ph: PhantomData, |
186 | } | 192 | } |
187 | } | 193 | } |
188 | } | 194 | } |
189 | 195 | ||
190 | impl<'a, N: AstNode<'a>> Iterator for AstNodeChildren<'a, N> { | 196 | impl<'a, N: AstNode<'a>> Iterator for AstChildren<'a, N> { |
191 | type Item = N; | 197 | type Item = N; |
192 | fn next(&mut self) -> Option<N> { | 198 | fn next(&mut self) -> Option<N> { |
193 | loop { | 199 | loop { |
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index 6ed658daa..77ae4c7db 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron | |||
@@ -238,9 +238,8 @@ Grammar( | |||
238 | ], | 238 | ], |
239 | ast: { | 239 | ast: { |
240 | "Root": ( | 240 | "Root": ( |
241 | traits: [ "FnDefOwner" ], | 241 | traits: [ "ModuleItemOwner", "FnDefOwner" ], |
242 | collections: [ | 242 | collections: [ |
243 | ["items", "ModuleItem"], | ||
244 | ["modules", "Module"], | 243 | ["modules", "Module"], |
245 | ] | 244 | ] |
246 | ), | 245 | ), |
@@ -271,12 +270,11 @@ Grammar( | |||
271 | ] ), | 270 | ] ), |
272 | "TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ), | 271 | "TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ), |
273 | "Module": ( | 272 | "Module": ( |
274 | traits: ["NameOwner", "AttrsOwner", "FnDefOwner" ], | 273 | traits: ["NameOwner", "AttrsOwner" ], |
275 | options: [ "ItemList" ] | 274 | options: [ "ItemList" ] |
276 | ), | 275 | ), |
277 | "ItemList": ( | 276 | "ItemList": ( |
278 | traits: [ "FnDefOwner" ], | 277 | traits: [ "FnDefOwner", "ModuleItemOwner" ], |
279 | collections: [ ["items", "ModuleItem"] ] | ||
280 | ), | 278 | ), |
281 | "ConstDef": ( traits: [ | 279 | "ConstDef": ( traits: [ |
282 | "NameOwner", | 280 | "NameOwner", |