aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/completion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/completion.rs')
-rw-r--r--crates/ra_analysis/src/completion.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs
new file mode 100644
index 000000000..a0fd6828d
--- /dev/null
+++ b/crates/ra_analysis/src/completion.rs
@@ -0,0 +1,61 @@
1use ra_editor::{CompletionItem, find_node_at_offset, complete_module_items};
2use ra_syntax::{
3 AtomEdit, File, TextUnit, AstNode,
4 ast::{self, ModuleItemOwner},
5};
6
7use crate::{
8 FileId, Cancelable,
9 db::{self, SyntaxDatabase},
10 descriptors::module::{ModulesDatabase, ModuleTree, ModuleId},
11};
12
13pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
14 let file = db.file_syntax(file_id);
15 let module_tree = db.module_tree()?;
16 let file = {
17 let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
18 file.reparse(&edit)
19 };
20 let target_file = match find_target_module(&module_tree, file_id, &file, offset) {
21 None => return Ok(None),
22 Some(target_module) => {
23 let file_id = target_module.file_id(&module_tree);
24 db.file_syntax(file_id)
25 }
26 };
27 let mut res = Vec::new();
28 complete_module_items(target_file.ast().items(), None, &mut res);
29 Ok(Some(res))
30}
31
32pub(crate) fn find_target_module(module_tree: &ModuleTree, file_id: FileId, file: &File, offset: TextUnit) -> Option<ModuleId> {
33 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset)?;
34 let mut crate_path = crate_path(name_ref)?;
35 let module_id = module_tree.any_module_for_file(file_id)?;
36 crate_path.pop();
37 let mut target_module = module_id.root(&module_tree);
38 for name in crate_path {
39 target_module = target_module.child(module_tree, name.text().as_str())?;
40 }
41 Some(target_module)
42}
43
44fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
45 let mut path = name_ref.syntax()
46 .parent().and_then(ast::PathSegment::cast)?
47 .parent_path();
48 let mut res = Vec::new();
49 loop {
50 let segment = path.segment()?;
51 match segment.kind()? {
52 ast::PathSegmentKind::Name(name) => res.push(name),
53 ast::PathSegmentKind::CrateKw => break,
54 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw =>
55 return None,
56 }
57 path = path.qualifier()?;
58 }
59 res.reverse();
60 Some(res)
61}