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.rs92
1 files changed, 63 insertions, 29 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 81f999090..5924a3fd5 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -98,30 +98,8 @@ impl<'a> AssistCtx<'a> {
98 Some(assist) 98 Some(assist)
99 } 99 }
100 100
101 pub(crate) fn add_assist_group( 101 pub(crate) fn add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> {
102 self, 102 AssistGroup { ctx: self, group_name: group_name.into(), assists: Vec::new() }
103 id: AssistId,
104 label: impl Into<String>,
105 f: impl FnOnce() -> Vec<ActionBuilder>,
106 ) -> Option<Assist> {
107 let label = AssistLabel::new(label.into(), id);
108 let assist = if self.should_compute_edit {
109 let actions = f();
110 assert!(!actions.is_empty(), "Assist cannot have no");
111
112 Assist::Resolved {
113 assist: ResolvedAssist {
114 label,
115 action_data: Either::Right(
116 actions.into_iter().map(ActionBuilder::build).collect(),
117 ),
118 },
119 }
120 } else {
121 Assist::Unresolved { label }
122 };
123
124 Some(assist)
125 } 103 }
126 104
127 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { 105 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
@@ -155,6 +133,67 @@ impl<'a> AssistCtx<'a> {
155 } 133 }
156} 134}
157 135
136pub(crate) struct AssistGroup<'a> {
137 ctx: AssistCtx<'a>,
138 group_name: String,
139 assists: Vec<Assist>,
140}
141
142impl<'a> AssistGroup<'a> {
143 pub(crate) fn add_assist(
144 &mut self,
145 id: AssistId,
146 label: impl Into<String>,
147 f: impl FnOnce(&mut ActionBuilder),
148 ) {
149 let label = AssistLabel::new(label.into(), id);
150
151 let assist = if self.ctx.should_compute_edit {
152 let action = {
153 let mut edit = ActionBuilder::default();
154 f(&mut edit);
155 edit.build()
156 };
157 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } }
158 } else {
159 Assist::Unresolved { label }
160 };
161
162 self.assists.push(assist)
163 }
164
165 pub(crate) fn finish(self) -> Option<Assist> {
166 assert!(!self.assists.is_empty());
167 let mut label = match &self.assists[0] {
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 }
195}
196
158#[derive(Default)] 197#[derive(Default)]
159pub(crate) struct ActionBuilder { 198pub(crate) struct ActionBuilder {
160 edit: TextEditBuilder, 199 edit: TextEditBuilder,
@@ -164,11 +203,6 @@ pub(crate) struct ActionBuilder {
164} 203}
165 204
166impl ActionBuilder { 205impl ActionBuilder {
167 /// Adds a custom label to the action, if it needs to be different from the assist label
168 pub(crate) fn label(&mut self, label: impl Into<String>) {
169 self.label = Some(label.into())
170 }
171
172 /// Replaces specified `range` of text with a given string. 206 /// Replaces specified `range` of text with a given string.
173 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 207 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
174 self.edit.replace(range, replace_with.into()) 208 self.edit.replace(range, replace_with.into())