aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-09-07 23:35:20 +0100
committerAleksey Kladov <[email protected]>2018-09-07 23:35:20 +0100
commit127814d9a7f62c834c0893ff05e933aac4be89e9 (patch)
tree412432e0308c8b22b28e3b84776b44b311b283da /crates/libeditor/src
parentff1c82216cc05f2621a301e30ab7a1102dea9d2b (diff)
nested mod completion
Diffstat (limited to 'crates/libeditor/src')
-rw-r--r--crates/libeditor/src/completion.rs58
-rw-r--r--crates/libeditor/src/scope/mod_scope.rs11
2 files changed, 47 insertions, 22 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
3use libsyntax2::{ 3use 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 @@
1use libsyntax2::{ 1use libsyntax2::{
2 AstNode, SyntaxNode, SyntaxNodeRef, SmolStr, ast 2 AstNode, SyntaxNode, SyntaxNodeRef, SmolStr,
3 ast::{self, AstChildren},
3}; 4};
4 5
5pub struct ModuleScope { 6pub struct ModuleScope {
@@ -16,9 +17,9 @@ enum EntryKind {
16} 17}
17 18
18impl ModuleScope { 19impl 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)]
86mod tests { 87mod 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())