diff options
Diffstat (limited to 'crates/libeditor/src')
-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 |
4 files changed, 95 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 | |||