diff options
author | Aleksey Kladov <[email protected]> | 2020-05-06 17:45:35 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-05-07 15:27:54 +0100 |
commit | 4867968d22899395e6551f22641b3617e995140c (patch) | |
tree | 4f3ab3a70fbbb901ccec3cd162da00eaa9cbad09 /crates | |
parent | f4cd75ac06dff7f5a95065a6c3868669e5c2ab27 (diff) |
Refactor assists API to be more convenient for adding new assists
It now duplicates completion API in its shape.
Diffstat (limited to 'crates')
38 files changed, 521 insertions, 593 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_context.rs index 871671de2..203ad1273 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -1,4 +1,6 @@ | |||
1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. | 1 | //! See `AssistContext` |
2 | |||
3 | use algo::find_covering_element; | ||
2 | use hir::Semantics; | 4 | use hir::Semantics; |
3 | use ra_db::{FileId, FileRange}; | 5 | use ra_db::{FileId, FileRange}; |
4 | use ra_fmt::{leading_indent, reindent}; | 6 | use ra_fmt::{leading_indent, reindent}; |
@@ -7,7 +9,7 @@ use ra_ide_db::{ | |||
7 | RootDatabase, | 9 | RootDatabase, |
8 | }; | 10 | }; |
9 | use ra_syntax::{ | 11 | use ra_syntax::{ |
10 | algo::{self, find_covering_element, find_node_at_offset, SyntaxRewriter}, | 12 | algo::{self, find_node_at_offset, SyntaxRewriter}, |
11 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, | 13 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, |
12 | TokenAtOffset, | 14 | TokenAtOffset, |
13 | }; | 15 | }; |
@@ -15,46 +17,17 @@ use ra_text_edit::TextEditBuilder; | |||
15 | 17 | ||
16 | use crate::{AssistId, AssistLabel, GroupLabel, ResolvedAssist}; | 18 | use crate::{AssistId, AssistLabel, GroupLabel, ResolvedAssist}; |
17 | 19 | ||
18 | #[derive(Clone, Debug)] | 20 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
19 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); | ||
20 | |||
21 | #[derive(Clone, Debug)] | ||
22 | pub(crate) struct AssistInfo { | ||
23 | pub(crate) label: AssistLabel, | ||
24 | pub(crate) group_label: Option<GroupLabel>, | ||
25 | pub(crate) source_change: Option<SourceChange>, | ||
26 | } | ||
27 | |||
28 | impl AssistInfo { | ||
29 | fn new(label: AssistLabel) -> AssistInfo { | ||
30 | AssistInfo { label, group_label: None, source_change: None } | ||
31 | } | ||
32 | |||
33 | fn resolved(self, source_change: SourceChange) -> AssistInfo { | ||
34 | AssistInfo { source_change: Some(source_change), ..self } | ||
35 | } | ||
36 | |||
37 | fn with_group(self, group_label: GroupLabel) -> AssistInfo { | ||
38 | AssistInfo { group_label: Some(group_label), ..self } | ||
39 | } | ||
40 | |||
41 | pub(crate) fn into_resolved(self) -> Option<ResolvedAssist> { | ||
42 | let label = self.label; | ||
43 | self.source_change.map(|source_change| ResolvedAssist { label, source_change }) | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /// `AssistCtx` allows to apply an assist or check if it could be applied. | ||
48 | /// | 21 | /// |
49 | /// Assists use a somewhat over-engineered approach, given the current needs. The | 22 | /// Assists use a somewhat over-engineered approach, given the current needs. |
50 | /// assists workflow consists of two phases. In the first phase, a user asks for | 23 | /// The assists workflow consists of two phases. In the first phase, a user asks |
51 | /// the list of available assists. In the second phase, the user picks a | 24 | /// for the list of available assists. In the second phase, the user picks a |
52 | /// particular assist and it gets applied. | 25 | /// particular assist and it gets applied. |
53 | /// | 26 | /// |
54 | /// There are two peculiarities here: | 27 | /// There are two peculiarities here: |
55 | /// | 28 | /// |
56 | /// * first, we ideally avoid computing more things then necessary to answer | 29 | /// * first, we ideally avoid computing more things then necessary to answer "is |
57 | /// "is assist applicable" in the first phase. | 30 | /// assist applicable" in the first phase. |
58 | /// * second, when we are applying assist, we don't have a guarantee that there | 31 | /// * second, when we are applying assist, we don't have a guarantee that there |
59 | /// weren't any changes between the point when user asked for assists and when | 32 | /// weren't any changes between the point when user asked for assists and when |
60 | /// they applied a particular assist. So, when applying assist, we need to do | 33 | /// they applied a particular assist. So, when applying assist, we need to do |
@@ -63,152 +36,158 @@ impl AssistInfo { | |||
63 | /// To avoid repeating the same code twice for both "check" and "apply" | 36 | /// To avoid repeating the same code twice for both "check" and "apply" |
64 | /// functions, we use an approach reminiscent of that of Django's function based | 37 | /// functions, we use an approach reminiscent of that of Django's function based |
65 | /// views dealing with forms. Each assist receives a runtime parameter, | 38 | /// views dealing with forms. Each assist receives a runtime parameter, |
66 | /// `should_compute_edit`. It first check if an edit is applicable (potentially | 39 | /// `resolve`. It first check if an edit is applicable (potentially computing |
67 | /// computing info required to compute the actual edit). If it is applicable, | 40 | /// info required to compute the actual edit). If it is applicable, and |
68 | /// and `should_compute_edit` is `true`, it then computes the actual edit. | 41 | /// `resolve` is `true`, it then computes the actual edit. |
69 | /// | 42 | /// |
70 | /// So, to implement the original assists workflow, we can first apply each edit | 43 | /// So, to implement the original assists workflow, we can first apply each edit |
71 | /// with `should_compute_edit = false`, and then applying the selected edit | 44 | /// with `resolve = false`, and then applying the selected edit again, with |
72 | /// again, with `should_compute_edit = true` this time. | 45 | /// `resolve = true` this time. |
73 | /// | 46 | /// |
74 | /// Note, however, that we don't actually use such two-phase logic at the | 47 | /// Note, however, that we don't actually use such two-phase logic at the |
75 | /// moment, because the LSP API is pretty awkward in this place, and it's much | 48 | /// moment, because the LSP API is pretty awkward in this place, and it's much |
76 | /// easier to just compute the edit eagerly :-) | 49 | /// easier to just compute the edit eagerly :-) |
77 | #[derive(Clone)] | 50 | pub(crate) struct AssistContext<'a> { |
78 | pub(crate) struct AssistCtx<'a> { | 51 | pub(crate) sema: Semantics<'a, RootDatabase>, |
79 | pub(crate) sema: &'a Semantics<'a, RootDatabase>, | 52 | pub(super) db: &'a RootDatabase, |
80 | pub(crate) db: &'a RootDatabase, | ||
81 | pub(crate) frange: FileRange, | 53 | pub(crate) frange: FileRange, |
82 | source_file: SourceFile, | 54 | source_file: SourceFile, |
83 | should_compute_edit: bool, | ||
84 | } | 55 | } |
85 | 56 | ||
86 | impl<'a> AssistCtx<'a> { | 57 | impl<'a> AssistContext<'a> { |
87 | pub fn new( | 58 | pub fn new(sema: Semantics<'a, RootDatabase>, frange: FileRange) -> AssistContext<'a> { |
88 | sema: &'a Semantics<'a, RootDatabase>, | ||
89 | frange: FileRange, | ||
90 | should_compute_edit: bool, | ||
91 | ) -> AssistCtx<'a> { | ||
92 | let source_file = sema.parse(frange.file_id); | 59 | let source_file = sema.parse(frange.file_id); |
93 | AssistCtx { sema, db: sema.db, frange, source_file, should_compute_edit } | 60 | let db = sema.db; |
61 | AssistContext { sema, db, frange, source_file } | ||
94 | } | 62 | } |
95 | 63 | ||
96 | pub(crate) fn add_assist( | 64 | // NB, this ignores active selection. |
97 | self, | 65 | pub(crate) fn offset(&self) -> TextSize { |
98 | id: AssistId, | 66 | self.frange.range.start() |
99 | label: impl Into<String>, | ||
100 | target: TextRange, | ||
101 | f: impl FnOnce(&mut ActionBuilder), | ||
102 | ) -> Option<Assist> { | ||
103 | let label = AssistLabel::new(id, label.into(), None, target); | ||
104 | let change_label = label.label.clone(); | ||
105 | let mut info = AssistInfo::new(label); | ||
106 | if self.should_compute_edit { | ||
107 | let source_change = { | ||
108 | let mut edit = ActionBuilder::new(&self); | ||
109 | f(&mut edit); | ||
110 | edit.build(change_label) | ||
111 | }; | ||
112 | info = info.resolved(source_change) | ||
113 | }; | ||
114 | |||
115 | Some(Assist(vec![info])) | ||
116 | } | ||
117 | |||
118 | pub(crate) fn add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> { | ||
119 | let group = GroupLabel(group_name.into()); | ||
120 | AssistGroup { ctx: self, group, assists: Vec::new() } | ||
121 | } | 67 | } |
122 | 68 | ||
123 | pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { | 69 | pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { |
124 | self.source_file.syntax().token_at_offset(self.frange.range.start()) | 70 | self.source_file.syntax().token_at_offset(self.offset()) |
125 | } | 71 | } |
126 | |||
127 | pub(crate) fn find_token_at_offset(&self, kind: SyntaxKind) -> Option<SyntaxToken> { | 72 | pub(crate) fn find_token_at_offset(&self, kind: SyntaxKind) -> Option<SyntaxToken> { |
128 | self.token_at_offset().find(|it| it.kind() == kind) | 73 | self.token_at_offset().find(|it| it.kind() == kind) |
129 | } | 74 | } |
130 | |||
131 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { | 75 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { |
132 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) | 76 | find_node_at_offset(self.source_file.syntax(), self.offset()) |
133 | } | 77 | } |
134 | |||
135 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { | 78 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { |
136 | self.sema | 79 | self.sema |
137 | .find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start()) | 80 | .find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start()) |
138 | } | 81 | } |
139 | |||
140 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 82 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
141 | find_covering_element(self.source_file.syntax(), self.frange.range) | 83 | find_covering_element(self.source_file.syntax(), self.frange.range) |
142 | } | 84 | } |
85 | // FIXME: remove | ||
143 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { | 86 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { |
144 | find_covering_element(self.source_file.syntax(), range) | 87 | find_covering_element(self.source_file.syntax(), range) |
145 | } | 88 | } |
146 | } | 89 | } |
147 | 90 | ||
148 | pub(crate) struct AssistGroup<'a> { | 91 | pub(crate) struct Assists { |
149 | ctx: AssistCtx<'a>, | 92 | resolve: bool, |
150 | group: GroupLabel, | 93 | file: FileId, |
151 | assists: Vec<AssistInfo>, | 94 | buf: Vec<(AssistLabel, Option<SourceChange>)>, |
152 | } | 95 | } |
153 | 96 | ||
154 | impl<'a> AssistGroup<'a> { | 97 | impl Assists { |
155 | pub(crate) fn add_assist( | 98 | pub(crate) fn new_resolved(ctx: &AssistContext) -> Assists { |
99 | Assists { resolve: true, file: ctx.frange.file_id, buf: Vec::new() } | ||
100 | } | ||
101 | pub(crate) fn new_unresolved(ctx: &AssistContext) -> Assists { | ||
102 | Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() } | ||
103 | } | ||
104 | |||
105 | pub(crate) fn finish_unresolved(self) -> Vec<AssistLabel> { | ||
106 | assert!(!self.resolve); | ||
107 | self.finish() | ||
108 | .into_iter() | ||
109 | .map(|(label, edit)| { | ||
110 | assert!(edit.is_none()); | ||
111 | label | ||
112 | }) | ||
113 | .collect() | ||
114 | } | ||
115 | |||
116 | pub(crate) fn finish_resolved(self) -> Vec<ResolvedAssist> { | ||
117 | assert!(self.resolve); | ||
118 | self.finish() | ||
119 | .into_iter() | ||
120 | .map(|(label, edit)| ResolvedAssist { label, source_change: edit.unwrap() }) | ||
121 | .collect() | ||
122 | } | ||
123 | |||
124 | pub(crate) fn add( | ||
156 | &mut self, | 125 | &mut self, |
157 | id: AssistId, | 126 | id: AssistId, |
158 | label: impl Into<String>, | 127 | label: impl Into<String>, |
159 | target: TextRange, | 128 | target: TextRange, |
160 | f: impl FnOnce(&mut ActionBuilder), | 129 | f: impl FnOnce(&mut AssistBuilder), |
161 | ) { | 130 | ) -> Option<()> { |
162 | let label = AssistLabel::new(id, label.into(), Some(self.group.clone()), target); | 131 | let label = AssistLabel::new(id, label.into(), None, target); |
132 | self.add_impl(label, f) | ||
133 | } | ||
134 | pub(crate) fn add_group( | ||
135 | &mut self, | ||
136 | group: &GroupLabel, | ||
137 | id: AssistId, | ||
138 | label: impl Into<String>, | ||
139 | target: TextRange, | ||
140 | f: impl FnOnce(&mut AssistBuilder), | ||
141 | ) -> Option<()> { | ||
142 | let label = AssistLabel::new(id, label.into(), Some(group.clone()), target); | ||
143 | self.add_impl(label, f) | ||
144 | } | ||
145 | fn add_impl(&mut self, label: AssistLabel, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | ||
163 | let change_label = label.label.clone(); | 146 | let change_label = label.label.clone(); |
164 | let mut info = AssistInfo::new(label).with_group(self.group.clone()); | 147 | let source_change = if self.resolve { |
165 | if self.ctx.should_compute_edit { | 148 | let mut builder = AssistBuilder::new(self.file); |
166 | let source_change = { | 149 | f(&mut builder); |
167 | let mut edit = ActionBuilder::new(&self.ctx); | 150 | Some(builder.finish(change_label)) |
168 | f(&mut edit); | 151 | } else { |
169 | edit.build(change_label) | 152 | None |
170 | }; | ||
171 | info = info.resolved(source_change) | ||
172 | }; | 153 | }; |
173 | 154 | ||
174 | self.assists.push(info) | 155 | self.buf.push((label, source_change)); |
156 | Some(()) | ||
175 | } | 157 | } |
176 | 158 | ||
177 | pub(crate) fn finish(self) -> Option<Assist> { | 159 | fn finish(mut self) -> Vec<(AssistLabel, Option<SourceChange>)> { |
178 | if self.assists.is_empty() { | 160 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); |
179 | None | 161 | self.buf |
180 | } else { | ||
181 | Some(Assist(self.assists)) | ||
182 | } | ||
183 | } | 162 | } |
184 | } | 163 | } |
185 | 164 | ||
186 | pub(crate) struct ActionBuilder<'a, 'b> { | 165 | pub(crate) struct AssistBuilder { |
187 | edit: TextEditBuilder, | 166 | edit: TextEditBuilder, |
188 | cursor_position: Option<TextSize>, | 167 | cursor_position: Option<TextSize>, |
189 | file: FileId, | 168 | file: FileId, |
190 | ctx: &'a AssistCtx<'b>, | ||
191 | } | 169 | } |
192 | 170 | ||
193 | impl<'a, 'b> ActionBuilder<'a, 'b> { | 171 | impl AssistBuilder { |
194 | fn new(ctx: &'a AssistCtx<'b>) -> Self { | 172 | pub(crate) fn new(file: FileId) -> AssistBuilder { |
195 | Self { | 173 | AssistBuilder { edit: TextEditBuilder::default(), cursor_position: None, file } |
196 | edit: TextEditBuilder::default(), | ||
197 | cursor_position: None, | ||
198 | file: ctx.frange.file_id, | ||
199 | ctx, | ||
200 | } | ||
201 | } | 174 | } |
202 | 175 | ||
203 | pub(crate) fn ctx(&self) -> &AssistCtx<'b> { | 176 | /// Remove specified `range` of text. |
204 | &self.ctx | 177 | pub(crate) fn delete(&mut self, range: TextRange) { |
178 | self.edit.delete(range) | ||
179 | } | ||
180 | /// Append specified `text` at the given `offset` | ||
181 | pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { | ||
182 | self.edit.insert(offset, text.into()) | ||
205 | } | 183 | } |
206 | |||
207 | /// Replaces specified `range` of text with a given string. | 184 | /// Replaces specified `range` of text with a given string. |
208 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { | 185 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { |
209 | self.edit.replace(range, replace_with.into()) | 186 | self.edit.replace(range, replace_with.into()) |
210 | } | 187 | } |
211 | 188 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | |
189 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | ||
190 | } | ||
212 | /// Replaces specified `node` of text with a given string, reindenting the | 191 | /// Replaces specified `node` of text with a given string, reindenting the |
213 | /// string to maintain `node`'s existing indent. | 192 | /// string to maintain `node`'s existing indent. |
214 | // FIXME: remove in favor of ra_syntax::edit::IndentLevel::increase_indent | 193 | // FIXME: remove in favor of ra_syntax::edit::IndentLevel::increase_indent |
@@ -223,42 +202,28 @@ impl<'a, 'b> ActionBuilder<'a, 'b> { | |||
223 | } | 202 | } |
224 | self.replace(node.text_range(), replace_with) | 203 | self.replace(node.text_range(), replace_with) |
225 | } | 204 | } |
226 | 205 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { | |
227 | /// Remove specified `range` of text. | 206 | let node = rewriter.rewrite_root().unwrap(); |
228 | #[allow(unused)] | 207 | let new = rewriter.rewrite(&node); |
229 | pub(crate) fn delete(&mut self, range: TextRange) { | 208 | algo::diff(&node, &new).into_text_edit(&mut self.edit) |
230 | self.edit.delete(range) | ||
231 | } | ||
232 | |||
233 | /// Append specified `text` at the given `offset` | ||
234 | pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { | ||
235 | self.edit.insert(offset, text.into()) | ||
236 | } | 209 | } |
237 | 210 | ||
238 | /// Specify desired position of the cursor after the assist is applied. | 211 | /// Specify desired position of the cursor after the assist is applied. |
239 | pub(crate) fn set_cursor(&mut self, offset: TextSize) { | 212 | pub(crate) fn set_cursor(&mut self, offset: TextSize) { |
240 | self.cursor_position = Some(offset) | 213 | self.cursor_position = Some(offset) |
241 | } | 214 | } |
215 | // FIXME: better API | ||
216 | pub(crate) fn set_file(&mut self, assist_file: FileId) { | ||
217 | self.file = assist_file; | ||
218 | } | ||
242 | 219 | ||
220 | // FIXME: kill this API | ||
243 | /// Get access to the raw `TextEditBuilder`. | 221 | /// Get access to the raw `TextEditBuilder`. |
244 | pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { | 222 | pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { |
245 | &mut self.edit | 223 | &mut self.edit |
246 | } | 224 | } |
247 | 225 | ||
248 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | 226 | fn finish(self, change_label: String) -> SourceChange { |
249 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | ||
250 | } | ||
251 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { | ||
252 | let node = rewriter.rewrite_root().unwrap(); | ||
253 | let new = rewriter.rewrite(&node); | ||
254 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | ||
255 | } | ||
256 | |||
257 | pub(crate) fn set_file(&mut self, assist_file: FileId) { | ||
258 | self.file = assist_file; | ||
259 | } | ||
260 | |||
261 | fn build(self, change_label: String) -> SourceChange { | ||
262 | let edit = self.edit.finish(); | 227 | let edit = self.edit.finish(); |
263 | if edit.is_empty() && self.cursor_position.is_none() { | 228 | if edit.is_empty() && self.cursor_position.is_none() { |
264 | panic!("Only call `add_assist` if the assist can be applied") | 229 | panic!("Only call `add_assist` if the assist can be applied") |
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index 869d4dc04..795a225a4 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -6,7 +6,10 @@ use ra_syntax::{ | |||
6 | }; | 6 | }; |
7 | use stdx::SepBy; | 7 | use stdx::SepBy; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | ||
11 | AssistId, | ||
12 | }; | ||
10 | 13 | ||
11 | // Assist: add_custom_impl | 14 | // Assist: add_custom_impl |
12 | // | 15 | // |
@@ -25,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
25 | // | 28 | // |
26 | // } | 29 | // } |
27 | // ``` | 30 | // ``` |
28 | pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { | 31 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
29 | let input = ctx.find_node_at_offset::<ast::AttrInput>()?; | 32 | let input = ctx.find_node_at_offset::<ast::AttrInput>()?; |
30 | let attr = input.syntax().parent().and_then(ast::Attr::cast)?; | 33 | let attr = input.syntax().parent().and_then(ast::Attr::cast)?; |
31 | 34 | ||
@@ -49,7 +52,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { | |||
49 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); | 52 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); |
50 | 53 | ||
51 | let target = attr.syntax().text_range(); | 54 | let target = attr.syntax().text_range(); |
52 | ctx.add_assist(AssistId("add_custom_impl"), label, target, |edit| { | 55 | acc.add(AssistId("add_custom_impl"), label, target, |edit| { |
53 | let new_attr_input = input | 56 | let new_attr_input = input |
54 | .syntax() | 57 | .syntax() |
55 | .descendants_with_tokens() | 58 | .descendants_with_tokens() |
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs index 2a6bb1cae..fb08c19e9 100644 --- a/crates/ra_assists/src/handlers/add_derive.rs +++ b/crates/ra_assists/src/handlers/add_derive.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | TextSize, | 4 | TextSize, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{AssistContext, AssistId, Assists}; |
8 | 8 | ||
9 | // Assist: add_derive | 9 | // Assist: add_derive |
10 | // | 10 | // |
@@ -24,11 +24,11 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
24 | // y: u32, | 24 | // y: u32, |
25 | // } | 25 | // } |
26 | // ``` | 26 | // ``` |
27 | pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { | 27 | pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
28 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 28 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
29 | let node_start = derive_insertion_offset(&nominal)?; | 29 | let node_start = derive_insertion_offset(&nominal)?; |
30 | let target = nominal.syntax().text_range(); | 30 | let target = nominal.syntax().text_range(); |
31 | ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { | 31 | acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { |
32 | let derive_attr = nominal | 32 | let derive_attr = nominal |
33 | .attrs() | 33 | .attrs() |
34 | .filter_map(|x| x.as_simple_call()) | 34 | .filter_map(|x| x.as_simple_call()) |
@@ -57,9 +57,10 @@ fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextSize> { | |||
57 | 57 | ||
58 | #[cfg(test)] | 58 | #[cfg(test)] |
59 | mod tests { | 59 | mod tests { |
60 | use super::*; | ||
61 | use crate::tests::{check_assist, check_assist_target}; | 60 | use crate::tests::{check_assist, check_assist_target}; |
62 | 61 | ||
62 | use super::*; | ||
63 | |||
63 | #[test] | 64 | #[test] |
64 | fn add_derive_new() { | 65 | fn add_derive_new() { |
65 | check_assist( | 66 | check_assist( |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index a59ec16b2..55409e501 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | TextRange, | 4 | TextRange, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{AssistContext, AssistId, Assists}; |
8 | 8 | ||
9 | // Assist: add_explicit_type | 9 | // Assist: add_explicit_type |
10 | // | 10 | // |
@@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
21 | // let x: i32 = 92; | 21 | // let x: i32 = 92; |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> { | 24 | pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; | 25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; |
26 | let expr = stmt.initializer()?; | 26 | let expr = stmt.initializer()?; |
27 | let pat = stmt.pat()?; | 27 | let pat = stmt.pat()?; |
@@ -59,7 +59,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> { | |||
59 | 59 | ||
60 | let db = ctx.db; | 60 | let db = ctx.db; |
61 | let new_type_string = ty.display_truncated(db, None).to_string(); | 61 | let new_type_string = ty.display_truncated(db, None).to_string(); |
62 | ctx.add_assist( | 62 | acc.add( |
63 | AssistId("add_explicit_type"), | 63 | AssistId("add_explicit_type"), |
64 | format!("Insert explicit type '{}'", new_type_string), | 64 | format!("Insert explicit type '{}'", new_type_string), |
65 | pat_range, | 65 | pat_range, |
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index 81deb3dfa..275184e24 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -4,10 +4,10 @@ use ra_syntax::{ | |||
4 | TextSize, | 4 | TextSize, |
5 | }; | 5 | }; |
6 | use stdx::format_to; | 6 | use stdx::format_to; |
7 | |||
8 | use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId}; | ||
9 | use test_utils::tested_by; | 7 | use test_utils::tested_by; |
10 | 8 | ||
9 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | ||
10 | |||
11 | // Assist add_from_impl_for_enum | 11 | // Assist add_from_impl_for_enum |
12 | // | 12 | // |
13 | // Adds a From impl for an enum variant with one tuple field | 13 | // Adds a From impl for an enum variant with one tuple field |
@@ -25,7 +25,7 @@ use test_utils::tested_by; | |||
25 | // } | 25 | // } |
26 | // } | 26 | // } |
27 | // ``` | 27 | // ``` |
28 | pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { | 28 | pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
29 | let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; | 29 | let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; |
30 | let variant_name = variant.name()?; | 30 | let variant_name = variant.name()?; |
31 | let enum_name = variant.parent_enum().name()?; | 31 | let enum_name = variant.parent_enum().name()?; |
@@ -42,13 +42,13 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { | |||
42 | _ => return None, | 42 | _ => return None, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | if existing_from_impl(ctx.sema, &variant).is_some() { | 45 | if existing_from_impl(&ctx.sema, &variant).is_some() { |
46 | tested_by!(test_add_from_impl_already_exists); | 46 | tested_by!(test_add_from_impl_already_exists); |
47 | return None; | 47 | return None; |
48 | } | 48 | } |
49 | 49 | ||
50 | let target = variant.syntax().text_range(); | 50 | let target = variant.syntax().text_range(); |
51 | ctx.add_assist( | 51 | acc.add( |
52 | AssistId("add_from_impl_for_enum"), | 52 | AssistId("add_from_impl_for_enum"), |
53 | "Add From impl for this enum variant", | 53 | "Add From impl for this enum variant", |
54 | target, | 54 | target, |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index 278079665..6b5616aa9 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | use hir::HirDisplay; | ||
2 | use ra_db::FileId; | ||
1 | use ra_syntax::{ | 3 | use ra_syntax::{ |
2 | ast::{self, AstNode}, | 4 | ast::{self, edit::IndentLevel, ArgListOwner, AstNode, ModuleItemOwner}, |
3 | SyntaxKind, SyntaxNode, TextSize, | 5 | SyntaxKind, SyntaxNode, TextSize, |
4 | }; | 6 | }; |
5 | |||
6 | use crate::{Assist, AssistCtx, AssistId}; | ||
7 | use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner}; | ||
8 | use hir::HirDisplay; | ||
9 | use ra_db::FileId; | ||
10 | use rustc_hash::{FxHashMap, FxHashSet}; | 7 | use rustc_hash::{FxHashMap, FxHashSet}; |
11 | 8 | ||
9 | use crate::{AssistContext, AssistId, Assists}; | ||
10 | |||
12 | // Assist: add_function | 11 | // Assist: add_function |
13 | // | 12 | // |
14 | // Adds a stub function with a signature matching the function under the cursor. | 13 | // Adds a stub function with a signature matching the function under the cursor. |
@@ -34,7 +33,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
34 | // } | 33 | // } |
35 | // | 34 | // |
36 | // ``` | 35 | // ``` |
37 | pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { | 36 | pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
38 | let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; | 37 | let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; |
39 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; | 38 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; |
40 | let path = path_expr.path()?; | 39 | let path = path_expr.path()?; |
@@ -59,7 +58,7 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { | |||
59 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 58 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; |
60 | 59 | ||
61 | let target = call.syntax().text_range(); | 60 | let target = call.syntax().text_range(); |
62 | ctx.add_assist(AssistId("add_function"), "Add function", target, |edit| { | 61 | acc.add(AssistId("add_function"), "Add function", target, |edit| { |
63 | let function_template = function_builder.render(); | 62 | let function_template = function_builder.render(); |
64 | edit.set_file(function_template.file); | 63 | edit.set_file(function_template.file); |
65 | edit.set_cursor(function_template.cursor_offset); | 64 | edit.set_cursor(function_template.cursor_offset); |
@@ -87,7 +86,7 @@ impl FunctionBuilder { | |||
87 | /// Prepares a generated function that matches `call` in `generate_in` | 86 | /// Prepares a generated function that matches `call` in `generate_in` |
88 | /// (or as close to `call` as possible, if `generate_in` is `None`) | 87 | /// (or as close to `call` as possible, if `generate_in` is `None`) |
89 | fn from_call( | 88 | fn from_call( |
90 | ctx: &AssistCtx, | 89 | ctx: &AssistContext, |
91 | call: &ast::CallExpr, | 90 | call: &ast::CallExpr, |
92 | path: &ast::Path, | 91 | path: &ast::Path, |
93 | target_module: Option<hir::InFile<hir::ModuleSource>>, | 92 | target_module: Option<hir::InFile<hir::ModuleSource>>, |
@@ -152,7 +151,7 @@ fn fn_name(call: &ast::Path) -> Option<ast::Name> { | |||
152 | 151 | ||
153 | /// Computes the type variables and arguments required for the generated function | 152 | /// Computes the type variables and arguments required for the generated function |
154 | fn fn_args( | 153 | fn fn_args( |
155 | ctx: &AssistCtx, | 154 | ctx: &AssistContext, |
156 | call: &ast::CallExpr, | 155 | call: &ast::CallExpr, |
157 | ) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> { | 156 | ) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> { |
158 | let mut arg_names = Vec::new(); | 157 | let mut arg_names = Vec::new(); |
@@ -219,7 +218,7 @@ fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> { | |||
219 | } | 218 | } |
220 | } | 219 | } |
221 | 220 | ||
222 | fn fn_arg_type(ctx: &AssistCtx, fn_arg: &ast::Expr) -> Option<String> { | 221 | fn fn_arg_type(ctx: &AssistContext, fn_arg: &ast::Expr) -> Option<String> { |
223 | let ty = ctx.sema.type_of_expr(fn_arg)?; | 222 | let ty = ctx.sema.type_of_expr(fn_arg)?; |
224 | if ty.is_unknown() { | 223 | if ty.is_unknown() { |
225 | return None; | 224 | return None; |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index 557344ebb..df114a0d8 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | }; | 4 | }; |
5 | use stdx::{format_to, SepBy}; | 5 | use stdx::{format_to, SepBy}; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{AssistContext, AssistId, Assists}; |
8 | 8 | ||
9 | // Assist: add_impl | 9 | // Assist: add_impl |
10 | // | 10 | // |
@@ -25,43 +25,36 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
25 | // | 25 | // |
26 | // } | 26 | // } |
27 | // ``` | 27 | // ``` |
28 | pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { | 28 | pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
30 | let name = nominal.name()?; | 30 | let name = nominal.name()?; |
31 | let target = nominal.syntax().text_range(); | 31 | let target = nominal.syntax().text_range(); |
32 | ctx.add_assist( | 32 | acc.add(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), target, |edit| { |
33 | AssistId("add_impl"), | 33 | let type_params = nominal.type_param_list(); |
34 | format!("Implement {}", name.text().as_str()), | 34 | let start_offset = nominal.syntax().text_range().end(); |
35 | target, | 35 | let mut buf = String::new(); |
36 | |edit| { | 36 | buf.push_str("\n\nimpl"); |
37 | let type_params = nominal.type_param_list(); | 37 | if let Some(type_params) = &type_params { |
38 | let start_offset = nominal.syntax().text_range().end(); | 38 | format_to!(buf, "{}", type_params.syntax()); |
39 | let mut buf = String::new(); | 39 | } |
40 | buf.push_str("\n\nimpl"); | 40 | buf.push_str(" "); |
41 | if let Some(type_params) = &type_params { | 41 | buf.push_str(name.text().as_str()); |
42 | format_to!(buf, "{}", type_params.syntax()); | 42 | if let Some(type_params) = type_params { |
43 | } | 43 | let lifetime_params = type_params |
44 | buf.push_str(" "); | 44 | .lifetime_params() |
45 | buf.push_str(name.text().as_str()); | 45 | .filter_map(|it| it.lifetime_token()) |
46 | if let Some(type_params) = type_params { | 46 | .map(|it| it.text().clone()); |
47 | let lifetime_params = type_params | 47 | let type_params = |
48 | .lifetime_params() | 48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); |
49 | .filter_map(|it| it.lifetime_token()) | ||
50 | .map(|it| it.text().clone()); | ||
51 | let type_params = type_params | ||
52 | .type_params() | ||
53 | .filter_map(|it| it.name()) | ||
54 | .map(|it| it.text().clone()); | ||
55 | 49 | ||
56 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 50 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); |
57 | format_to!(buf, "<{}>", generic_params) | 51 | format_to!(buf, "<{}>", generic_params) |
58 | } | 52 | } |
59 | buf.push_str(" {\n"); | 53 | buf.push_str(" {\n"); |
60 | edit.set_cursor(start_offset + TextSize::of(&buf)); | 54 | edit.set_cursor(start_offset + TextSize::of(&buf)); |
61 | buf.push_str("\n}"); | 55 | buf.push_str("\n}"); |
62 | edit.insert(start_offset, buf); | 56 | edit.insert(start_offset, buf); |
63 | }, | 57 | }) |
64 | ) | ||
65 | } | 58 | } |
66 | 59 | ||
67 | #[cfg(test)] | 60 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 7df786590..3482a75bf 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -9,9 +9,10 @@ use ra_syntax::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | assist_context::{AssistContext, Assists}, | ||
12 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
13 | utils::{get_missing_assoc_items, resolve_target_trait}, | 14 | utils::{get_missing_assoc_items, resolve_target_trait}, |
14 | Assist, AssistCtx, AssistId, | 15 | AssistId, |
15 | }; | 16 | }; |
16 | 17 | ||
17 | #[derive(PartialEq)] | 18 | #[derive(PartialEq)] |
@@ -50,8 +51,9 @@ enum AddMissingImplMembersMode { | |||
50 | // | 51 | // |
51 | // } | 52 | // } |
52 | // ``` | 53 | // ``` |
53 | pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option<Assist> { | 54 | pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
54 | add_missing_impl_members_inner( | 55 | add_missing_impl_members_inner( |
56 | acc, | ||
55 | ctx, | 57 | ctx, |
56 | AddMissingImplMembersMode::NoDefaultMethods, | 58 | AddMissingImplMembersMode::NoDefaultMethods, |
57 | "add_impl_missing_members", | 59 | "add_impl_missing_members", |
@@ -91,8 +93,9 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option<Assist> { | |||
91 | // | 93 | // |
92 | // } | 94 | // } |
93 | // ``` | 95 | // ``` |
94 | pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option<Assist> { | 96 | pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
95 | add_missing_impl_members_inner( | 97 | add_missing_impl_members_inner( |
98 | acc, | ||
96 | ctx, | 99 | ctx, |
97 | AddMissingImplMembersMode::DefaultMethodsOnly, | 100 | AddMissingImplMembersMode::DefaultMethodsOnly, |
98 | "add_impl_default_members", | 101 | "add_impl_default_members", |
@@ -101,11 +104,12 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option<Assist> { | |||
101 | } | 104 | } |
102 | 105 | ||
103 | fn add_missing_impl_members_inner( | 106 | fn add_missing_impl_members_inner( |
104 | ctx: AssistCtx, | 107 | acc: &mut Assists, |
108 | ctx: &AssistContext, | ||
105 | mode: AddMissingImplMembersMode, | 109 | mode: AddMissingImplMembersMode, |
106 | assist_id: &'static str, | 110 | assist_id: &'static str, |
107 | label: &'static str, | 111 | label: &'static str, |
108 | ) -> Option<Assist> { | 112 | ) -> Option<()> { |
109 | let _p = ra_prof::profile("add_missing_impl_members_inner"); | 113 | let _p = ra_prof::profile("add_missing_impl_members_inner"); |
110 | let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?; | 114 | let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?; |
111 | let impl_item_list = impl_def.item_list()?; | 115 | let impl_item_list = impl_def.item_list()?; |
@@ -142,12 +146,11 @@ fn add_missing_impl_members_inner( | |||
142 | return None; | 146 | return None; |
143 | } | 147 | } |
144 | 148 | ||
145 | let sema = ctx.sema; | ||
146 | let target = impl_def.syntax().text_range(); | 149 | let target = impl_def.syntax().text_range(); |
147 | ctx.add_assist(AssistId(assist_id), label, target, |edit| { | 150 | acc.add(AssistId(assist_id), label, target, |edit| { |
148 | let n_existing_items = impl_item_list.assoc_items().count(); | 151 | let n_existing_items = impl_item_list.assoc_items().count(); |
149 | let source_scope = sema.scope_for_def(trait_); | 152 | let source_scope = ctx.sema.scope_for_def(trait_); |
150 | let target_scope = sema.scope(impl_item_list.syntax()); | 153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); |
151 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) | 154 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) |
152 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); | 155 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); |
153 | let items = missing_items | 156 | let items = missing_items |
@@ -170,13 +173,12 @@ fn add_missing_impl_members_inner( | |||
170 | } | 173 | } |
171 | 174 | ||
172 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 175 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
173 | if fn_def.body().is_none() { | 176 | if fn_def.body().is_some() { |
174 | let body = make::block_expr(None, Some(make::expr_todo())); | 177 | return fn_def; |
175 | let body = IndentLevel(1).increase_indent(body); | ||
176 | fn_def.with_body(body) | ||
177 | } else { | ||
178 | fn_def | ||
179 | } | 178 | } |
179 | let body = make::block_expr(None, Some(make::expr_todo())); | ||
180 | let body = IndentLevel(1).increase_indent(body); | ||
181 | fn_def.with_body(body) | ||
180 | } | 182 | } |
181 | 183 | ||
182 | #[cfg(test)] | 184 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index 1c3f8435a..fe7451dcf 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
@@ -7,7 +7,7 @@ use ra_syntax::{ | |||
7 | }; | 7 | }; |
8 | use stdx::{format_to, SepBy}; | 8 | use stdx::{format_to, SepBy}; |
9 | 9 | ||
10 | use crate::{Assist, AssistCtx, AssistId}; | 10 | use crate::{AssistContext, AssistId, Assists}; |
11 | 11 | ||
12 | // Assist: add_new | 12 | // Assist: add_new |
13 | // | 13 | // |
@@ -29,7 +29,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
29 | // } | 29 | // } |
30 | // | 30 | // |
31 | // ``` | 31 | // ``` |
32 | pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { | 32 | pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
33 | let strukt = ctx.find_node_at_offset::<ast::StructDef>()?; | 33 | let strukt = ctx.find_node_at_offset::<ast::StructDef>()?; |
34 | 34 | ||
35 | // We want to only apply this to non-union structs with named fields | 35 | // We want to only apply this to non-union structs with named fields |
@@ -42,7 +42,7 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { | |||
42 | let impl_def = find_struct_impl(&ctx, &strukt)?; | 42 | let impl_def = find_struct_impl(&ctx, &strukt)?; |
43 | 43 | ||
44 | let target = strukt.syntax().text_range(); | 44 | let target = strukt.syntax().text_range(); |
45 | ctx.add_assist(AssistId("add_new"), "Add default constructor", target, |edit| { | 45 | acc.add(AssistId("add_new"), "Add default constructor", target, |edit| { |
46 | let mut buf = String::with_capacity(512); | 46 | let mut buf = String::with_capacity(512); |
47 | 47 | ||
48 | if impl_def.is_some() { | 48 | if impl_def.is_some() { |
@@ -123,7 +123,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { | |||
123 | // | 123 | // |
124 | // FIXME: change the new fn checking to a more semantic approach when that's more | 124 | // FIXME: change the new fn checking to a more semantic approach when that's more |
125 | // viable (e.g. we process proc macros, etc) | 125 | // viable (e.g. we process proc macros, etc) |
126 | fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { | 126 | fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { |
127 | let db = ctx.db; | 127 | let db = ctx.db; |
128 | let module = strukt.syntax().ancestors().find(|node| { | 128 | let module = strukt.syntax().ancestors().find(|node| { |
129 | ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) | 129 | ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) |
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index a5b26e5b9..0feba5e11 100644 --- a/crates/ra_assists/src/handlers/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::ast::{self, AstNode}; | 1 | use ra_syntax::ast::{self, AstNode}; |
2 | 2 | ||
3 | use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; | 3 | use crate::{utils::invert_boolean_expression, AssistContext, AssistId, Assists}; |
4 | 4 | ||
5 | // Assist: apply_demorgan | 5 | // Assist: apply_demorgan |
6 | // | 6 | // |
@@ -21,7 +21,7 @@ use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; | |||
21 | // if !(x == 4 && y) {} | 21 | // if !(x == 4 && y) {} |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> { | 24 | pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
25 | let expr = ctx.find_node_at_offset::<ast::BinExpr>()?; | 25 | let expr = ctx.find_node_at_offset::<ast::BinExpr>()?; |
26 | let op = expr.op_kind()?; | 26 | let op = expr.op_kind()?; |
27 | let op_range = expr.op_token()?.text_range(); | 27 | let op_range = expr.op_token()?.text_range(); |
@@ -39,7 +39,7 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> { | |||
39 | let rhs_range = rhs.syntax().text_range(); | 39 | let rhs_range = rhs.syntax().text_range(); |
40 | let not_rhs = invert_boolean_expression(rhs); | 40 | let not_rhs = invert_boolean_expression(rhs); |
41 | 41 | ||
42 | ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { | 42 | acc.add(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { |
43 | edit.replace(op_range, opposite_op); | 43 | edit.replace(op_range, opposite_op); |
44 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); | 44 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); |
45 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); | 45 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 2224b9714..78d23150d 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use std::collections::BTreeSet; | 1 | use std::collections::BTreeSet; |
2 | 2 | ||
3 | use either::Either; | ||
3 | use hir::{ | 4 | use hir::{ |
4 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, | 5 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, |
5 | Type, | 6 | Type, |
@@ -12,12 +13,7 @@ use ra_syntax::{ | |||
12 | }; | 13 | }; |
13 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
14 | 15 | ||
15 | use crate::{ | 16 | use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, GroupLabel}; |
16 | assist_ctx::{Assist, AssistCtx}, | ||
17 | utils::insert_use_statement, | ||
18 | AssistId, | ||
19 | }; | ||
20 | use either::Either; | ||
21 | 17 | ||
22 | // Assist: auto_import | 18 | // Assist: auto_import |
23 | // | 19 | // |
@@ -38,7 +34,7 @@ use either::Either; | |||
38 | // } | 34 | // } |
39 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 35 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
40 | // ``` | 36 | // ``` |
41 | pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | 37 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
42 | let auto_import_assets = AutoImportAssets::new(&ctx)?; | 38 | let auto_import_assets = AutoImportAssets::new(&ctx)?; |
43 | let proposed_imports = auto_import_assets.search_for_imports(ctx.db); | 39 | let proposed_imports = auto_import_assets.search_for_imports(ctx.db); |
44 | if proposed_imports.is_empty() { | 40 | if proposed_imports.is_empty() { |
@@ -46,13 +42,19 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
46 | } | 42 | } |
47 | 43 | ||
48 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; | 44 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; |
49 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); | 45 | let group = auto_import_assets.get_import_group_message(); |
50 | for import in proposed_imports { | 46 | for import in proposed_imports { |
51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), range, |edit| { | 47 | acc.add_group( |
52 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); | 48 | &group, |
53 | }); | 49 | AssistId("auto_import"), |
50 | format!("Import `{}`", &import), | ||
51 | range, | ||
52 | |builder| { | ||
53 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, ctx, builder); | ||
54 | }, | ||
55 | ); | ||
54 | } | 56 | } |
55 | group.finish() | 57 | Some(()) |
56 | } | 58 | } |
57 | 59 | ||
58 | #[derive(Debug)] | 60 | #[derive(Debug)] |
@@ -63,7 +65,7 @@ struct AutoImportAssets { | |||
63 | } | 65 | } |
64 | 66 | ||
65 | impl AutoImportAssets { | 67 | impl AutoImportAssets { |
66 | fn new(ctx: &AssistCtx) -> Option<Self> { | 68 | fn new(ctx: &AssistContext) -> Option<Self> { |
67 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { | 69 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { |
68 | Self::for_regular_path(path_under_caret, &ctx) | 70 | Self::for_regular_path(path_under_caret, &ctx) |
69 | } else { | 71 | } else { |
@@ -71,7 +73,7 @@ impl AutoImportAssets { | |||
71 | } | 73 | } |
72 | } | 74 | } |
73 | 75 | ||
74 | fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistCtx) -> Option<Self> { | 76 | fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistContext) -> Option<Self> { |
75 | let syntax_under_caret = method_call.syntax().to_owned(); | 77 | let syntax_under_caret = method_call.syntax().to_owned(); |
76 | let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; | 78 | let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; |
77 | Some(Self { | 79 | Some(Self { |
@@ -81,7 +83,7 @@ impl AutoImportAssets { | |||
81 | }) | 83 | }) |
82 | } | 84 | } |
83 | 85 | ||
84 | fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistCtx) -> Option<Self> { | 86 | fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> { |
85 | let syntax_under_caret = path_under_caret.syntax().to_owned(); | 87 | let syntax_under_caret = path_under_caret.syntax().to_owned(); |
86 | if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { | 88 | if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { |
87 | return None; | 89 | return None; |
@@ -104,8 +106,8 @@ impl AutoImportAssets { | |||
104 | } | 106 | } |
105 | } | 107 | } |
106 | 108 | ||
107 | fn get_import_group_message(&self) -> String { | 109 | fn get_import_group_message(&self) -> GroupLabel { |
108 | match &self.import_candidate { | 110 | let name = match &self.import_candidate { |
109 | ImportCandidate::UnqualifiedName(name) => format!("Import {}", name), | 111 | ImportCandidate::UnqualifiedName(name) => format!("Import {}", name), |
110 | ImportCandidate::QualifierStart(qualifier_start) => { | 112 | ImportCandidate::QualifierStart(qualifier_start) => { |
111 | format!("Import {}", qualifier_start) | 113 | format!("Import {}", qualifier_start) |
@@ -116,7 +118,8 @@ impl AutoImportAssets { | |||
116 | ImportCandidate::TraitMethod(_, trait_method_name) => { | 118 | ImportCandidate::TraitMethod(_, trait_method_name) => { |
117 | format!("Import a trait for method {}", trait_method_name) | 119 | format!("Import a trait for method {}", trait_method_name) |
118 | } | 120 | } |
119 | } | 121 | }; |
122 | GroupLabel(name) | ||
120 | } | 123 | } |
121 | 124 | ||
122 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { | 125 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { |
@@ -383,7 +386,7 @@ mod tests { | |||
383 | } | 386 | } |
384 | ", | 387 | ", |
385 | r" | 388 | r" |
386 | use PubMod1::PubStruct; | 389 | use PubMod3::PubStruct; |
387 | 390 | ||
388 | PubSt<|>ruct | 391 | PubSt<|>ruct |
389 | 392 | ||
diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs index 1e8d986cd..5c907097e 100644 --- a/crates/ra_assists/src/handlers/change_return_type_to_result.rs +++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast, AstNode, | 2 | ast::{self, BlockExpr, Expr, LoopBodyOwner}, |
3 | AstNode, | ||
3 | SyntaxKind::{COMMENT, WHITESPACE}, | 4 | SyntaxKind::{COMMENT, WHITESPACE}, |
4 | SyntaxNode, TextSize, | 5 | SyntaxNode, TextSize, |
5 | }; | 6 | }; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{AssistContext, AssistId, Assists}; |
8 | use ast::{BlockExpr, Expr, LoopBodyOwner}; | ||
9 | 9 | ||
10 | // Assist: change_return_type_to_result | 10 | // Assist: change_return_type_to_result |
11 | // | 11 | // |
@@ -18,7 +18,7 @@ use ast::{BlockExpr, Expr, LoopBodyOwner}; | |||
18 | // ``` | 18 | // ``` |
19 | // fn foo() -> Result<i32, > { Ok(42i32) } | 19 | // fn foo() -> Result<i32, > { Ok(42i32) } |
20 | // ``` | 20 | // ``` |
21 | pub(crate) fn change_return_type_to_result(ctx: AssistCtx) -> Option<Assist> { | 21 | pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
22 | let fn_def = ctx.find_node_at_offset::<ast::FnDef>(); | 22 | let fn_def = ctx.find_node_at_offset::<ast::FnDef>(); |
23 | let fn_def = &mut fn_def?; | 23 | let fn_def = &mut fn_def?; |
24 | let ret_type = &fn_def.ret_type()?.type_ref()?; | 24 | let ret_type = &fn_def.ret_type()?.type_ref()?; |
@@ -33,7 +33,7 @@ pub(crate) fn change_return_type_to_result(ctx: AssistCtx) -> Option<Assist> { | |||
33 | return None; | 33 | return None; |
34 | } | 34 | } |
35 | 35 | ||
36 | ctx.add_assist( | 36 | acc.add( |
37 | AssistId("change_return_type_to_result"), | 37 | AssistId("change_return_type_to_result"), |
38 | "Change return type to Result", | 38 | "Change return type to Result", |
39 | ret_type.syntax().text_range(), | 39 | ret_type.syntax().text_range(), |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 489db83e6..e631766ef 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -7,10 +7,10 @@ use ra_syntax::{ | |||
7 | }, | 7 | }, |
8 | SyntaxNode, TextSize, T, | 8 | SyntaxNode, TextSize, T, |
9 | }; | 9 | }; |
10 | |||
11 | use crate::{Assist, AssistCtx, AssistId}; | ||
12 | use test_utils::tested_by; | 10 | use test_utils::tested_by; |
13 | 11 | ||
12 | use crate::{AssistContext, AssistId, Assists}; | ||
13 | |||
14 | // Assist: change_visibility | 14 | // Assist: change_visibility |
15 | // | 15 | // |
16 | // Adds or changes existing visibility specifier. | 16 | // Adds or changes existing visibility specifier. |
@@ -22,14 +22,14 @@ use test_utils::tested_by; | |||
22 | // ``` | 22 | // ``` |
23 | // pub(crate) fn frobnicate() {} | 23 | // pub(crate) fn frobnicate() {} |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn change_visibility(ctx: AssistCtx) -> Option<Assist> { | 25 | pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() { | 26 | if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() { |
27 | return change_vis(ctx, vis); | 27 | return change_vis(acc, vis); |
28 | } | 28 | } |
29 | add_vis(ctx) | 29 | add_vis(acc, ctx) |
30 | } | 30 | } |
31 | 31 | ||
32 | fn add_vis(ctx: AssistCtx) -> Option<Assist> { | 32 | fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
33 | let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { | 33 | let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { |
34 | T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, | 34 | T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, |
35 | _ => false, | 35 | _ => false, |
@@ -66,15 +66,10 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> { | |||
66 | return None; | 66 | return None; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | ctx.add_assist( | 69 | acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| { |
70 | AssistId("change_visibility"), | 70 | edit.insert(offset, "pub(crate) "); |
71 | "Change visibility to pub(crate)", | 71 | edit.set_cursor(offset); |
72 | target, | 72 | }) |
73 | |edit| { | ||
74 | edit.insert(offset, "pub(crate) "); | ||
75 | edit.set_cursor(offset); | ||
76 | }, | ||
77 | ) | ||
78 | } | 73 | } |
79 | 74 | ||
80 | fn vis_offset(node: &SyntaxNode) -> TextSize { | 75 | fn vis_offset(node: &SyntaxNode) -> TextSize { |
@@ -88,10 +83,10 @@ fn vis_offset(node: &SyntaxNode) -> TextSize { | |||
88 | .unwrap_or_else(|| node.text_range().start()) | 83 | .unwrap_or_else(|| node.text_range().start()) |
89 | } | 84 | } |
90 | 85 | ||
91 | fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | 86 | fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { |
92 | if vis.syntax().text() == "pub" { | 87 | if vis.syntax().text() == "pub" { |
93 | let target = vis.syntax().text_range(); | 88 | let target = vis.syntax().text_range(); |
94 | return ctx.add_assist( | 89 | return acc.add( |
95 | AssistId("change_visibility"), | 90 | AssistId("change_visibility"), |
96 | "Change Visibility to pub(crate)", | 91 | "Change Visibility to pub(crate)", |
97 | target, | 92 | target, |
@@ -103,7 +98,7 @@ fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | |||
103 | } | 98 | } |
104 | if vis.syntax().text() == "pub(crate)" { | 99 | if vis.syntax().text() == "pub(crate)" { |
105 | let target = vis.syntax().text_range(); | 100 | let target = vis.syntax().text_range(); |
106 | return ctx.add_assist( | 101 | return acc.add( |
107 | AssistId("change_visibility"), | 102 | AssistId("change_visibility"), |
108 | "Change visibility to pub", | 103 | "Change visibility to pub", |
109 | target, | 104 | target, |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 4bd6040b2..ccf91797c 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | assist_ctx::{Assist, AssistCtx}, | 12 | assist_context::{AssistContext, Assists}, |
13 | utils::invert_boolean_expression, | 13 | utils::invert_boolean_expression, |
14 | AssistId, | 14 | AssistId, |
15 | }; | 15 | }; |
@@ -36,7 +36,7 @@ use crate::{ | |||
36 | // bar(); | 36 | // bar(); |
37 | // } | 37 | // } |
38 | // ``` | 38 | // ``` |
39 | pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | 39 | pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
40 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | 40 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; |
41 | if if_expr.else_branch().is_some() { | 41 | if if_expr.else_branch().is_some() { |
42 | return None; | 42 | return None; |
@@ -96,93 +96,88 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
96 | let cursor_position = ctx.frange.range.start(); | 96 | let cursor_position = ctx.frange.range.start(); |
97 | 97 | ||
98 | let target = if_expr.syntax().text_range(); | 98 | let target = if_expr.syntax().text_range(); |
99 | ctx.add_assist( | 99 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { |
100 | AssistId("convert_to_guarded_return"), | 100 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
101 | "Convert to guarded return", | 101 | let new_block = match if_let_pat { |
102 | target, | 102 | None => { |
103 | |edit| { | 103 | // If. |
104 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 104 | let new_expr = { |
105 | let new_block = match if_let_pat { | 105 | let then_branch = |
106 | None => { | 106 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); |
107 | // If. | 107 | let cond = invert_boolean_expression(cond_expr); |
108 | let new_expr = { | 108 | let e = make::expr_if(make::condition(cond, None), then_branch); |
109 | let then_branch = | 109 | if_indent_level.increase_indent(e) |
110 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); | 110 | }; |
111 | let cond = invert_boolean_expression(cond_expr); | 111 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) |
112 | let e = make::expr_if(make::condition(cond, None), then_branch); | 112 | } |
113 | if_indent_level.increase_indent(e) | 113 | Some((path, bound_ident)) => { |
114 | }; | 114 | // If-let. |
115 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | 115 | let match_expr = { |
116 | } | 116 | let happy_arm = { |
117 | Some((path, bound_ident)) => { | 117 | let pat = make::tuple_struct_pat( |
118 | // If-let. | 118 | path, |
119 | let match_expr = { | 119 | once(make::bind_pat(make::name("it")).into()), |
120 | let happy_arm = { | ||
121 | let pat = make::tuple_struct_pat( | ||
122 | path, | ||
123 | once(make::bind_pat(make::name("it")).into()), | ||
124 | ); | ||
125 | let expr = { | ||
126 | let name_ref = make::name_ref("it"); | ||
127 | let segment = make::path_segment(name_ref); | ||
128 | let path = make::path_unqualified(segment); | ||
129 | make::expr_path(path) | ||
130 | }; | ||
131 | make::match_arm(once(pat.into()), expr) | ||
132 | }; | ||
133 | |||
134 | let sad_arm = make::match_arm( | ||
135 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate | ||
136 | once(make::placeholder_pat().into()), | ||
137 | early_expression, | ||
138 | ); | 120 | ); |
139 | 121 | let expr = { | |
140 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) | 122 | let name_ref = make::name_ref("it"); |
123 | let segment = make::path_segment(name_ref); | ||
124 | let path = make::path_unqualified(segment); | ||
125 | make::expr_path(path) | ||
126 | }; | ||
127 | make::match_arm(once(pat.into()), expr) | ||
141 | }; | 128 | }; |
142 | 129 | ||
143 | let let_stmt = make::let_stmt( | 130 | let sad_arm = make::match_arm( |
144 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), | 131 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate |
145 | Some(match_expr), | 132 | once(make::placeholder_pat().into()), |
133 | early_expression, | ||
146 | ); | 134 | ); |
147 | let let_stmt = if_indent_level.increase_indent(let_stmt); | 135 | |
148 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | 136 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) |
149 | } | 137 | }; |
150 | }; | 138 | |
151 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | 139 | let let_stmt = make::let_stmt( |
152 | edit.set_cursor(cursor_position); | 140 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), |
153 | 141 | Some(match_expr), | |
154 | fn replace( | ||
155 | new_expr: &SyntaxNode, | ||
156 | then_block: &ast::BlockExpr, | ||
157 | parent_block: &ast::BlockExpr, | ||
158 | if_expr: &ast::IfExpr, | ||
159 | ) -> SyntaxNode { | ||
160 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | ||
161 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
162 | let end_of_then = | ||
163 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
164 | end_of_then.prev_sibling_or_token().unwrap() | ||
165 | } else { | ||
166 | end_of_then | ||
167 | }; | ||
168 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
169 | then_block_items | ||
170 | .syntax() | ||
171 | .children_with_tokens() | ||
172 | .skip(1) | ||
173 | .take_while(|i| *i != end_of_then), | ||
174 | ); | 142 | ); |
175 | replace_children( | 143 | let let_stmt = if_indent_level.increase_indent(let_stmt); |
176 | &parent_block.syntax(), | 144 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) |
177 | RangeInclusive::new( | ||
178 | if_expr.clone().syntax().clone().into(), | ||
179 | if_expr.syntax().clone().into(), | ||
180 | ), | ||
181 | &mut then_statements, | ||
182 | ) | ||
183 | } | 145 | } |
184 | }, | 146 | }; |
185 | ) | 147 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); |
148 | edit.set_cursor(cursor_position); | ||
149 | |||
150 | fn replace( | ||
151 | new_expr: &SyntaxNode, | ||
152 | then_block: &ast::BlockExpr, | ||
153 | parent_block: &ast::BlockExpr, | ||
154 | if_expr: &ast::IfExpr, | ||
155 | ) -> SyntaxNode { | ||
156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | ||
157 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
158 | let end_of_then = | ||
159 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
160 | end_of_then.prev_sibling_or_token().unwrap() | ||
161 | } else { | ||
162 | end_of_then | ||
163 | }; | ||
164 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
165 | then_block_items | ||
166 | .syntax() | ||
167 | .children_with_tokens() | ||
168 | .skip(1) | ||
169 | .take_while(|i| *i != end_of_then), | ||
170 | ); | ||
171 | replace_children( | ||
172 | &parent_block.syntax(), | ||
173 | RangeInclusive::new( | ||
174 | if_expr.clone().syntax().clone().into(), | ||
175 | if_expr.syntax().clone().into(), | ||
176 | ), | ||
177 | &mut then_statements, | ||
178 | ) | ||
179 | } | ||
180 | }) | ||
186 | } | 181 | } |
187 | 182 | ||
188 | #[cfg(test)] | 183 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 7c8f8bdf2..13c1e7e80 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -5,7 +5,7 @@ use itertools::Itertools; | |||
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; | 6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{AssistContext, AssistId, Assists}; |
9 | 9 | ||
10 | // Assist: fill_match_arms | 10 | // Assist: fill_match_arms |
11 | // | 11 | // |
@@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
31 | // } | 31 | // } |
32 | // } | 32 | // } |
33 | // ``` | 33 | // ``` |
34 | pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | 34 | pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
35 | let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; | 35 | let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; |
36 | let match_arm_list = match_expr.match_arm_list()?; | 36 | let match_arm_list = match_expr.match_arm_list()?; |
37 | 37 | ||
@@ -93,7 +93,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
93 | } | 93 | } |
94 | 94 | ||
95 | let target = match_expr.syntax().text_range(); | 95 | let target = match_expr.syntax().text_range(); |
96 | ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { | 96 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { |
97 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); | 97 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); |
98 | edit.set_cursor(expr.syntax().text_range().start()); | 98 | edit.set_cursor(expr.syntax().text_range().start()); |
99 | edit.replace_ast(match_arm_list, new_arm_list); | 99 | edit.replace_ast(match_arm_list, new_arm_list); |
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index cb7264d7b..692ba4895 100644 --- a/crates/ra_assists/src/handlers/flip_binexpr.rs +++ b/crates/ra_assists/src/handlers/flip_binexpr.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::ast::{AstNode, BinExpr, BinOp}; | 1 | use ra_syntax::ast::{AstNode, BinExpr, BinOp}; |
2 | 2 | ||
3 | use crate::{Assist, AssistCtx, AssistId}; | 3 | use crate::{AssistContext, AssistId, Assists}; |
4 | 4 | ||
5 | // Assist: flip_binexpr | 5 | // Assist: flip_binexpr |
6 | // | 6 | // |
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
17 | // let _ = 2 + 90; | 17 | // let _ = 2 + 90; |
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> { | 20 | pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | let expr = ctx.find_node_at_offset::<BinExpr>()?; | 21 | let expr = ctx.find_node_at_offset::<BinExpr>()?; |
22 | let lhs = expr.lhs()?.syntax().clone(); | 22 | let lhs = expr.lhs()?.syntax().clone(); |
23 | let rhs = expr.rhs()?.syntax().clone(); | 23 | let rhs = expr.rhs()?.syntax().clone(); |
@@ -33,7 +33,7 @@ pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> { | |||
33 | return None; | 33 | return None; |
34 | } | 34 | } |
35 | 35 | ||
36 | ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { | 36 | acc.add(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { |
37 | if let FlipAction::FlipAndReplaceOp(new_op) = action { | 37 | if let FlipAction::FlipAndReplaceOp(new_op) = action { |
38 | edit.replace(op_range, new_op); | 38 | edit.replace(op_range, new_op); |
39 | } | 39 | } |
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index 24982ae22..dfe2a7fed 100644 --- a/crates/ra_assists/src/handlers/flip_comma.rs +++ b/crates/ra_assists/src/handlers/flip_comma.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::{algo::non_trivia_sibling, Direction, T}; | 1 | use ra_syntax::{algo::non_trivia_sibling, Direction, T}; |
2 | 2 | ||
3 | use crate::{Assist, AssistCtx, AssistId}; | 3 | use crate::{AssistContext, AssistId, Assists}; |
4 | 4 | ||
5 | // Assist: flip_comma | 5 | // Assist: flip_comma |
6 | // | 6 | // |
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
17 | // ((3, 4), (1, 2)); | 17 | // ((3, 4), (1, 2)); |
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> { | 20 | pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | let comma = ctx.find_token_at_offset(T![,])?; | 21 | let comma = ctx.find_token_at_offset(T![,])?; |
22 | let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; | 22 | let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; |
23 | let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; | 23 | let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; |
@@ -28,7 +28,7 @@ pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> { | |||
28 | return None; | 28 | return None; |
29 | } | 29 | } |
30 | 30 | ||
31 | ctx.add_assist(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { | 31 | acc.add(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { |
32 | edit.replace(prev.text_range(), next.to_string()); | 32 | edit.replace(prev.text_range(), next.to_string()); |
33 | edit.replace(next.text_range(), prev.to_string()); | 33 | edit.replace(next.text_range(), prev.to_string()); |
34 | }) | 34 | }) |
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index 6a3b2df67..8a08702ab 100644 --- a/crates/ra_assists/src/handlers/flip_trait_bound.rs +++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | Direction, T, | 4 | Direction, T, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{AssistContext, AssistId, Assists}; |
8 | 8 | ||
9 | // Assist: flip_trait_bound | 9 | // Assist: flip_trait_bound |
10 | // | 10 | // |
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
17 | // ``` | 17 | // ``` |
18 | // fn foo<T: Copy + Clone>() { } | 18 | // fn foo<T: Copy + Clone>() { } |
19 | // ``` | 19 | // ``` |
20 | pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> { | 20 | pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | // We want to replicate the behavior of `flip_binexpr` by only suggesting | 21 | // We want to replicate the behavior of `flip_binexpr` by only suggesting |
22 | // the assist when the cursor is on a `+` | 22 | // the assist when the cursor is on a `+` |
23 | let plus = ctx.find_token_at_offset(T![+])?; | 23 | let plus = ctx.find_token_at_offset(T![+])?; |
@@ -33,7 +33,7 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> { | |||
33 | ); | 33 | ); |
34 | 34 | ||
35 | let target = plus.text_range(); | 35 | let target = plus.text_range(); |
36 | ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| { | 36 | acc.add(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| { |
37 | edit.replace(before.text_range(), after.to_string()); | 37 | edit.replace(before.text_range(), after.to_string()); |
38 | edit.replace(after.text_range(), before.to_string()); | 38 | edit.replace(after.text_range(), before.to_string()); |
39 | }) | 39 | }) |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index e5765c845..5b26814d3 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -5,7 +5,10 @@ use ra_syntax::{ | |||
5 | }; | 5 | }; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::{assist_ctx::ActionBuilder, Assist, AssistCtx, AssistId}; | 8 | use crate::{ |
9 | assist_context::{AssistContext, Assists}, | ||
10 | AssistId, | ||
11 | }; | ||
9 | 12 | ||
10 | // Assist: inline_local_variable | 13 | // Assist: inline_local_variable |
11 | // | 14 | // |
@@ -23,7 +26,7 @@ use crate::{assist_ctx::ActionBuilder, Assist, AssistCtx, AssistId}; | |||
23 | // (1 + 2) * 4; | 26 | // (1 + 2) * 4; |
24 | // } | 27 | // } |
25 | // ``` | 28 | // ``` |
26 | pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | 29 | pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
27 | let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; | 30 | let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; |
28 | let bind_pat = match let_stmt.pat()? { | 31 | let bind_pat = match let_stmt.pat()? { |
29 | ast::Pat::BindPat(pat) => pat, | 32 | ast::Pat::BindPat(pat) => pat, |
@@ -33,7 +36,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
33 | tested_by!(test_not_inline_mut_variable); | 36 | tested_by!(test_not_inline_mut_variable); |
34 | return None; | 37 | return None; |
35 | } | 38 | } |
36 | if !bind_pat.syntax().text_range().contains_inclusive(ctx.frange.range.start()) { | 39 | if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) { |
37 | tested_by!(not_applicable_outside_of_bind_pat); | 40 | tested_by!(not_applicable_outside_of_bind_pat); |
38 | return None; | 41 | return None; |
39 | } | 42 | } |
@@ -107,20 +110,14 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
107 | let init_in_paren = format!("({})", &init_str); | 110 | let init_in_paren = format!("({})", &init_str); |
108 | 111 | ||
109 | let target = bind_pat.syntax().text_range(); | 112 | let target = bind_pat.syntax().text_range(); |
110 | ctx.add_assist( | 113 | acc.add(AssistId("inline_local_variable"), "Inline variable", target, move |builder| { |
111 | AssistId("inline_local_variable"), | 114 | builder.delete(delete_range); |
112 | "Inline variable", | 115 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { |
113 | target, | 116 | let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; |
114 | move |edit: &mut ActionBuilder| { | 117 | builder.replace(desc.file_range.range, replacement) |
115 | edit.delete(delete_range); | 118 | } |
116 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { | 119 | builder.set_cursor(delete_range.start()) |
117 | let replacement = | 120 | }) |
118 | if should_wrap { init_in_paren.clone() } else { init_str.clone() }; | ||
119 | edit.replace(desc.file_range.range, replacement) | ||
120 | } | ||
121 | edit.set_cursor(delete_range.start()) | ||
122 | }, | ||
123 | ) | ||
124 | } | 121 | } |
125 | 122 | ||
126 | #[cfg(test)] | 123 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 3c340ff3b..fdf3ada0d 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | use stdx::format_to; | 9 | use stdx::format_to; |
10 | use test_utils::tested_by; | 10 | use test_utils::tested_by; |
11 | 11 | ||
12 | use crate::{Assist, AssistCtx, AssistId}; | 12 | use crate::{AssistContext, AssistId, Assists}; |
13 | 13 | ||
14 | // Assist: introduce_variable | 14 | // Assist: introduce_variable |
15 | // | 15 | // |
@@ -27,7 +27,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
27 | // var_name * 4; | 27 | // var_name * 4; |
28 | // } | 28 | // } |
29 | // ``` | 29 | // ``` |
30 | pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | 30 | pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
31 | if ctx.frange.range.is_empty() { | 31 | if ctx.frange.range.is_empty() { |
32 | return None; | 32 | return None; |
33 | } | 33 | } |
@@ -43,7 +43,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | let target = expr.syntax().text_range(); | 45 | let target = expr.syntax().text_range(); |
46 | ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { | 46 | acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { |
47 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
48 | 48 | ||
49 | let cursor_offset = if wrap_in_block { | 49 | let cursor_offset = if wrap_in_block { |
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs index b16271443..527c7caef 100644 --- a/crates/ra_assists/src/handlers/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -3,7 +3,11 @@ use ra_syntax::{ | |||
3 | T, | 3 | T, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; | 6 | use crate::{ |
7 | assist_context::{AssistContext, Assists}, | ||
8 | utils::invert_boolean_expression, | ||
9 | AssistId, | ||
10 | }; | ||
7 | 11 | ||
8 | // Assist: invert_if | 12 | // Assist: invert_if |
9 | // | 13 | // |
@@ -24,7 +28,7 @@ use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; | |||
24 | // } | 28 | // } |
25 | // ``` | 29 | // ``` |
26 | 30 | ||
27 | pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { | 31 | pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
28 | let if_keyword = ctx.find_token_at_offset(T![if])?; | 32 | let if_keyword = ctx.find_token_at_offset(T![if])?; |
29 | let expr = ast::IfExpr::cast(if_keyword.parent())?; | 33 | let expr = ast::IfExpr::cast(if_keyword.parent())?; |
30 | let if_range = if_keyword.text_range(); | 34 | let if_range = if_keyword.text_range(); |
@@ -40,21 +44,21 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { | |||
40 | 44 | ||
41 | let cond = expr.condition()?.expr()?; | 45 | let cond = expr.condition()?.expr()?; |
42 | let then_node = expr.then_branch()?.syntax().clone(); | 46 | let then_node = expr.then_branch()?.syntax().clone(); |
47 | let else_block = match expr.else_branch()? { | ||
48 | ast::ElseBranch::Block(it) => it, | ||
49 | ast::ElseBranch::IfExpr(_) => return None, | ||
50 | }; | ||
43 | 51 | ||
44 | if let ast::ElseBranch::Block(else_block) = expr.else_branch()? { | 52 | let cond_range = cond.syntax().text_range(); |
45 | let cond_range = cond.syntax().text_range(); | 53 | let flip_cond = invert_boolean_expression(cond); |
46 | let flip_cond = invert_boolean_expression(cond); | 54 | let else_node = else_block.syntax(); |
47 | let else_node = else_block.syntax(); | 55 | let else_range = else_node.text_range(); |
48 | let else_range = else_node.text_range(); | 56 | let then_range = then_node.text_range(); |
49 | let then_range = then_node.text_range(); | 57 | acc.add(AssistId("invert_if"), "Invert if", if_range, |edit| { |
50 | return ctx.add_assist(AssistId("invert_if"), "Invert if", if_range, |edit| { | 58 | edit.replace(cond_range, flip_cond.syntax().text()); |
51 | edit.replace(cond_range, flip_cond.syntax().text()); | 59 | edit.replace(else_range, then_node.text()); |
52 | edit.replace(else_range, then_node.text()); | 60 | edit.replace(then_range, else_node.text()); |
53 | edit.replace(then_range, else_node.text()); | 61 | }) |
54 | }); | ||
55 | } | ||
56 | |||
57 | None | ||
58 | } | 62 | } |
59 | 63 | ||
60 | #[cfg(test)] | 64 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index de74d83d8..8e1d93312 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -6,7 +6,10 @@ use ra_syntax::{ | |||
6 | AstNode, Direction, InsertPosition, SyntaxElement, T, | 6 | AstNode, Direction, InsertPosition, SyntaxElement, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | ||
11 | AssistId, | ||
12 | }; | ||
10 | 13 | ||
11 | // Assist: merge_imports | 14 | // Assist: merge_imports |
12 | // | 15 | // |
@@ -20,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
20 | // ``` | 23 | // ``` |
21 | // use std::{fmt::Formatter, io}; | 24 | // use std::{fmt::Formatter, io}; |
22 | // ``` | 25 | // ``` |
23 | pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | 26 | pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
24 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | 27 | let tree: ast::UseTree = ctx.find_node_at_offset()?; |
25 | let mut rewriter = SyntaxRewriter::default(); | 28 | let mut rewriter = SyntaxRewriter::default(); |
26 | let mut offset = ctx.frange.range.start(); | 29 | let mut offset = ctx.frange.range.start(); |
@@ -53,10 +56,10 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | |||
53 | }; | 56 | }; |
54 | 57 | ||
55 | let target = tree.syntax().text_range(); | 58 | let target = tree.syntax().text_range(); |
56 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", target, |edit| { | 59 | acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { |
57 | edit.rewrite(rewriter); | 60 | builder.rewrite(rewriter); |
58 | // FIXME: we only need because our diff is imprecise | 61 | // FIXME: we only need because our diff is imprecise |
59 | edit.set_cursor(offset); | 62 | builder.set_cursor(offset); |
60 | }) | 63 | }) |
61 | } | 64 | } |
62 | 65 | ||
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index 7c4d9d55d..cfe4df47b 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::{ | |||
6 | Direction, TextSize, | 6 | Direction, TextSize, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId, TextRange}; | 9 | use crate::{AssistContext, AssistId, Assists, TextRange}; |
10 | 10 | ||
11 | // Assist: merge_match_arms | 11 | // Assist: merge_match_arms |
12 | // | 12 | // |
@@ -32,7 +32,7 @@ use crate::{Assist, AssistCtx, AssistId, TextRange}; | |||
32 | // } | 32 | // } |
33 | // } | 33 | // } |
34 | // ``` | 34 | // ``` |
35 | pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> { | 35 | pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
36 | let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?; | 36 | let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?; |
37 | // Don't try to handle arms with guards for now - can add support for this later | 37 | // Don't try to handle arms with guards for now - can add support for this later |
38 | if current_arm.guard().is_some() { | 38 | if current_arm.guard().is_some() { |
@@ -70,7 +70,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
70 | return None; | 70 | return None; |
71 | } | 71 | } |
72 | 72 | ||
73 | ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| { | 73 | acc.add(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| { |
74 | let pats = if arms_to_merge.iter().any(contains_placeholder) { | 74 | let pats = if arms_to_merge.iter().any(contains_placeholder) { |
75 | "_".into() | 75 | "_".into() |
76 | } else { | 76 | } else { |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index 44e50cb6e..a41aacfc3 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | T, | 5 | T, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{AssistContext, AssistId, Assists}; |
9 | 9 | ||
10 | // Assist: move_bounds_to_where_clause | 10 | // Assist: move_bounds_to_where_clause |
11 | // | 11 | // |
@@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
22 | // f(x) | 22 | // f(x) |
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { | 25 | pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; | 26 | let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; |
27 | 27 | ||
28 | let mut type_params = type_param_list.type_params(); | 28 | let mut type_params = type_param_list.type_params(); |
@@ -50,36 +50,29 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { | |||
50 | }; | 50 | }; |
51 | 51 | ||
52 | let target = type_param_list.syntax().text_range(); | 52 | let target = type_param_list.syntax().text_range(); |
53 | ctx.add_assist( | 53 | acc.add(AssistId("move_bounds_to_where_clause"), "Move to where clause", target, |edit| { |
54 | AssistId("move_bounds_to_where_clause"), | 54 | let new_params = type_param_list |
55 | "Move to where clause", | 55 | .type_params() |
56 | target, | 56 | .filter(|it| it.type_bound_list().is_some()) |
57 | |edit| { | 57 | .map(|type_param| { |
58 | let new_params = type_param_list | 58 | let without_bounds = type_param.remove_bounds(); |
59 | .type_params() | 59 | (type_param, without_bounds) |
60 | .filter(|it| it.type_bound_list().is_some()) | 60 | }); |
61 | .map(|type_param| { | 61 | |
62 | let without_bounds = type_param.remove_bounds(); | 62 | let new_type_param_list = type_param_list.replace_descendants(new_params); |
63 | (type_param, without_bounds) | 63 | edit.replace_ast(type_param_list.clone(), new_type_param_list); |
64 | }); | 64 | |
65 | 65 | let where_clause = { | |
66 | let new_type_param_list = type_param_list.replace_descendants(new_params); | 66 | let predicates = type_param_list.type_params().filter_map(build_predicate); |
67 | edit.replace_ast(type_param_list.clone(), new_type_param_list); | 67 | make::where_clause(predicates) |
68 | 68 | }; | |
69 | let where_clause = { | 69 | |
70 | let predicates = type_param_list.type_params().filter_map(build_predicate); | 70 | let to_insert = match anchor.prev_sibling_or_token() { |
71 | make::where_clause(predicates) | 71 | Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), |
72 | }; | 72 | _ => format!(" {}", where_clause.syntax()), |
73 | 73 | }; | |
74 | let to_insert = match anchor.prev_sibling_or_token() { | 74 | edit.insert(anchor.text_range().start(), to_insert); |
75 | Some(ref elem) if elem.kind() == WHITESPACE => { | 75 | }) |
76 | format!("{} ", where_clause.syntax()) | ||
77 | } | ||
78 | _ => format!(" {}", where_clause.syntax()), | ||
79 | }; | ||
80 | edit.insert(anchor.text_range().start(), to_insert); | ||
81 | }, | ||
82 | ) | ||
83 | } | 76 | } |
84 | 77 | ||
85 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 78 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { |
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index 29bc9a9ff..fc0335b57 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | TextSize, | 4 | TextSize, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{AssistContext, AssistId, Assists}; |
8 | 8 | ||
9 | // Assist: move_guard_to_arm_body | 9 | // Assist: move_guard_to_arm_body |
10 | // | 10 | // |
@@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
31 | // } | 31 | // } |
32 | // } | 32 | // } |
33 | // ``` | 33 | // ``` |
34 | pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> { | 34 | pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
35 | let match_arm = ctx.find_node_at_offset::<MatchArm>()?; | 35 | let match_arm = ctx.find_node_at_offset::<MatchArm>()?; |
36 | let guard = match_arm.guard()?; | 36 | let guard = match_arm.guard()?; |
37 | let space_before_guard = guard.syntax().prev_sibling_or_token(); | 37 | let space_before_guard = guard.syntax().prev_sibling_or_token(); |
@@ -41,7 +41,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> { | |||
41 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); | 41 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); |
42 | 42 | ||
43 | let target = guard.syntax().text_range(); | 43 | let target = guard.syntax().text_range(); |
44 | ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { | 44 | acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { |
45 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { | 45 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { |
46 | Some(tok) => { | 46 | Some(tok) => { |
47 | if ast::Whitespace::cast(tok.clone()).is_some() { | 47 | if ast::Whitespace::cast(tok.clone()).is_some() { |
@@ -88,7 +88,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> { | |||
88 | // } | 88 | // } |
89 | // } | 89 | // } |
90 | // ``` | 90 | // ``` |
91 | pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | 91 | pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
92 | let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; | 92 | let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; |
93 | let match_pat = match_arm.pat()?; | 93 | let match_pat = match_arm.pat()?; |
94 | 94 | ||
@@ -109,7 +109,7 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | |||
109 | let buf = format!(" if {}", cond.syntax().text()); | 109 | let buf = format!(" if {}", cond.syntax().text()); |
110 | 110 | ||
111 | let target = if_expr.syntax().text_range(); | 111 | let target = if_expr.syntax().text_range(); |
112 | ctx.add_assist( | 112 | acc.add( |
113 | AssistId("move_arm_cond_to_match_guard"), | 113 | AssistId("move_arm_cond_to_match_guard"), |
114 | "Move condition to match guard", | 114 | "Move condition to match guard", |
115 | target, | 115 | target, |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 155c679b4..c20ffe0b3 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | TextSize, | 5 | TextSize, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{AssistContext, AssistId, Assists}; |
9 | 9 | ||
10 | // Assist: make_raw_string | 10 | // Assist: make_raw_string |
11 | // | 11 | // |
@@ -22,11 +22,11 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
22 | // r#"Hello, World!"#; | 22 | // r#"Hello, World!"#; |
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { | 25 | pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; | 26 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; |
27 | let value = token.value()?; | 27 | let value = token.value()?; |
28 | let target = token.syntax().text_range(); | 28 | let target = token.syntax().text_range(); |
29 | ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| { | 29 | acc.add(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| { |
30 | let max_hash_streak = count_hashes(&value); | 30 | let max_hash_streak = count_hashes(&value); |
31 | let mut hashes = String::with_capacity(max_hash_streak + 1); | 31 | let mut hashes = String::with_capacity(max_hash_streak + 1); |
32 | for _ in 0..hashes.capacity() { | 32 | for _ in 0..hashes.capacity() { |
@@ -51,11 +51,11 @@ pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { | |||
51 | // "Hello, \"World!\""; | 51 | // "Hello, \"World!\""; |
52 | // } | 52 | // } |
53 | // ``` | 53 | // ``` |
54 | pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { | 54 | pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
55 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; | 55 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; |
56 | let value = token.value()?; | 56 | let value = token.value()?; |
57 | let target = token.syntax().text_range(); | 57 | let target = token.syntax().text_range(); |
58 | ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| { | 58 | acc.add(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| { |
59 | // parse inside string to escape `"` | 59 | // parse inside string to escape `"` |
60 | let escaped = value.escape_default().to_string(); | 60 | let escaped = value.escape_default().to_string(); |
61 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); | 61 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); |
@@ -77,10 +77,10 @@ pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { | |||
77 | // r##"Hello, World!"##; | 77 | // r##"Hello, World!"##; |
78 | // } | 78 | // } |
79 | // ``` | 79 | // ``` |
80 | pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { | 80 | pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
81 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 81 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
82 | let target = token.text_range(); | 82 | let target = token.text_range(); |
83 | ctx.add_assist(AssistId("add_hash"), "Add # to raw string", target, |edit| { | 83 | acc.add(AssistId("add_hash"), "Add # to raw string", target, |edit| { |
84 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); | 84 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); |
85 | edit.insert(token.text_range().end(), "#"); | 85 | edit.insert(token.text_range().end(), "#"); |
86 | }) | 86 | }) |
@@ -101,7 +101,7 @@ pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { | |||
101 | // r"Hello, World!"; | 101 | // r"Hello, World!"; |
102 | // } | 102 | // } |
103 | // ``` | 103 | // ``` |
104 | pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> { | 104 | pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
105 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 105 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
106 | let text = token.text().as_str(); | 106 | let text = token.text().as_str(); |
107 | if text.starts_with("r\"") { | 107 | if text.starts_with("r\"") { |
@@ -109,7 +109,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> { | |||
109 | return None; | 109 | return None; |
110 | } | 110 | } |
111 | let target = token.text_range(); | 111 | let target = token.text_range(); |
112 | ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| { | 112 | acc.add(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| { |
113 | let result = &text[2..text.len() - 1]; | 113 | let result = &text[2..text.len() - 1]; |
114 | let result = if result.starts_with('\"') { | 114 | let result = if result.starts_with('\"') { |
115 | // FIXME: this logic is wrong, not only the last has has to handled specially | 115 | // FIXME: this logic is wrong, not only the last has has to handled specially |
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index e6e02f2ae..8eef578cf 100644 --- a/crates/ra_assists/src/handlers/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs | |||
@@ -3,7 +3,7 @@ use ra_syntax::{ | |||
3 | TextSize, T, | 3 | TextSize, T, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 6 | use crate::{AssistContext, AssistId, Assists}; |
7 | 7 | ||
8 | // Assist: remove_dbg | 8 | // Assist: remove_dbg |
9 | // | 9 | // |
@@ -20,7 +20,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
20 | // 92; | 20 | // 92; |
21 | // } | 21 | // } |
22 | // ``` | 22 | // ``` |
23 | pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> { | 23 | pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; | 24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; |
25 | 25 | ||
26 | if !is_valid_macrocall(¯o_call, "dbg")? { | 26 | if !is_valid_macrocall(¯o_call, "dbg")? { |
@@ -58,7 +58,7 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | let target = macro_call.syntax().text_range(); | 60 | let target = macro_call.syntax().text_range(); |
61 | ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { | 61 | acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { |
62 | edit.replace(macro_range, macro_content); | 62 | edit.replace(macro_range, macro_content); |
63 | edit.set_cursor(cursor_pos); | 63 | edit.set_cursor(cursor_pos); |
64 | }) | 64 | }) |
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs index 9f72f879d..dce546db7 100644 --- a/crates/ra_assists/src/handlers/remove_mut.rs +++ b/crates/ra_assists/src/handlers/remove_mut.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::{SyntaxKind, TextRange, T}; | 1 | use ra_syntax::{SyntaxKind, TextRange, T}; |
2 | 2 | ||
3 | use crate::{Assist, AssistCtx, AssistId}; | 3 | use crate::{AssistContext, AssistId, Assists}; |
4 | 4 | ||
5 | // Assist: remove_mut | 5 | // Assist: remove_mut |
6 | // | 6 | // |
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
17 | // fn feed(&self, amount: u32) {} | 17 | // fn feed(&self, amount: u32) {} |
18 | // } | 18 | // } |
19 | // ``` | 19 | // ``` |
20 | pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> { | 20 | pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
21 | let mut_token = ctx.find_token_at_offset(T![mut])?; | 21 | let mut_token = ctx.find_token_at_offset(T![mut])?; |
22 | let delete_from = mut_token.text_range().start(); | 22 | let delete_from = mut_token.text_range().start(); |
23 | let delete_to = match mut_token.next_token() { | 23 | let delete_to = match mut_token.next_token() { |
@@ -26,7 +26,7 @@ pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> { | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | let target = mut_token.text_range(); | 28 | let target = mut_token.text_range(); |
29 | ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { | 29 | acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { |
30 | edit.set_cursor(delete_from); | 30 | edit.set_cursor(delete_from); |
31 | edit.delete(TextRange::new(delete_from, delete_to)); | 31 | edit.delete(TextRange::new(delete_from, delete_to)); |
32 | }) | 32 | }) |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 0b930dea2..757f6406e 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -3,18 +3,9 @@ use std::collections::HashMap; | |||
3 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | 3 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; |
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; |
7 | algo, | 7 | |
8 | ast::{self, Path, RecordLit, RecordPat}, | 8 | use crate::{AssistContext, AssistId, Assists}; |
9 | match_ast, AstNode, SyntaxKind, | ||
10 | SyntaxKind::*, | ||
11 | SyntaxNode, | ||
12 | }; | ||
13 | |||
14 | use crate::{ | ||
15 | assist_ctx::{Assist, AssistCtx}, | ||
16 | AssistId, | ||
17 | }; | ||
18 | 9 | ||
19 | // Assist: reorder_fields | 10 | // Assist: reorder_fields |
20 | // | 11 | // |
@@ -31,13 +22,13 @@ use crate::{ | |||
31 | // const test: Foo = Foo {foo: 1, bar: 0} | 22 | // const test: Foo = Foo {foo: 1, bar: 0} |
32 | // ``` | 23 | // ``` |
33 | // | 24 | // |
34 | pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> { | 25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
35 | reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx)) | 26 | reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) |
36 | } | 27 | } |
37 | 28 | ||
38 | fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { | 29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
39 | let record = ctx.find_node_at_offset::<R>()?; | 30 | let record = ctx.find_node_at_offset::<R>()?; |
40 | let path = record.syntax().children().find_map(Path::cast)?; | 31 | let path = record.syntax().children().find_map(ast::Path::cast)?; |
41 | 32 | ||
42 | let ranks = compute_fields_ranks(&path, &ctx)?; | 33 | let ranks = compute_fields_ranks(&path, &ctx)?; |
43 | 34 | ||
@@ -51,7 +42,7 @@ fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { | |||
51 | } | 42 | } |
52 | 43 | ||
53 | let target = record.syntax().text_range(); | 44 | let target = record.syntax().text_range(); |
54 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { | 45 | acc.add(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { |
55 | for (old, new) in fields.iter().zip(&sorted_fields) { | 46 | for (old, new) in fields.iter().zip(&sorted_fields) { |
56 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | 47 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); |
57 | } | 48 | } |
@@ -96,9 +87,9 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option | |||
96 | } | 87 | } |
97 | } | 88 | } |
98 | 89 | ||
99 | fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> { | 90 | fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> { |
100 | Some( | 91 | Some( |
101 | struct_definition(path, ctx.sema)? | 92 | struct_definition(path, &ctx.sema)? |
102 | .fields(ctx.db) | 93 | .fields(ctx.db) |
103 | .iter() | 94 | .iter() |
104 | .enumerate() | 95 | .enumerate() |
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 2eb8348f8..a59a06efa 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | AstNode, | 4 | AstNode, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; | 7 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; |
8 | 8 | ||
9 | // Assist: replace_if_let_with_match | 9 | // Assist: replace_if_let_with_match |
10 | // | 10 | // |
@@ -32,7 +32,7 @@ use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; | |||
32 | // } | 32 | // } |
33 | // } | 33 | // } |
34 | // ``` | 34 | // ``` |
35 | pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | 35 | pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
36 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | 36 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; |
37 | let cond = if_expr.condition()?; | 37 | let cond = if_expr.condition()?; |
38 | let pat = cond.pat()?; | 38 | let pat = cond.pat()?; |
@@ -43,36 +43,31 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
43 | ast::ElseBranch::IfExpr(_) => return None, | 43 | ast::ElseBranch::IfExpr(_) => return None, |
44 | }; | 44 | }; |
45 | 45 | ||
46 | let sema = ctx.sema; | ||
47 | let target = if_expr.syntax().text_range(); | 46 | let target = if_expr.syntax().text_range(); |
48 | ctx.add_assist( | 47 | acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { |
49 | AssistId("replace_if_let_with_match"), | 48 | let match_expr = { |
50 | "Replace with match", | 49 | let then_arm = { |
51 | target, | 50 | let then_expr = unwrap_trivial_block(then_block); |
52 | move |edit| { | 51 | make::match_arm(vec![pat.clone()], then_expr) |
53 | let match_expr = { | ||
54 | let then_arm = { | ||
55 | let then_expr = unwrap_trivial_block(then_block); | ||
56 | make::match_arm(vec![pat.clone()], then_expr) | ||
57 | }; | ||
58 | let else_arm = { | ||
59 | let pattern = sema | ||
60 | .type_of_pat(&pat) | ||
61 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | ||
62 | .map(|it| it.sad_pattern()) | ||
63 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
64 | let else_expr = unwrap_trivial_block(else_block); | ||
65 | make::match_arm(vec![pattern], else_expr) | ||
66 | }; | ||
67 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
68 | }; | 52 | }; |
53 | let else_arm = { | ||
54 | let pattern = ctx | ||
55 | .sema | ||
56 | .type_of_pat(&pat) | ||
57 | .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) | ||
58 | .map(|it| it.sad_pattern()) | ||
59 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
60 | let else_expr = unwrap_trivial_block(else_block); | ||
61 | make::match_arm(vec![pattern], else_expr) | ||
62 | }; | ||
63 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
64 | }; | ||
69 | 65 | ||
70 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); | 66 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); |
71 | 67 | ||
72 | edit.set_cursor(if_expr.syntax().text_range().start()); | 68 | edit.set_cursor(if_expr.syntax().text_range().start()); |
73 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); | 69 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); |
74 | }, | 70 | }) |
75 | ) | ||
76 | } | 71 | } |
77 | 72 | ||
78 | #[cfg(test)] | 73 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index a5509a567..d3f214591 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -9,11 +9,7 @@ use ra_syntax::{ | |||
9 | AstNode, T, | 9 | AstNode, T, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; |
13 | assist_ctx::{Assist, AssistCtx}, | ||
14 | utils::TryEnum, | ||
15 | AssistId, | ||
16 | }; | ||
17 | 13 | ||
18 | // Assist: replace_let_with_if_let | 14 | // Assist: replace_let_with_if_let |
19 | // | 15 | // |
@@ -39,16 +35,16 @@ use crate::{ | |||
39 | // | 35 | // |
40 | // fn compute() -> Option<i32> { None } | 36 | // fn compute() -> Option<i32> { None } |
41 | // ``` | 37 | // ``` |
42 | pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | 38 | pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
43 | let let_kw = ctx.find_token_at_offset(T![let])?; | 39 | let let_kw = ctx.find_token_at_offset(T![let])?; |
44 | let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?; | 40 | let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?; |
45 | let init = let_stmt.initializer()?; | 41 | let init = let_stmt.initializer()?; |
46 | let original_pat = let_stmt.pat()?; | 42 | let original_pat = let_stmt.pat()?; |
47 | let ty = ctx.sema.type_of_expr(&init)?; | 43 | let ty = ctx.sema.type_of_expr(&init)?; |
48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); | 44 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty).map(|it| it.happy_case()); |
49 | 45 | ||
50 | let target = let_kw.text_range(); | 46 | let target = let_kw.text_range(); |
51 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { | 47 | acc.add(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { |
52 | let with_placeholder: ast::Pat = match happy_variant { | 48 | let with_placeholder: ast::Pat = match happy_variant { |
53 | None => make::placeholder_pat().into(), | 49 | None => make::placeholder_pat().into(), |
54 | Some(var_name) => make::tuple_struct_pat( | 50 | Some(var_name) => make::tuple_struct_pat( |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index fd41da64b..1a81d8a0e 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -1,11 +1,7 @@ | |||
1 | use hir; | 1 | use hir; |
2 | use ra_syntax::{ast, AstNode, SmolStr, TextRange}; | 2 | use ra_syntax::{ast, AstNode, SmolStr, TextRange}; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists}; |
5 | assist_ctx::{Assist, AssistCtx}, | ||
6 | utils::insert_use_statement, | ||
7 | AssistId, | ||
8 | }; | ||
9 | 5 | ||
10 | // Assist: replace_qualified_name_with_use | 6 | // Assist: replace_qualified_name_with_use |
11 | // | 7 | // |
@@ -20,7 +16,10 @@ use crate::{ | |||
20 | // | 16 | // |
21 | // fn process(map: HashMap<String, String>) {} | 17 | // fn process(map: HashMap<String, String>) {} |
22 | // ``` | 18 | // ``` |
23 | pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> { | 19 | pub(crate) fn replace_qualified_name_with_use( |
20 | acc: &mut Assists, | ||
21 | ctx: &AssistContext, | ||
22 | ) -> Option<()> { | ||
24 | let path: ast::Path = ctx.find_node_at_offset()?; | 23 | let path: ast::Path = ctx.find_node_at_offset()?; |
25 | // We don't want to mess with use statements | 24 | // We don't want to mess with use statements |
26 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { | 25 | if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { |
@@ -34,18 +33,18 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
34 | } | 33 | } |
35 | 34 | ||
36 | let target = path.syntax().text_range(); | 35 | let target = path.syntax().text_range(); |
37 | ctx.add_assist( | 36 | acc.add( |
38 | AssistId("replace_qualified_name_with_use"), | 37 | AssistId("replace_qualified_name_with_use"), |
39 | "Replace qualified path with use", | 38 | "Replace qualified path with use", |
40 | target, | 39 | target, |
41 | |edit| { | 40 | |builder| { |
42 | let path_to_import = hir_path.mod_path().clone(); | 41 | let path_to_import = hir_path.mod_path().clone(); |
43 | insert_use_statement(path.syntax(), &path_to_import, edit); | 42 | insert_use_statement(path.syntax(), &path_to_import, ctx, builder); |
44 | 43 | ||
45 | if let Some(last) = path.segment() { | 44 | if let Some(last) = path.segment() { |
46 | // Here we are assuming the assist will provide a correct use statement | 45 | // Here we are assuming the assist will provide a correct use statement |
47 | // so we can delete the path qualifier | 46 | // so we can delete the path qualifier |
48 | edit.delete(TextRange::new( | 47 | builder.delete(TextRange::new( |
49 | path.syntax().text_range().start(), | 48 | path.syntax().text_range().start(), |
50 | last.syntax().text_range().start(), | 49 | last.syntax().text_range().start(), |
51 | )); | 50 | )); |
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index c6b73da67..a46998b8e 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | AstNode, | 5 | AstNode, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; | 8 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; |
9 | 9 | ||
10 | // Assist: replace_unwrap_with_match | 10 | // Assist: replace_unwrap_with_match |
11 | // | 11 | // |
@@ -29,7 +29,7 @@ use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; | |||
29 | // }; | 29 | // }; |
30 | // } | 30 | // } |
31 | // ``` | 31 | // ``` |
32 | pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { | 32 | pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
33 | let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?; | 33 | let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?; |
34 | let name = method_call.name_ref()?; | 34 | let name = method_call.name_ref()?; |
35 | if name.text() != "unwrap" { | 35 | if name.text() != "unwrap" { |
@@ -37,33 +37,26 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
37 | } | 37 | } |
38 | let caller = method_call.expr()?; | 38 | let caller = method_call.expr()?; |
39 | let ty = ctx.sema.type_of_expr(&caller)?; | 39 | let ty = ctx.sema.type_of_expr(&caller)?; |
40 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case(); | 40 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); |
41 | let target = method_call.syntax().text_range(); | 41 | let target = method_call.syntax().text_range(); |
42 | ctx.add_assist( | 42 | acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |edit| { |
43 | AssistId("replace_unwrap_with_match"), | 43 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); |
44 | "Replace unwrap with match", | 44 | let it = make::bind_pat(make::name("a")).into(); |
45 | target, | 45 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); |
46 | |edit| { | ||
47 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | ||
48 | let it = make::bind_pat(make::name("a")).into(); | ||
49 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
50 | 46 | ||
51 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 47 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
52 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 48 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
53 | 49 | ||
54 | let unreachable_call = make::unreachable_macro_call().into(); | 50 | let unreachable_call = make::unreachable_macro_call().into(); |
55 | let err_arm = | 51 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); |
56 | make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | ||
57 | 52 | ||
58 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 53 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
59 | let match_expr = make::expr_match(caller.clone(), match_arm_list); | 54 | let match_expr = make::expr_match(caller.clone(), match_arm_list); |
60 | let match_expr = | 55 | let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); |
61 | IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | ||
62 | 56 | ||
63 | edit.set_cursor(caller.syntax().text_range().start()); | 57 | edit.set_cursor(caller.syntax().text_range().start()); |
64 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | 58 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); |
65 | }, | 59 | }) |
66 | ) | ||
67 | } | 60 | } |
68 | 61 | ||
69 | #[cfg(test)] | 62 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index d49563974..159033731 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
@@ -2,7 +2,7 @@ use std::iter::successors; | |||
2 | 2 | ||
3 | use ra_syntax::{ast, AstNode, T}; | 3 | use ra_syntax::{ast, AstNode, T}; |
4 | 4 | ||
5 | use crate::{Assist, AssistCtx, AssistId}; | 5 | use crate::{AssistContext, AssistId, Assists}; |
6 | 6 | ||
7 | // Assist: split_import | 7 | // Assist: split_import |
8 | // | 8 | // |
@@ -15,7 +15,7 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
15 | // ``` | 15 | // ``` |
16 | // use std::{collections::HashMap}; | 16 | // use std::{collections::HashMap}; |
17 | // ``` | 17 | // ``` |
18 | pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> { | 18 | pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
19 | let colon_colon = ctx.find_token_at_offset(T![::])?; | 19 | let colon_colon = ctx.find_token_at_offset(T![::])?; |
20 | let path = ast::Path::cast(colon_colon.parent())?.qualifier()?; | 20 | let path = ast::Path::cast(colon_colon.parent())?.qualifier()?; |
21 | let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; | 21 | let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; |
@@ -29,7 +29,7 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> { | |||
29 | let cursor = ctx.frange.range.start(); | 29 | let cursor = ctx.frange.range.start(); |
30 | 30 | ||
31 | let target = colon_colon.text_range(); | 31 | let target = colon_colon.text_range(); |
32 | ctx.add_assist(AssistId("split_import"), "Split import", target, |edit| { | 32 | acc.add(AssistId("split_import"), "Split import", target, |edit| { |
33 | edit.replace_ast(use_tree, new_tree); | 33 | edit.replace_ast(use_tree, new_tree); |
34 | edit.set_cursor(cursor); | 34 | edit.set_cursor(cursor); |
35 | }) | 35 | }) |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 6df927abb..eba0631a4 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use crate::{Assist, AssistCtx, AssistId}; | 1 | use crate::{AssistContext, AssistId, Assists}; |
2 | 2 | ||
3 | use ast::LoopBodyOwner; | 3 | use ast::LoopBodyOwner; |
4 | use ra_fmt::unwrap_trivial_block; | 4 | use ra_fmt::unwrap_trivial_block; |
@@ -21,7 +21,7 @@ use ra_syntax::{ast, match_ast, AstNode, TextRange, T}; | |||
21 | // println!("foo"); | 21 | // println!("foo"); |
22 | // } | 22 | // } |
23 | // ``` | 23 | // ``` |
24 | pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | 24 | pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
25 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | 25 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; |
26 | let block = ast::BlockExpr::cast(l_curly_token.parent())?; | 26 | let block = ast::BlockExpr::cast(l_curly_token.parent())?; |
27 | let parent = block.syntax().parent()?; | 27 | let parent = block.syntax().parent()?; |
@@ -58,7 +58,7 @@ pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | let target = expr_to_unwrap.syntax().text_range(); | 60 | let target = expr_to_unwrap.syntax().text_range(); |
61 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", target, |edit| { | 61 | acc.add(AssistId("unwrap_block"), "Unwrap block", target, |edit| { |
62 | edit.set_cursor(expr.syntax().text_range().start()); | 62 | edit.set_cursor(expr.syntax().text_range().start()); |
63 | 63 | ||
64 | let pat_start: &[_] = &[' ', '{', '\n']; | 64 | let pat_start: &[_] = &[' ', '{', '\n']; |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 0473fd8c2..011613762 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -10,7 +10,7 @@ macro_rules! eprintln { | |||
10 | ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; | 10 | ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; |
11 | } | 11 | } |
12 | 12 | ||
13 | mod assist_ctx; | 13 | mod assist_context; |
14 | mod marks; | 14 | mod marks; |
15 | #[cfg(test)] | 15 | #[cfg(test)] |
16 | mod tests; | 16 | mod tests; |
@@ -22,7 +22,7 @@ use ra_db::FileRange; | |||
22 | use ra_ide_db::{source_change::SourceChange, RootDatabase}; | 22 | use ra_ide_db::{source_change::SourceChange, RootDatabase}; |
23 | use ra_syntax::TextRange; | 23 | use ra_syntax::TextRange; |
24 | 24 | ||
25 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; | 25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
26 | 26 | ||
27 | /// Unique identifier of the assist, should not be shown to the user | 27 | /// Unique identifier of the assist, should not be shown to the user |
28 | /// directly. | 28 | /// directly. |
@@ -68,13 +68,12 @@ pub struct ResolvedAssist { | |||
68 | /// returned, without actual edits. | 68 | /// returned, without actual edits. |
69 | pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> { | 69 | pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabel> { |
70 | let sema = Semantics::new(db); | 70 | let sema = Semantics::new(db); |
71 | let ctx = AssistCtx::new(&sema, range, false); | 71 | let ctx = AssistContext::new(sema, range); |
72 | handlers::all() | 72 | let mut acc = Assists::new_unresolved(&ctx); |
73 | .iter() | 73 | handlers::all().iter().for_each(|handler| { |
74 | .filter_map(|f| f(ctx.clone())) | 74 | handler(&mut acc, &ctx); |
75 | .flat_map(|it| it.0) | 75 | }); |
76 | .map(|a| a.label) | 76 | acc.finish_unresolved() |
77 | .collect() | ||
78 | } | 77 | } |
79 | 78 | ||
80 | /// Return all the assists applicable at the given position. | 79 | /// Return all the assists applicable at the given position. |
@@ -83,31 +82,30 @@ pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabe | |||
83 | /// computed. | 82 | /// computed. |
84 | pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { | 83 | pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { |
85 | let sema = Semantics::new(db); | 84 | let sema = Semantics::new(db); |
86 | let ctx = AssistCtx::new(&sema, range, true); | 85 | let ctx = AssistContext::new(sema, range); |
87 | let mut a = handlers::all() | 86 | let mut acc = Assists::new_resolved(&ctx); |
88 | .iter() | 87 | handlers::all().iter().for_each(|handler| { |
89 | .filter_map(|f| f(ctx.clone())) | 88 | handler(&mut acc, &ctx); |
90 | .flat_map(|it| it.0) | 89 | }); |
91 | .map(|it| it.into_resolved().unwrap()) | 90 | acc.finish_resolved() |
92 | .collect::<Vec<_>>(); | ||
93 | a.sort_by_key(|it| it.label.target.len()); | ||
94 | a | ||
95 | } | 91 | } |
96 | 92 | ||
97 | mod handlers { | 93 | mod handlers { |
98 | use crate::{Assist, AssistCtx}; | 94 | use crate::{AssistContext, Assists}; |
99 | 95 | ||
100 | pub(crate) type Handler = fn(AssistCtx) -> Option<Assist>; | 96 | pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>; |
101 | 97 | ||
102 | mod add_custom_impl; | 98 | mod add_custom_impl; |
103 | mod add_derive; | 99 | mod add_derive; |
104 | mod add_explicit_type; | 100 | mod add_explicit_type; |
101 | mod add_from_impl_for_enum; | ||
105 | mod add_function; | 102 | mod add_function; |
106 | mod add_impl; | 103 | mod add_impl; |
107 | mod add_missing_impl_members; | 104 | mod add_missing_impl_members; |
108 | mod add_new; | 105 | mod add_new; |
109 | mod apply_demorgan; | 106 | mod apply_demorgan; |
110 | mod auto_import; | 107 | mod auto_import; |
108 | mod change_return_type_to_result; | ||
111 | mod change_visibility; | 109 | mod change_visibility; |
112 | mod early_return; | 110 | mod early_return; |
113 | mod fill_match_arms; | 111 | mod fill_match_arms; |
@@ -124,14 +122,12 @@ mod handlers { | |||
124 | mod raw_string; | 122 | mod raw_string; |
125 | mod remove_dbg; | 123 | mod remove_dbg; |
126 | mod remove_mut; | 124 | mod remove_mut; |
125 | mod reorder_fields; | ||
127 | mod replace_if_let_with_match; | 126 | mod replace_if_let_with_match; |
128 | mod replace_let_with_if_let; | 127 | mod replace_let_with_if_let; |
129 | mod replace_qualified_name_with_use; | 128 | mod replace_qualified_name_with_use; |
130 | mod replace_unwrap_with_match; | 129 | mod replace_unwrap_with_match; |
131 | mod split_import; | 130 | mod split_import; |
132 | mod change_return_type_to_result; | ||
133 | mod add_from_impl_for_enum; | ||
134 | mod reorder_fields; | ||
135 | mod unwrap_block; | 131 | mod unwrap_block; |
136 | 132 | ||
137 | pub(crate) fn all() -> &'static [Handler] { | 133 | pub(crate) fn all() -> &'static [Handler] { |
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 17e3ece9f..45b2d9733 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -11,7 +11,7 @@ use test_utils::{ | |||
11 | RangeOrOffset, | 11 | RangeOrOffset, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{handlers::Handler, resolved_assists, AssistCtx}; | 14 | use crate::{handlers::Handler, resolved_assists, AssistContext, Assists}; |
15 | 15 | ||
16 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 16 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { |
17 | let (mut db, file_id) = RootDatabase::with_single_file(text); | 17 | let (mut db, file_id) = RootDatabase::with_single_file(text); |
@@ -71,7 +71,7 @@ enum ExpectedResult<'a> { | |||
71 | Target(&'a str), | 71 | Target(&'a str), |
72 | } | 72 | } |
73 | 73 | ||
74 | fn check(assist: Handler, before: &str, expected: ExpectedResult) { | 74 | fn check(handler: Handler, before: &str, expected: ExpectedResult) { |
75 | let (text_without_caret, file_with_caret_id, range_or_offset, db) = if before.contains("//-") { | 75 | let (text_without_caret, file_with_caret_id, range_or_offset, db) = if before.contains("//-") { |
76 | let (mut db, position) = RootDatabase::with_position(before); | 76 | let (mut db, position) = RootDatabase::with_position(before); |
77 | db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)])); | 77 | db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)])); |
@@ -90,17 +90,20 @@ fn check(assist: Handler, before: &str, expected: ExpectedResult) { | |||
90 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; | 90 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; |
91 | 91 | ||
92 | let sema = Semantics::new(&db); | 92 | let sema = Semantics::new(&db); |
93 | let assist_ctx = AssistCtx::new(&sema, frange, true); | 93 | let ctx = AssistContext::new(sema, frange); |
94 | 94 | let mut acc = Assists::new_resolved(&ctx); | |
95 | match (assist(assist_ctx), expected) { | 95 | handler(&mut acc, &ctx); |
96 | let mut res = acc.finish_resolved(); | ||
97 | let assist = res.pop(); | ||
98 | match (assist, expected) { | ||
96 | (Some(assist), ExpectedResult::After(after)) => { | 99 | (Some(assist), ExpectedResult::After(after)) => { |
97 | let mut action = assist.0[0].source_change.clone().unwrap(); | 100 | let mut source_change = assist.source_change; |
98 | let change = action.source_file_edits.pop().unwrap(); | 101 | let change = source_change.source_file_edits.pop().unwrap(); |
99 | 102 | ||
100 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); | 103 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); |
101 | change.edit.apply(&mut actual); | 104 | change.edit.apply(&mut actual); |
102 | 105 | ||
103 | match action.cursor_position { | 106 | match source_change.cursor_position { |
104 | None => { | 107 | None => { |
105 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { | 108 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { |
106 | let off = change | 109 | let off = change |
@@ -116,7 +119,7 @@ fn check(assist: Handler, before: &str, expected: ExpectedResult) { | |||
116 | assert_eq_text!(after, &actual); | 119 | assert_eq_text!(after, &actual); |
117 | } | 120 | } |
118 | (Some(assist), ExpectedResult::Target(target)) => { | 121 | (Some(assist), ExpectedResult::Target(target)) => { |
119 | let range = assist.0[0].label.target; | 122 | let range = assist.label.target; |
120 | assert_eq_text!(&text_without_caret[range], target); | 123 | assert_eq_text!(&text_without_caret[range], target); |
121 | } | 124 | } |
122 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 125 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index c1f447efe..1214e3cd4 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs | |||
@@ -2,7 +2,6 @@ | |||
2 | // FIXME: rewrite according to the plan, outlined in | 2 | // FIXME: rewrite according to the plan, outlined in |
3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 | 3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 |
4 | 4 | ||
5 | use crate::assist_ctx::ActionBuilder; | ||
6 | use hir::{self, ModPath}; | 5 | use hir::{self, ModPath}; |
7 | use ra_syntax::{ | 6 | use ra_syntax::{ |
8 | ast::{self, NameOwner}, | 7 | ast::{self, NameOwner}, |
@@ -12,6 +11,8 @@ use ra_syntax::{ | |||
12 | }; | 11 | }; |
13 | use ra_text_edit::TextEditBuilder; | 12 | use ra_text_edit::TextEditBuilder; |
14 | 13 | ||
14 | use crate::assist_context::{AssistBuilder, AssistContext}; | ||
15 | |||
15 | /// Creates and inserts a use statement for the given path to import. | 16 | /// Creates and inserts a use statement for the given path to import. |
16 | /// The use statement is inserted in the scope most appropriate to the | 17 | /// The use statement is inserted in the scope most appropriate to the |
17 | /// the cursor position given, additionally merged with the existing use imports. | 18 | /// the cursor position given, additionally merged with the existing use imports. |
@@ -19,10 +20,11 @@ pub(crate) fn insert_use_statement( | |||
19 | // Ideally the position of the cursor, used to | 20 | // Ideally the position of the cursor, used to |
20 | position: &SyntaxNode, | 21 | position: &SyntaxNode, |
21 | path_to_import: &ModPath, | 22 | path_to_import: &ModPath, |
22 | edit: &mut ActionBuilder, | 23 | ctx: &AssistContext, |
24 | builder: &mut AssistBuilder, | ||
23 | ) { | 25 | ) { |
24 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); | 26 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); |
25 | let container = edit.ctx().sema.ancestors_with_macros(position.clone()).find_map(|n| { | 27 | let container = ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| { |
26 | if let Some(module) = ast::Module::cast(n.clone()) { | 28 | if let Some(module) = ast::Module::cast(n.clone()) { |
27 | return module.item_list().map(|it| it.syntax().clone()); | 29 | return module.item_list().map(|it| it.syntax().clone()); |
28 | } | 30 | } |
@@ -31,7 +33,7 @@ pub(crate) fn insert_use_statement( | |||
31 | 33 | ||
32 | if let Some(container) = container { | 34 | if let Some(container) = container { |
33 | let action = best_action_for_target(container, position.clone(), &target); | 35 | let action = best_action_for_target(container, position.clone(), &target); |
34 | make_assist(&action, &target, edit.text_edit_builder()); | 36 | make_assist(&action, &target, builder.text_edit_builder()); |
35 | } | 37 | } |
36 | } | 38 | } |
37 | 39 | ||