aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assist_ctx.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assist_ctx.rs')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs83
1 files changed, 38 insertions, 45 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 5924a3fd5..5aab5fb8b 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,5 +1,4 @@
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 either::Either;
3use hir::{InFile, SourceAnalyzer, SourceBinder}; 2use hir::{InFile, SourceAnalyzer, SourceBinder};
4use ra_db::{FileRange, SourceDatabase}; 3use ra_db::{FileRange, SourceDatabase};
5use ra_fmt::{leading_indent, reindent}; 4use ra_fmt::{leading_indent, reindent};
@@ -11,12 +10,36 @@ use ra_syntax::{
11}; 10};
12use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
13 12
14use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist}; 13use crate::{AssistAction, AssistId, AssistLabel, GroupLabel, ResolvedAssist};
15 14
16#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
17pub(crate) enum Assist { 16pub(crate) struct Assist(pub(crate) Vec<AssistInfo>);
18 Unresolved { label: AssistLabel }, 17
19 Resolved { assist: ResolvedAssist }, 18#[derive(Clone, Debug)]
19pub(crate) struct AssistInfo {
20 pub(crate) label: AssistLabel,
21 pub(crate) group_label: Option<GroupLabel>,
22 pub(crate) action: Option<AssistAction>,
23}
24
25impl AssistInfo {
26 fn new(label: AssistLabel) -> AssistInfo {
27 AssistInfo { label, group_label: None, action: None }
28 }
29
30 fn resolved(self, action: AssistAction) -> AssistInfo {
31 AssistInfo { action: Some(action), ..self }
32 }
33
34 fn with_group(self, group_label: GroupLabel) -> AssistInfo {
35 AssistInfo { group_label: Some(group_label), ..self }
36 }
37
38 pub(crate) fn into_resolved(self) -> Option<ResolvedAssist> {
39 let label = self.label;
40 let group_label = self.group_label;
41 self.action.map(|action| ResolvedAssist { label, group_label, action })
42 }
20} 43}
21 44
22pub(crate) type AssistHandler = fn(AssistCtx) -> Option<Assist>; 45pub(crate) type AssistHandler = fn(AssistCtx) -> Option<Assist>;
@@ -84,18 +107,17 @@ impl<'a> AssistCtx<'a> {
84 ) -> Option<Assist> { 107 ) -> Option<Assist> {
85 let label = AssistLabel::new(label.into(), id); 108 let label = AssistLabel::new(label.into(), id);
86 109
87 let assist = if self.should_compute_edit { 110 let mut info = AssistInfo::new(label);
111 if self.should_compute_edit {
88 let action = { 112 let action = {
89 let mut edit = ActionBuilder::default(); 113 let mut edit = ActionBuilder::default();
90 f(&mut edit); 114 f(&mut edit);
91 edit.build() 115 edit.build()
92 }; 116 };
93 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } } 117 info = info.resolved(action)
94 } else {
95 Assist::Unresolved { label }
96 }; 118 };
97 119
98 Some(assist) 120 Some(Assist(vec![info]))
99 } 121 }
100 122
101 pub(crate) fn add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> { 123 pub(crate) fn add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> {
@@ -136,7 +158,7 @@ impl<'a> AssistCtx<'a> {
136pub(crate) struct AssistGroup<'a> { 158pub(crate) struct AssistGroup<'a> {
137 ctx: AssistCtx<'a>, 159 ctx: AssistCtx<'a>,
138 group_name: String, 160 group_name: String,
139 assists: Vec<Assist>, 161 assists: Vec<AssistInfo>,
140} 162}
141 163
142impl<'a> AssistGroup<'a> { 164impl<'a> AssistGroup<'a> {
@@ -148,49 +170,22 @@ impl<'a> AssistGroup<'a> {
148 ) { 170 ) {
149 let label = AssistLabel::new(label.into(), id); 171 let label = AssistLabel::new(label.into(), id);
150 172
151 let assist = if self.ctx.should_compute_edit { 173 let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone()));
174 if self.ctx.should_compute_edit {
152 let action = { 175 let action = {
153 let mut edit = ActionBuilder::default(); 176 let mut edit = ActionBuilder::default();
154 f(&mut edit); 177 f(&mut edit);
155 edit.build() 178 edit.build()
156 }; 179 };
157 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } } 180 info = info.resolved(action)
158 } else {
159 Assist::Unresolved { label }
160 }; 181 };
161 182
162 self.assists.push(assist) 183 self.assists.push(info)
163 } 184 }
164 185
165 pub(crate) fn finish(self) -> Option<Assist> { 186 pub(crate) fn finish(self) -> Option<Assist> {
166 assert!(!self.assists.is_empty()); 187 assert!(!self.assists.is_empty());
167 let mut label = match &self.assists[0] { 188 Some(Assist(self.assists))
168 Assist::Unresolved { label } => label.clone(),
169 Assist::Resolved { assist } => assist.label.clone(),
170 };
171 label.label = self.group_name;
172 let assist = if self.ctx.should_compute_edit {
173 Assist::Resolved {
174 assist: ResolvedAssist {
175 label,
176 action_data: Either::Right(
177 self.assists
178 .into_iter()
179 .map(|assist| match assist {
180 Assist::Resolved {
181 assist:
182 ResolvedAssist { label: _, action_data: Either::Left(it) },
183 } => it,
184 _ => unreachable!(),
185 })
186 .collect(),
187 ),
188 },
189 }
190 } else {
191 Assist::Unresolved { label }
192 };
193 Some(assist)
194 } 189 }
195} 190}
196 191
@@ -199,7 +194,6 @@ pub(crate) struct ActionBuilder {
199 edit: TextEditBuilder, 194 edit: TextEditBuilder,
200 cursor_position: Option<TextUnit>, 195 cursor_position: Option<TextUnit>,
201 target: Option<TextRange>, 196 target: Option<TextRange>,
202 label: Option<String>,
203} 197}
204 198
205impl ActionBuilder { 199impl ActionBuilder {
@@ -261,7 +255,6 @@ impl ActionBuilder {
261 edit: self.edit.finish(), 255 edit: self.edit.finish(),
262 cursor_position: self.cursor_position, 256 cursor_position: self.cursor_position,
263 target: self.target, 257 target: self.target,
264 label: self.label,
265 } 258 }
266 } 259 }
267} 260}