diff options
author | Aleksey Kladov <[email protected]> | 2018-08-28 17:23:55 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-28 17:23:55 +0100 |
commit | 537ea620bb2a73a5e79872f414af23cf4bf03179 (patch) | |
tree | 875b5c789e027615be5466a74bf7053a6798da0d /crates | |
parent | d34588bf83898870d7f9b4b49ac2a5f71c77dabb (diff) |
complete items from module scope
Diffstat (limited to 'crates')
-rw-r--r-- | crates/libeditor/src/completion.rs | 53 | ||||
-rw-r--r-- | crates/libeditor/src/lib.rs | 6 | ||||
-rw-r--r-- | crates/libeditor/src/scope/mod.rs | 7 | ||||
-rw-r--r-- | crates/libeditor/src/scope/mod_scope.rs | 47 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/generated.rs | 4 | ||||
-rw-r--r-- | crates/libsyntax2/src/grammar.ron | 1 |
6 files changed, 100 insertions, 18 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 | } |
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs index b2e2c4782..06dac9d6d 100644 --- a/crates/libeditor/src/lib.rs +++ b/crates/libeditor/src/lib.rs | |||
@@ -18,7 +18,7 @@ mod test_utils; | |||
18 | 18 | ||
19 | use libsyntax2::{ | 19 | use libsyntax2::{ |
20 | File, TextUnit, TextRange, SyntaxNodeRef, | 20 | File, TextUnit, TextRange, SyntaxNodeRef, |
21 | ast::{AstNode, NameOwner}, | 21 | ast::{self, AstNode, NameOwner}, |
22 | algo::{walk, find_leaf_at_offset, ancestors}, | 22 | algo::{walk, find_leaf_at_offset, ancestors}, |
23 | SyntaxKind::{self, *}, | 23 | SyntaxKind::{self, *}, |
24 | }; | 24 | }; |
@@ -126,8 +126,8 @@ pub fn syntax_tree(file: &File) -> String { | |||
126 | } | 126 | } |
127 | 127 | ||
128 | pub fn runnables(file: &File) -> Vec<Runnable> { | 128 | pub fn runnables(file: &File) -> Vec<Runnable> { |
129 | file.ast() | 129 | walk::preorder(file.syntax()) |
130 | .functions() | 130 | .filter_map(ast::FnDef::cast) |
131 | .filter_map(|f| { | 131 | .filter_map(|f| { |
132 | let name = f.name()?.text(); | 132 | let name = f.name()?.text(); |
133 | let kind = if name == "main" { | 133 | let kind = if name == "main" { |
diff --git a/crates/libeditor/src/scope/mod.rs b/crates/libeditor/src/scope/mod.rs index 1a77a8b6e..2f25230f8 100644 --- a/crates/libeditor/src/scope/mod.rs +++ b/crates/libeditor/src/scope/mod.rs | |||
@@ -1,3 +1,8 @@ | |||
1 | mod fn_scope; | 1 | mod fn_scope; |
2 | mod mod_scope; | ||
3 | |||
4 | pub use self::{ | ||
5 | fn_scope::FnScopes, | ||
6 | mod_scope::ModuleScope, | ||
7 | }; | ||
2 | 8 | ||
3 | pub use self::fn_scope::FnScopes; | ||
diff --git a/crates/libeditor/src/scope/mod_scope.rs b/crates/libeditor/src/scope/mod_scope.rs new file mode 100644 index 000000000..0e51108d9 --- /dev/null +++ b/crates/libeditor/src/scope/mod_scope.rs | |||
@@ -0,0 +1,47 @@ | |||
1 | use libsyntax2::{ | ||
2 | AstNode, SyntaxNode, SmolStr, ast | ||
3 | }; | ||
4 | |||
5 | pub struct ModuleScope { | ||
6 | entries: Vec<Entry>, | ||
7 | } | ||
8 | |||
9 | impl ModuleScope { | ||
10 | pub fn new(m: ast::Root) -> ModuleScope { | ||
11 | let entries = m.items().filter_map(|item| { | ||
12 | match item { | ||
13 | ast::ModuleItem::StructDef(item) => Entry::new(item), | ||
14 | ast::ModuleItem::EnumDef(item) => Entry::new(item), | ||
15 | ast::ModuleItem::FnDef(item) => Entry::new(item), | ||
16 | ast::ModuleItem::TraitDef(item) => Entry::new(item), | ||
17 | ast::ModuleItem::ExternCrateItem(_) | | ||
18 | ast::ModuleItem::ImplItem(_) | | ||
19 | ast::ModuleItem::UseItem(_) => None | ||
20 | } | ||
21 | }).collect(); | ||
22 | |||
23 | ModuleScope { entries } | ||
24 | } | ||
25 | |||
26 | pub fn entries(&self) -> &[Entry] { | ||
27 | self.entries.as_slice() | ||
28 | } | ||
29 | } | ||
30 | |||
31 | pub struct Entry { | ||
32 | name: SyntaxNode, | ||
33 | } | ||
34 | |||
35 | impl Entry { | ||
36 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> { | ||
37 | let name = item.name()?; | ||
38 | Some(Entry { name: name.syntax().owned() }) | ||
39 | } | ||
40 | pub fn name(&self) -> SmolStr { | ||
41 | self.ast().text() | ||
42 | } | ||
43 | fn ast(&self) -> ast::Name { | ||
44 | ast::Name::cast(self.name.borrowed()).unwrap() | ||
45 | } | ||
46 | } | ||
47 | |||
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index b24fd2aba..2b400b847 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs | |||
@@ -1441,6 +1441,10 @@ impl<'a> AstNode<'a> for Root<'a> { | |||
1441 | } | 1441 | } |
1442 | 1442 | ||
1443 | impl<'a> Root<'a> { | 1443 | impl<'a> Root<'a> { |
1444 | pub fn items(self) -> impl Iterator<Item = ModuleItem<'a>> + 'a { | ||
1445 | super::children(self) | ||
1446 | } | ||
1447 | |||
1444 | pub fn functions(self) -> impl Iterator<Item = FnDef<'a>> + 'a { | 1448 | pub fn functions(self) -> impl Iterator<Item = FnDef<'a>> + 'a { |
1445 | super::children(self) | 1449 | super::children(self) |
1446 | } | 1450 | } |
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index c3a29c10c..8055a4687 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron | |||
@@ -238,6 +238,7 @@ Grammar( | |||
238 | ast: { | 238 | ast: { |
239 | "Root": ( | 239 | "Root": ( |
240 | collections: [ | 240 | collections: [ |
241 | ["items", "ModuleItem"], | ||
241 | ["functions", "FnDef"], | 242 | ["functions", "FnDef"], |
242 | ["modules", "Module"], | 243 | ["modules", "Module"], |
243 | ] | 244 | ] |