aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor')
-rw-r--r--crates/libeditor/src/completion.rs178
-rw-r--r--crates/libeditor/tests/test.rs3
2 files changed, 111 insertions, 70 deletions
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs
index 351781ec4..6335dba17 100644
--- a/crates/libeditor/src/completion.rs
+++ b/crates/libeditor/src/completion.rs
@@ -7,6 +7,7 @@ use libsyntax2::{
7 ancestors, 7 ancestors,
8 visit::{visitor_ctx, VisitorCtx}, 8 visit::{visitor_ctx, VisitorCtx},
9 walk::preorder, 9 walk::preorder,
10 generate,
10 }, 11 },
11}; 12};
12 13
@@ -27,86 +28,125 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI
27 file.incremental_reparse(&edit)? 28 file.incremental_reparse(&edit)?
28 }; 29 };
29 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?; 30 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
30 Some(complete(name_ref)) 31 let fn_def = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next()?;
32 let scopes = compute_scopes(fn_def);
33 Some(complete(name_ref, &scopes))
31} 34}
32 35
33fn complete(name_ref: ast::NameRef) -> Vec<CompletionItem> { 36fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec<CompletionItem> {
34 let mut res = Vec::new(); 37 scopes.scope_chain(name_ref.syntax())
35 for node in ancestors(name_ref.syntax()) { 38 .flat_map(|scope| scopes.entries(scope).iter())
36 process_scope(node, &mut res); 39 .map(|entry| CompletionItem {
37 } 40 name: entry.name().to_string()
38 res
39}
40
41fn process_scope(node: SyntaxNodeRef, sink: &mut Vec<CompletionItem>) {
42 let _ = visitor_ctx(sink)
43 .visit::<ast::Block, _>(|block, sink| {
44 block.let_stmts()
45 .filter_map(|it| it.pat())
46 .for_each(move |it| process_pat(it, sink))
47 })
48 .visit::<ast::FnDef, _>(|fn_def, sink| {
49 fn_def.param_list().into_iter()
50 .flat_map(|it| it.params())
51 .filter_map(|it| it.pat())
52 .for_each(move |it| process_pat(it, sink))
53 }) 41 })
54 .accept(node); 42 .collect()
43}
55 44
56 fn process_pat(pat: ast::Pat, sink: &mut Vec<CompletionItem>) { 45fn compute_scopes(fn_def: ast::FnDef) -> FnScopes {
57 let items = preorder(pat.syntax()) 46 let mut scopes = FnScopes::new();
58 .filter_map(ast::BindPat::cast) 47 let root = scopes.root_scope();
59 .filter_map(ast::BindPat::name) 48 fn_def.param_list().into_iter()
60 .map(|name| CompletionItem { name: name.text().to_string() }); 49 .flat_map(|it| it.params())
61 sink.extend(items); 50 .filter_map(|it| it.pat())
51 .for_each(|it| scopes.add_bindings(root, it));
52
53 let mut scope = root;
54 if let Some(body) = fn_def.body() {
55 for child in body.syntax().children() {
56 let _ = visitor_ctx((&mut scopes, &mut scope))
57 .visit::<ast::LetStmt, _>(|stmt, (scopes, scope)| {
58 *scope = scopes.new_scope(*scope);
59 if let Some(pat) = stmt.pat() {
60 scopes.add_bindings(*scope, pat);
61 }
62 if let Some(expr) = stmt.initializer() {
63 scopes.set_scope(expr.syntax(), *scope)
64 }
65 })
66 .visit::<ast::ExprStmt, _>(|expr, (scopes, scope)| {
67 scopes.set_scope(expr.syntax(), *scope)
68 })
69 .visit::<ast::Expr, _>(|expr, (scopes, scope)| {
70 scopes.set_scope(expr.syntax(), *scope)
71 })
72 .accept(child);
73 }
62 } 74 }
75 scopes
63} 76}
64 77
65// fn compute_scopes(fn_def: ast::FnDef) -> FnScopes { 78type ScopeId = usize;
66// let mut scopes = FnScopes::new();
67// }
68
69// type ScopeId = usize;
70 79
71// struct FnScopes { 80struct FnScopes {
72// scopes: Vec<ScopeData>, 81 scopes: Vec<ScopeData>,
73// scope_for_expr: HashMap<SyntaxNode, ScopeId>, 82 scope_for: HashMap<SyntaxNode, ScopeId>,
74// } 83}
75
76// impl FnScopes {
77// fn new() -> FnScopes {
78// FnScopes {
79// scopes: vec![],
80// scope_for_expr: HashMap::new(),
81// }
82// }
83 84
84// fn new_scope(&mut Self) -> ScopeId { 85impl FnScopes {
85// let res = self.scopes.len(); 86 fn new() -> FnScopes {
86// self.scopes.push(ScopeData { parent: None, entries: vec![] }) 87 FnScopes {
87// } 88 scopes: vec![],
89 scope_for: HashMap::new(),
90 }
91 }
92 fn root_scope(&mut self) -> ScopeId {
93 let res = self.scopes.len();
94 self.scopes.push(ScopeData { parent: None, entries: vec![] });
95 res
96 }
97 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
98 let res = self.scopes.len();
99 self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
100 res
101 }
102 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
103 let entries = preorder(pat.syntax())
104 .filter_map(ast::BindPat::cast)
105 .filter_map(ScopeEntry::new);
106 self.scopes[scope].entries.extend(entries);
107 }
108 fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
109 self.scope_for.insert(node.owned(), scope);
110 }
111 fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
112 &self.scopes[scope].entries
113 }
114 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
115 ancestors(node)
116 .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
117 .next()
118 }
119 fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
120 generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
121 }
122}
88 123
89// fn set_parent 124struct ScopeData {
90// } 125 parent: Option<ScopeId>,
126 entries: Vec<ScopeEntry>
127}
91 128
92// struct ScopeData { 129struct ScopeEntry {
93// parent: Option<ScopeId>, 130 syntax: SyntaxNode
94// entries: Vec<ScopeEntry> 131}
95// }
96 132
97// struct ScopeEntry { 133impl ScopeEntry {
98// syntax: SyntaxNode 134 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
99// } 135 if pat.name().is_some() {
136 Some(ScopeEntry { syntax: pat.syntax().owned() })
137 } else {
138 None
139 }
140 }
100 141
101// impl ScopeEntry { 142 fn name(&self) -> SmolStr {
102// fn name(&self) -> SmolStr { 143 self.ast().name()
103// self.ast().name() 144 .unwrap()
104// .unwrap() 145 .text()
105// .text() 146 }
106// }
107 147
108// fn ast(&self) -> ast::BindPat { 148 fn ast(&self) -> ast::BindPat {
109// ast::BindPat::cast(self.syntax.borrowed()) 149 ast::BindPat::cast(self.syntax.borrowed())
110// .unwrap() 150 .unwrap()
111// } 151 }
112// } 152}
diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs
index ecdc149c7..7979bfffe 100644
--- a/crates/libeditor/tests/test.rs
+++ b/crates/libeditor/tests/test.rs
@@ -268,7 +268,8 @@ fn test_completion() {
268 do_check(r" 268 do_check(r"
269fn quux(x: i32) { 269fn quux(x: i32) {
270 let y = 92; 270 let y = 92;
271 1 + <|> 271 1 + <|>;
272 let z = ();
272} 273}
273", r#"[CompletionItem { name: "y" }, 274", r#"[CompletionItem { name: "y" },
274 CompletionItem { name: "x" }]"#); 275 CompletionItem { name: "x" }]"#);