aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/lib.rs
diff options
context:
space:
mode:
authorAndrea Pretto <[email protected]>2019-02-11 17:07:21 +0000
committerAndrea Pretto <[email protected]>2019-02-11 17:07:21 +0000
commit5c9c0d3ae2735b4b32a44742bac800ca616fdde8 (patch)
tree8ad5dc9a548915729bcc87085a1a145d4ba2a00a /crates/ra_assists/src/lib.rs
parentaf62fde57fe58f4aa06608568dc26535731800a0 (diff)
ra_assists: assist "providers" can produce multiple assists
Diffstat (limited to 'crates/ra_assists/src/lib.rs')
-rw-r--r--crates/ra_assists/src/lib.rs75
1 files changed, 59 insertions, 16 deletions
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index af578893e..c607a5142 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -7,6 +7,8 @@
7 7
8mod assist_ctx; 8mod assist_ctx;
9 9
10use itertools::Itertools;
11
10use ra_text_edit::TextEdit; 12use ra_text_edit::TextEdit;
11use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction}; 13use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction};
12use ra_db::FileRange; 14use ra_db::FileRange;
@@ -14,12 +16,13 @@ use hir::db::HirDatabase;
14 16
15pub(crate) use crate::assist_ctx::{AssistCtx, Assist}; 17pub(crate) use crate::assist_ctx::{AssistCtx, Assist};
16 18
17#[derive(Debug)] 19#[derive(Debug, Clone)]
18pub struct AssistLabel { 20pub struct AssistLabel {
19 /// Short description of the assist, as shown in the UI. 21 /// Short description of the assist, as shown in the UI.
20 pub label: String, 22 pub label: String,
21} 23}
22 24
25#[derive(Debug, Clone)]
23pub struct AssistAction { 26pub struct AssistAction {
24 pub edit: TextEdit, 27 pub edit: TextEdit,
25 pub cursor_position: Option<TextUnit>, 28 pub cursor_position: Option<TextUnit>,
@@ -39,10 +42,10 @@ where
39 .iter() 42 .iter()
40 .filter_map(|f| f(ctx.clone())) 43 .filter_map(|f| f(ctx.clone()))
41 .map(|a| match a { 44 .map(|a| match a {
42 Assist::Unresolved(label) => label, 45 Assist::Unresolved(labels) => labels,
43 Assist::Resolved(..) => unreachable!(), 46 Assist::Resolved(..) => unreachable!(),
44 }) 47 })
45 .collect() 48 .concat()
46 }) 49 })
47} 50}
48 51
@@ -61,10 +64,10 @@ where
61 .iter() 64 .iter()
62 .filter_map(|f| f(ctx.clone())) 65 .filter_map(|f| f(ctx.clone()))
63 .map(|a| match a { 66 .map(|a| match a {
64 Assist::Resolved(label, action) => (label, action), 67 Assist::Resolved(labels_actions) => labels_actions,
65 Assist::Unresolved(..) => unreachable!(), 68 Assist::Unresolved(..) => unreachable!(),
66 }) 69 })
67 .collect::<Vec<(AssistLabel, AssistAction)>>(); 70 .concat();
68 a.sort_by(|a, b| match (a.1.target, b.1.target) { 71 a.sort_by(|a, b| match (a.1.target, b.1.target) {
69 (Some(a), Some(b)) => a.len().cmp(&b.len()), 72 (Some(a), Some(b)) => a.len().cmp(&b.len()),
70 (Some(_), None) => Ordering::Less, 73 (Some(_), None) => Ordering::Less,
@@ -119,17 +122,51 @@ mod helpers {
119 before: &str, 122 before: &str,
120 after: &str, 123 after: &str,
121 ) { 124 ) {
125 check_assist_nth_action(assist, before, after, 0)
126 }
127
128 pub(crate) fn check_assist_range(
129 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
130 before: &str,
131 after: &str,
132 ) {
133 check_assist_range_nth_action(assist, before, after, 0)
134 }
135
136 pub(crate) fn check_assist_target(
137 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
138 before: &str,
139 target: &str,
140 ) {
141 check_assist_target_nth_action(assist, before, target, 0)
142 }
143
144 pub(crate) fn check_assist_range_target(
145 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
146 before: &str,
147 target: &str,
148 ) {
149 check_assist_range_target_nth_action(assist, before, target, 0)
150 }
151
152 pub(crate) fn check_assist_nth_action(
153 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
154 before: &str,
155 after: &str,
156 index: usize,
157 ) {
122 let (before_cursor_pos, before) = extract_offset(before); 158 let (before_cursor_pos, before) = extract_offset(before);
123 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 159 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
124 let frange = 160 let frange =
125 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 161 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
126 let assist = 162 let assist =
127 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 163 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
128 let action = match assist { 164 let labels_actions = match assist {
129 Assist::Unresolved(_) => unreachable!(), 165 Assist::Unresolved(_) => unreachable!(),
130 Assist::Resolved(_, it) => it, 166 Assist::Resolved(labels_actions) => labels_actions,
131 }; 167 };
132 168
169 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
133 let actual = action.edit.apply(&before); 170 let actual = action.edit.apply(&before);
134 let actual_cursor_pos = match action.cursor_position { 171 let actual_cursor_pos = match action.cursor_position {
135 None => action 172 None => action
@@ -142,21 +179,23 @@ mod helpers {
142 assert_eq_text!(after, &actual); 179 assert_eq_text!(after, &actual);
143 } 180 }
144 181
145 pub(crate) fn check_assist_range( 182 pub(crate) fn check_assist_range_nth_action(
146 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 183 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
147 before: &str, 184 before: &str,
148 after: &str, 185 after: &str,
186 index: usize,
149 ) { 187 ) {
150 let (range, before) = extract_range(before); 188 let (range, before) = extract_range(before);
151 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 189 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
152 let frange = FileRange { file_id, range }; 190 let frange = FileRange { file_id, range };
153 let assist = 191 let assist =
154 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 192 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
155 let action = match assist { 193 let labels_actions = match assist {
156 Assist::Unresolved(_) => unreachable!(), 194 Assist::Unresolved(_) => unreachable!(),
157 Assist::Resolved(_, it) => it, 195 Assist::Resolved(labels_actions) => labels_actions,
158 }; 196 };
159 197
198 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
160 let mut actual = action.edit.apply(&before); 199 let mut actual = action.edit.apply(&before);
161 if let Some(pos) = action.cursor_position { 200 if let Some(pos) = action.cursor_position {
162 actual = add_cursor(&actual, pos); 201 actual = add_cursor(&actual, pos);
@@ -164,10 +203,11 @@ mod helpers {
164 assert_eq_text!(after, &actual); 203 assert_eq_text!(after, &actual);
165 } 204 }
166 205
167 pub(crate) fn check_assist_target( 206 pub(crate) fn check_assist_target_nth_action(
168 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 207 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
169 before: &str, 208 before: &str,
170 target: &str, 209 target: &str,
210 index: usize,
171 ) { 211 ) {
172 let (before_cursor_pos, before) = extract_offset(before); 212 let (before_cursor_pos, before) = extract_offset(before);
173 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 213 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
@@ -175,30 +215,33 @@ mod helpers {
175 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 215 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
176 let assist = 216 let assist =
177 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 217 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
178 let action = match assist { 218 let labels_actions = match assist {
179 Assist::Unresolved(_) => unreachable!(), 219 Assist::Unresolved(_) => unreachable!(),
180 Assist::Resolved(_, it) => it, 220 Assist::Resolved(labels_actions) => labels_actions,
181 }; 221 };
182 222
223 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
183 let range = action.target.expect("expected target on action"); 224 let range = action.target.expect("expected target on action");
184 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 225 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
185 } 226 }
186 227
187 pub(crate) fn check_assist_range_target( 228 pub(crate) fn check_assist_range_target_nth_action(
188 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 229 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
189 before: &str, 230 before: &str,
190 target: &str, 231 target: &str,
232 index: usize,
191 ) { 233 ) {
192 let (range, before) = extract_range(before); 234 let (range, before) = extract_range(before);
193 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 235 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
194 let frange = FileRange { file_id, range }; 236 let frange = FileRange { file_id, range };
195 let assist = 237 let assist =
196 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 238 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
197 let action = match assist { 239 let labels_actions = match assist {
198 Assist::Unresolved(_) => unreachable!(), 240 Assist::Unresolved(_) => unreachable!(),
199 Assist::Resolved(_, it) => it, 241 Assist::Resolved(labels_actions) => labels_actions,
200 }; 242 };
201 243
244 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
202 let range = action.target.expect("expected target on action"); 245 let range = action.target.expect("expected target on action");
203 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 246 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
204 } 247 }