aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/assists.rs24
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs136
-rw-r--r--crates/ra_ide/src/inlay_hints.rs5
3 files changed, 12 insertions, 153 deletions
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs
index b60b1a60d..40d56a4f7 100644
--- a/crates/ra_ide/src/assists.rs
+++ b/crates/ra_ide/src/assists.rs
@@ -1,6 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use either::Either;
4use ra_assists::{resolved_assists, AssistAction, AssistLabel}; 3use ra_assists::{resolved_assists, AssistAction, AssistLabel};
5use ra_db::{FilePosition, FileRange}; 4use ra_db::{FilePosition, FileRange};
6use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
@@ -13,7 +12,8 @@ pub use ra_assists::AssistId;
13pub struct Assist { 12pub struct Assist {
14 pub id: AssistId, 13 pub id: AssistId,
15 pub label: String, 14 pub label: String,
16 pub change_data: Either<SourceChange, Vec<SourceChange>>, 15 pub group_label: Option<String>,
16 pub source_change: SourceChange,
17} 17}
18 18
19pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { 19pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
@@ -25,17 +25,8 @@ pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
25 Assist { 25 Assist {
26 id: assist_label.id, 26 id: assist_label.id,
27 label: assist_label.label.clone(), 27 label: assist_label.label.clone(),
28 change_data: match assist.action_data { 28 group_label: assist.group_label.map(|it| it.0),
29 Either::Left(action) => { 29 source_change: action_to_edit(assist.action, file_id, assist_label),
30 Either::Left(action_to_edit(action, file_id, assist_label))
31 }
32 Either::Right(actions) => Either::Right(
33 actions
34 .into_iter()
35 .map(|action| action_to_edit(action, file_id, assist_label))
36 .collect(),
37 ),
38 },
39 } 30 }
40 }) 31 })
41 .collect() 32 .collect()
@@ -47,9 +38,6 @@ fn action_to_edit(
47 assist_label: &AssistLabel, 38 assist_label: &AssistLabel,
48) -> SourceChange { 39) -> SourceChange {
49 let file_edit = SourceFileEdit { file_id, edit: action.edit }; 40 let file_edit = SourceFileEdit { file_id, edit: action.edit };
50 SourceChange::source_file_edit( 41 SourceChange::source_file_edit(assist_label.label.clone(), file_edit)
51 action.label.unwrap_or_else(|| assist_label.label.clone()), 42 .with_cursor_opt(action.cursor_position.map(|offset| FilePosition { offset, file_id }))
52 file_edit,
53 )
54 .with_cursor_opt(action.cursor_position.map(|offset| FilePosition { offset, file_id }))
55} 43}
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index 64b04ec2b..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::auto_import_text_edit; 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,138 +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 auto_import_text_edit(
30 &ctx.token.parent(),
31 &ctx.token.parent(),
32 &path,
33 &mut builder,
34 );
35 builder.finish()
36 };
37
38 // Hack: copied this check form conv.rs beacause auto import can produce edits
39 // that invalidate assert in conv_with.
40 if edit
41 .as_atoms()
42 .iter()
43 .filter(|atom| !ctx.source_range().is_subrange(&atom.delete))
44 .all(|atom| ctx.source_range().intersection(&atom.delete).is_none())
45 {
46 CompletionItem::new(
47 CompletionKind::Reference,
48 ctx.source_range(),
49 build_import_label(&name, &path),
50 )
51 .text_edit(edit)
52 .add_to(acc);
53 }
54 });
55 }
56}
57
58fn build_import_label(name: &str, path: &ModPath) -> String {
59 let mut buf = String::with_capacity(64);
60 buf.push_str(name);
61 buf.push_str(" (");
62 buf.push_str(&path.to_string());
63 buf.push_str(")");
64 buf
65}
66
67#[derive(Debug, Clone, Default)]
68pub(crate) struct ImportResolver {
69 // todo: use fst crate or something like that
70 dummy_names: Vec<(SmolStr, ModPath)>,
71}
72
73impl ImportResolver {
74 pub(crate) fn new() -> Self {
75 use hir::name;
76
77 let dummy_names = vec![
78 (
79 SmolStr::new("fmt"),
80 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![fmt]] },
81 ),
82 (
83 SmolStr::new("io"),
84 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![io]] },
85 ),
86 (
87 SmolStr::new("iter"),
88 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![iter]] },
89 ),
90 (
91 SmolStr::new("hash"),
92 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![hash]] },
93 ),
94 (
95 SmolStr::new("Debug"),
96 ModPath {
97 kind: PathKind::Plain,
98 segments: vec![name![std], name![fmt], name![Debug]],
99 },
100 ),
101 (
102 SmolStr::new("Display"),
103 ModPath {
104 kind: PathKind::Plain,
105 segments: vec![name![std], name![fmt], name![Display]],
106 },
107 ),
108 (
109 SmolStr::new("Hash"),
110 ModPath {
111 kind: PathKind::Plain,
112 segments: vec![name![std], name![hash], name![Hash]],
113 },
114 ),
115 (
116 SmolStr::new("Hasher"),
117 ModPath {
118 kind: PathKind::Plain,
119 segments: vec![name![std], name![hash], name![Hasher]],
120 },
121 ),
122 (
123 SmolStr::new("Iterator"),
124 ModPath {
125 kind: PathKind::Plain,
126 segments: vec![name![std], name![iter], name![Iterator]],
127 },
128 ),
129 ];
130
131 ImportResolver { dummy_names }
132 }
133
134 // Returns a map of importable items filtered by name.
135 // The map associates item name with its full path.
136 // todo: should return Resolutions
137 pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, ModPath> {
138 if name.len() > 1 {
139 self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
140 } else {
141 FxHashMap::default()
142 }
143 }
144} 13}
145 14
146#[cfg(test)] 15#[cfg(test)]
147mod tests { 16mod tests {
148 use crate::completion::{do_completion, CompletionItem, CompletionKind};
149 use insta::assert_debug_snapshot; 17 use insta::assert_debug_snapshot;
150 18
19 use crate::completion::{do_completion, CompletionItem, CompletionKind};
20
151 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 21 fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
152 do_completion(code, CompletionKind::Reference) 22 do_completion(code, CompletionKind::Reference)
153 } 23 }
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 6b0d3d996..2ae97e65f 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -80,8 +80,7 @@ fn get_inlay_hints(
80 }, 80 },
81 ast::MatchArmList(it) => { 81 ast::MatchArmList(it) => {
82 it.arms() 82 it.arms()
83 .map(|match_arm| match_arm.pats()) 83 .filter_map(|match_arm| match_arm.pat())
84 .flatten()
85 .for_each(|root_pat| get_pat_type_hints(acc, db, &analyzer, root_pat, true, max_inlay_hint_length)); 84 .for_each(|root_pat| get_pat_type_hints(acc, db, &analyzer, root_pat, true, max_inlay_hint_length));
86 }, 85 },
87 ast::CallExpr(it) => { 86 ast::CallExpr(it) => {
@@ -202,6 +201,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
202 Some(pat) => pats_to_process.push_back(pat), 201 Some(pat) => pats_to_process.push_back(pat),
203 _ => leaf_pats.push(maybe_leaf_pat), 202 _ => leaf_pats.push(maybe_leaf_pat),
204 }, 203 },
204 ast::Pat::OrPat(ref_pat) => pats_to_process.extend(ref_pat.pats()),
205 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()), 205 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
206 ast::Pat::RecordPat(record_pat) => { 206 ast::Pat::RecordPat(record_pat) => {
207 if let Some(pat_list) = record_pat.record_field_pat_list() { 207 if let Some(pat_list) = record_pat.record_field_pat_list() {
@@ -222,6 +222,7 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
222 ast::Pat::TupleStructPat(tuple_struct_pat) => { 222 ast::Pat::TupleStructPat(tuple_struct_pat) => {
223 pats_to_process.extend(tuple_struct_pat.args()) 223 pats_to_process.extend(tuple_struct_pat.args())
224 } 224 }
225 ast::Pat::ParenPat(inner_pat) => pats_to_process.extend(inner_pat.pat()),
225 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()), 226 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
226 _ => (), 227 _ => (),
227 } 228 }