diff options
author | Aleksey Kladov <[email protected]> | 2018-10-24 16:37:25 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-10-24 16:37:25 +0100 |
commit | 69d07df201307fb7c539cdb20b8f1c1c12840386 (patch) | |
tree | 08cccd64582510ce2c82ceec729504a80e33f5b1 /crates/ra_analysis | |
parent | 9a7db8fa009c612168ef16f6ed72315b5406ed09 (diff) |
Complete crate:: paths
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/completion.rs | 61 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 22 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_analysis/src/roots.rs | 3 | ||||
-rw-r--r-- | crates/ra_analysis/tests/tests.rs | 14 |
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 @@ | |||
1 | use ra_editor::{CompletionItem, find_node_at_offset, complete_module_items}; | ||
2 | use ra_syntax::{ | ||
3 | AtomEdit, File, TextUnit, AstNode, | ||
4 | ast::{self, ModuleItemOwner}, | ||
5 | }; | ||
6 | |||
7 | use crate::{ | ||
8 | FileId, Cancelable, | ||
9 | db::{self, SyntaxDatabase}, | ||
10 | descriptors::module::{ModulesDatabase, ModuleTree, ModuleId}, | ||
11 | }; | ||
12 | |||
13 | pub(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 | |||
32 | pub(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 | |||
44 | fn 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 | ||
8 | use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit}; | 8 | use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit, CompletionItem}; |
9 | use ra_syntax::{ | 9 | use 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; | |||
11 | mod imp; | 11 | mod imp; |
12 | mod roots; | 12 | mod roots; |
13 | mod symbol_index; | 13 | mod symbol_index; |
14 | mod completion; | ||
14 | 15 | ||
15 | use std::{fmt::Debug, sync::Arc}; | 16 | use 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 @@ | |||
1 | use std::{sync::Arc}; | 1 | use std::{sync::Arc}; |
2 | 2 | ||
3 | use ra_editor::LineIndex; | ||
4 | use ra_syntax::File; | ||
5 | use rustc_hash::FxHashSet; | 3 | use rustc_hash::FxHashSet; |
6 | use rayon::prelude::*; | 4 | use rayon::prelude::*; |
7 | use salsa::Database; | 5 | use 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] | ||
269 | fn 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 | } | ||