aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-10-24 16:37:25 +0100
committerAleksey Kladov <[email protected]>2018-10-24 16:37:25 +0100
commit69d07df201307fb7c539cdb20b8f1c1c12840386 (patch)
tree08cccd64582510ce2c82ceec729504a80e33f5b1 /crates/ra_analysis
parent9a7db8fa009c612168ef16f6ed72315b5406ed09 (diff)
Complete crate:: paths
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion.rs61
-rw-r--r--crates/ra_analysis/src/imp.rs22
-rw-r--r--crates/ra_analysis/src/lib.rs4
-rw-r--r--crates/ra_analysis/src/roots.rs3
-rw-r--r--crates/ra_analysis/tests/tests.rs14
5 files changed, 98 insertions, 6 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}
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index f142b6c43..f3e5b2887 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -5,7 +5,7 @@ use std::{
5 sync::Arc, 5 sync::Arc,
6}; 6};
7 7
8use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit}; 8use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit, CompletionItem};
9use ra_syntax::{ 9use ra_syntax::{
10 ast::{self, ArgListOwner, Expr, NameOwner}, 10 ast::{self, ArgListOwner, Expr, NameOwner},
11 AstNode, File, SmolStr, 11 AstNode, File, SmolStr,
@@ -197,6 +197,26 @@ impl AnalysisImpl {
197 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 197 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
198 self.data.crate_graph.crate_roots[&crate_id] 198 self.data.crate_graph.crate_roots[&crate_id]
199 } 199 }
200 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
201 let mut res = Vec::new();
202 let mut has_completions = false;
203 let file = self.file_syntax(file_id);
204 if let Some(scope_based) = ra_editor::scope_completion(&file, offset) {
205 res.extend(scope_based);
206 has_completions = true;
207 }
208 let root = self.root(file_id);
209 if let Some(scope_based) = crate::completion::resolve_based_completion(root.db(), file_id, offset)? {
210 res.extend(scope_based);
211 has_completions = true;
212 }
213 let res = if has_completions {
214 Some(res)
215 } else {
216 None
217 };
218 Ok(res)
219 }
200 pub fn approximately_resolve_symbol( 220 pub fn approximately_resolve_symbol(
201 &self, 221 &self,
202 file_id: FileId, 222 file_id: FileId,
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 67a239a5c..7078e2d31 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -11,6 +11,7 @@ mod descriptors;
11mod imp; 11mod imp;
12mod roots; 12mod roots;
13mod symbol_index; 13mod symbol_index;
14mod completion;
14 15
15use std::{fmt::Debug, sync::Arc}; 16use std::{fmt::Debug, sync::Arc};
16 17
@@ -246,8 +247,7 @@ impl Analysis {
246 Ok(ra_editor::highlight(&file)) 247 Ok(ra_editor::highlight(&file))
247 } 248 }
248 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { 249 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
249 let file = self.imp.file_syntax(file_id); 250 self.imp.completions(file_id, offset)
250 Ok(ra_editor::scope_completion(&file, offset))
251 } 251 }
252 pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> { 252 pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> {
253 Ok(self.imp.assists(file_id, range)) 253 Ok(self.imp.assists(file_id, range))
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs
index aa0243720..1e9e613ac 100644
--- a/crates/ra_analysis/src/roots.rs
+++ b/crates/ra_analysis/src/roots.rs
@@ -1,7 +1,5 @@
1use std::{sync::Arc}; 1use std::{sync::Arc};
2 2
3use ra_editor::LineIndex;
4use ra_syntax::File;
5use rustc_hash::FxHashSet; 3use rustc_hash::FxHashSet;
6use rayon::prelude::*; 4use rayon::prelude::*;
7use salsa::Database; 5use salsa::Database;
@@ -10,7 +8,6 @@ use crate::{
10 Cancelable, 8 Cancelable,
11 db::{self, FilesDatabase, SyntaxDatabase}, 9 db::{self, FilesDatabase, SyntaxDatabase},
12 imp::FileResolverImp, 10 imp::FileResolverImp,
13 descriptors::module::{ModulesDatabase, ModuleTree},
14 symbol_index::SymbolIndex, 11 symbol_index::SymbolIndex,
15 FileId, 12 FileId,
16}; 13};
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 7ae3d0eeb..52fae71ae 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -264,3 +264,17 @@ fn test_find_all_refs_for_param_inside() {
264 let refs = get_all_refs(code); 264 let refs = get_all_refs(code);
265 assert_eq!(refs.len(), 2); 265 assert_eq!(refs.len(), 2);
266} 266}
267
268#[test]
269fn test_complete_crate_path() {
270 let snap = analysis(&[
271 ("/lib.rs", "mod foo; struct Spam;"),
272 ("/foo.rs", "use crate::Sp"),
273 ]);
274 let completions = snap.completions(FileId(2), 13.into()).unwrap().unwrap();
275 assert_eq_dbg(
276 r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
277 CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
278 &completions,
279 );
280}