aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs36
-rw-r--r--crates/ra_assists/src/lib.rs83
2 files changed, 37 insertions, 82 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index c5e9056af..1908bdec9 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -14,8 +14,8 @@ use crate::{AssistAction, AssistId, AssistLabel};
14 14
15#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
16pub(crate) enum Assist { 16pub(crate) enum Assist {
17 Unresolved(Vec<AssistLabel>), 17 Unresolved { label: AssistLabel },
18 Resolved(Vec<(AssistLabel, AssistAction)>), 18 Resolved { label: AssistLabel, action: AssistAction },
19} 19}
20 20
21/// `AssistCtx` allows to apply an assist or check if it could be applied. 21/// `AssistCtx` allows to apply an assist or check if it could be applied.
@@ -54,7 +54,6 @@ pub(crate) struct AssistCtx<'a, DB> {
54 pub(crate) frange: FileRange, 54 pub(crate) frange: FileRange,
55 source_file: SourceFile, 55 source_file: SourceFile,
56 should_compute_edit: bool, 56 should_compute_edit: bool,
57 assist: Assist,
58} 57}
59 58
60impl<'a, DB> Clone for AssistCtx<'a, DB> { 59impl<'a, DB> Clone for AssistCtx<'a, DB> {
@@ -64,7 +63,6 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> {
64 frange: self.frange, 63 frange: self.frange,
65 source_file: self.source_file.clone(), 64 source_file: self.source_file.clone(),
66 should_compute_edit: self.should_compute_edit, 65 should_compute_edit: self.should_compute_edit,
67 assist: self.assist.clone(),
68 } 66 }
69 } 67 }
70} 68}
@@ -75,32 +73,30 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
75 F: FnOnce(AssistCtx<DB>) -> T, 73 F: FnOnce(AssistCtx<DB>) -> T,
76 { 74 {
77 let parse = db.parse(frange.file_id); 75 let parse = db.parse(frange.file_id);
78 let assist =
79 if should_compute_edit { Assist::Resolved(vec![]) } else { Assist::Unresolved(vec![]) };
80 76
81 let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit, assist }; 77 let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit };
82 f(ctx) 78 f(ctx)
83 } 79 }
84 80
85 pub(crate) fn add_assist( 81 pub(crate) fn add_assist(
86 mut self, 82 self,
87 id: AssistId, 83 id: AssistId,
88 label: impl Into<String>, 84 label: impl Into<String>,
89 f: impl FnOnce(&mut AssistBuilder), 85 f: impl FnOnce(&mut AssistBuilder),
90 ) -> Option<Assist> { 86 ) -> Option<Assist> {
91 let label = AssistLabel { label: label.into(), id }; 87 let label = AssistLabel { label: label.into(), id };
92 match &mut self.assist { 88 let assist = if self.should_compute_edit {
93 Assist::Unresolved(labels) => labels.push(label), 89 let action = {
94 Assist::Resolved(labels_actions) => { 90 let mut edit = AssistBuilder::default();
95 let action = { 91 f(&mut edit);
96 let mut edit = AssistBuilder::default(); 92 edit.build()
97 f(&mut edit); 93 };
98 edit.build() 94 Assist::Resolved { label, action }
99 }; 95 } else {
100 labels_actions.push((label, action)); 96 Assist::Unresolved { label }
101 } 97 };
102 } 98
103 Some(self.assist) 99 Some(assist)
104 } 100 }
105 101
106 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { 102 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 7a1657d87..38599d4f1 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -11,7 +11,6 @@ mod marks;
11mod doc_tests; 11mod doc_tests;
12 12
13use hir::db::HirDatabase; 13use hir::db::HirDatabase;
14use itertools::Itertools;
15use ra_db::FileRange; 14use ra_db::FileRange;
16use ra_syntax::{TextRange, TextUnit}; 15use ra_syntax::{TextRange, TextUnit};
17use ra_text_edit::TextEdit; 16use ra_text_edit::TextEdit;
@@ -51,10 +50,10 @@ where
51 .iter() 50 .iter()
52 .filter_map(|f| f(ctx.clone())) 51 .filter_map(|f| f(ctx.clone()))
53 .map(|a| match a { 52 .map(|a| match a {
54 Assist::Unresolved(labels) => labels, 53 Assist::Unresolved { label } => label,
55 Assist::Resolved(..) => unreachable!(), 54 Assist::Resolved { .. } => unreachable!(),
56 }) 55 })
57 .concat() 56 .collect()
58 }) 57 })
59} 58}
60 59
@@ -73,10 +72,10 @@ where
73 .iter() 72 .iter()
74 .filter_map(|f| f(ctx.clone())) 73 .filter_map(|f| f(ctx.clone()))
75 .map(|a| match a { 74 .map(|a| match a {
76 Assist::Resolved(labels_actions) => labels_actions, 75 Assist::Resolved { label, action } => (label, action),
77 Assist::Unresolved(..) => unreachable!(), 76 Assist::Unresolved { .. } => unreachable!(),
78 }) 77 })
79 .concat(); 78 .collect::<Vec<_>>();
80 a.sort_by(|a, b| match (a.1.target, b.1.target) { 79 a.sort_by(|a, b| match (a.1.target, b.1.target) {
81 (Some(a), Some(b)) => a.len().cmp(&b.len()), 80 (Some(a), Some(b)) => a.len().cmp(&b.len()),
82 (Some(_), None) => Ordering::Less, 81 (Some(_), None) => Ordering::Less,
@@ -159,51 +158,17 @@ mod helpers {
159 before: &str, 158 before: &str,
160 after: &str, 159 after: &str,
161 ) { 160 ) {
162 check_assist_nth_action(assist, before, after, 0)
163 }
164
165 pub(crate) fn check_assist_range(
166 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
167 before: &str,
168 after: &str,
169 ) {
170 check_assist_range_nth_action(assist, before, after, 0)
171 }
172
173 pub(crate) fn check_assist_target(
174 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
175 before: &str,
176 target: &str,
177 ) {
178 check_assist_target_nth_action(assist, before, target, 0)
179 }
180
181 pub(crate) fn check_assist_range_target(
182 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
183 before: &str,
184 target: &str,
185 ) {
186 check_assist_range_target_nth_action(assist, before, target, 0)
187 }
188
189 pub(crate) fn check_assist_nth_action(
190 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
191 before: &str,
192 after: &str,
193 index: usize,
194 ) {
195 let (before_cursor_pos, before) = extract_offset(before); 161 let (before_cursor_pos, before) = extract_offset(before);
196 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 162 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
197 let frange = 163 let frange =
198 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 164 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
199 let assist = 165 let assist =
200 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 166 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
201 let labels_actions = match assist { 167 let action = match assist {
202 Assist::Unresolved(_) => unreachable!(), 168 Assist::Unresolved { .. } => unreachable!(),
203 Assist::Resolved(labels_actions) => labels_actions, 169 Assist::Resolved { action, .. } => action,
204 }; 170 };
205 171
206 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
207 let actual = action.edit.apply(&before); 172 let actual = action.edit.apply(&before);
208 let actual_cursor_pos = match action.cursor_position { 173 let actual_cursor_pos = match action.cursor_position {
209 None => action 174 None => action
@@ -216,23 +181,21 @@ mod helpers {
216 assert_eq_text!(after, &actual); 181 assert_eq_text!(after, &actual);
217 } 182 }
218 183
219 pub(crate) fn check_assist_range_nth_action( 184 pub(crate) fn check_assist_range(
220 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 185 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
221 before: &str, 186 before: &str,
222 after: &str, 187 after: &str,
223 index: usize,
224 ) { 188 ) {
225 let (range, before) = extract_range(before); 189 let (range, before) = extract_range(before);
226 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 190 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
227 let frange = FileRange { file_id, range }; 191 let frange = FileRange { file_id, range };
228 let assist = 192 let assist =
229 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 193 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
230 let labels_actions = match assist { 194 let action = match assist {
231 Assist::Unresolved(_) => unreachable!(), 195 Assist::Unresolved { .. } => unreachable!(),
232 Assist::Resolved(labels_actions) => labels_actions, 196 Assist::Resolved { action, .. } => action,
233 }; 197 };
234 198
235 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
236 let mut actual = action.edit.apply(&before); 199 let mut actual = action.edit.apply(&before);
237 if let Some(pos) = action.cursor_position { 200 if let Some(pos) = action.cursor_position {
238 actual = add_cursor(&actual, pos); 201 actual = add_cursor(&actual, pos);
@@ -240,11 +203,10 @@ mod helpers {
240 assert_eq_text!(after, &actual); 203 assert_eq_text!(after, &actual);
241 } 204 }
242 205
243 pub(crate) fn check_assist_target_nth_action( 206 pub(crate) fn check_assist_target(
244 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 207 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
245 before: &str, 208 before: &str,
246 target: &str, 209 target: &str,
247 index: usize,
248 ) { 210 ) {
249 let (before_cursor_pos, before) = extract_offset(before); 211 let (before_cursor_pos, before) = extract_offset(before);
250 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 212 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
@@ -252,33 +214,30 @@ mod helpers {
252 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 214 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
253 let assist = 215 let assist =
254 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 216 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
255 let labels_actions = match assist { 217 let action = match assist {
256 Assist::Unresolved(_) => unreachable!(), 218 Assist::Unresolved { .. } => unreachable!(),
257 Assist::Resolved(labels_actions) => labels_actions, 219 Assist::Resolved { action, .. } => action,
258 }; 220 };
259 221
260 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
261 let range = action.target.expect("expected target on action"); 222 let range = action.target.expect("expected target on action");
262 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 223 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
263 } 224 }
264 225
265 pub(crate) fn check_assist_range_target_nth_action( 226 pub(crate) fn check_assist_range_target(
266 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 227 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
267 before: &str, 228 before: &str,
268 target: &str, 229 target: &str,
269 index: usize,
270 ) { 230 ) {
271 let (range, before) = extract_range(before); 231 let (range, before) = extract_range(before);
272 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 232 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
273 let frange = FileRange { file_id, range }; 233 let frange = FileRange { file_id, range };
274 let assist = 234 let assist =
275 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 235 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
276 let labels_actions = match assist { 236 let action = match assist {
277 Assist::Unresolved(_) => unreachable!(), 237 Assist::Unresolved { .. } => unreachable!(),
278 Assist::Resolved(labels_actions) => labels_actions, 238 Assist::Resolved { action, .. } => action,
279 }; 239 };
280 240
281 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
282 let range = action.target.expect("expected target on action"); 241 let range = action.target.expect("expected target on action");
283 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 242 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
284 } 243 }