aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs131
1 files changed, 3 insertions, 128 deletions
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index aaa9985d4..e2ee86dd1 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -1,12 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_assists::insert_use_statement; 3use crate::completion::{CompletionContext, Completions};
4use ra_syntax::{ast, AstNode, SmolStr};
5use ra_text_edit::TextEditBuilder;
6use rustc_hash::FxHashMap;
7
8use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
9use hir::{ModPath, PathKind};
10 4
11pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
12 if !ctx.is_trivial_path { 6 if !ctx.is_trivial_path {
@@ -16,133 +10,14 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
16 ctx.analyzer.process_all_names(ctx.db, &mut |name, res| { 10 ctx.analyzer.process_all_names(ctx.db, &mut |name, res| {
17 acc.add_resolution(ctx, name.to_string(), &res) 11 acc.add_resolution(ctx, name.to_string(), &res)
18 }); 12 });
19
20 // auto-import
21 // We fetch ident from the original file, because we need to pre-filter auto-imports
22 if ast::NameRef::cast(ctx.token.parent()).is_some() {
23 let import_resolver = ImportResolver::new();
24 let import_names = import_resolver.all_names(ctx.token.text());
25 import_names.into_iter().for_each(|(name, path)| {
26 let edit = {
27 let mut builder = TextEditBuilder::default();
28 builder.replace(ctx.source_range(), name.to_string());
29 insert_use_statement(&ctx.token.parent(), &ctx.token.parent(), &path, &mut builder);
30 builder.finish()
31 };
32
33 // Hack: copied this check form conv.rs beacause auto import can produce edits
34 // that invalidate assert in conv_with.
35 if edit
36 .as_atoms()
37 .iter()
38 .filter(|atom| !ctx.source_range().is_subrange(&atom.delete))
39 .all(|atom| ctx.source_range().intersection(&atom.delete).is_none())
40 {
41 CompletionItem::new(
42 CompletionKind::Reference,
43 ctx.source_range(),
44 build_import_label(&name, &path),
45 )
46 .text_edit(edit)
47 .add_to(acc);
48 }
49 });
50 }
51}
52
53fn build_import_label(name: &str, path: &ModPath) -> String {
54 let mut buf = String::with_capacity(64);
55 buf.push_str(name);
56 buf.push_str(" (");
57 buf.push_str(&path.to_string());
58 buf.push_str(")");
59 buf
60}
61
62#[derive(Debug, Clone, Default)]
63pub(crate) struct ImportResolver {
64 // todo: use fst crate or something like that
65 dummy_names: Vec<(SmolStr, ModPath)>,
66}
67
68impl ImportResolver {
69 pub(crate) fn new() -> Self {
70 use hir::name;
71
72 let dummy_names = vec![
73 (
74 SmolStr::new("fmt"),
75 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![fmt]] },
76 ),
77 (
78 SmolStr::new("io"),
79 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![io]] },
80 ),
81 (
82 SmolStr::new("iter"),
83 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![iter]] },
84 ),
85 (
86 SmolStr::new("hash"),
87 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![hash]] },
88 ),
89 (
90 SmolStr::new("Debug"),
91 ModPath {
92 kind: PathKind::Plain,
93 segments: vec![name![std], name![fmt], name![Debug]],
94 },
95 ),
96 (
97 SmolStr::new("Display"),
98 ModPath {
99 kind: PathKind::Plain,
100 segments: vec![name![std], name![fmt], name![Display]],
101 },
102 ),
103 (
104 SmolStr::new("Hash"),
105 ModPath {
106 kind: PathKind::Plain,
107 segments: vec![name![std], name![hash], name![Hash]],
108 },
109 ),
110 (
111 SmolStr::new("Hasher"),
112 ModPath {
113 kind: PathKind::Plain,
114 segments: vec![name![std], name![hash], name![Hasher]],
115 },
116 ),
117 (
118 SmolStr::new("Iterator"),
119 ModPath {
120 kind: PathKind::Plain,
121 segments: vec![name![std], name![iter], name![Iterator]],
122 },
123 ),
124 ];
125
126 ImportResolver { dummy_names }
127 }
128
129 // Returns a map of importable items filtered by name.
130 // The map associates item name with its full path.
131 // todo: should return Resolutions
132 pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, ModPath> {
133 if name.len() > 1 {
134 self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
135 } else {
136 FxHashMap::default()
137 }
138 }
139} 13}
140 14
141#[cfg(test)] 15#[cfg(test)]
142mod tests { 16mod tests {
143 use crate::completion::{do_completion, CompletionItem, CompletionKind};
144 use insta::assert_debug_snapshot; 17 use insta::assert_debug_snapshot;
145 18
19 use crate::completion::{do_completion, CompletionItem, CompletionKind};
20
146 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 21 fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
147 do_completion(code, CompletionKind::Reference) 22 do_completion(code, CompletionKind::Reference)
148 } 23 }