diff options
Diffstat (limited to 'crates/libeditor/src/completion.rs')
-rw-r--r-- | crates/libeditor/src/completion.rs | 58 |
1 files changed, 41 insertions, 17 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; |