diff options
author | Jeremy Kolb <[email protected]> | 2020-06-28 23:36:05 +0100 |
---|---|---|
committer | kjeremy <[email protected]> | 2020-07-02 22:13:02 +0100 |
commit | b98c16a034620913f3dbc67bd3f48ad2686face7 (patch) | |
tree | 10f90c96791cfd82bb160a1a5c7474ccc17d5b8b /crates/ra_assists/src | |
parent | 4cb8bf03c588dcf244d25785de3878b6ef3f7958 (diff) |
Categorize assists
Diffstat (limited to 'crates/ra_assists/src')
40 files changed, 702 insertions, 501 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 3640bb4d2..c35d0254a 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -19,7 +19,7 @@ use ra_text_edit::TextEditBuilder; | |||
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | assist_config::{AssistConfig, SnippetCap}, | 21 | assist_config::{AssistConfig, SnippetCap}, |
22 | Assist, AssistId, GroupLabel, ResolvedAssist, | 22 | Assist, AssistId, AssistKind, GroupLabel, ResolvedAssist, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 25 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
@@ -135,22 +135,24 @@ impl Assists { | |||
135 | pub(crate) fn add( | 135 | pub(crate) fn add( |
136 | &mut self, | 136 | &mut self, |
137 | id: AssistId, | 137 | id: AssistId, |
138 | kind: AssistKind, | ||
138 | label: impl Into<String>, | 139 | label: impl Into<String>, |
139 | target: TextRange, | 140 | target: TextRange, |
140 | f: impl FnOnce(&mut AssistBuilder), | 141 | f: impl FnOnce(&mut AssistBuilder), |
141 | ) -> Option<()> { | 142 | ) -> Option<()> { |
142 | let label = Assist::new(id, label.into(), None, target); | 143 | let label = Assist::new(id, kind, label.into(), None, target); |
143 | self.add_impl(label, f) | 144 | self.add_impl(label, f) |
144 | } | 145 | } |
145 | pub(crate) fn add_group( | 146 | pub(crate) fn add_group( |
146 | &mut self, | 147 | &mut self, |
147 | group: &GroupLabel, | 148 | group: &GroupLabel, |
148 | id: AssistId, | 149 | id: AssistId, |
150 | kind: AssistKind, | ||
149 | label: impl Into<String>, | 151 | label: impl Into<String>, |
150 | target: TextRange, | 152 | target: TextRange, |
151 | f: impl FnOnce(&mut AssistBuilder), | 153 | f: impl FnOnce(&mut AssistBuilder), |
152 | ) -> Option<()> { | 154 | ) -> Option<()> { |
153 | let label = Assist::new(id, label.into(), Some(group.clone()), target); | 155 | let label = Assist::new(id, kind, label.into(), Some(group.clone()), target); |
154 | self.add_impl(label, f) | 156 | self.add_impl(label, f) |
155 | } | 157 | } |
156 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 158 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index fa70c8496..e86b01dbb 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -8,7 +8,7 @@ use stdx::SepBy; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | 10 | assist_context::{AssistContext, Assists}, |
11 | AssistId, | 11 | AssistId, AssistKind, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | // Assist: add_custom_impl | 14 | // Assist: add_custom_impl |
@@ -52,7 +52,7 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
52 | 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); |
53 | 53 | ||
54 | let target = attr.syntax().text_range(); | 54 | let target = attr.syntax().text_range(); |
55 | acc.add(AssistId("add_custom_impl"), label, target, |builder| { | 55 | acc.add(AssistId("add_custom_impl"), AssistKind::Refactor, label, target, |builder| { |
56 | let new_attr_input = input | 56 | let new_attr_input = input |
57 | .syntax() | 57 | .syntax() |
58 | .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 b123b8498..3b7a570b0 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::{AssistContext, AssistId, Assists}; | 7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
8 | 8 | ||
9 | // Assist: add_derive | 9 | // Assist: add_derive |
10 | // | 10 | // |
@@ -29,7 +29,7 @@ pub(crate) fn add_derive(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 node_start = derive_insertion_offset(&nominal)?; | 30 | let node_start = derive_insertion_offset(&nominal)?; |
31 | let target = nominal.syntax().text_range(); | 31 | let target = nominal.syntax().text_range(); |
32 | acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |builder| { | 32 | acc.add(AssistId("add_derive"), AssistKind::Refactor, "Add `#[derive]`", target, |builder| { |
33 | let derive_attr = nominal | 33 | let derive_attr = nominal |
34 | .attrs() | 34 | .attrs() |
35 | .filter_map(|x| x.as_simple_call()) | 35 | .filter_map(|x| x.as_simple_call()) |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 11df922a2..653137d43 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::{AssistContext, AssistId, Assists}; | 7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
8 | 8 | ||
9 | // Assist: add_explicit_type | 9 | // Assist: add_explicit_type |
10 | // | 10 | // |
@@ -60,6 +60,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
60 | let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?; | 60 | let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?; |
61 | acc.add( | 61 | acc.add( |
62 | AssistId("add_explicit_type"), | 62 | AssistId("add_explicit_type"), |
63 | AssistKind::RefactorRewrite, | ||
63 | format!("Insert explicit type `{}`", inferred_type), | 64 | format!("Insert explicit type `{}`", inferred_type), |
64 | pat_range, | 65 | pat_range, |
65 | |builder| match ascribed_ty { | 66 | |builder| match ascribed_ty { |
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 b0e56e1b5..505085c54 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 | |||
@@ -2,7 +2,7 @@ use ra_ide_db::RootDatabase; | |||
2 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 2 | use ra_syntax::ast::{self, AstNode, NameOwner}; |
3 | use test_utils::mark; | 3 | use test_utils::mark; |
4 | 4 | ||
5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | 5 | use crate::{utils::FamousDefs, AssistContext, AssistId, AssistKind, Assists}; |
6 | 6 | ||
7 | // Assist: add_from_impl_for_enum | 7 | // Assist: add_from_impl_for_enum |
8 | // | 8 | // |
@@ -46,6 +46,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> | |||
46 | let target = variant.syntax().text_range(); | 46 | let target = variant.syntax().text_range(); |
47 | acc.add( | 47 | acc.add( |
48 | AssistId("add_from_impl_for_enum"), | 48 | AssistId("add_from_impl_for_enum"), |
49 | AssistKind::Refactor, | ||
49 | "Add From impl for this enum variant", | 50 | "Add From impl for this enum variant", |
50 | target, | 51 | target, |
51 | |edit| { | 52 | |edit| { |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index fc4e82309..a11bc2551 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -13,7 +13,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
13 | use crate::{ | 13 | use crate::{ |
14 | assist_config::SnippetCap, | 14 | assist_config::SnippetCap, |
15 | utils::{render_snippet, Cursor}, | 15 | utils::{render_snippet, Cursor}, |
16 | AssistContext, AssistId, Assists, | 16 | AssistContext, AssistId, AssistKind, Assists, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | // Assist: add_function | 19 | // Assist: add_function |
@@ -62,15 +62,21 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
62 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 62 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; |
63 | 63 | ||
64 | let target = call.syntax().text_range(); | 64 | let target = call.syntax().text_range(); |
65 | acc.add(AssistId("add_function"), "Add function", target, |builder| { | 65 | acc.add( |
66 | let function_template = function_builder.render(); | 66 | AssistId("add_function"), |
67 | builder.edit_file(function_template.file); | 67 | AssistKind::RefactorExtract, |
68 | let new_fn = function_template.to_string(ctx.config.snippet_cap); | 68 | "Add function", |
69 | match ctx.config.snippet_cap { | 69 | target, |
70 | Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), | 70 | |builder| { |
71 | None => builder.insert(function_template.insert_offset, new_fn), | 71 | let function_template = function_builder.render(); |
72 | } | 72 | builder.edit_file(function_template.file); |
73 | }) | 73 | let new_fn = function_template.to_string(ctx.config.snippet_cap); |
74 | match ctx.config.snippet_cap { | ||
75 | Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), | ||
76 | None => builder.insert(function_template.insert_offset, new_fn), | ||
77 | } | ||
78 | }, | ||
79 | ) | ||
74 | } | 80 | } |
75 | 81 | ||
76 | struct FunctionTemplate { | 82 | struct FunctionTemplate { |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index eceba7d0a..405e3c568 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner}; | 1 | use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner}; |
2 | use stdx::{format_to, SepBy}; | 2 | use stdx::{format_to, SepBy}; |
3 | 3 | ||
4 | use crate::{AssistContext, AssistId, Assists}; | 4 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
5 | 5 | ||
6 | // Assist: add_impl | 6 | // Assist: add_impl |
7 | // | 7 | // |
@@ -26,38 +26,46 @@ pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
26 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 26 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
27 | let name = nominal.name()?; | 27 | let name = nominal.name()?; |
28 | let target = nominal.syntax().text_range(); | 28 | let target = nominal.syntax().text_range(); |
29 | acc.add(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), target, |edit| { | 29 | acc.add( |
30 | let type_params = nominal.type_param_list(); | 30 | AssistId("add_impl"), |
31 | let start_offset = nominal.syntax().text_range().end(); | 31 | AssistKind::Refactor, |
32 | let mut buf = String::new(); | 32 | format!("Implement {}", name.text().as_str()), |
33 | buf.push_str("\n\nimpl"); | 33 | target, |
34 | if let Some(type_params) = &type_params { | 34 | |edit| { |
35 | format_to!(buf, "{}", type_params.syntax()); | 35 | let type_params = nominal.type_param_list(); |
36 | } | 36 | let start_offset = nominal.syntax().text_range().end(); |
37 | buf.push_str(" "); | 37 | let mut buf = String::new(); |
38 | buf.push_str(name.text().as_str()); | 38 | buf.push_str("\n\nimpl"); |
39 | if let Some(type_params) = type_params { | 39 | if let Some(type_params) = &type_params { |
40 | let lifetime_params = type_params | 40 | format_to!(buf, "{}", type_params.syntax()); |
41 | .lifetime_params() | 41 | } |
42 | .filter_map(|it| it.lifetime_token()) | 42 | buf.push_str(" "); |
43 | .map(|it| it.text().clone()); | 43 | buf.push_str(name.text().as_str()); |
44 | let type_params = | 44 | if let Some(type_params) = type_params { |
45 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 45 | let lifetime_params = type_params |
46 | .lifetime_params() | ||
47 | .filter_map(|it| it.lifetime_token()) | ||
48 | .map(|it| it.text().clone()); | ||
49 | let type_params = type_params | ||
50 | .type_params() | ||
51 | .filter_map(|it| it.name()) | ||
52 | .map(|it| it.text().clone()); | ||
46 | 53 | ||
47 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 54 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); |
48 | format_to!(buf, "<{}>", generic_params) | 55 | format_to!(buf, "<{}>", generic_params) |
49 | } | ||
50 | match ctx.config.snippet_cap { | ||
51 | Some(cap) => { | ||
52 | buf.push_str(" {\n $0\n}"); | ||
53 | edit.insert_snippet(cap, start_offset, buf); | ||
54 | } | 56 | } |
55 | None => { | 57 | match ctx.config.snippet_cap { |
56 | buf.push_str(" {\n}"); | 58 | Some(cap) => { |
57 | edit.insert(start_offset, buf); | 59 | buf.push_str(" {\n $0\n}"); |
60 | edit.insert_snippet(cap, start_offset, buf); | ||
61 | } | ||
62 | None => { | ||
63 | buf.push_str(" {\n}"); | ||
64 | edit.insert(start_offset, buf); | ||
65 | } | ||
58 | } | 66 | } |
59 | } | 67 | }, |
60 | }) | 68 | ) |
61 | } | 69 | } |
62 | 70 | ||
63 | #[cfg(test)] | 71 | #[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 77e092f62..13b441a29 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | assist_context::{AssistContext, Assists}, | 12 | assist_context::{AssistContext, Assists}, |
13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
14 | utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, | 14 | utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, |
15 | AssistId, | 15 | AssistId, AssistKind, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | #[derive(PartialEq)] | 18 | #[derive(PartialEq)] |
@@ -147,7 +147,7 @@ fn add_missing_impl_members_inner( | |||
147 | } | 147 | } |
148 | 148 | ||
149 | let target = impl_def.syntax().text_range(); | 149 | let target = impl_def.syntax().text_range(); |
150 | acc.add(AssistId(assist_id), label, target, |builder| { | 150 | acc.add(AssistId(assist_id), AssistKind::QuickFix, label, target, |builder| { |
151 | let n_existing_items = impl_item_list.assoc_items().count(); | 151 | let n_existing_items = impl_item_list.assoc_items().count(); |
152 | let source_scope = ctx.sema.scope_for_def(trait_); | 152 | let source_scope = ctx.sema.scope_for_def(trait_); |
153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); | 153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); |
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index e41b2aa06..4cd3ca264 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::{AssistContext, AssistId, Assists}; | 10 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
11 | 11 | ||
12 | // Assist: add_new | 12 | // Assist: add_new |
13 | // | 13 | // |
@@ -42,50 +42,56 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
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 | acc.add(AssistId("add_new"), "Add default constructor", target, |builder| { | 45 | acc.add( |
46 | let mut buf = String::with_capacity(512); | 46 | AssistId("add_new"), |
47 | 47 | AssistKind::Refactor, | |
48 | if impl_def.is_some() { | 48 | "Add default constructor", |
49 | buf.push('\n'); | 49 | target, |
50 | } | 50 | |builder| { |
51 | 51 | let mut buf = String::with_capacity(512); | |
52 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); | 52 | |
53 | 53 | if impl_def.is_some() { | |
54 | let params = field_list | ||
55 | .fields() | ||
56 | .filter_map(|f| { | ||
57 | Some(format!("{}: {}", f.name()?.syntax(), f.ascribed_type()?.syntax())) | ||
58 | }) | ||
59 | .sep_by(", "); | ||
60 | let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); | ||
61 | |||
62 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); | ||
63 | |||
64 | let start_offset = impl_def | ||
65 | .and_then(|impl_def| { | ||
66 | buf.push('\n'); | 54 | buf.push('\n'); |
67 | let start = impl_def | ||
68 | .syntax() | ||
69 | .descendants_with_tokens() | ||
70 | .find(|t| t.kind() == T!['{'])? | ||
71 | .text_range() | ||
72 | .end(); | ||
73 | |||
74 | Some(start) | ||
75 | }) | ||
76 | .unwrap_or_else(|| { | ||
77 | buf = generate_impl_text(&strukt, &buf); | ||
78 | strukt.syntax().text_range().end() | ||
79 | }); | ||
80 | |||
81 | match ctx.config.snippet_cap { | ||
82 | None => builder.insert(start_offset, buf), | ||
83 | Some(cap) => { | ||
84 | buf = buf.replace("fn new", "fn $0new"); | ||
85 | builder.insert_snippet(cap, start_offset, buf); | ||
86 | } | 55 | } |
87 | } | 56 | |
88 | }) | 57 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); |
58 | |||
59 | let params = field_list | ||
60 | .fields() | ||
61 | .filter_map(|f| { | ||
62 | Some(format!("{}: {}", f.name()?.syntax(), f.ascribed_type()?.syntax())) | ||
63 | }) | ||
64 | .sep_by(", "); | ||
65 | let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); | ||
66 | |||
67 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); | ||
68 | |||
69 | let start_offset = impl_def | ||
70 | .and_then(|impl_def| { | ||
71 | buf.push('\n'); | ||
72 | let start = impl_def | ||
73 | .syntax() | ||
74 | .descendants_with_tokens() | ||
75 | .find(|t| t.kind() == T!['{'])? | ||
76 | .text_range() | ||
77 | .end(); | ||
78 | |||
79 | Some(start) | ||
80 | }) | ||
81 | .unwrap_or_else(|| { | ||
82 | buf = generate_impl_text(&strukt, &buf); | ||
83 | strukt.syntax().text_range().end() | ||
84 | }); | ||
85 | |||
86 | match ctx.config.snippet_cap { | ||
87 | None => builder.insert(start_offset, buf), | ||
88 | Some(cap) => { | ||
89 | buf = buf.replace("fn new", "fn $0new"); | ||
90 | builder.insert_snippet(cap, start_offset, buf); | ||
91 | } | ||
92 | } | ||
93 | }, | ||
94 | ) | ||
89 | } | 95 | } |
90 | 96 | ||
91 | // Generates the surrounding `impl Type { <code> }` including type and lifetime | 97 | // Generates the surrounding `impl Type { <code> }` including type and lifetime |
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs index 26acf81f2..7a807fbde 100644 --- a/crates/ra_assists/src/handlers/add_turbo_fish.rs +++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs | |||
@@ -4,7 +4,7 @@ use test_utils::mark; | |||
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | assist_context::{AssistContext, Assists}, | 6 | assist_context::{AssistContext, Assists}, |
7 | AssistId, | 7 | AssistId, AssistKind, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | // Assist: add_turbo_fish | 10 | // Assist: add_turbo_fish |
@@ -45,12 +45,16 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
45 | mark::hit!(add_turbo_fish_non_generic); | 45 | mark::hit!(add_turbo_fish_non_generic); |
46 | return None; | 46 | return None; |
47 | } | 47 | } |
48 | acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { | 48 | acc.add( |
49 | match ctx.config.snippet_cap { | 49 | AssistId("add_turbo_fish"), |
50 | AssistKind::RefactorRewrite, | ||
51 | "Add `::<>`", | ||
52 | ident.text_range(), | ||
53 | |builder| match ctx.config.snippet_cap { | ||
50 | Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"), | 54 | Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"), |
51 | None => builder.insert(ident.text_range().end(), "::<_>"), | 55 | None => builder.insert(ident.text_range().end(), "::<_>"), |
52 | } | 56 | }, |
53 | }) | 57 | ) |
54 | } | 58 | } |
55 | 59 | ||
56 | #[cfg(test)] | 60 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index 233e8fb8e..a1fd6e112 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, AssistContext, AssistId, Assists}; | 3 | use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; |
4 | 4 | ||
5 | // Assist: apply_demorgan | 5 | // Assist: apply_demorgan |
6 | // | 6 | // |
@@ -39,11 +39,17 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
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 | acc.add(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { | 42 | acc.add( |
43 | edit.replace(op_range, opposite_op); | 43 | AssistId("apply_demorgan"), |
44 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); | 44 | AssistKind::RefactorRewrite, |
45 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); | 45 | "Apply De Morgan's law", |
46 | }) | 46 | op_range, |
47 | |edit| { | ||
48 | edit.replace(op_range, opposite_op); | ||
49 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); | ||
50 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); | ||
51 | }, | ||
52 | ) | ||
47 | } | 53 | } |
48 | 54 | ||
49 | // Return the opposite text for a given logical operator, if it makes sense | 55 | // Return the opposite text for a given logical operator, if it makes sense |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 4cd77adbf..4d97ed101 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -13,7 +13,9 @@ use ra_syntax::{ | |||
13 | }; | 13 | }; |
14 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
15 | 15 | ||
16 | use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, GroupLabel}; | 16 | use crate::{ |
17 | utils::insert_use_statement, AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
18 | }; | ||
17 | 19 | ||
18 | // Assist: auto_import | 20 | // Assist: auto_import |
19 | // | 21 | // |
@@ -47,6 +49,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
47 | acc.add_group( | 49 | acc.add_group( |
48 | &group, | 50 | &group, |
49 | AssistId("auto_import"), | 51 | AssistId("auto_import"), |
52 | AssistKind::QuickFix, | ||
50 | format!("Import `{}`", &import), | 53 | format!("Import `{}`", &import), |
51 | range, | 54 | range, |
52 | |builder| { | 55 | |builder| { |
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 855baf187..2be6d5e49 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 | |||
@@ -3,7 +3,7 @@ use ra_syntax::{ | |||
3 | AstNode, SyntaxNode, | 3 | AstNode, SyntaxNode, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{AssistContext, AssistId, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | // Assist: change_return_type_to_result | 9 | // Assist: change_return_type_to_result |
@@ -36,6 +36,7 @@ pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContex | |||
36 | 36 | ||
37 | acc.add( | 37 | acc.add( |
38 | AssistId("change_return_type_to_result"), | 38 | AssistId("change_return_type_to_result"), |
39 | AssistKind::RefactorRewrite, | ||
39 | "Change return type to Result", | 40 | "Change return type to Result", |
40 | type_ref.syntax().text_range(), | 41 | type_ref.syntax().text_range(), |
41 | |builder| { | 42 | |builder| { |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 157c7b665..34c7e481d 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::{ | |||
6 | }; | 6 | }; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | use crate::{utils::vis_offset, AssistContext, AssistId, Assists}; | 9 | use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; |
10 | 10 | ||
11 | // Assist: change_visibility | 11 | // Assist: change_visibility |
12 | // | 12 | // |
@@ -62,9 +62,15 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
62 | return None; | 62 | return None; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| { | 65 | acc.add( |
66 | edit.insert(offset, "pub(crate) "); | 66 | AssistId("change_visibility"), |
67 | }) | 67 | AssistKind::RefactorRewrite, |
68 | "Change visibility to pub(crate)", | ||
69 | target, | ||
70 | |edit| { | ||
71 | edit.insert(offset, "pub(crate) "); | ||
72 | }, | ||
73 | ) | ||
68 | } | 74 | } |
69 | 75 | ||
70 | fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | 76 | fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { |
@@ -72,6 +78,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | |||
72 | let target = vis.syntax().text_range(); | 78 | let target = vis.syntax().text_range(); |
73 | return acc.add( | 79 | return acc.add( |
74 | AssistId("change_visibility"), | 80 | AssistId("change_visibility"), |
81 | AssistKind::RefactorRewrite, | ||
75 | "Change Visibility to pub(crate)", | 82 | "Change Visibility to pub(crate)", |
76 | target, | 83 | target, |
77 | |edit| { | 84 | |edit| { |
@@ -83,6 +90,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | |||
83 | let target = vis.syntax().text_range(); | 90 | let target = vis.syntax().text_range(); |
84 | return acc.add( | 91 | return acc.add( |
85 | AssistId("change_visibility"), | 92 | AssistId("change_visibility"), |
93 | AssistKind::RefactorRewrite, | ||
86 | "Change visibility to pub", | 94 | "Change visibility to pub", |
87 | target, | 95 | target, |
88 | |edit| { | 96 | |edit| { |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index dfade7432..9ccd42cd7 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -15,7 +15,7 @@ use ra_syntax::{ | |||
15 | use crate::{ | 15 | use crate::{ |
16 | assist_context::{AssistContext, Assists}, | 16 | assist_context::{AssistContext, Assists}, |
17 | utils::invert_boolean_expression, | 17 | utils::invert_boolean_expression, |
18 | AssistId, | 18 | AssistId, AssistKind, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | // Assist: convert_to_guarded_return | 21 | // Assist: convert_to_guarded_return |
@@ -99,86 +99,93 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
100 | 100 | ||
101 | let target = if_expr.syntax().text_range(); | 101 | let target = if_expr.syntax().text_range(); |
102 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { | 102 | acc.add( |
103 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 103 | AssistId("convert_to_guarded_return"), |
104 | let new_block = match if_let_pat { | 104 | AssistKind::RefactorRewrite, |
105 | None => { | 105 | "Convert to guarded return", |
106 | // If. | 106 | target, |
107 | let new_expr = { | 107 | |edit| { |
108 | let then_branch = | 108 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
109 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); | 109 | let new_block = match if_let_pat { |
110 | let cond = invert_boolean_expression(cond_expr); | 110 | None => { |
111 | make::expr_if(make::condition(cond, None), then_branch).indent(if_indent_level) | 111 | // If. |
112 | }; | 112 | let new_expr = { |
113 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | 113 | let then_branch = |
114 | } | 114 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); |
115 | Some((path, bound_ident)) => { | 115 | let cond = invert_boolean_expression(cond_expr); |
116 | // If-let. | 116 | make::expr_if(make::condition(cond, None), then_branch) |
117 | let match_expr = { | 117 | .indent(if_indent_level) |
118 | let happy_arm = { | ||
119 | let pat = make::tuple_struct_pat( | ||
120 | path, | ||
121 | once(make::bind_pat(make::name("it")).into()), | ||
122 | ); | ||
123 | let expr = { | ||
124 | let name_ref = make::name_ref("it"); | ||
125 | let segment = make::path_segment(name_ref); | ||
126 | let path = make::path_unqualified(segment); | ||
127 | make::expr_path(path) | ||
128 | }; | ||
129 | make::match_arm(once(pat.into()), expr) | ||
130 | }; | 118 | }; |
119 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | ||
120 | } | ||
121 | Some((path, bound_ident)) => { | ||
122 | // If-let. | ||
123 | let match_expr = { | ||
124 | let happy_arm = { | ||
125 | let pat = make::tuple_struct_pat( | ||
126 | path, | ||
127 | once(make::bind_pat(make::name("it")).into()), | ||
128 | ); | ||
129 | let expr = { | ||
130 | let name_ref = make::name_ref("it"); | ||
131 | let segment = make::path_segment(name_ref); | ||
132 | let path = make::path_unqualified(segment); | ||
133 | make::expr_path(path) | ||
134 | }; | ||
135 | make::match_arm(once(pat.into()), expr) | ||
136 | }; | ||
131 | 137 | ||
132 | let sad_arm = make::match_arm( | 138 | let sad_arm = make::match_arm( |
133 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate | 139 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate |
134 | once(make::placeholder_pat().into()), | 140 | once(make::placeholder_pat().into()), |
135 | early_expression, | 141 | early_expression, |
136 | ); | 142 | ); |
137 | 143 | ||
138 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) | 144 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) |
139 | }; | 145 | }; |
140 | 146 | ||
141 | let let_stmt = make::let_stmt( | 147 | let let_stmt = make::let_stmt( |
142 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), | 148 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), |
143 | Some(match_expr), | 149 | Some(match_expr), |
150 | ); | ||
151 | let let_stmt = let_stmt.indent(if_indent_level); | ||
152 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | ||
153 | } | ||
154 | }; | ||
155 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | ||
156 | |||
157 | fn replace( | ||
158 | new_expr: &SyntaxNode, | ||
159 | then_block: &ast::BlockExpr, | ||
160 | parent_block: &ast::BlockExpr, | ||
161 | if_expr: &ast::IfExpr, | ||
162 | ) -> SyntaxNode { | ||
163 | let then_block_items = then_block.dedent(IndentLevel(1)); | ||
164 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
165 | let end_of_then = | ||
166 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
167 | end_of_then.prev_sibling_or_token().unwrap() | ||
168 | } else { | ||
169 | end_of_then | ||
170 | }; | ||
171 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
172 | then_block_items | ||
173 | .syntax() | ||
174 | .children_with_tokens() | ||
175 | .skip(1) | ||
176 | .take_while(|i| *i != end_of_then), | ||
144 | ); | 177 | ); |
145 | let let_stmt = let_stmt.indent(if_indent_level); | 178 | replace_children( |
146 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | 179 | &parent_block.syntax(), |
180 | RangeInclusive::new( | ||
181 | if_expr.clone().syntax().clone().into(), | ||
182 | if_expr.syntax().clone().into(), | ||
183 | ), | ||
184 | &mut then_statements, | ||
185 | ) | ||
147 | } | 186 | } |
148 | }; | 187 | }, |
149 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | 188 | ) |
150 | |||
151 | fn replace( | ||
152 | new_expr: &SyntaxNode, | ||
153 | then_block: &ast::BlockExpr, | ||
154 | parent_block: &ast::BlockExpr, | ||
155 | if_expr: &ast::IfExpr, | ||
156 | ) -> SyntaxNode { | ||
157 | let then_block_items = then_block.dedent(IndentLevel(1)); | ||
158 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
159 | let end_of_then = | ||
160 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
161 | end_of_then.prev_sibling_or_token().unwrap() | ||
162 | } else { | ||
163 | end_of_then | ||
164 | }; | ||
165 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
166 | then_block_items | ||
167 | .syntax() | ||
168 | .children_with_tokens() | ||
169 | .skip(1) | ||
170 | .take_while(|i| *i != end_of_then), | ||
171 | ); | ||
172 | replace_children( | ||
173 | &parent_block.syntax(), | ||
174 | RangeInclusive::new( | ||
175 | if_expr.clone().syntax().clone().into(), | ||
176 | if_expr.syntax().clone().into(), | ||
177 | ), | ||
178 | &mut then_statements, | ||
179 | ) | ||
180 | } | ||
181 | }) | ||
182 | } | 189 | } |
183 | 190 | ||
184 | #[cfg(test)] | 191 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index ca19cf198..e1ae485c9 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -10,7 +10,8 @@ use ra_syntax::{ | |||
10 | use rustc_hash::FxHashSet; | 10 | use rustc_hash::FxHashSet; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId, Assists, | 13 | assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId, |
14 | AssistKind, Assists, | ||
14 | }; | 15 | }; |
15 | 16 | ||
16 | // Assist: extract_struct_from_enum_variant | 17 | // Assist: extract_struct_from_enum_variant |
@@ -49,6 +50,7 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
49 | let target = variant.syntax().text_range(); | 50 | let target = variant.syntax().text_range(); |
50 | acc.add( | 51 | acc.add( |
51 | AssistId("extract_struct_from_enum_variant"), | 52 | AssistId("extract_struct_from_enum_variant"), |
53 | AssistKind::RefactorRewrite, | ||
52 | "Extract struct from enum variant", | 54 | "Extract struct from enum variant", |
53 | target, | 55 | target, |
54 | |builder| { | 56 | |builder| { |
diff --git a/crates/ra_assists/src/handlers/extract_variable.rs b/crates/ra_assists/src/handlers/extract_variable.rs index c4150d2bb..8f7ffdaff 100644 --- a/crates/ra_assists/src/handlers/extract_variable.rs +++ b/crates/ra_assists/src/handlers/extract_variable.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | use stdx::format_to; | 9 | use stdx::format_to; |
10 | use test_utils::mark; | 10 | use test_utils::mark; |
11 | 11 | ||
12 | use crate::{AssistContext, AssistId, Assists}; | 12 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
13 | 13 | ||
14 | // Assist: extract_variable | 14 | // Assist: extract_variable |
15 | // | 15 | // |
@@ -43,80 +43,86 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | let target = expr.syntax().text_range(); | 45 | let target = expr.syntax().text_range(); |
46 | acc.add(AssistId("extract_variable"), "Extract into variable", target, move |edit| { | 46 | acc.add( |
47 | let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) { | 47 | AssistId("extract_variable"), |
48 | Some(field) => field.name_ref(), | 48 | AssistKind::RefactorExtract, |
49 | None => None, | 49 | "Extract into variable", |
50 | }; | 50 | target, |
51 | 51 | move |edit| { | |
52 | let mut buf = String::new(); | 52 | let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) { |
53 | 53 | Some(field) => field.name_ref(), | |
54 | let var_name = match &field_shorthand { | 54 | None => None, |
55 | Some(it) => it.to_string(), | 55 | }; |
56 | None => "var_name".to_string(), | 56 | |
57 | }; | 57 | let mut buf = String::new(); |
58 | let expr_range = match &field_shorthand { | 58 | |
59 | Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()), | 59 | let var_name = match &field_shorthand { |
60 | None => expr.syntax().text_range(), | 60 | Some(it) => it.to_string(), |
61 | }; | 61 | None => "var_name".to_string(), |
62 | 62 | }; | |
63 | if wrap_in_block { | 63 | let expr_range = match &field_shorthand { |
64 | format_to!(buf, "{{ let {} = ", var_name); | 64 | Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()), |
65 | } else { | 65 | None => expr.syntax().text_range(), |
66 | format_to!(buf, "let {} = ", var_name); | 66 | }; |
67 | }; | 67 | |
68 | format_to!(buf, "{}", expr.syntax()); | 68 | if wrap_in_block { |
69 | 69 | format_to!(buf, "{{ let {} = ", var_name); | |
70 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); | 70 | } else { |
71 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { | 71 | format_to!(buf, "let {} = ", var_name); |
72 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) | 72 | }; |
73 | } else { | 73 | format_to!(buf, "{}", expr.syntax()); |
74 | false | 74 | |
75 | }; | 75 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); |
76 | if is_full_stmt { | 76 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { |
77 | mark::hit!(test_extract_var_expr_stmt); | 77 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) |
78 | if full_stmt.unwrap().semicolon_token().is_none() { | 78 | } else { |
79 | buf.push_str(";"); | 79 | false |
80 | }; | ||
81 | if is_full_stmt { | ||
82 | mark::hit!(test_extract_var_expr_stmt); | ||
83 | if full_stmt.unwrap().semicolon_token().is_none() { | ||
84 | buf.push_str(";"); | ||
85 | } | ||
86 | match ctx.config.snippet_cap { | ||
87 | Some(cap) => { | ||
88 | let snip = buf | ||
89 | .replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); | ||
90 | edit.replace_snippet(cap, expr_range, snip) | ||
91 | } | ||
92 | None => edit.replace(expr_range, buf), | ||
93 | } | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | buf.push_str(";"); | ||
98 | |||
99 | // We want to maintain the indent level, | ||
100 | // but we do not want to duplicate possible | ||
101 | // extra newlines in the indent block | ||
102 | let text = indent.text(); | ||
103 | if text.starts_with('\n') { | ||
104 | buf.push_str("\n"); | ||
105 | buf.push_str(text.trim_start_matches('\n')); | ||
106 | } else { | ||
107 | buf.push_str(text); | ||
80 | } | 108 | } |
109 | |||
110 | edit.replace(expr_range, var_name.clone()); | ||
111 | let offset = anchor_stmt.text_range().start(); | ||
81 | match ctx.config.snippet_cap { | 112 | match ctx.config.snippet_cap { |
82 | Some(cap) => { | 113 | Some(cap) => { |
83 | let snip = | 114 | let snip = |
84 | buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); | 115 | buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); |
85 | edit.replace_snippet(cap, expr_range, snip) | 116 | edit.insert_snippet(cap, offset, snip) |
86 | } | 117 | } |
87 | None => edit.replace(expr_range, buf), | 118 | None => edit.insert(offset, buf), |
88 | } | 119 | } |
89 | return; | ||
90 | } | ||
91 | 120 | ||
92 | buf.push_str(";"); | 121 | if wrap_in_block { |
93 | 122 | edit.insert(anchor_stmt.text_range().end(), " }"); | |
94 | // We want to maintain the indent level, | ||
95 | // but we do not want to duplicate possible | ||
96 | // extra newlines in the indent block | ||
97 | let text = indent.text(); | ||
98 | if text.starts_with('\n') { | ||
99 | buf.push_str("\n"); | ||
100 | buf.push_str(text.trim_start_matches('\n')); | ||
101 | } else { | ||
102 | buf.push_str(text); | ||
103 | } | ||
104 | |||
105 | edit.replace(expr_range, var_name.clone()); | ||
106 | let offset = anchor_stmt.text_range().start(); | ||
107 | match ctx.config.snippet_cap { | ||
108 | Some(cap) => { | ||
109 | let snip = | ||
110 | buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); | ||
111 | edit.insert_snippet(cap, offset, snip) | ||
112 | } | 123 | } |
113 | None => edit.insert(offset, buf), | 124 | }, |
114 | } | 125 | ) |
115 | |||
116 | if wrap_in_block { | ||
117 | edit.insert(anchor_stmt.text_range().end(), " }"); | ||
118 | } | ||
119 | }) | ||
120 | } | 126 | } |
121 | 127 | ||
122 | /// Check whether the node is a valid expression which can be extracted to a variable. | 128 | /// Check whether the node is a valid expression which can be extracted to a variable. |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 5b1235682..96610dbf5 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -8,7 +8,7 @@ use test_utils::mark; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | utils::{render_snippet, Cursor, FamousDefs}, | 10 | utils::{render_snippet, Cursor, FamousDefs}, |
11 | AssistContext, AssistId, Assists, | 11 | AssistContext, AssistId, AssistKind, Assists, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | // Assist: fill_match_arms | 14 | // Assist: fill_match_arms |
@@ -103,24 +103,30 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
103 | } | 103 | } |
104 | 104 | ||
105 | let target = match_expr.syntax().text_range(); | 105 | let target = match_expr.syntax().text_range(); |
106 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |builder| { | 106 | acc.add( |
107 | let new_arm_list = match_arm_list.remove_placeholder(); | 107 | AssistId("fill_match_arms"), |
108 | let n_old_arms = new_arm_list.arms().count(); | 108 | AssistKind::RefactorRewrite, |
109 | let new_arm_list = new_arm_list.append_arms(missing_arms); | 109 | "Fill match arms", |
110 | let first_new_arm = new_arm_list.arms().nth(n_old_arms); | 110 | target, |
111 | let old_range = match_arm_list.syntax().text_range(); | 111 | |builder| { |
112 | match (first_new_arm, ctx.config.snippet_cap) { | 112 | let new_arm_list = match_arm_list.remove_placeholder(); |
113 | (Some(first_new_arm), Some(cap)) => { | 113 | let n_old_arms = new_arm_list.arms().count(); |
114 | let snippet = render_snippet( | 114 | let new_arm_list = new_arm_list.append_arms(missing_arms); |
115 | cap, | 115 | let first_new_arm = new_arm_list.arms().nth(n_old_arms); |
116 | new_arm_list.syntax(), | 116 | let old_range = match_arm_list.syntax().text_range(); |
117 | Cursor::Before(first_new_arm.syntax()), | 117 | match (first_new_arm, ctx.config.snippet_cap) { |
118 | ); | 118 | (Some(first_new_arm), Some(cap)) => { |
119 | builder.replace_snippet(cap, old_range, snippet); | 119 | let snippet = render_snippet( |
120 | } | 120 | cap, |
121 | _ => builder.replace(old_range, new_arm_list.to_string()), | 121 | new_arm_list.syntax(), |
122 | } | 122 | Cursor::Before(first_new_arm.syntax()), |
123 | }) | 123 | ); |
124 | builder.replace_snippet(cap, old_range, snippet); | ||
125 | } | ||
126 | _ => builder.replace(old_range, new_arm_list.to_string()), | ||
127 | } | ||
128 | }, | ||
129 | ) | ||
124 | } | 130 | } |
125 | 131 | ||
126 | fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool { | 132 | fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool { |
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs index c0f57c329..9c6f9efc2 100644 --- a/crates/ra_assists/src/handlers/fix_visibility.rs +++ b/crates/ra_assists/src/handlers/fix_visibility.rs | |||
@@ -2,7 +2,7 @@ use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; | |||
2 | use ra_db::FileId; | 2 | use ra_db::FileId; |
3 | use ra_syntax::{ast, AstNode, TextRange, TextSize}; | 3 | use ra_syntax::{ast, AstNode, TextRange, TextSize}; |
4 | 4 | ||
5 | use crate::{utils::vis_offset, AssistContext, AssistId, Assists}; | 5 | use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; |
6 | 6 | ||
7 | // FIXME: this really should be a fix for diagnostic, rather than an assist. | 7 | // FIXME: this really should be a fix for diagnostic, rather than an assist. |
8 | 8 | ||
@@ -58,7 +58,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O | |||
58 | Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), | 58 | Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), |
59 | }; | 59 | }; |
60 | 60 | ||
61 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { | 61 | acc.add(AssistId("fix_visibility"), AssistKind::QuickFix, assist_label, target, |builder| { |
62 | builder.edit_file(target_file); | 62 | builder.edit_file(target_file); |
63 | match ctx.config.snippet_cap { | 63 | match ctx.config.snippet_cap { |
64 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | 64 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), |
@@ -101,7 +101,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
101 | let assist_label = | 101 | let assist_label = |
102 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); | 102 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); |
103 | 103 | ||
104 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { | 104 | acc.add(AssistId("fix_visibility"), AssistKind::QuickFix, assist_label, target, |builder| { |
105 | builder.edit_file(target_file); | 105 | builder.edit_file(target_file); |
106 | match ctx.config.snippet_cap { | 106 | match ctx.config.snippet_cap { |
107 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | 107 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), |
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index 573196576..aee55762f 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::{AssistContext, AssistId, Assists}; | 3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
4 | 4 | ||
5 | // Assist: flip_binexpr | 5 | // Assist: flip_binexpr |
6 | // | 6 | // |
@@ -33,13 +33,19 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
33 | return None; | 33 | return None; |
34 | } | 34 | } |
35 | 35 | ||
36 | acc.add(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { | 36 | acc.add( |
37 | if let FlipAction::FlipAndReplaceOp(new_op) = action { | 37 | AssistId("flip_binexpr"), |
38 | edit.replace(op_range, new_op); | 38 | AssistKind::RefactorRewrite, |
39 | } | 39 | "Flip binary expression", |
40 | edit.replace(lhs.text_range(), rhs.text()); | 40 | op_range, |
41 | edit.replace(rhs.text_range(), lhs.text()); | 41 | |edit| { |
42 | }) | 42 | if let FlipAction::FlipAndReplaceOp(new_op) = action { |
43 | edit.replace(op_range, new_op); | ||
44 | } | ||
45 | edit.replace(lhs.text_range(), rhs.text()); | ||
46 | edit.replace(rhs.text_range(), lhs.text()); | ||
47 | }, | ||
48 | ) | ||
43 | } | 49 | } |
44 | 50 | ||
45 | enum FlipAction { | 51 | enum FlipAction { |
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index a57a1c463..9971ffa71 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::{AssistContext, AssistId, Assists}; | 3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
4 | 4 | ||
5 | // Assist: flip_comma | 5 | // Assist: flip_comma |
6 | // | 6 | // |
@@ -28,10 +28,16 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
28 | return None; | 28 | return None; |
29 | } | 29 | } |
30 | 30 | ||
31 | acc.add(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { | 31 | acc.add( |
32 | edit.replace(prev.text_range(), next.to_string()); | 32 | AssistId("flip_comma"), |
33 | edit.replace(next.text_range(), prev.to_string()); | 33 | AssistKind::RefactorRewrite, |
34 | }) | 34 | "Flip comma", |
35 | comma.text_range(), | ||
36 | |edit| { | ||
37 | edit.replace(prev.text_range(), next.to_string()); | ||
38 | edit.replace(next.text_range(), prev.to_string()); | ||
39 | }, | ||
40 | ) | ||
35 | } | 41 | } |
36 | 42 | ||
37 | #[cfg(test)] | 43 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index 0115adc8b..192f70ccb 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::{AssistContext, AssistId, Assists}; | 7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
8 | 8 | ||
9 | // Assist: flip_trait_bound | 9 | // Assist: flip_trait_bound |
10 | // | 10 | // |
@@ -33,10 +33,16 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
33 | ); | 33 | ); |
34 | 34 | ||
35 | let target = plus.text_range(); | 35 | let target = plus.text_range(); |
36 | acc.add(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| { | 36 | acc.add( |
37 | edit.replace(before.text_range(), after.to_string()); | 37 | AssistId("flip_trait_bound"), |
38 | edit.replace(after.text_range(), before.to_string()); | 38 | AssistKind::RefactorRewrite, |
39 | }) | 39 | "Flip trait bounds", |
40 | target, | ||
41 | |edit| { | ||
42 | edit.replace(before.text_range(), after.to_string()); | ||
43 | edit.replace(after.text_range(), before.to_string()); | ||
44 | }, | ||
45 | ) | ||
40 | } | 46 | } |
41 | 47 | ||
42 | #[cfg(test)] | 48 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 259839535..f1bd8b46d 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -7,7 +7,7 @@ use test_utils::mark; | |||
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | assist_context::{AssistContext, Assists}, | 9 | assist_context::{AssistContext, Assists}, |
10 | AssistId, | 10 | AssistId, AssistKind, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | // Assist: inline_local_variable | 13 | // Assist: inline_local_variable |
@@ -110,13 +110,20 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
110 | let init_in_paren = format!("({})", &init_str); | 110 | let init_in_paren = format!("({})", &init_str); |
111 | 111 | ||
112 | let target = bind_pat.syntax().text_range(); | 112 | let target = bind_pat.syntax().text_range(); |
113 | acc.add(AssistId("inline_local_variable"), "Inline variable", target, move |builder| { | 113 | acc.add( |
114 | builder.delete(delete_range); | 114 | AssistId("inline_local_variable"), |
115 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { | 115 | AssistKind::RefactorInline, |
116 | let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; | 116 | "Inline variable", |
117 | builder.replace(desc.file_range.range, replacement) | 117 | target, |
118 | } | 118 | move |builder| { |
119 | }) | 119 | builder.delete(delete_range); |
120 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { | ||
121 | let replacement = | ||
122 | if should_wrap { init_in_paren.clone() } else { init_str.clone() }; | ||
123 | builder.replace(desc.file_range.range, replacement) | ||
124 | } | ||
125 | }, | ||
126 | ) | ||
120 | } | 127 | } |
121 | 128 | ||
122 | #[cfg(test)] | 129 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs index 28fcbc9ba..374274824 100644 --- a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{ | |||
4 | }; | 4 | }; |
5 | use rustc_hash::FxHashSet; | 5 | use rustc_hash::FxHashSet; |
6 | 6 | ||
7 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, Assists}; | 7 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; |
8 | 8 | ||
9 | static ASSIST_NAME: &str = "introduce_named_lifetime"; | 9 | static ASSIST_NAME: &str = "introduce_named_lifetime"; |
10 | static ASSIST_LABEL: &str = "Introduce named lifetime"; | 10 | static ASSIST_LABEL: &str = "Introduce named lifetime"; |
@@ -83,7 +83,7 @@ fn generate_fn_def_assist( | |||
83 | _ => return None, | 83 | _ => return None, |
84 | } | 84 | } |
85 | }; | 85 | }; |
86 | acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| { | 86 | acc.add(AssistId(ASSIST_NAME), AssistKind::Refactor, ASSIST_LABEL, lifetime_loc, |builder| { |
87 | add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param); | 87 | add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param); |
88 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); | 88 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); |
89 | loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param))); | 89 | loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param))); |
@@ -98,7 +98,7 @@ fn generate_impl_def_assist( | |||
98 | ) -> Option<()> { | 98 | ) -> Option<()> { |
99 | let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?; | 99 | let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?; |
100 | let end_of_impl_kw = impl_def.impl_token()?.text_range().end(); | 100 | let end_of_impl_kw = impl_def.impl_token()?.text_range().end(); |
101 | acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| { | 101 | acc.add(AssistId(ASSIST_NAME), AssistKind::Refactor, ASSIST_LABEL, lifetime_loc, |builder| { |
102 | add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); | 102 | add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); |
103 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); | 103 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); |
104 | }) | 104 | }) |
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs index 59d278eb9..eebb2364d 100644 --- a/crates/ra_assists/src/handlers/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::{ | |||
6 | use crate::{ | 6 | use crate::{ |
7 | assist_context::{AssistContext, Assists}, | 7 | assist_context::{AssistContext, Assists}, |
8 | utils::invert_boolean_expression, | 8 | utils::invert_boolean_expression, |
9 | AssistId, | 9 | AssistId, AssistKind, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | // Assist: invert_if | 12 | // Assist: invert_if |
@@ -54,7 +54,7 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
54 | let else_node = else_block.syntax(); | 54 | let else_node = else_block.syntax(); |
55 | let else_range = else_node.text_range(); | 55 | let else_range = else_node.text_range(); |
56 | let then_range = then_node.text_range(); | 56 | let then_range = then_node.text_range(); |
57 | acc.add(AssistId("invert_if"), "Invert if", if_range, |edit| { | 57 | acc.add(AssistId("invert_if"), AssistKind::RefactorRewrite, "Invert if", if_range, |edit| { |
58 | edit.replace(cond_range, flip_cond.syntax().text()); | 58 | edit.replace(cond_range, flip_cond.syntax().text()); |
59 | edit.replace(else_range, then_node.text()); | 59 | edit.replace(else_range, then_node.text()); |
60 | edit.replace(then_range, else_node.text()); | 60 | 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 ac0b3035c..b0458e17f 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -8,7 +8,7 @@ use ra_syntax::{ | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | 10 | assist_context::{AssistContext, Assists}, |
11 | AssistId, | 11 | AssistId, AssistKind, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | // Assist: merge_imports | 14 | // Assist: merge_imports |
@@ -56,9 +56,15 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | let target = tree.syntax().text_range(); | 58 | let target = tree.syntax().text_range(); |
59 | acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { | 59 | acc.add( |
60 | builder.rewrite(rewriter); | 60 | AssistId("merge_imports"), |
61 | }) | 61 | AssistKind::RefactorRewrite, |
62 | "Merge imports", | ||
63 | target, | ||
64 | |builder| { | ||
65 | builder.rewrite(rewriter); | ||
66 | }, | ||
67 | ) | ||
62 | } | 68 | } |
63 | 69 | ||
64 | fn next_prev() -> impl Iterator<Item = Direction> { | 70 | fn next_prev() -> impl Iterator<Item = Direction> { |
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index 90ce66378..f0f11a046 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, | 6 | Direction, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{AssistContext, AssistId, Assists, TextRange}; | 9 | use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange}; |
10 | 10 | ||
11 | // Assist: merge_match_arms | 11 | // Assist: merge_match_arms |
12 | // | 12 | // |
@@ -59,25 +59,31 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
59 | return None; | 59 | return None; |
60 | } | 60 | } |
61 | 61 | ||
62 | acc.add(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| { | 62 | acc.add( |
63 | let pats = if arms_to_merge.iter().any(contains_placeholder) { | 63 | AssistId("merge_match_arms"), |
64 | "_".into() | 64 | AssistKind::RefactorRewrite, |
65 | } else { | 65 | "Merge match arms", |
66 | arms_to_merge | 66 | current_text_range, |
67 | .iter() | 67 | |edit| { |
68 | .filter_map(ast::MatchArm::pat) | 68 | let pats = if arms_to_merge.iter().any(contains_placeholder) { |
69 | .map(|x| x.syntax().to_string()) | 69 | "_".into() |
70 | .collect::<Vec<String>>() | 70 | } else { |
71 | .join(" | ") | 71 | arms_to_merge |
72 | }; | 72 | .iter() |
73 | 73 | .filter_map(ast::MatchArm::pat) | |
74 | let arm = format!("{} => {}", pats, current_expr.syntax().text()); | 74 | .map(|x| x.syntax().to_string()) |
75 | 75 | .collect::<Vec<String>>() | |
76 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); | 76 | .join(" | ") |
77 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); | 77 | }; |
78 | 78 | ||
79 | edit.replace(TextRange::new(start, end), arm); | 79 | let arm = format!("{} => {}", pats, current_expr.syntax().text()); |
80 | }) | 80 | |
81 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); | ||
82 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); | ||
83 | |||
84 | edit.replace(TextRange::new(start, end), arm); | ||
85 | }, | ||
86 | ) | ||
81 | } | 87 | } |
82 | 88 | ||
83 | fn contains_placeholder(a: &ast::MatchArm) -> bool { | 89 | fn contains_placeholder(a: &ast::MatchArm) -> bool { |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index be2a7eddc..bcedd39a8 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::{AssistContext, AssistId, Assists}; | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
9 | 9 | ||
10 | // Assist: move_bounds_to_where_clause | 10 | // Assist: move_bounds_to_where_clause |
11 | // | 11 | // |
@@ -50,29 +50,37 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext | |||
50 | }; | 50 | }; |
51 | 51 | ||
52 | let target = type_param_list.syntax().text_range(); | 52 | let target = type_param_list.syntax().text_range(); |
53 | acc.add(AssistId("move_bounds_to_where_clause"), "Move to where clause", target, |edit| { | 53 | acc.add( |
54 | let new_params = type_param_list | 54 | AssistId("move_bounds_to_where_clause"), |
55 | .type_params() | 55 | AssistKind::RefactorRewrite, |
56 | .filter(|it| it.type_bound_list().is_some()) | 56 | "Move to where clause", |
57 | .map(|type_param| { | 57 | target, |
58 | let without_bounds = type_param.remove_bounds(); | 58 | |edit| { |
59 | (type_param, without_bounds) | 59 | let new_params = type_param_list |
60 | }); | 60 | .type_params() |
61 | 61 | .filter(|it| it.type_bound_list().is_some()) | |
62 | let new_type_param_list = type_param_list.replace_descendants(new_params); | 62 | .map(|type_param| { |
63 | edit.replace_ast(type_param_list.clone(), new_type_param_list); | 63 | let without_bounds = type_param.remove_bounds(); |
64 | 64 | (type_param, without_bounds) | |
65 | let where_clause = { | 65 | }); |
66 | let predicates = type_param_list.type_params().filter_map(build_predicate); | 66 | |
67 | make::where_clause(predicates) | 67 | let new_type_param_list = type_param_list.replace_descendants(new_params); |
68 | }; | 68 | edit.replace_ast(type_param_list.clone(), new_type_param_list); |
69 | 69 | ||
70 | let to_insert = match anchor.prev_sibling_or_token() { | 70 | let where_clause = { |
71 | Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), | 71 | let predicates = type_param_list.type_params().filter_map(build_predicate); |
72 | _ => format!(" {}", where_clause.syntax()), | 72 | make::where_clause(predicates) |
73 | }; | 73 | }; |
74 | edit.insert(anchor.text_range().start(), to_insert); | 74 | |
75 | }) | 75 | let to_insert = match anchor.prev_sibling_or_token() { |
76 | Some(ref elem) if elem.kind() == WHITESPACE => { | ||
77 | format!("{} ", where_clause.syntax()) | ||
78 | } | ||
79 | _ => format!(" {}", where_clause.syntax()), | ||
80 | }; | ||
81 | edit.insert(anchor.text_range().start(), to_insert); | ||
82 | }, | ||
83 | ) | ||
76 | } | 84 | } |
77 | 85 | ||
78 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 86 | 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 7edcf0748..7f3aaf4f7 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -3,7 +3,7 @@ use ra_syntax::{ | |||
3 | SyntaxKind::WHITESPACE, | 3 | SyntaxKind::WHITESPACE, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{AssistContext, AssistId, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
7 | 7 | ||
8 | // Assist: move_guard_to_arm_body | 8 | // Assist: move_guard_to_arm_body |
9 | // | 9 | // |
@@ -40,17 +40,23 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> | |||
40 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); | 40 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); |
41 | 41 | ||
42 | let target = guard.syntax().text_range(); | 42 | let target = guard.syntax().text_range(); |
43 | acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { | 43 | acc.add( |
44 | match space_before_guard { | 44 | AssistId("move_guard_to_arm_body"), |
45 | Some(element) if element.kind() == WHITESPACE => { | 45 | AssistKind::RefactorExtract, |
46 | edit.delete(element.text_range()); | 46 | "Move guard to arm body", |
47 | } | 47 | target, |
48 | _ => (), | 48 | |edit| { |
49 | }; | 49 | match space_before_guard { |
50 | Some(element) if element.kind() == WHITESPACE => { | ||
51 | edit.delete(element.text_range()); | ||
52 | } | ||
53 | _ => (), | ||
54 | }; | ||
50 | 55 | ||
51 | edit.delete(guard.syntax().text_range()); | 56 | edit.delete(guard.syntax().text_range()); |
52 | edit.replace_node_and_indent(arm_expr.syntax(), buf); | 57 | edit.replace_node_and_indent(arm_expr.syntax(), buf); |
53 | }) | 58 | }, |
59 | ) | ||
54 | } | 60 | } |
55 | 61 | ||
56 | // Assist: move_arm_cond_to_match_guard | 62 | // Assist: move_arm_cond_to_match_guard |
@@ -101,6 +107,7 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
101 | let target = if_expr.syntax().text_range(); | 107 | let target = if_expr.syntax().text_range(); |
102 | acc.add( | 108 | acc.add( |
103 | AssistId("move_arm_cond_to_match_guard"), | 109 | AssistId("move_arm_cond_to_match_guard"), |
110 | AssistKind::RefactorRewrite, | ||
104 | "Move condition to match guard", | 111 | "Move condition to match guard", |
105 | target, | 112 | target, |
106 | |edit| { | 113 | |edit| { |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index d22d0aa55..8d0dac528 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::{AssistContext, AssistId, Assists}; | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
9 | 9 | ||
10 | // Assist: make_raw_string | 10 | // Assist: make_raw_string |
11 | // | 11 | // |
@@ -26,14 +26,23 @@ 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 | acc.add(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| { | 29 | acc.add( |
30 | let max_hash_streak = count_hashes(&value); | 30 | AssistId("make_raw_string"), |
31 | let mut hashes = String::with_capacity(max_hash_streak + 1); | 31 | AssistKind::RefactorRewrite, |
32 | for _ in 0..hashes.capacity() { | 32 | "Rewrite as raw string", |
33 | hashes.push('#'); | 33 | target, |
34 | } | 34 | |edit| { |
35 | edit.replace(token.syntax().text_range(), format!("r{}\"{}\"{}", hashes, value, hashes)); | 35 | let max_hash_streak = count_hashes(&value); |
36 | }) | 36 | let mut hashes = String::with_capacity(max_hash_streak + 1); |
37 | for _ in 0..hashes.capacity() { | ||
38 | hashes.push('#'); | ||
39 | } | ||
40 | edit.replace( | ||
41 | token.syntax().text_range(), | ||
42 | format!("r{}\"{}\"{}", hashes, value, hashes), | ||
43 | ); | ||
44 | }, | ||
45 | ) | ||
37 | } | 46 | } |
38 | 47 | ||
39 | // Assist: make_usual_string | 48 | // Assist: make_usual_string |
@@ -55,11 +64,17 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
55 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; | 64 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; |
56 | let value = token.value()?; | 65 | let value = token.value()?; |
57 | let target = token.syntax().text_range(); | 66 | let target = token.syntax().text_range(); |
58 | acc.add(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| { | 67 | acc.add( |
59 | // parse inside string to escape `"` | 68 | AssistId("make_usual_string"), |
60 | let escaped = value.escape_default().to_string(); | 69 | AssistKind::RefactorRewrite, |
61 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); | 70 | "Rewrite as regular string", |
62 | }) | 71 | target, |
72 | |edit| { | ||
73 | // parse inside string to escape `"` | ||
74 | let escaped = value.escape_default().to_string(); | ||
75 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); | ||
76 | }, | ||
77 | ) | ||
63 | } | 78 | } |
64 | 79 | ||
65 | // Assist: add_hash | 80 | // Assist: add_hash |
@@ -80,7 +95,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
80 | pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 95 | pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
81 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 96 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
82 | let target = token.text_range(); | 97 | let target = token.text_range(); |
83 | acc.add(AssistId("add_hash"), "Add # to raw string", target, |edit| { | 98 | acc.add(AssistId("add_hash"), AssistKind::Refactor, "Add # to raw string", target, |edit| { |
84 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); | 99 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); |
85 | edit.insert(token.text_range().end(), "#"); | 100 | edit.insert(token.text_range().end(), "#"); |
86 | }) | 101 | }) |
@@ -109,18 +124,24 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
109 | return None; | 124 | return None; |
110 | } | 125 | } |
111 | let target = token.text_range(); | 126 | let target = token.text_range(); |
112 | acc.add(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| { | 127 | acc.add( |
113 | let result = &text[2..text.len() - 1]; | 128 | AssistId("remove_hash"), |
114 | let result = if result.starts_with('\"') { | 129 | AssistKind::RefactorRewrite, |
115 | // FIXME: this logic is wrong, not only the last has has to handled specially | 130 | "Remove hash from raw string", |
116 | // no more hash, escape | 131 | target, |
117 | let internal_str = &result[1..result.len() - 1]; | 132 | |edit| { |
118 | format!("\"{}\"", internal_str.escape_default().to_string()) | 133 | let result = &text[2..text.len() - 1]; |
119 | } else { | 134 | let result = if result.starts_with('\"') { |
120 | result.to_owned() | 135 | // FIXME: this logic is wrong, not only the last has has to handled specially |
121 | }; | 136 | // no more hash, escape |
122 | edit.replace(token.text_range(), format!("r{}", result)); | 137 | let internal_str = &result[1..result.len() - 1]; |
123 | }) | 138 | format!("\"{}\"", internal_str.escape_default().to_string()) |
139 | } else { | ||
140 | result.to_owned() | ||
141 | }; | ||
142 | edit.replace(token.text_range(), format!("r{}", result)); | ||
143 | }, | ||
144 | ) | ||
124 | } | 145 | } |
125 | 146 | ||
126 | fn count_hashes(s: &str) -> usize { | 147 | fn count_hashes(s: &str) -> usize { |
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index 961ee1731..e5571676f 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::{AssistContext, AssistId, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
7 | 7 | ||
8 | // Assist: remove_dbg | 8 | // Assist: remove_dbg |
9 | // | 9 | // |
@@ -38,7 +38,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | let target = macro_call.syntax().text_range(); | 40 | let target = macro_call.syntax().text_range(); |
41 | acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |builder| { | 41 | acc.add(AssistId("remove_dbg"), AssistKind::Refactor, "Remove dbg!()", target, |builder| { |
42 | builder.replace(macro_range, macro_content); | 42 | builder.replace(macro_range, macro_content); |
43 | }) | 43 | }) |
44 | } | 44 | } |
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs index fe4eada03..a8173694a 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::{AssistContext, AssistId, Assists}; | 3 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
4 | 4 | ||
5 | // Assist: remove_mut | 5 | // Assist: remove_mut |
6 | // | 6 | // |
@@ -26,7 +26,13 @@ pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | let target = mut_token.text_range(); | 28 | let target = mut_token.text_range(); |
29 | acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |builder| { | 29 | acc.add( |
30 | builder.delete(TextRange::new(delete_from, delete_to)); | 30 | AssistId("remove_mut"), |
31 | }) | 31 | AssistKind::Refactor, |
32 | "Remove `mut` keyword", | ||
33 | target, | ||
34 | |builder| { | ||
35 | builder.delete(TextRange::new(delete_from, delete_to)); | ||
36 | }, | ||
37 | ) | ||
32 | } | 38 | } |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index b8cf30e7f..4a542a5d7 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -5,7 +5,7 @@ use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | |||
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; | 6 | use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; |
7 | 7 | ||
8 | use crate::{AssistContext, AssistId, Assists}; | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
9 | 9 | ||
10 | // Assist: reorder_fields | 10 | // Assist: reorder_fields |
11 | // | 11 | // |
@@ -42,11 +42,17 @@ fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
42 | } | 42 | } |
43 | 43 | ||
44 | let target = record.syntax().text_range(); | 44 | let target = record.syntax().text_range(); |
45 | acc.add(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { | 45 | acc.add( |
46 | for (old, new) in fields.iter().zip(&sorted_fields) { | 46 | AssistId("reorder_fields"), |
47 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | 47 | AssistKind::RefactorRewrite, |
48 | } | 48 | "Reorder record fields", |
49 | }) | 49 | target, |
50 | |edit| { | ||
51 | for (old, new) in fields.iter().zip(&sorted_fields) { | ||
52 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | ||
53 | } | ||
54 | }, | ||
55 | ) | ||
50 | } | 56 | } |
51 | 57 | ||
52 | fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> { | 58 | fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> { |
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 dfcd787de..9ef121a4c 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 | |||
@@ -8,7 +8,7 @@ use ra_syntax::{ | |||
8 | AstNode, | 8 | AstNode, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; | 11 | use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists}; |
12 | 12 | ||
13 | // Assist: replace_if_let_with_match | 13 | // Assist: replace_if_let_with_match |
14 | // | 14 | // |
@@ -48,29 +48,36 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
48 | }; | 48 | }; |
49 | 49 | ||
50 | let target = if_expr.syntax().text_range(); | 50 | let target = if_expr.syntax().text_range(); |
51 | acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { | 51 | acc.add( |
52 | let match_expr = { | 52 | AssistId("replace_if_let_with_match"), |
53 | let then_arm = { | 53 | AssistKind::RefactorRewrite, |
54 | let then_block = then_block.reset_indent().indent(IndentLevel(1)); | 54 | "Replace with match", |
55 | let then_expr = unwrap_trivial_block(then_block); | 55 | target, |
56 | make::match_arm(vec![pat.clone()], then_expr) | 56 | move |edit| { |
57 | let match_expr = { | ||
58 | let then_arm = { | ||
59 | let then_block = then_block.reset_indent().indent(IndentLevel(1)); | ||
60 | let then_expr = unwrap_trivial_block(then_block); | ||
61 | make::match_arm(vec![pat.clone()], then_expr) | ||
62 | }; | ||
63 | let else_arm = { | ||
64 | let pattern = ctx | ||
65 | .sema | ||
66 | .type_of_pat(&pat) | ||
67 | .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) | ||
68 | .map(|it| it.sad_pattern()) | ||
69 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
70 | let else_expr = unwrap_trivial_block(else_block); | ||
71 | make::match_arm(vec![pattern], else_expr) | ||
72 | }; | ||
73 | let match_expr = | ||
74 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])); | ||
75 | match_expr.indent(IndentLevel::from_node(if_expr.syntax())) | ||
57 | }; | 76 | }; |
58 | let else_arm = { | ||
59 | let pattern = ctx | ||
60 | .sema | ||
61 | .type_of_pat(&pat) | ||
62 | .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) | ||
63 | .map(|it| it.sad_pattern()) | ||
64 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
65 | let else_expr = unwrap_trivial_block(else_block); | ||
66 | make::match_arm(vec![pattern], else_expr) | ||
67 | }; | ||
68 | let match_expr = make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])); | ||
69 | match_expr.indent(IndentLevel::from_node(if_expr.syntax())) | ||
70 | }; | ||
71 | 77 | ||
72 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); | 78 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); |
73 | }) | 79 | }, |
80 | ) | ||
74 | } | 81 | } |
75 | 82 | ||
76 | #[cfg(test)] | 83 | #[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 761557ac0..174ff1fb4 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,7 +9,7 @@ use ra_syntax::{ | |||
9 | AstNode, T, | 9 | AstNode, T, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; | 12 | use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists}; |
13 | 13 | ||
14 | // Assist: replace_let_with_if_let | 14 | // Assist: replace_let_with_if_let |
15 | // | 15 | // |
@@ -44,24 +44,32 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> | |||
44 | 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()); |
45 | 45 | ||
46 | let target = let_kw.text_range(); | 46 | let target = let_kw.text_range(); |
47 | acc.add(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { | 47 | acc.add( |
48 | let with_placeholder: ast::Pat = match happy_variant { | 48 | AssistId("replace_let_with_if_let"), |
49 | None => make::placeholder_pat().into(), | 49 | AssistKind::RefactorRewrite, |
50 | Some(var_name) => make::tuple_struct_pat( | 50 | "Replace with if-let", |
51 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), | 51 | target, |
52 | once(make::placeholder_pat().into()), | 52 | |edit| { |
53 | ) | 53 | let with_placeholder: ast::Pat = match happy_variant { |
54 | .into(), | 54 | None => make::placeholder_pat().into(), |
55 | }; | 55 | Some(var_name) => make::tuple_struct_pat( |
56 | let block = make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax())); | 56 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), |
57 | let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block); | 57 | once(make::placeholder_pat().into()), |
58 | let stmt = make::expr_stmt(if_); | 58 | ) |
59 | .into(), | ||
60 | }; | ||
61 | let block = | ||
62 | make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax())); | ||
63 | let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block); | ||
64 | let stmt = make::expr_stmt(if_); | ||
59 | 65 | ||
60 | let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); | 66 | let placeholder = |
61 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | 67 | stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); |
68 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | ||
62 | 69 | ||
63 | 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)); |
64 | }) | 71 | }, |
72 | ) | ||
65 | } | 73 | } |
66 | 74 | ||
67 | #[cfg(test)] | 75 | #[cfg(test)] |
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 b4784c333..5e06f7f0e 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 | |||
@@ -3,7 +3,7 @@ use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNo | |||
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | utils::{find_insert_use_container, insert_use_statement}, | 5 | utils::{find_insert_use_container, insert_use_statement}, |
6 | AssistContext, AssistId, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | // Assist: replace_qualified_name_with_use | 9 | // Assist: replace_qualified_name_with_use |
@@ -38,6 +38,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
38 | let target = path.syntax().text_range(); | 38 | let target = path.syntax().text_range(); |
39 | acc.add( | 39 | acc.add( |
40 | AssistId("replace_qualified_name_with_use"), | 40 | AssistId("replace_qualified_name_with_use"), |
41 | AssistKind::RefactorRewrite, | ||
41 | "Replace qualified path with use", | 42 | "Replace qualified path with use", |
42 | target, | 43 | target, |
43 | |builder| { | 44 | |builder| { |
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 cff7dfb81..5f9705be1 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | utils::{render_snippet, Cursor, TryEnum}, | 13 | utils::{render_snippet, Cursor, TryEnum}, |
14 | AssistContext, AssistId, Assists, | 14 | AssistContext, AssistId, AssistKind, Assists, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | // Assist: replace_unwrap_with_match | 17 | // Assist: replace_unwrap_with_match |
@@ -46,37 +46,44 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
46 | let ty = ctx.sema.type_of_expr(&caller)?; | 46 | let ty = ctx.sema.type_of_expr(&caller)?; |
47 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); | 47 | let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); |
48 | let target = method_call.syntax().text_range(); | 48 | let target = method_call.syntax().text_range(); |
49 | acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |builder| { | 49 | acc.add( |
50 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | 50 | AssistId("replace_unwrap_with_match"), |
51 | let it = make::bind_pat(make::name("a")).into(); | 51 | AssistKind::RefactorRewrite, |
52 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | 52 | "Replace unwrap with match", |
53 | target, | ||
54 | |builder| { | ||
55 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | ||
56 | let it = make::bind_pat(make::name("a")).into(); | ||
57 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
53 | 58 | ||
54 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 59 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
55 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 60 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
56 | 61 | ||
57 | let unreachable_call = make::expr_unreachable(); | 62 | let unreachable_call = make::expr_unreachable(); |
58 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | 63 | let err_arm = |
64 | make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | ||
59 | 65 | ||
60 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 66 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
61 | let match_expr = make::expr_match(caller.clone(), match_arm_list) | 67 | let match_expr = make::expr_match(caller.clone(), match_arm_list) |
62 | .indent(IndentLevel::from_node(method_call.syntax())); | 68 | .indent(IndentLevel::from_node(method_call.syntax())); |
63 | 69 | ||
64 | let range = method_call.syntax().text_range(); | 70 | let range = method_call.syntax().text_range(); |
65 | match ctx.config.snippet_cap { | 71 | match ctx.config.snippet_cap { |
66 | Some(cap) => { | 72 | Some(cap) => { |
67 | let err_arm = match_expr | 73 | let err_arm = match_expr |
68 | .syntax() | 74 | .syntax() |
69 | .descendants() | 75 | .descendants() |
70 | .filter_map(ast::MatchArm::cast) | 76 | .filter_map(ast::MatchArm::cast) |
71 | .last() | 77 | .last() |
72 | .unwrap(); | 78 | .unwrap(); |
73 | let snippet = | 79 | let snippet = |
74 | render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax())); | 80 | render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax())); |
75 | builder.replace_snippet(cap, range, snippet) | 81 | builder.replace_snippet(cap, range, snippet) |
82 | } | ||
83 | None => builder.replace(range, match_expr.to_string()), | ||
76 | } | 84 | } |
77 | None => builder.replace(range, match_expr.to_string()), | 85 | }, |
78 | } | 86 | ) |
79 | }) | ||
80 | } | 87 | } |
81 | 88 | ||
82 | #[cfg(test)] | 89 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index 38aa199a0..c0cf8d923 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::{AssistContext, AssistId, Assists}; | 5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
6 | 6 | ||
7 | // Assist: split_import | 7 | // Assist: split_import |
8 | // | 8 | // |
@@ -28,7 +28,7 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
28 | } | 28 | } |
29 | 29 | ||
30 | let target = colon_colon.text_range(); | 30 | let target = colon_colon.text_range(); |
31 | acc.add(AssistId("split_import"), "Split import", target, |edit| { | 31 | acc.add(AssistId("split_import"), AssistKind::RefactorExtract, "Split import", target, |edit| { |
32 | edit.replace_ast(use_tree, new_tree); | 32 | edit.replace_ast(use_tree, new_tree); |
33 | }) | 33 | }) |
34 | } | 34 | } |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 1fb13f481..a66fba7c3 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -7,7 +7,7 @@ use ra_syntax::{ | |||
7 | AstNode, TextRange, T, | 7 | AstNode, TextRange, T, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{AssistContext, AssistId, Assists}; | 10 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
11 | 11 | ||
12 | // Assist: unwrap_block | 12 | // Assist: unwrap_block |
13 | // | 13 | // |
@@ -50,35 +50,47 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
50 | let ancestor_then_branch = ancestor.then_branch()?; | 50 | let ancestor_then_branch = ancestor.then_branch()?; |
51 | 51 | ||
52 | let target = then_branch.syntax().text_range(); | 52 | let target = then_branch.syntax().text_range(); |
53 | return acc.add(assist_id, assist_label, target, |edit| { | 53 | return acc.add( |
54 | let range_to_del_else_if = TextRange::new( | 54 | assist_id, |
55 | ancestor_then_branch.syntax().text_range().end(), | 55 | AssistKind::Refactor, |
56 | l_curly_token.text_range().start(), | 56 | assist_label, |
57 | ); | 57 | target, |
58 | let range_to_del_rest = TextRange::new( | 58 | |edit| { |
59 | then_branch.syntax().text_range().end(), | 59 | let range_to_del_else_if = TextRange::new( |
60 | if_expr.syntax().text_range().end(), | 60 | ancestor_then_branch.syntax().text_range().end(), |
61 | ); | 61 | l_curly_token.text_range().start(), |
62 | 62 | ); | |
63 | edit.delete(range_to_del_rest); | 63 | let range_to_del_rest = TextRange::new( |
64 | edit.delete(range_to_del_else_if); | 64 | then_branch.syntax().text_range().end(), |
65 | edit.replace( | 65 | if_expr.syntax().text_range().end(), |
66 | target, | 66 | ); |
67 | update_expr_string(then_branch.to_string(), &[' ', '{']), | 67 | |
68 | ); | 68 | edit.delete(range_to_del_rest); |
69 | }); | 69 | edit.delete(range_to_del_else_if); |
70 | edit.replace( | ||
71 | target, | ||
72 | update_expr_string(then_branch.to_string(), &[' ', '{']), | ||
73 | ); | ||
74 | }, | ||
75 | ); | ||
70 | } | 76 | } |
71 | } else { | 77 | } else { |
72 | let target = block.syntax().text_range(); | 78 | let target = block.syntax().text_range(); |
73 | return acc.add(assist_id, assist_label, target, |edit| { | 79 | return acc.add( |
74 | let range_to_del = TextRange::new( | 80 | assist_id, |
75 | then_branch.syntax().text_range().end(), | 81 | AssistKind::RefactorRewrite, |
76 | l_curly_token.text_range().start(), | 82 | assist_label, |
77 | ); | 83 | target, |
84 | |edit| { | ||
85 | let range_to_del = TextRange::new( | ||
86 | then_branch.syntax().text_range().end(), | ||
87 | l_curly_token.text_range().start(), | ||
88 | ); | ||
78 | 89 | ||
79 | edit.delete(range_to_del); | 90 | edit.delete(range_to_del); |
80 | edit.replace(target, update_expr_string(block.to_string(), &[' ', '{'])); | 91 | edit.replace(target, update_expr_string(block.to_string(), &[' ', '{'])); |
81 | }); | 92 | }, |
93 | ); | ||
82 | } | 94 | } |
83 | } | 95 | } |
84 | _ => return None, | 96 | _ => return None, |
@@ -86,7 +98,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
86 | 98 | ||
87 | let unwrapped = unwrap_trivial_block(block); | 99 | let unwrapped = unwrap_trivial_block(block); |
88 | let target = unwrapped.syntax().text_range(); | 100 | let target = unwrapped.syntax().text_range(); |
89 | acc.add(assist_id, assist_label, target, |builder| { | 101 | acc.add(assist_id, AssistKind::RefactorRewrite, assist_label, target, |builder| { |
90 | builder.replace( | 102 | builder.replace( |
91 | parent.syntax().text_range(), | 103 | parent.syntax().text_range(), |
92 | update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']), | 104 | update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']), |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 1745f44a5..dd26e192f 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -37,6 +37,7 @@ pub struct GroupLabel(pub String); | |||
37 | #[derive(Debug, Clone)] | 37 | #[derive(Debug, Clone)] |
38 | pub struct Assist { | 38 | pub struct Assist { |
39 | pub id: AssistId, | 39 | pub id: AssistId, |
40 | pub kind: AssistKind, | ||
40 | /// Short description of the assist, as shown in the UI. | 41 | /// Short description of the assist, as shown in the UI. |
41 | pub label: String, | 42 | pub label: String, |
42 | pub group: Option<GroupLabel>, | 43 | pub group: Option<GroupLabel>, |
@@ -51,6 +52,18 @@ pub struct ResolvedAssist { | |||
51 | pub source_change: SourceChange, | 52 | pub source_change: SourceChange, |
52 | } | 53 | } |
53 | 54 | ||
55 | #[derive(Debug, Copy, Clone)] | ||
56 | pub enum AssistKind { | ||
57 | None, | ||
58 | QuickFix, | ||
59 | Refactor, | ||
60 | RefactorExtract, | ||
61 | RefactorInline, | ||
62 | RefactorRewrite, | ||
63 | Source, | ||
64 | OrganizeImports, | ||
65 | } | ||
66 | |||
54 | impl Assist { | 67 | impl Assist { |
55 | /// Return all the assists applicable at the given position. | 68 | /// Return all the assists applicable at the given position. |
56 | /// | 69 | /// |
@@ -86,13 +99,14 @@ impl Assist { | |||
86 | 99 | ||
87 | pub(crate) fn new( | 100 | pub(crate) fn new( |
88 | id: AssistId, | 101 | id: AssistId, |
102 | kind: AssistKind, | ||
89 | label: String, | 103 | label: String, |
90 | group: Option<GroupLabel>, | 104 | group: Option<GroupLabel>, |
91 | target: TextRange, | 105 | target: TextRange, |
92 | ) -> Assist { | 106 | ) -> Assist { |
93 | // FIXME: make fields private, so that this invariant can't be broken | 107 | // FIXME: make fields private, so that this invariant can't be broken |
94 | assert!(label.starts_with(|c: char| c.is_uppercase())); | 108 | assert!(label.starts_with(|c: char| c.is_uppercase())); |
95 | Assist { id, label, group, target } | 109 | Assist { id, kind, label, group, target } |
96 | } | 110 | } |
97 | } | 111 | } |
98 | 112 | ||