diff options
36 files changed, 292 insertions, 256 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 83dd270c6..600e5689c 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -94,9 +94,10 @@ impl<'a> AssistCtx<'a> { | |||
94 | self, | 94 | self, |
95 | id: AssistId, | 95 | id: AssistId, |
96 | label: impl Into<String>, | 96 | label: impl Into<String>, |
97 | target: TextRange, | ||
97 | f: impl FnOnce(&mut ActionBuilder), | 98 | f: impl FnOnce(&mut ActionBuilder), |
98 | ) -> Option<Assist> { | 99 | ) -> Option<Assist> { |
99 | let label = AssistLabel::new(id, label.into(), None); | 100 | let label = AssistLabel::new(id, label.into(), None, target); |
100 | 101 | ||
101 | let mut info = AssistInfo::new(label); | 102 | let mut info = AssistInfo::new(label); |
102 | if self.should_compute_edit { | 103 | if self.should_compute_edit { |
@@ -152,9 +153,10 @@ impl<'a> AssistGroup<'a> { | |||
152 | &mut self, | 153 | &mut self, |
153 | id: AssistId, | 154 | id: AssistId, |
154 | label: impl Into<String>, | 155 | label: impl Into<String>, |
156 | target: TextRange, | ||
155 | f: impl FnOnce(&mut ActionBuilder), | 157 | f: impl FnOnce(&mut ActionBuilder), |
156 | ) { | 158 | ) { |
157 | let label = AssistLabel::new(id, label.into(), Some(self.group.clone())); | 159 | let label = AssistLabel::new(id, label.into(), Some(self.group.clone()), target); |
158 | 160 | ||
159 | let mut info = AssistInfo::new(label).with_group(self.group.clone()); | 161 | let mut info = AssistInfo::new(label).with_group(self.group.clone()); |
160 | if self.ctx.should_compute_edit { | 162 | if self.ctx.should_compute_edit { |
@@ -181,7 +183,6 @@ impl<'a> AssistGroup<'a> { | |||
181 | pub(crate) struct ActionBuilder<'a, 'b> { | 183 | pub(crate) struct ActionBuilder<'a, 'b> { |
182 | edit: TextEditBuilder, | 184 | edit: TextEditBuilder, |
183 | cursor_position: Option<TextSize>, | 185 | cursor_position: Option<TextSize>, |
184 | target: Option<TextRange>, | ||
185 | file: AssistFile, | 186 | file: AssistFile, |
186 | ctx: &'a AssistCtx<'b>, | 187 | ctx: &'a AssistCtx<'b>, |
187 | } | 188 | } |
@@ -191,7 +192,6 @@ impl<'a, 'b> ActionBuilder<'a, 'b> { | |||
191 | Self { | 192 | Self { |
192 | edit: TextEditBuilder::default(), | 193 | edit: TextEditBuilder::default(), |
193 | cursor_position: None, | 194 | cursor_position: None, |
194 | target: None, | ||
195 | file: AssistFile::default(), | 195 | file: AssistFile::default(), |
196 | ctx, | 196 | ctx, |
197 | } | 197 | } |
@@ -237,14 +237,6 @@ impl<'a, 'b> ActionBuilder<'a, 'b> { | |||
237 | self.cursor_position = Some(offset) | 237 | self.cursor_position = Some(offset) |
238 | } | 238 | } |
239 | 239 | ||
240 | /// Specify that the assist should be active withing the `target` range. | ||
241 | /// | ||
242 | /// Target ranges are used to sort assists: the smaller the target range, | ||
243 | /// the more specific assist is, and so it should be sorted first. | ||
244 | pub(crate) fn target(&mut self, target: TextRange) { | ||
245 | self.target = Some(target) | ||
246 | } | ||
247 | |||
248 | /// Get access to the raw `TextEditBuilder`. | 240 | /// Get access to the raw `TextEditBuilder`. |
249 | pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { | 241 | pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { |
250 | &mut self.edit | 242 | &mut self.edit |
@@ -267,7 +259,6 @@ impl<'a, 'b> ActionBuilder<'a, 'b> { | |||
267 | AssistAction { | 259 | AssistAction { |
268 | edit: self.edit.finish(), | 260 | edit: self.edit.finish(), |
269 | cursor_position: self.cursor_position, | 261 | cursor_position: self.cursor_position, |
270 | target: self.target, | ||
271 | file: self.file, | 262 | file: self.file, |
272 | } | 263 | } |
273 | } | 264 | } |
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index b72f7aeac..869d4dc04 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -48,9 +48,8 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { | |||
48 | let label = | 48 | let label = |
49 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); | 49 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); |
50 | 50 | ||
51 | ctx.add_assist(AssistId("add_custom_impl"), label, |edit| { | 51 | let target = attr.syntax().text_range(); |
52 | edit.target(attr.syntax().text_range()); | 52 | ctx.add_assist(AssistId("add_custom_impl"), label, target, |edit| { |
53 | |||
54 | let new_attr_input = input | 53 | let new_attr_input = input |
55 | .syntax() | 54 | .syntax() |
56 | .descendants_with_tokens() | 55 | .descendants_with_tokens() |
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs index 3629dac6b..2a6bb1cae 100644 --- a/crates/ra_assists/src/handlers/add_derive.rs +++ b/crates/ra_assists/src/handlers/add_derive.rs | |||
@@ -27,7 +27,8 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
27 | pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { | 27 | pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { |
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 | ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", |edit| { | 30 | let target = nominal.syntax().text_range(); |
31 | ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { | ||
31 | let derive_attr = nominal | 32 | let derive_attr = nominal |
32 | .attrs() | 33 | .attrs() |
33 | .filter_map(|x| x.as_simple_call()) | 34 | .filter_map(|x| x.as_simple_call()) |
@@ -41,7 +42,6 @@ pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { | |||
41 | } | 42 | } |
42 | Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'), | 43 | Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'), |
43 | }; | 44 | }; |
44 | edit.target(nominal.syntax().text_range()); | ||
45 | edit.set_cursor(offset) | 45 | edit.set_cursor(offset) |
46 | }) | 46 | }) |
47 | } | 47 | } |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index e39e1f4f3..a59ec16b2 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -62,8 +62,8 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> { | |||
62 | ctx.add_assist( | 62 | ctx.add_assist( |
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 | |edit| { | 66 | |edit| { |
66 | edit.target(pat_range); | ||
67 | if let Some(ascribed_ty) = ascribed_ty { | 67 | if let Some(ascribed_ty) = ascribed_ty { |
68 | edit.replace(ascribed_ty.syntax().text_range(), new_type_string); | 68 | edit.replace(ascribed_ty.syntax().text_range(), new_type_string); |
69 | } else { | 69 | } else { |
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 ee0d5ce98..81deb3dfa 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 | |||
@@ -47,9 +47,11 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { | |||
47 | return None; | 47 | return None; |
48 | } | 48 | } |
49 | 49 | ||
50 | let target = variant.syntax().text_range(); | ||
50 | ctx.add_assist( | 51 | ctx.add_assist( |
51 | AssistId("add_from_impl_for_enum"), | 52 | AssistId("add_from_impl_for_enum"), |
52 | "Add From impl for this enum variant", | 53 | "Add From impl for this enum variant", |
54 | target, | ||
53 | |edit| { | 55 | |edit| { |
54 | let start_offset = variant.parent_enum().syntax().text_range().end(); | 56 | let start_offset = variant.parent_enum().syntax().text_range().end(); |
55 | let mut buf = String::new(); | 57 | let mut buf = String::new(); |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index cb2afc863..76c0f9783 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -57,9 +57,9 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { | |||
57 | 57 | ||
58 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 58 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; |
59 | 59 | ||
60 | ctx.add_assist(AssistId("add_function"), "Add function", |edit| { | 60 | let target = call.syntax().text_range(); |
61 | edit.target(call.syntax().text_range()); | 61 | // TODO: assert here? |
62 | 62 | ctx.add_assist(AssistId("add_function"), "Add function", target, |edit| { | |
63 | if let Some(function_template) = function_builder.render() { | 63 | if let Some(function_template) = function_builder.render() { |
64 | edit.set_file(function_template.file); | 64 | edit.set_file(function_template.file); |
65 | edit.set_cursor(function_template.cursor_offset); | 65 | edit.set_cursor(function_template.cursor_offset); |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index 3d390c20b..557344ebb 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -28,33 +28,40 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
28 | pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { | 28 | pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { |
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 | ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| { | 31 | let target = nominal.syntax().text_range(); |
32 | edit.target(nominal.syntax().text_range()); | 32 | ctx.add_assist( |
33 | let type_params = nominal.type_param_list(); | 33 | AssistId("add_impl"), |
34 | let start_offset = nominal.syntax().text_range().end(); | 34 | format!("Implement {}", name.text().as_str()), |
35 | let mut buf = String::new(); | 35 | target, |
36 | buf.push_str("\n\nimpl"); | 36 | |edit| { |
37 | if let Some(type_params) = &type_params { | 37 | let type_params = nominal.type_param_list(); |
38 | format_to!(buf, "{}", type_params.syntax()); | 38 | let start_offset = nominal.syntax().text_range().end(); |
39 | } | 39 | let mut buf = String::new(); |
40 | buf.push_str(" "); | 40 | buf.push_str("\n\nimpl"); |
41 | buf.push_str(name.text().as_str()); | 41 | if let Some(type_params) = &type_params { |
42 | if let Some(type_params) = type_params { | 42 | format_to!(buf, "{}", type_params.syntax()); |
43 | let lifetime_params = type_params | 43 | } |
44 | .lifetime_params() | 44 | buf.push_str(" "); |
45 | .filter_map(|it| it.lifetime_token()) | 45 | buf.push_str(name.text().as_str()); |
46 | .map(|it| it.text().clone()); | 46 | if let Some(type_params) = type_params { |
47 | let type_params = | 47 | let lifetime_params = type_params |
48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 48 | .lifetime_params() |
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()); | ||
49 | 55 | ||
50 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 56 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); |
51 | format_to!(buf, "<{}>", generic_params) | 57 | format_to!(buf, "<{}>", generic_params) |
52 | } | 58 | } |
53 | buf.push_str(" {\n"); | 59 | buf.push_str(" {\n"); |
54 | edit.set_cursor(start_offset + TextSize::of(&buf)); | 60 | edit.set_cursor(start_offset + TextSize::of(&buf)); |
55 | buf.push_str("\n}"); | 61 | buf.push_str("\n}"); |
56 | edit.insert(start_offset, buf); | 62 | edit.insert(start_offset, buf); |
57 | }) | 63 | }, |
64 | ) | ||
58 | } | 65 | } |
59 | 66 | ||
60 | #[cfg(test)] | 67 | #[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 f7a101503..7df786590 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -107,10 +107,10 @@ fn add_missing_impl_members_inner( | |||
107 | label: &'static str, | 107 | label: &'static str, |
108 | ) -> Option<Assist> { | 108 | ) -> Option<Assist> { |
109 | let _p = ra_prof::profile("add_missing_impl_members_inner"); | 109 | let _p = ra_prof::profile("add_missing_impl_members_inner"); |
110 | let impl_node = ctx.find_node_at_offset::<ast::ImplDef>()?; | 110 | let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?; |
111 | let impl_item_list = impl_node.item_list()?; | 111 | let impl_item_list = impl_def.item_list()?; |
112 | 112 | ||
113 | let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?; | 113 | let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; |
114 | 114 | ||
115 | let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { | 115 | let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { |
116 | match item { | 116 | match item { |
@@ -121,7 +121,7 @@ fn add_missing_impl_members_inner( | |||
121 | .map(|it| it.text().clone()) | 121 | .map(|it| it.text().clone()) |
122 | }; | 122 | }; |
123 | 123 | ||
124 | let missing_items = get_missing_assoc_items(&ctx.sema, &impl_node) | 124 | let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) |
125 | .iter() | 125 | .iter() |
126 | .map(|i| match i { | 126 | .map(|i| match i { |
127 | hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), | 127 | hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), |
@@ -143,13 +143,13 @@ fn add_missing_impl_members_inner( | |||
143 | } | 143 | } |
144 | 144 | ||
145 | let sema = ctx.sema; | 145 | let sema = ctx.sema; |
146 | 146 | let target = impl_def.syntax().text_range(); | |
147 | ctx.add_assist(AssistId(assist_id), label, |edit| { | 147 | ctx.add_assist(AssistId(assist_id), label, target, |edit| { |
148 | let n_existing_items = impl_item_list.assoc_items().count(); | 148 | let n_existing_items = impl_item_list.assoc_items().count(); |
149 | let source_scope = sema.scope_for_def(trait_); | 149 | let source_scope = sema.scope_for_def(trait_); |
150 | let target_scope = sema.scope(impl_item_list.syntax()); | 150 | let target_scope = sema.scope(impl_item_list.syntax()); |
151 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) | 151 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) |
152 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_node)); | 152 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); |
153 | let items = missing_items | 153 | let items = missing_items |
154 | .into_iter() | 154 | .into_iter() |
155 | .map(|it| ast_transform::apply(&*ast_transform, it)) | 155 | .map(|it| ast_transform::apply(&*ast_transform, it)) |
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index 1b5d604d1..1c3f8435a 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
@@ -41,9 +41,8 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { | |||
41 | // Return early if we've found an existing new fn | 41 | // Return early if we've found an existing new fn |
42 | let impl_def = find_struct_impl(&ctx, &strukt)?; | 42 | let impl_def = find_struct_impl(&ctx, &strukt)?; |
43 | 43 | ||
44 | ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| { | 44 | let target = strukt.syntax().text_range(); |
45 | edit.target(strukt.syntax().text_range()); | 45 | ctx.add_assist(AssistId("add_new"), "Add default constructor", target, |edit| { |
46 | |||
47 | let mut buf = String::with_capacity(512); | 46 | let mut buf = String::with_capacity(512); |
48 | 47 | ||
49 | if impl_def.is_some() { | 48 | if impl_def.is_some() { |
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index a0c48d872..a5b26e5b9 100644 --- a/crates/ra_assists/src/handlers/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -39,8 +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", |edit| { | 42 | ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { |
43 | edit.target(op_range); | ||
44 | edit.replace(op_range, opposite_op); | 43 | edit.replace(op_range, opposite_op); |
45 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); | 44 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); |
46 | 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 9e4171ccd..2224b9714 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -48,8 +48,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
48 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; | 48 | 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()); | 49 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); |
50 | for import in proposed_imports { | 50 | for import in proposed_imports { |
51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { | 51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), range, |edit| { |
52 | edit.target(range); | ||
53 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); | 52 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); |
54 | }); | 53 | }); |
55 | } | 54 | } |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 6ac1f8e69..489db83e6 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -66,11 +66,15 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> { | |||
66 | return None; | 66 | return None; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { | 69 | ctx.add_assist( |
70 | edit.target(target); | 70 | AssistId("change_visibility"), |
71 | edit.insert(offset, "pub(crate) "); | 71 | "Change visibility to pub(crate)", |
72 | edit.set_cursor(offset); | 72 | target, |
73 | }) | 73 | |edit| { |
74 | edit.insert(offset, "pub(crate) "); | ||
75 | edit.set_cursor(offset); | ||
76 | }, | ||
77 | ) | ||
74 | } | 78 | } |
75 | 79 | ||
76 | fn vis_offset(node: &SyntaxNode) -> TextSize { | 80 | fn vis_offset(node: &SyntaxNode) -> TextSize { |
@@ -86,22 +90,28 @@ fn vis_offset(node: &SyntaxNode) -> TextSize { | |||
86 | 90 | ||
87 | fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | 91 | fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { |
88 | if vis.syntax().text() == "pub" { | 92 | if vis.syntax().text() == "pub" { |
93 | let target = vis.syntax().text_range(); | ||
89 | return ctx.add_assist( | 94 | return ctx.add_assist( |
90 | AssistId("change_visibility"), | 95 | AssistId("change_visibility"), |
91 | "Change Visibility to pub(crate)", | 96 | "Change Visibility to pub(crate)", |
97 | target, | ||
92 | |edit| { | 98 | |edit| { |
93 | edit.target(vis.syntax().text_range()); | ||
94 | edit.replace(vis.syntax().text_range(), "pub(crate)"); | 99 | edit.replace(vis.syntax().text_range(), "pub(crate)"); |
95 | edit.set_cursor(vis.syntax().text_range().start()) | 100 | edit.set_cursor(vis.syntax().text_range().start()) |
96 | }, | 101 | }, |
97 | ); | 102 | ); |
98 | } | 103 | } |
99 | if vis.syntax().text() == "pub(crate)" { | 104 | if vis.syntax().text() == "pub(crate)" { |
100 | return ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub", |edit| { | 105 | let target = vis.syntax().text_range(); |
101 | edit.target(vis.syntax().text_range()); | 106 | return ctx.add_assist( |
102 | edit.replace(vis.syntax().text_range(), "pub"); | 107 | AssistId("change_visibility"), |
103 | edit.set_cursor(vis.syntax().text_range().start()); | 108 | "Change visibility to pub", |
104 | }); | 109 | target, |
110 | |edit| { | ||
111 | edit.replace(vis.syntax().text_range(), "pub"); | ||
112 | edit.set_cursor(vis.syntax().text_range().start()); | ||
113 | }, | ||
114 | ); | ||
105 | } | 115 | } |
106 | None | 116 | None |
107 | } | 117 | } |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 55ccc37b0..4bd6040b2 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -95,89 +95,94 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
96 | let cursor_position = ctx.frange.range.start(); | 96 | let cursor_position = ctx.frange.range.start(); |
97 | 97 | ||
98 | ctx.add_assist(AssistId("convert_to_guarded_return"), "Convert to guarded return", |edit| { | 98 | let target = if_expr.syntax().text_range(); |
99 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 99 | ctx.add_assist( |
100 | let new_block = match if_let_pat { | 100 | AssistId("convert_to_guarded_return"), |
101 | None => { | 101 | "Convert to guarded return", |
102 | // If. | 102 | target, |
103 | let new_expr = { | 103 | |edit| { |
104 | let then_branch = | 104 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
105 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); | 105 | let new_block = match if_let_pat { |
106 | let cond = invert_boolean_expression(cond_expr); | 106 | None => { |
107 | let e = make::expr_if(make::condition(cond, None), then_branch); | 107 | // If. |
108 | if_indent_level.increase_indent(e) | 108 | let new_expr = { |
109 | }; | 109 | let then_branch = |
110 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | 110 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); |
111 | } | 111 | let cond = invert_boolean_expression(cond_expr); |
112 | Some((path, bound_ident)) => { | 112 | let e = make::expr_if(make::condition(cond, None), then_branch); |
113 | // If-let. | 113 | if_indent_level.increase_indent(e) |
114 | let match_expr = { | ||
115 | let happy_arm = { | ||
116 | let pat = make::tuple_struct_pat( | ||
117 | path, | ||
118 | once(make::bind_pat(make::name("it")).into()), | ||
119 | ); | ||
120 | let expr = { | ||
121 | let name_ref = make::name_ref("it"); | ||
122 | let segment = make::path_segment(name_ref); | ||
123 | let path = make::path_unqualified(segment); | ||
124 | make::expr_path(path) | ||
125 | }; | ||
126 | make::match_arm(once(pat.into()), expr) | ||
127 | }; | 114 | }; |
115 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | ||
116 | } | ||
117 | Some((path, bound_ident)) => { | ||
118 | // If-let. | ||
119 | let match_expr = { | ||
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 | }; | ||
128 | 133 | ||
129 | let sad_arm = make::match_arm( | 134 | let sad_arm = make::match_arm( |
130 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate | 135 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate |
131 | once(make::placeholder_pat().into()), | 136 | once(make::placeholder_pat().into()), |
132 | early_expression, | 137 | early_expression, |
133 | ); | 138 | ); |
134 | 139 | ||
135 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) | 140 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) |
136 | }; | 141 | }; |
137 | 142 | ||
138 | let let_stmt = make::let_stmt( | 143 | let let_stmt = make::let_stmt( |
139 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), | 144 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), |
140 | Some(match_expr), | 145 | Some(match_expr), |
146 | ); | ||
147 | let let_stmt = if_indent_level.increase_indent(let_stmt); | ||
148 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | ||
149 | } | ||
150 | }; | ||
151 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | ||
152 | edit.set_cursor(cursor_position); | ||
153 | |||
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), | ||
141 | ); | 174 | ); |
142 | let let_stmt = if_indent_level.increase_indent(let_stmt); | 175 | replace_children( |
143 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | 176 | &parent_block.syntax(), |
177 | RangeInclusive::new( | ||
178 | if_expr.clone().syntax().clone().into(), | ||
179 | if_expr.syntax().clone().into(), | ||
180 | ), | ||
181 | &mut then_statements, | ||
182 | ) | ||
144 | } | 183 | } |
145 | }; | 184 | }, |
146 | edit.target(if_expr.syntax().text_range()); | 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 | }) | ||
181 | } | 186 | } |
182 | 187 | ||
183 | #[cfg(test)] | 188 | #[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 1f9cd5585..7c8f8bdf2 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -92,10 +92,9 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
92 | return None; | 92 | return None; |
93 | } | 93 | } |
94 | 94 | ||
95 | ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", |edit| { | 95 | let target = match_expr.syntax().text_range(); |
96 | ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { | ||
96 | 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); |
97 | |||
98 | edit.target(match_expr.syntax().text_range()); | ||
99 | edit.set_cursor(expr.syntax().text_range().start()); | 98 | edit.set_cursor(expr.syntax().text_range().start()); |
100 | edit.replace_ast(match_arm_list, new_arm_list); | 99 | edit.replace_ast(match_arm_list, new_arm_list); |
101 | }) | 100 | }) |
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index 41db963dc..cb7264d7b 100644 --- a/crates/ra_assists/src/handlers/flip_binexpr.rs +++ b/crates/ra_assists/src/handlers/flip_binexpr.rs | |||
@@ -33,8 +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", |edit| { | 36 | ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { |
37 | edit.target(op_range); | ||
38 | if let FlipAction::FlipAndReplaceOp(new_op) = action { | 37 | if let FlipAction::FlipAndReplaceOp(new_op) = action { |
39 | edit.replace(op_range, new_op); | 38 | edit.replace(op_range, new_op); |
40 | } | 39 | } |
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index e65c9a41d..24982ae22 100644 --- a/crates/ra_assists/src/handlers/flip_comma.rs +++ b/crates/ra_assists/src/handlers/flip_comma.rs | |||
@@ -28,8 +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", |edit| { | 31 | ctx.add_assist(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { |
32 | edit.target(comma.text_range()); | ||
33 | edit.replace(prev.text_range(), next.to_string()); | 32 | edit.replace(prev.text_range(), next.to_string()); |
34 | edit.replace(next.text_range(), prev.to_string()); | 33 | edit.replace(next.text_range(), prev.to_string()); |
35 | }) | 34 | }) |
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index f186da585..6a3b2df67 100644 --- a/crates/ra_assists/src/handlers/flip_trait_bound.rs +++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs | |||
@@ -32,8 +32,8 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> { | |||
32 | non_trivia_sibling(plus.clone().into(), Direction::Next)?, | 32 | non_trivia_sibling(plus.clone().into(), Direction::Next)?, |
33 | ); | 33 | ); |
34 | 34 | ||
35 | ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", |edit| { | 35 | let target = plus.text_range(); |
36 | edit.target(plus.text_range()); | 36 | ctx.add_assist(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 5f3b8dfd1..e5765c845 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -106,9 +106,11 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
106 | let init_str = initializer_expr.syntax().text().to_string(); | 106 | let init_str = initializer_expr.syntax().text().to_string(); |
107 | let init_in_paren = format!("({})", &init_str); | 107 | let init_in_paren = format!("({})", &init_str); |
108 | 108 | ||
109 | let target = bind_pat.syntax().text_range(); | ||
109 | ctx.add_assist( | 110 | ctx.add_assist( |
110 | AssistId("inline_local_variable"), | 111 | AssistId("inline_local_variable"), |
111 | "Inline variable", | 112 | "Inline variable", |
113 | target, | ||
112 | move |edit: &mut ActionBuilder| { | 114 | move |edit: &mut ActionBuilder| { |
113 | edit.delete(delete_range); | 115 | edit.delete(delete_range); |
114 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { | 116 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 9c2c20b22..3c340ff3b 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -42,7 +42,8 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
42 | if indent.kind() != WHITESPACE { | 42 | if indent.kind() != WHITESPACE { |
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", move |edit| { | 45 | let target = expr.syntax().text_range(); |
46 | ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { | ||
46 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
47 | 48 | ||
48 | let cursor_offset = if wrap_in_block { | 49 | let cursor_offset = if wrap_in_block { |
@@ -79,7 +80,6 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
79 | buf.push_str(text); | 80 | buf.push_str(text); |
80 | } | 81 | } |
81 | 82 | ||
82 | edit.target(expr.syntax().text_range()); | ||
83 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); | 83 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); |
84 | edit.insert(anchor_stmt.text_range().start(), buf); | 84 | edit.insert(anchor_stmt.text_range().start(), buf); |
85 | if wrap_in_block { | 85 | 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 303c1806d..b16271443 100644 --- a/crates/ra_assists/src/handlers/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -47,8 +47,7 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { | |||
47 | let else_node = else_block.syntax(); | 47 | let else_node = else_block.syntax(); |
48 | let else_range = else_node.text_range(); | 48 | let else_range = else_node.text_range(); |
49 | let then_range = then_node.text_range(); | 49 | let then_range = then_node.text_range(); |
50 | return ctx.add_assist(AssistId("invert_if"), "Invert if", |edit| { | 50 | return ctx.add_assist(AssistId("invert_if"), "Invert if", if_range, |edit| { |
51 | edit.target(if_range); | ||
52 | edit.replace(cond_range, flip_cond.syntax().text()); | 51 | edit.replace(cond_range, flip_cond.syntax().text()); |
53 | edit.replace(else_range, then_node.text()); | 52 | edit.replace(else_range, then_node.text()); |
54 | edit.replace(then_range, else_node.text()); | 53 | edit.replace(then_range, else_node.text()); |
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 9a2083609..de74d83d8 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -52,7 +52,8 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | |||
52 | } | 52 | } |
53 | }; | 53 | }; |
54 | 54 | ||
55 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| { | 55 | let target = tree.syntax().text_range(); |
56 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", target, |edit| { | ||
56 | edit.rewrite(rewriter); | 57 | edit.rewrite(rewriter); |
57 | // FIXME: we only need because our diff is imprecise | 58 | // FIXME: we only need because our diff is imprecise |
58 | edit.set_cursor(offset); | 59 | edit.set_cursor(offset); |
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index 9ae099b41..7c4d9d55d 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
@@ -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", |edit| { | 73 | ctx.add_assist(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 { |
@@ -87,7 +87,6 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
87 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); | 87 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); |
88 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); | 88 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); |
89 | 89 | ||
90 | edit.target(current_text_range); | ||
91 | edit.set_cursor(match cursor_pos { | 90 | edit.set_cursor(match cursor_pos { |
92 | CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset, | 91 | CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset, |
93 | CursorPos::InPat(offset) => offset, | 92 | CursorPos::InPat(offset) => offset, |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index 89956aea9..44e50cb6e 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -49,30 +49,37 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { | |||
49 | } | 49 | } |
50 | }; | 50 | }; |
51 | 51 | ||
52 | ctx.add_assist(AssistId("move_bounds_to_where_clause"), "Move to where clause", |edit| { | 52 | let target = type_param_list.syntax().text_range(); |
53 | let new_params = type_param_list | 53 | ctx.add_assist( |
54 | .type_params() | 54 | AssistId("move_bounds_to_where_clause"), |
55 | .filter(|it| it.type_bound_list().is_some()) | 55 | "Move to where clause", |
56 | .map(|type_param| { | 56 | target, |
57 | let without_bounds = type_param.remove_bounds(); | 57 | |edit| { |
58 | (type_param, without_bounds) | 58 | let new_params = type_param_list |
59 | }); | 59 | .type_params() |
60 | 60 | .filter(|it| it.type_bound_list().is_some()) | |
61 | let new_type_param_list = type_param_list.replace_descendants(new_params); | 61 | .map(|type_param| { |
62 | edit.replace_ast(type_param_list.clone(), new_type_param_list); | 62 | let without_bounds = type_param.remove_bounds(); |
63 | 63 | (type_param, without_bounds) | |
64 | let where_clause = { | 64 | }); |
65 | let predicates = type_param_list.type_params().filter_map(build_predicate); | 65 | |
66 | make::where_clause(predicates) | 66 | let new_type_param_list = type_param_list.replace_descendants(new_params); |
67 | }; | 67 | edit.replace_ast(type_param_list.clone(), new_type_param_list); |
68 | 68 | ||
69 | let to_insert = match anchor.prev_sibling_or_token() { | 69 | let where_clause = { |
70 | Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), | 70 | let predicates = type_param_list.type_params().filter_map(build_predicate); |
71 | _ => format!(" {}", where_clause.syntax()), | 71 | make::where_clause(predicates) |
72 | }; | 72 | }; |
73 | edit.insert(anchor.text_range().start(), to_insert); | 73 | |
74 | edit.target(type_param_list.syntax().text_range()); | 74 | let to_insert = match anchor.prev_sibling_or_token() { |
75 | }) | 75 | Some(ref elem) if elem.kind() == WHITESPACE => { |
76 | format!("{} ", where_clause.syntax()) | ||
77 | } | ||
78 | _ => format!(" {}", where_clause.syntax()), | ||
79 | }; | ||
80 | edit.insert(anchor.text_range().start(), to_insert); | ||
81 | }, | ||
82 | ) | ||
76 | } | 83 | } |
77 | 84 | ||
78 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 85 | 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 f2aa7e594..29bc9a9ff 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -40,8 +40,8 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> { | |||
40 | let arm_expr = match_arm.expr()?; | 40 | let arm_expr = match_arm.expr()?; |
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 | ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", |edit| { | 43 | let target = guard.syntax().text_range(); |
44 | edit.target(guard.syntax().text_range()); | 44 | ctx.add_assist(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() { |
@@ -108,11 +108,12 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | |||
108 | 108 | ||
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 | ctx.add_assist( | 112 | ctx.add_assist( |
112 | AssistId("move_arm_cond_to_match_guard"), | 113 | AssistId("move_arm_cond_to_match_guard"), |
113 | "Move condition to match guard", | 114 | "Move condition to match guard", |
115 | target, | ||
114 | |edit| { | 116 | |edit| { |
115 | edit.target(if_expr.syntax().text_range()); | ||
116 | let then_only_expr = then_block.statements().next().is_none(); | 117 | let then_only_expr = then_block.statements().next().is_none(); |
117 | 118 | ||
118 | match &then_block.expr() { | 119 | match &then_block.expr() { |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 542f7a637..155c679b4 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
@@ -25,8 +25,8 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
25 | pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { | 25 | pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { |
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 | ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", |edit| { | 28 | let target = token.syntax().text_range(); |
29 | edit.target(token.syntax().text_range()); | 29 | ctx.add_assist(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() { |
@@ -54,8 +54,8 @@ pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { | |||
54 | pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { | 54 | pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { |
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 | ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", |edit| { | 57 | let target = token.syntax().text_range(); |
58 | edit.target(token.syntax().text_range()); | 58 | ctx.add_assist(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)); |
@@ -79,8 +79,8 @@ pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { | |||
79 | // ``` | 79 | // ``` |
80 | pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { | 80 | pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { |
81 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 81 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
82 | ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| { | 82 | let target = token.text_range(); |
83 | edit.target(token.text_range()); | 83 | ctx.add_assist(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 | }) |
@@ -108,8 +108,8 @@ pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> { | |||
108 | // no hash to remove | 108 | // no hash to remove |
109 | return None; | 109 | return None; |
110 | } | 110 | } |
111 | ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", |edit| { | 111 | let target = token.text_range(); |
112 | edit.target(token.text_range()); | 112 | ctx.add_assist(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 ddfb21a7e..e6e02f2ae 100644 --- a/crates/ra_assists/src/handlers/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs | |||
@@ -57,8 +57,8 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> { | |||
57 | text.slice(without_parens).to_string() | 57 | text.slice(without_parens).to_string() |
58 | }; | 58 | }; |
59 | 59 | ||
60 | ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", |edit| { | 60 | let target = macro_call.syntax().text_range(); |
61 | edit.target(macro_call.syntax().text_range()); | 61 | ctx.add_assist(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 e598023b2..9f72f879d 100644 --- a/crates/ra_assists/src/handlers/remove_mut.rs +++ b/crates/ra_assists/src/handlers/remove_mut.rs | |||
@@ -25,7 +25,8 @@ pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> { | |||
25 | _ => mut_token.text_range().end(), | 25 | _ => mut_token.text_range().end(), |
26 | }; | 26 | }; |
27 | 27 | ||
28 | ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", |edit| { | 28 | let target = mut_token.text_range(); |
29 | ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { | ||
29 | edit.set_cursor(delete_from); | 30 | edit.set_cursor(delete_from); |
30 | edit.delete(TextRange::new(delete_from, delete_to)); | 31 | edit.delete(TextRange::new(delete_from, delete_to)); |
31 | }) | 32 | }) |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index a57e327b8..0b930dea2 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -50,11 +50,11 @@ fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { | |||
50 | return None; | 50 | return None; |
51 | } | 51 | } |
52 | 52 | ||
53 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { | 53 | let target = record.syntax().text_range(); |
54 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { | ||
54 | for (old, new) in fields.iter().zip(&sorted_fields) { | 55 | for (old, new) in fields.iter().zip(&sorted_fields) { |
55 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | 56 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); |
56 | } | 57 | } |
57 | edit.target(record.syntax().text_range()) | ||
58 | }) | 58 | }) |
59 | } | 59 | } |
60 | 60 | ||
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 d0df3b84e..2eb8348f8 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 | |||
@@ -44,30 +44,35 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | let sema = ctx.sema; | 46 | let sema = ctx.sema; |
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| { | 47 | let target = if_expr.syntax().text_range(); |
48 | let match_expr = { | 48 | ctx.add_assist( |
49 | let then_arm = { | 49 | AssistId("replace_if_let_with_match"), |
50 | let then_expr = unwrap_trivial_block(then_block); | 50 | "Replace with match", |
51 | make::match_arm(vec![pat.clone()], then_expr) | 51 | target, |
52 | move |edit| { | ||
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])) | ||
52 | }; | 68 | }; |
53 | let else_arm = { | ||
54 | let pattern = sema | ||
55 | .type_of_pat(&pat) | ||
56 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | ||
57 | .map(|it| it.sad_pattern()) | ||
58 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
59 | let else_expr = unwrap_trivial_block(else_block); | ||
60 | make::match_arm(vec![pattern], else_expr) | ||
61 | }; | ||
62 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
63 | }; | ||
64 | 69 | ||
65 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); | 70 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); |
66 | 71 | ||
67 | edit.target(if_expr.syntax().text_range()); | 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 | ) |
71 | } | 76 | } |
72 | 77 | ||
73 | #[cfg(test)] | 78 | #[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 dc4d16055..a5509a567 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 | |||
@@ -47,7 +47,8 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | |||
47 | let ty = ctx.sema.type_of_expr(&init)?; | 47 | let ty = ctx.sema.type_of_expr(&init)?; |
48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); | 48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); |
49 | 49 | ||
50 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { | 50 | let target = let_kw.text_range(); |
51 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { | ||
51 | let with_placeholder: ast::Pat = match happy_variant { | 52 | let with_placeholder: ast::Pat = match happy_variant { |
52 | None => make::placeholder_pat().into(), | 53 | None => make::placeholder_pat().into(), |
53 | Some(var_name) => make::tuple_struct_pat( | 54 | Some(var_name) => make::tuple_struct_pat( |
@@ -67,7 +68,6 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | |||
67 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | 68 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); |
68 | 69 | ||
69 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); | 70 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); |
70 | edit.target(let_kw.text_range()); | ||
71 | edit.set_cursor(target_offset); | 71 | edit.set_cursor(target_offset); |
72 | }) | 72 | }) |
73 | } | 73 | } |
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 624178924..fd41da64b 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 | |||
@@ -33,9 +33,11 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
33 | return None; | 33 | return None; |
34 | } | 34 | } |
35 | 35 | ||
36 | let target = path.syntax().text_range(); | ||
36 | ctx.add_assist( | 37 | ctx.add_assist( |
37 | AssistId("replace_qualified_name_with_use"), | 38 | AssistId("replace_qualified_name_with_use"), |
38 | "Replace qualified path with use", | 39 | "Replace qualified path with use", |
40 | target, | ||
39 | |edit| { | 41 | |edit| { |
40 | let path_to_import = hir_path.mod_path().clone(); | 42 | let path_to_import = hir_path.mod_path().clone(); |
41 | insert_use_statement(path.syntax(), &path_to_import, edit); | 43 | insert_use_statement(path.syntax(), &path_to_import, edit); |
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 dcb471edb..c6b73da67 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -38,26 +38,32 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
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(); | ||
42 | ctx.add_assist( | ||
43 | AssistId("replace_unwrap_with_match"), | ||
44 | "Replace unwrap with match", | ||
45 | target, | ||
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(); | ||
41 | 50 | ||
42 | ctx.add_assist(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", |edit| { | 51 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
43 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | 52 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
44 | let it = make::bind_pat(make::name("a")).into(); | ||
45 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
46 | 53 | ||
47 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 54 | let unreachable_call = make::unreachable_macro_call().into(); |
48 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 55 | let err_arm = |
56 | make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | ||
49 | 57 | ||
50 | let unreachable_call = make::unreachable_macro_call().into(); | 58 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
51 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | 59 | let match_expr = make::expr_match(caller.clone(), match_arm_list); |
60 | let match_expr = | ||
61 | IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | ||
52 | 62 | ||
53 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 63 | edit.set_cursor(caller.syntax().text_range().start()); |
54 | let match_expr = make::expr_match(caller.clone(), match_arm_list); | 64 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); |
55 | let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | 65 | }, |
56 | 66 | ) | |
57 | edit.target(method_call.syntax().text_range()); | ||
58 | edit.set_cursor(caller.syntax().text_range().start()); | ||
59 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | ||
60 | }) | ||
61 | } | 67 | } |
62 | 68 | ||
63 | #[cfg(test)] | 69 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index a59f2f76f..d49563974 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
@@ -28,8 +28,8 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> { | |||
28 | } | 28 | } |
29 | let cursor = ctx.frange.range.start(); | 29 | let cursor = ctx.frange.range.start(); |
30 | 30 | ||
31 | ctx.add_assist(AssistId("split_import"), "Split import", |edit| { | 31 | let target = colon_colon.text_range(); |
32 | edit.target(colon_colon.text_range()); | 32 | ctx.add_assist(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 89992117d..6df927abb 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -57,9 +57,9 @@ pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | |||
57 | } | 57 | } |
58 | }; | 58 | }; |
59 | 59 | ||
60 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| { | 60 | let target = expr_to_unwrap.syntax().text_range(); |
61 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", target, |edit| { | ||
61 | edit.set_cursor(expr.syntax().text_range().start()); | 62 | edit.set_cursor(expr.syntax().text_range().start()); |
62 | edit.target(expr_to_unwrap.syntax().text_range()); | ||
63 | 63 | ||
64 | let pat_start: &[_] = &[' ', '{', '\n']; | 64 | let pat_start: &[_] = &[' ', '{', '\n']; |
65 | let expr_to_unwrap = expr_to_unwrap.to_string(); | 65 | let expr_to_unwrap = expr_to_unwrap.to_string(); |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index b794b021d..f4f37614f 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -36,16 +36,24 @@ pub struct AssistLabel { | |||
36 | /// Short description of the assist, as shown in the UI. | 36 | /// Short description of the assist, as shown in the UI. |
37 | pub label: String, | 37 | pub label: String, |
38 | pub group: Option<GroupLabel>, | 38 | pub group: Option<GroupLabel>, |
39 | /// Target ranges are used to sort assists: the smaller the target range, | ||
40 | /// the more specific assist is, and so it should be sorted first. | ||
41 | pub target: TextRange, | ||
39 | } | 42 | } |
40 | 43 | ||
41 | #[derive(Clone, Debug)] | 44 | #[derive(Clone, Debug)] |
42 | pub struct GroupLabel(pub String); | 45 | pub struct GroupLabel(pub String); |
43 | 46 | ||
44 | impl AssistLabel { | 47 | impl AssistLabel { |
45 | pub(crate) fn new(id: AssistId, label: String, group: Option<GroupLabel>) -> AssistLabel { | 48 | pub(crate) fn new( |
49 | id: AssistId, | ||
50 | label: String, | ||
51 | group: Option<GroupLabel>, | ||
52 | target: TextRange, | ||
53 | ) -> AssistLabel { | ||
46 | // FIXME: make fields private, so that this invariant can't be broken | 54 | // FIXME: make fields private, so that this invariant can't be broken |
47 | assert!(label.starts_with(|c: char| c.is_uppercase())); | 55 | assert!(label.starts_with(|c: char| c.is_uppercase())); |
48 | AssistLabel { id, label, group } | 56 | AssistLabel { id, label, group, target } |
49 | } | 57 | } |
50 | } | 58 | } |
51 | 59 | ||
@@ -53,8 +61,6 @@ impl AssistLabel { | |||
53 | pub struct AssistAction { | 61 | pub struct AssistAction { |
54 | pub edit: TextEdit, | 62 | pub edit: TextEdit, |
55 | pub cursor_position: Option<TextSize>, | 63 | pub cursor_position: Option<TextSize>, |
56 | // FIXME: This belongs to `AssistLabel` | ||
57 | pub target: Option<TextRange>, | ||
58 | pub file: AssistFile, | 64 | pub file: AssistFile, |
59 | } | 65 | } |
60 | 66 | ||
@@ -104,7 +110,7 @@ pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssi | |||
104 | .flat_map(|it| it.0) | 110 | .flat_map(|it| it.0) |
105 | .map(|it| it.into_resolved().unwrap()) | 111 | .map(|it| it.into_resolved().unwrap()) |
106 | .collect::<Vec<_>>(); | 112 | .collect::<Vec<_>>(); |
107 | a.sort_by_key(|it| it.action.target.map_or(TextSize::from(!0u32), |it| it.len())); | 113 | a.sort_by_key(|it| it.label.target.len()); |
108 | a | 114 | a |
109 | } | 115 | } |
110 | 116 | ||
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 483e11931..dd9026df6 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -118,8 +118,7 @@ fn check(assist: Handler, before: &str, expected: ExpectedResult) { | |||
118 | assert_eq_text!(after, &actual); | 118 | assert_eq_text!(after, &actual); |
119 | } | 119 | } |
120 | (Some(assist), ExpectedResult::Target(target)) => { | 120 | (Some(assist), ExpectedResult::Target(target)) => { |
121 | let action = assist.0[0].action.clone().unwrap(); | 121 | let range = assist.0[0].label.target; |
122 | let range = action.target.expect("expected target on action"); | ||
123 | assert_eq_text!(&text_without_caret[range], target); | 122 | assert_eq_text!(&text_without_caret[range], target); |
124 | } | 123 | } |
125 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 124 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |