diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_scope.rs | 55 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_context.rs | 23 |
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 @@ | |||
1 | use crate::completion::{Completions, CompletionContext}; | 1 | use ra_text_edit::TextEditBuilder; |
2 | use ra_syntax::SmolStr; | ||
3 | use ra_assists::auto_import; | ||
4 | use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext}; | ||
2 | 5 | ||
3 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(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 | |||
37 | fn 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 | |||
46 | fn 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 | }; |
8 | use hir::source_binder; | ||
9 | 8 | ||
10 | use crate::{db, FilePosition}; | 9 | use hir::{ source_binder, Name }; |
11 | 10 | ||
11 | use 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 | ||