aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
authorAndrea Pretto <[email protected]>2019-04-15 15:11:32 +0100
committerAndrea Pretto <[email protected]>2019-04-21 23:14:58 +0100
commit914421495835380b96e0016763fda6eff31a8179 (patch)
tree86b348e13e9272f1320aad0416313c0f6f93a19c /crates/ra_ide_api
parentcf0eff2e332f46eda4fcecb043854c9c0d710e4e (diff)
complete_import: add new import resolver infrastructure with some hardcoded importable name.
Changes complete_scope to support that.
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs55
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs23
2 files changed, 70 insertions, 8 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index fd256fc3b..63d475823 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -1,12 +1,57 @@
1use crate::completion::{Completions, CompletionContext}; 1use ra_text_edit::TextEditBuilder;
2use ra_syntax::SmolStr;
3use ra_assists::auto_import;
4use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext};
2 5
3pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
4 if !ctx.is_trivial_path { 7 if ctx.is_trivial_path {
5 return; 8 let names = ctx.analyzer.all_names(ctx.db);
9 names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res));
6 } 10 }
7 let names = ctx.analyzer.all_names(ctx.db);
8 11
9 names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res)); 12 if let Some(name) = ctx.path_ident.as_ref() {
13 let import_names = ctx.analyzer.all_import_names(ctx.db, name);
14 import_names.into_iter().for_each(|(name, path)| {
15 let edit = {
16 let mut builder = TextEditBuilder::default();
17 builder.replace(ctx.source_range(), name.to_string());
18 auto_import::auto_import_text_edit(
19 ctx.token.parent(),
20 ctx.token.parent(),
21 &path,
22 &mut builder,
23 );
24 builder.finish()
25 };
26 CompletionItem::new(
27 CompletionKind::Reference,
28 ctx.source_range(),
29 build_import_label(&name, &path),
30 )
31 .text_edit(edit)
32 .add_to(acc)
33 });
34 }
35}
36
37fn build_import_label(name: &str, path: &Vec<SmolStr>) -> String {
38 let mut buf = String::with_capacity(64);
39 buf.push_str(name);
40 buf.push_str(" (");
41 fmt_import_path(path, &mut buf);
42 buf.push_str(")");
43 buf
44}
45
46fn fmt_import_path(path: &Vec<SmolStr>, buf: &mut String) {
47 let mut segments = path.iter();
48 if let Some(s) = segments.next() {
49 buf.push_str(&s);
50 }
51 for s in segments {
52 buf.push_str("::");
53 buf.push_str(&s);
54 }
10} 55}
11 56
12#[cfg(test)] 57#[cfg(test)]
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 359f2cffa..ca8f7900d 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -5,10 +5,10 @@ use ra_syntax::{
5 algo::{find_token_at_offset, find_covering_element, find_node_at_offset}, 5 algo::{find_token_at_offset, find_covering_element, find_node_at_offset},
6 SyntaxKind::*, 6 SyntaxKind::*,
7}; 7};
8use hir::source_binder;
9 8
10use crate::{db, FilePosition}; 9use hir::{ source_binder, Name };
11 10
11use crate::{db, FilePosition};
12/// `CompletionContext` is created early during completion to figure out, where 12/// `CompletionContext` is created early during completion to figure out, where
13/// exactly is the cursor, syntax-wise. 13/// exactly is the cursor, syntax-wise.
14#[derive(Debug)] 14#[derive(Debug)]
@@ -27,8 +27,10 @@ pub(crate) struct CompletionContext<'a> {
27 pub(super) is_pat_binding: bool, 27 pub(super) is_pat_binding: bool,
28 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 28 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
29 pub(super) is_trivial_path: bool, 29 pub(super) is_trivial_path: bool,
30 /// If not a trivial, path, the prefix (qualifier). 30 /// If not a trivial path, the prefix (qualifier).
31 pub(super) path_prefix: Option<hir::Path>, 31 pub(super) path_prefix: Option<hir::Path>,
32 /// If a trivial path, the ident.
33 pub(super) path_ident: Option<Name>,
32 pub(super) after_if: bool, 34 pub(super) after_if: bool,
33 /// `true` if we are a statement or a last expr in the block. 35 /// `true` if we are a statement or a last expr in the block.
34 pub(super) can_be_stmt: bool, 36 pub(super) can_be_stmt: bool,
@@ -63,6 +65,7 @@ impl<'a> CompletionContext<'a> {
63 is_pat_binding: false, 65 is_pat_binding: false,
64 is_trivial_path: false, 66 is_trivial_path: false,
65 path_prefix: None, 67 path_prefix: None,
68 path_ident: None,
66 after_if: false, 69 after_if: false,
67 can_be_stmt: false, 70 can_be_stmt: false,
68 is_new_item: false, 71 is_new_item: false,
@@ -83,6 +86,18 @@ impl<'a> CompletionContext<'a> {
83 } 86 }
84 87
85 fn fill(&mut self, original_file: &'a SourceFile, offset: TextUnit) { 88 fn fill(&mut self, original_file: &'a SourceFile, offset: TextUnit) {
89 // We heed the original NameRef before the "intellijRulezz" hack
90 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(original_file.syntax(), offset)
91 {
92 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
93 if let Some(path) = hir::Path::from_ast(path) {
94 if let Some(ident) = path.as_ident() {
95 self.path_ident = Some(ident.clone());
96 }
97 }
98 }
99 }
100
86 // Insert a fake ident to get a valid parse tree. We will use this file 101 // Insert a fake ident to get a valid parse tree. We will use this file
87 // to determine context, though the original_file will be used for 102 // to determine context, though the original_file will be used for
88 // actual completion. 103 // actual completion.
@@ -151,6 +166,7 @@ impl<'a> CompletionContext<'a> {
151 Some(it) => it, 166 Some(it) => it,
152 None => return, 167 None => return,
153 }; 168 };
169
154 if let Some(segment) = ast::PathSegment::cast(parent) { 170 if let Some(segment) = ast::PathSegment::cast(parent) {
155 let path = segment.parent_path(); 171 let path = segment.parent_path();
156 self.is_call = path 172 self.is_call = path
@@ -167,6 +183,7 @@ impl<'a> CompletionContext<'a> {
167 return; 183 return;
168 } 184 }
169 } 185 }
186
170 if path.qualifier().is_none() { 187 if path.qualifier().is_none() {
171 self.is_trivial_path = true; 188 self.is_trivial_path = true;
172 189