aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs25
-rw-r--r--crates/ra_assists/src/doc_tests.rs8
-rw-r--r--crates/ra_assists/src/lib.rs40
3 files changed, 45 insertions, 28 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 879216a36..e13f969c7 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,5 +1,6 @@
1//! This module defines `AssistCtx` -- the API surface that is exposed to assists. 1//! This module defines `AssistCtx` -- the API surface that is exposed to assists.
2use hir::{db::HirDatabase, InFile, SourceAnalyzer}; 2use hir::{db::HirDatabase, InFile, SourceAnalyzer};
3use itertools::Either;
3use ra_db::FileRange; 4use ra_db::FileRange;
4use ra_fmt::{leading_indent, reindent}; 5use ra_fmt::{leading_indent, reindent};
5use ra_syntax::{ 6use ra_syntax::{
@@ -9,12 +10,12 @@ use ra_syntax::{
9}; 10};
10use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
11 12
12use crate::{AssistAction, AssistId, AssistLabel}; 13use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist};
13 14
14#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
15pub(crate) enum Assist { 16pub(crate) enum Assist {
16 Unresolved { label: AssistLabel }, 17 Unresolved { label: AssistLabel },
17 Resolved { label: AssistLabel, action: AssistAction, alternative_actions: Vec<AssistAction> }, 18 Resolved { assist: ResolvedAssist },
18} 19}
19 20
20/// `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.
@@ -92,7 +93,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
92 f(&mut edit); 93 f(&mut edit);
93 edit.build() 94 edit.build()
94 }; 95 };
95 Assist::Resolved { label, action, alternative_actions: Vec::default() } 96 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } }
96 } else { 97 } else {
97 Assist::Unresolved { label } 98 Assist::Unresolved { label }
98 }; 99 };
@@ -105,18 +106,20 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
105 self, 106 self,
106 id: AssistId, 107 id: AssistId,
107 label: impl Into<String>, 108 label: impl Into<String>,
108 f: impl FnOnce() -> (ActionBuilder, Vec<ActionBuilder>), 109 f: impl FnOnce() -> Vec<ActionBuilder>,
109 ) -> Option<Assist> { 110 ) -> Option<Assist> {
110 let label = AssistLabel { label: label.into(), id }; 111 let label = AssistLabel { label: label.into(), id };
111 let assist = if self.should_compute_edit { 112 let assist = if self.should_compute_edit {
112 let (action, alternative_actions) = f(); 113 let actions = f();
114 assert!(!actions.is_empty(), "Assist cannot have no");
115
113 Assist::Resolved { 116 Assist::Resolved {
114 label, 117 assist: ResolvedAssist {
115 action: action.build(), 118 label,
116 alternative_actions: alternative_actions 119 action_data: Either::Right(
117 .into_iter() 120 actions.into_iter().map(ActionBuilder::build).collect(),
118 .map(ActionBuilder::build) 121 ),
119 .collect(), 122 },
120 } 123 }
121 } else { 124 } else {
122 Assist::Unresolved { label } 125 Assist::Unresolved { label }
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index 21bee228d..5dc1ee233 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -15,21 +15,21 @@ fn check(assist_id: &str, before: &str, after: &str) {
15 let (db, file_id) = TestDB::with_single_file(&before); 15 let (db, file_id) = TestDB::with_single_file(&before);
16 let frange = FileRange { file_id, range: selection.into() }; 16 let frange = FileRange { file_id, range: selection.into() };
17 17
18 let (_assist_id, action, _) = crate::assists(&db, frange) 18 let assist = crate::assists(&db, frange)
19 .into_iter() 19 .into_iter()
20 .find(|(id, _, _)| id.id.0 == assist_id) 20 .find(|assist| assist.label.id.0 == assist_id)
21 .unwrap_or_else(|| { 21 .unwrap_or_else(|| {
22 panic!( 22 panic!(
23 "\n\nAssist is not applicable: {}\nAvailable assists: {}", 23 "\n\nAssist is not applicable: {}\nAvailable assists: {}",
24 assist_id, 24 assist_id,
25 crate::assists(&db, frange) 25 crate::assists(&db, frange)
26 .into_iter() 26 .into_iter()
27 .map(|(id, _, _)| id.id.0) 27 .map(|assist| assist.label.id.0)
28 .collect::<Vec<_>>() 28 .collect::<Vec<_>>()
29 .join(", ") 29 .join(", ")
30 ) 30 )
31 }); 31 });
32 32
33 let actual = action.edit.apply(&before); 33 let actual = assist.get_first_action().edit.apply(&before);
34 assert_eq_text!(after, &actual); 34 assert_eq_text!(after, &actual);
35} 35}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 95a530821..a2983ae87 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -14,6 +14,7 @@ mod test_db;
14pub mod ast_transform; 14pub mod ast_transform;
15 15
16use hir::db::HirDatabase; 16use hir::db::HirDatabase;
17use itertools::Either;
17use ra_db::FileRange; 18use ra_db::FileRange;
18use ra_syntax::{TextRange, TextUnit}; 19use ra_syntax::{TextRange, TextUnit};
19use ra_text_edit::TextEdit; 20use ra_text_edit::TextEdit;
@@ -41,6 +42,21 @@ pub struct AssistAction {
41 pub target: Option<TextRange>, 42 pub target: Option<TextRange>,
42} 43}
43 44
45#[derive(Debug, Clone)]
46pub struct ResolvedAssist {
47 pub label: AssistLabel,
48 pub action_data: Either<AssistAction, Vec<AssistAction>>,
49}
50
51impl ResolvedAssist {
52 pub fn get_first_action(&self) -> AssistAction {
53 match &self.action_data {
54 Either::Left(action) => action.clone(),
55 Either::Right(actions) => actions[0].clone(),
56 }
57 }
58}
59
44/// Return all the assists applicable at the given position. 60/// Return all the assists applicable at the given position.
45/// 61///
46/// Assists are returned in the "unresolved" state, that is only labels are 62/// Assists are returned in the "unresolved" state, that is only labels are
@@ -65,7 +81,7 @@ where
65/// 81///
66/// Assists are returned in the "resolved" state, that is with edit fully 82/// Assists are returned in the "resolved" state, that is with edit fully
67/// computed. 83/// computed.
68pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction, Vec<AssistAction>)> 84pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist>
69where 85where
70 H: HirDatabase + 'static, 86 H: HirDatabase + 'static,
71{ 87{
@@ -76,13 +92,11 @@ where
76 .iter() 92 .iter()
77 .filter_map(|f| f(ctx.clone())) 93 .filter_map(|f| f(ctx.clone()))
78 .map(|a| match a { 94 .map(|a| match a {
79 Assist::Resolved { label, action, alternative_actions } => { 95 Assist::Resolved { assist } => assist,
80 (label, action, alternative_actions)
81 }
82 Assist::Unresolved { .. } => unreachable!(), 96 Assist::Unresolved { .. } => unreachable!(),
83 }) 97 })
84 .collect::<Vec<_>>(); 98 .collect::<Vec<_>>();
85 a.sort_by(|a, b| match (a.1.target, b.1.target) { 99 a.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) {
86 (Some(a), Some(b)) => a.len().cmp(&b.len()), 100 (Some(a), Some(b)) => a.len().cmp(&b.len()),
87 (Some(_), None) => Ordering::Less, 101 (Some(_), None) => Ordering::Less,
88 (None, Some(_)) => Ordering::Greater, 102 (None, Some(_)) => Ordering::Greater,
@@ -177,7 +191,7 @@ mod helpers {
177 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 191 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
178 let action = match assist { 192 let action = match assist {
179 Assist::Unresolved { .. } => unreachable!(), 193 Assist::Unresolved { .. } => unreachable!(),
180 Assist::Resolved { action, .. } => action, 194 Assist::Resolved { assist } => assist.get_first_action(),
181 }; 195 };
182 196
183 let actual = action.edit.apply(&before); 197 let actual = action.edit.apply(&before);
@@ -204,7 +218,7 @@ mod helpers {
204 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 218 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
205 let action = match assist { 219 let action = match assist {
206 Assist::Unresolved { .. } => unreachable!(), 220 Assist::Unresolved { .. } => unreachable!(),
207 Assist::Resolved { action, .. } => action, 221 Assist::Resolved { assist } => assist.get_first_action(),
208 }; 222 };
209 223
210 let mut actual = action.edit.apply(&before); 224 let mut actual = action.edit.apply(&before);
@@ -227,7 +241,7 @@ mod helpers {
227 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 241 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
228 let action = match assist { 242 let action = match assist {
229 Assist::Unresolved { .. } => unreachable!(), 243 Assist::Unresolved { .. } => unreachable!(),
230 Assist::Resolved { action, .. } => action, 244 Assist::Resolved { assist } => assist.get_first_action(),
231 }; 245 };
232 246
233 let range = action.target.expect("expected target on action"); 247 let range = action.target.expect("expected target on action");
@@ -246,7 +260,7 @@ mod helpers {
246 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 260 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
247 let action = match assist { 261 let action = match assist {
248 Assist::Unresolved { .. } => unreachable!(), 262 Assist::Unresolved { .. } => unreachable!(),
249 Assist::Resolved { action, .. } => action, 263 Assist::Resolved { assist } => assist.get_first_action(),
250 }; 264 };
251 265
252 let range = action.target.expect("expected target on action"); 266 let range = action.target.expect("expected target on action");
@@ -296,10 +310,10 @@ mod tests {
296 let mut assists = assists.iter(); 310 let mut assists = assists.iter();
297 311
298 assert_eq!( 312 assert_eq!(
299 assists.next().expect("expected assist").0.label, 313 assists.next().expect("expected assist").label.label,
300 "Change visibility to pub(crate)" 314 "Change visibility to pub(crate)"
301 ); 315 );
302 assert_eq!(assists.next().expect("expected assist").0.label, "Add `#[derive]`"); 316 assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`");
303 } 317 }
304 318
305 #[test] 319 #[test]
@@ -318,7 +332,7 @@ mod tests {
318 let assists = super::assists(&db, frange); 332 let assists = super::assists(&db, frange);
319 let mut assists = assists.iter(); 333 let mut assists = assists.iter();
320 334
321 assert_eq!(assists.next().expect("expected assist").0.label, "Extract into variable"); 335 assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable");
322 assert_eq!(assists.next().expect("expected assist").0.label, "Replace with match"); 336 assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match");
323 } 337 }
324} 338}