aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-05-06 17:45:35 +0100
committerAleksey Kladov <[email protected]>2020-05-07 15:27:54 +0100
commit4867968d22899395e6551f22641b3617e995140c (patch)
tree4f3ab3a70fbbb901ccec3cd162da00eaa9cbad09 /crates/ra_assists/src/handlers
parentf4cd75ac06dff7f5a95065a6c3868669e5c2ab27 (diff)
Refactor assists API to be more convenient for adding new assists
It now duplicates completion API in its shape.
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/add_custom_impl.rs9
-rw-r--r--crates/ra_assists/src/handlers/add_derive.rs9
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs6
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs10
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs21
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs61
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs32
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs8
-rw-r--r--crates/ra_assists/src/handlers/apply_demorgan.rs6
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs41
-rw-r--r--crates/ra_assists/src/handlers/change_return_type_to_result.rs10
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs31
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs161
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ra_assists/src/handlers/flip_binexpr.rs6
-rw-r--r--crates/ra_assists/src/handlers/flip_comma.rs6
-rw-r--r--crates/ra_assists/src/handlers/flip_trait_bound.rs6
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs31
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs6
-rw-r--r--crates/ra_assists/src/handlers/invert_if.rs36
-rw-r--r--crates/ra_assists/src/handlers/merge_imports.rs13
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs6
-rw-r--r--crates/ra_assists/src/handlers/move_bounds.rs57
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs10
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs18
-rw-r--r--crates/ra_assists/src/handlers/remove_dbg.rs6
-rw-r--r--crates/ra_assists/src/handlers/remove_mut.rs6
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs29
-rw-r--r--crates/ra_assists/src/handlers/replace_if_let_with_match.rs51
-rw-r--r--crates/ra_assists/src/handlers/replace_let_with_if_let.rs12
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs19
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs41
-rw-r--r--crates/ra_assists/src/handlers/split_import.rs6
-rw-r--r--crates/ra_assists/src/handlers/unwrap_block.rs6
34 files changed, 372 insertions, 410 deletions
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs
index 869d4dc04..795a225a4 100644
--- a/crates/ra_assists/src/handlers/add_custom_impl.rs
+++ b/crates/ra_assists/src/handlers/add_custom_impl.rs
@@ -6,7 +6,10 @@ use ra_syntax::{
6}; 6};
7use stdx::SepBy; 7use stdx::SepBy;
8 8
9use crate::{Assist, AssistCtx, AssistId}; 9use crate::{
10 assist_context::{AssistContext, Assists},
11 AssistId,
12};
10 13
11// Assist: add_custom_impl 14// Assist: add_custom_impl
12// 15//
@@ -25,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId};
25// 28//
26// } 29// }
27// ``` 30// ```
28pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { 31pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
29 let input = ctx.find_node_at_offset::<ast::AttrInput>()?; 32 let input = ctx.find_node_at_offset::<ast::AttrInput>()?;
30 let attr = input.syntax().parent().and_then(ast::Attr::cast)?; 33 let attr = input.syntax().parent().and_then(ast::Attr::cast)?;
31 34
@@ -49,7 +52,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
49 format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); 52 format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name);
50 53
51 let target = attr.syntax().text_range(); 54 let target = attr.syntax().text_range();
52 ctx.add_assist(AssistId("add_custom_impl"), label, target, |edit| { 55 acc.add(AssistId("add_custom_impl"), label, target, |edit| {
53 let new_attr_input = input 56 let new_attr_input = input
54 .syntax() 57 .syntax()
55 .descendants_with_tokens() 58 .descendants_with_tokens()
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs
index 2a6bb1cae..fb08c19e9 100644
--- a/crates/ra_assists/src/handlers/add_derive.rs
+++ b/crates/ra_assists/src/handlers/add_derive.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 TextSize, 4 TextSize,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{AssistContext, AssistId, Assists};
8 8
9// Assist: add_derive 9// Assist: add_derive
10// 10//
@@ -24,11 +24,11 @@ use crate::{Assist, AssistCtx, AssistId};
24// y: u32, 24// y: u32,
25// } 25// }
26// ``` 26// ```
27pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { 27pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; 28 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
29 let node_start = derive_insertion_offset(&nominal)?; 29 let node_start = derive_insertion_offset(&nominal)?;
30 let target = nominal.syntax().text_range(); 30 let target = nominal.syntax().text_range();
31 ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { 31 acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |edit| {
32 let derive_attr = nominal 32 let derive_attr = nominal
33 .attrs() 33 .attrs()
34 .filter_map(|x| x.as_simple_call()) 34 .filter_map(|x| x.as_simple_call())
@@ -57,9 +57,10 @@ fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextSize> {
57 57
58#[cfg(test)] 58#[cfg(test)]
59mod tests { 59mod tests {
60 use super::*;
61 use crate::tests::{check_assist, check_assist_target}; 60 use crate::tests::{check_assist, check_assist_target};
62 61
62 use super::*;
63
63 #[test] 64 #[test]
64 fn add_derive_new() { 65 fn add_derive_new() {
65 check_assist( 66 check_assist(
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index a59ec16b2..55409e501 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 TextRange, 4 TextRange,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{AssistContext, AssistId, Assists};
8 8
9// Assist: add_explicit_type 9// Assist: add_explicit_type
10// 10//
@@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId};
21// let x: i32 = 92; 21// let x: i32 = 92;
22// } 22// }
23// ``` 23// ```
24pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> { 24pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let stmt = ctx.find_node_at_offset::<LetStmt>()?; 25 let stmt = ctx.find_node_at_offset::<LetStmt>()?;
26 let expr = stmt.initializer()?; 26 let expr = stmt.initializer()?;
27 let pat = stmt.pat()?; 27 let pat = stmt.pat()?;
@@ -59,7 +59,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> {
59 59
60 let db = ctx.db; 60 let db = ctx.db;
61 let new_type_string = ty.display_truncated(db, None).to_string(); 61 let new_type_string = ty.display_truncated(db, None).to_string();
62 ctx.add_assist( 62 acc.add(
63 AssistId("add_explicit_type"), 63 AssistId("add_explicit_type"),
64 format!("Insert explicit type '{}'", new_type_string), 64 format!("Insert explicit type '{}'", new_type_string),
65 pat_range, 65 pat_range,
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index 81deb3dfa..275184e24 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -4,10 +4,10 @@ use ra_syntax::{
4 TextSize, 4 TextSize,
5}; 5};
6use stdx::format_to; 6use stdx::format_to;
7
8use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId};
9use test_utils::tested_by; 7use test_utils::tested_by;
10 8
9use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};
10
11// Assist add_from_impl_for_enum 11// Assist add_from_impl_for_enum
12// 12//
13// Adds a From impl for an enum variant with one tuple field 13// Adds a From impl for an enum variant with one tuple field
@@ -25,7 +25,7 @@ use test_utils::tested_by;
25// } 25// }
26// } 26// }
27// ``` 27// ```
28pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { 28pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
29 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; 29 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
30 let variant_name = variant.name()?; 30 let variant_name = variant.name()?;
31 let enum_name = variant.parent_enum().name()?; 31 let enum_name = variant.parent_enum().name()?;
@@ -42,13 +42,13 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> {
42 _ => return None, 42 _ => return None,
43 }; 43 };
44 44
45 if existing_from_impl(ctx.sema, &variant).is_some() { 45 if existing_from_impl(&ctx.sema, &variant).is_some() {
46 tested_by!(test_add_from_impl_already_exists); 46 tested_by!(test_add_from_impl_already_exists);
47 return None; 47 return None;
48 } 48 }
49 49
50 let target = variant.syntax().text_range(); 50 let target = variant.syntax().text_range();
51 ctx.add_assist( 51 acc.add(
52 AssistId("add_from_impl_for_enum"), 52 AssistId("add_from_impl_for_enum"),
53 "Add From impl for this enum variant", 53 "Add From impl for this enum variant",
54 target, 54 target,
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index 278079665..6b5616aa9 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -1,14 +1,13 @@
1use hir::HirDisplay;
2use ra_db::FileId;
1use ra_syntax::{ 3use ra_syntax::{
2 ast::{self, AstNode}, 4 ast::{self, edit::IndentLevel, ArgListOwner, AstNode, ModuleItemOwner},
3 SyntaxKind, SyntaxNode, TextSize, 5 SyntaxKind, SyntaxNode, TextSize,
4}; 6};
5
6use crate::{Assist, AssistCtx, AssistId};
7use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner};
8use hir::HirDisplay;
9use ra_db::FileId;
10use rustc_hash::{FxHashMap, FxHashSet}; 7use rustc_hash::{FxHashMap, FxHashSet};
11 8
9use crate::{AssistContext, AssistId, Assists};
10
12// Assist: add_function 11// Assist: add_function
13// 12//
14// Adds a stub function with a signature matching the function under the cursor. 13// Adds a stub function with a signature matching the function under the cursor.
@@ -34,7 +33,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
34// } 33// }
35// 34//
36// ``` 35// ```
37pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { 36pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
38 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; 37 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
39 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; 38 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
40 let path = path_expr.path()?; 39 let path = path_expr.path()?;
@@ -59,7 +58,7 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
59 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; 58 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
60 59
61 let target = call.syntax().text_range(); 60 let target = call.syntax().text_range();
62 ctx.add_assist(AssistId("add_function"), "Add function", target, |edit| { 61 acc.add(AssistId("add_function"), "Add function", target, |edit| {
63 let function_template = function_builder.render(); 62 let function_template = function_builder.render();
64 edit.set_file(function_template.file); 63 edit.set_file(function_template.file);
65 edit.set_cursor(function_template.cursor_offset); 64 edit.set_cursor(function_template.cursor_offset);
@@ -87,7 +86,7 @@ impl FunctionBuilder {
87 /// Prepares a generated function that matches `call` in `generate_in` 86 /// Prepares a generated function that matches `call` in `generate_in`
88 /// (or as close to `call` as possible, if `generate_in` is `None`) 87 /// (or as close to `call` as possible, if `generate_in` is `None`)
89 fn from_call( 88 fn from_call(
90 ctx: &AssistCtx, 89 ctx: &AssistContext,
91 call: &ast::CallExpr, 90 call: &ast::CallExpr,
92 path: &ast::Path, 91 path: &ast::Path,
93 target_module: Option<hir::InFile<hir::ModuleSource>>, 92 target_module: Option<hir::InFile<hir::ModuleSource>>,
@@ -152,7 +151,7 @@ fn fn_name(call: &ast::Path) -> Option<ast::Name> {
152 151
153/// Computes the type variables and arguments required for the generated function 152/// Computes the type variables and arguments required for the generated function
154fn fn_args( 153fn fn_args(
155 ctx: &AssistCtx, 154 ctx: &AssistContext,
156 call: &ast::CallExpr, 155 call: &ast::CallExpr,
157) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> { 156) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> {
158 let mut arg_names = Vec::new(); 157 let mut arg_names = Vec::new();
@@ -219,7 +218,7 @@ fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
219 } 218 }
220} 219}
221 220
222fn fn_arg_type(ctx: &AssistCtx, fn_arg: &ast::Expr) -> Option<String> { 221fn fn_arg_type(ctx: &AssistContext, fn_arg: &ast::Expr) -> Option<String> {
223 let ty = ctx.sema.type_of_expr(fn_arg)?; 222 let ty = ctx.sema.type_of_expr(fn_arg)?;
224 if ty.is_unknown() { 223 if ty.is_unknown() {
225 return None; 224 return None;
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
index 557344ebb..df114a0d8 100644
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ b/crates/ra_assists/src/handlers/add_impl.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4}; 4};
5use stdx::{format_to, SepBy}; 5use stdx::{format_to, SepBy};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{AssistContext, AssistId, Assists};
8 8
9// Assist: add_impl 9// Assist: add_impl
10// 10//
@@ -25,43 +25,36 @@ use crate::{Assist, AssistCtx, AssistId};
25// 25//
26// } 26// }
27// ``` 27// ```
28pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { 28pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; 29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
30 let name = nominal.name()?; 30 let name = nominal.name()?;
31 let target = nominal.syntax().text_range(); 31 let target = nominal.syntax().text_range();
32 ctx.add_assist( 32 acc.add(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), target, |edit| {
33 AssistId("add_impl"), 33 let type_params = nominal.type_param_list();
34 format!("Implement {}", name.text().as_str()), 34 let start_offset = nominal.syntax().text_range().end();
35 target, 35 let mut buf = String::new();
36 |edit| { 36 buf.push_str("\n\nimpl");
37 let type_params = nominal.type_param_list(); 37 if let Some(type_params) = &type_params {
38 let start_offset = nominal.syntax().text_range().end(); 38 format_to!(buf, "{}", type_params.syntax());
39 let mut buf = String::new(); 39 }
40 buf.push_str("\n\nimpl"); 40 buf.push_str(" ");
41 if let Some(type_params) = &type_params { 41 buf.push_str(name.text().as_str());
42 format_to!(buf, "{}", type_params.syntax()); 42 if let Some(type_params) = type_params {
43 } 43 let lifetime_params = type_params
44 buf.push_str(" "); 44 .lifetime_params()
45 buf.push_str(name.text().as_str()); 45 .filter_map(|it| it.lifetime_token())
46 if let Some(type_params) = type_params { 46 .map(|it| it.text().clone());
47 let lifetime_params = type_params 47 let type_params =
48 .lifetime_params() 48 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
49 .filter_map(|it| it.lifetime_token())
50 .map(|it| it.text().clone());
51 let type_params = type_params
52 .type_params()
53 .filter_map(|it| it.name())
54 .map(|it| it.text().clone());
55 49
56 let generic_params = lifetime_params.chain(type_params).sep_by(", "); 50 let generic_params = lifetime_params.chain(type_params).sep_by(", ");
57 format_to!(buf, "<{}>", generic_params) 51 format_to!(buf, "<{}>", generic_params)
58 } 52 }
59 buf.push_str(" {\n"); 53 buf.push_str(" {\n");
60 edit.set_cursor(start_offset + TextSize::of(&buf)); 54 edit.set_cursor(start_offset + TextSize::of(&buf));
61 buf.push_str("\n}"); 55 buf.push_str("\n}");
62 edit.insert(start_offset, buf); 56 edit.insert(start_offset, buf);
63 }, 57 })
64 )
65} 58}
66 59
67#[cfg(test)] 60#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index 7df786590..3482a75bf 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -9,9 +9,10 @@ use ra_syntax::{
9}; 9};
10 10
11use crate::{ 11use crate::{
12 assist_context::{AssistContext, Assists},
12 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 13 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
13 utils::{get_missing_assoc_items, resolve_target_trait}, 14 utils::{get_missing_assoc_items, resolve_target_trait},
14 Assist, AssistCtx, AssistId, 15 AssistId,
15}; 16};
16 17
17#[derive(PartialEq)] 18#[derive(PartialEq)]
@@ -50,8 +51,9 @@ enum AddMissingImplMembersMode {
50// 51//
51// } 52// }
52// ``` 53// ```
53pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option<Assist> { 54pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
54 add_missing_impl_members_inner( 55 add_missing_impl_members_inner(
56 acc,
55 ctx, 57 ctx,
56 AddMissingImplMembersMode::NoDefaultMethods, 58 AddMissingImplMembersMode::NoDefaultMethods,
57 "add_impl_missing_members", 59 "add_impl_missing_members",
@@ -91,8 +93,9 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option<Assist> {
91// 93//
92// } 94// }
93// ``` 95// ```
94pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option<Assist> { 96pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
95 add_missing_impl_members_inner( 97 add_missing_impl_members_inner(
98 acc,
96 ctx, 99 ctx,
97 AddMissingImplMembersMode::DefaultMethodsOnly, 100 AddMissingImplMembersMode::DefaultMethodsOnly,
98 "add_impl_default_members", 101 "add_impl_default_members",
@@ -101,11 +104,12 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option<Assist> {
101} 104}
102 105
103fn add_missing_impl_members_inner( 106fn add_missing_impl_members_inner(
104 ctx: AssistCtx, 107 acc: &mut Assists,
108 ctx: &AssistContext,
105 mode: AddMissingImplMembersMode, 109 mode: AddMissingImplMembersMode,
106 assist_id: &'static str, 110 assist_id: &'static str,
107 label: &'static str, 111 label: &'static str,
108) -> Option<Assist> { 112) -> Option<()> {
109 let _p = ra_prof::profile("add_missing_impl_members_inner"); 113 let _p = ra_prof::profile("add_missing_impl_members_inner");
110 let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?; 114 let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?;
111 let impl_item_list = impl_def.item_list()?; 115 let impl_item_list = impl_def.item_list()?;
@@ -142,12 +146,11 @@ fn add_missing_impl_members_inner(
142 return None; 146 return None;
143 } 147 }
144 148
145 let sema = ctx.sema;
146 let target = impl_def.syntax().text_range(); 149 let target = impl_def.syntax().text_range();
147 ctx.add_assist(AssistId(assist_id), label, target, |edit| { 150 acc.add(AssistId(assist_id), label, target, |edit| {
148 let n_existing_items = impl_item_list.assoc_items().count(); 151 let n_existing_items = impl_item_list.assoc_items().count();
149 let source_scope = sema.scope_for_def(trait_); 152 let source_scope = ctx.sema.scope_for_def(trait_);
150 let target_scope = sema.scope(impl_item_list.syntax()); 153 let target_scope = ctx.sema.scope(impl_item_list.syntax());
151 let ast_transform = QualifyPaths::new(&target_scope, &source_scope) 154 let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
152 .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); 155 .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def));
153 let items = missing_items 156 let items = missing_items
@@ -170,13 +173,12 @@ fn add_missing_impl_members_inner(
170} 173}
171 174
172fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 175fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
173 if fn_def.body().is_none() { 176 if fn_def.body().is_some() {
174 let body = make::block_expr(None, Some(make::expr_todo())); 177 return fn_def;
175 let body = IndentLevel(1).increase_indent(body);
176 fn_def.with_body(body)
177 } else {
178 fn_def
179 } 178 }
179 let body = make::block_expr(None, Some(make::expr_todo()));
180 let body = IndentLevel(1).increase_indent(body);
181 fn_def.with_body(body)
180} 182}
181 183
182#[cfg(test)] 184#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 1c3f8435a..fe7451dcf 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7}; 7};
8use stdx::{format_to, SepBy}; 8use stdx::{format_to, SepBy};
9 9
10use crate::{Assist, AssistCtx, AssistId}; 10use crate::{AssistContext, AssistId, Assists};
11 11
12// Assist: add_new 12// Assist: add_new
13// 13//
@@ -29,7 +29,7 @@ use crate::{Assist, AssistCtx, AssistId};
29// } 29// }
30// 30//
31// ``` 31// ```
32pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { 32pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let strukt = ctx.find_node_at_offset::<ast::StructDef>()?; 33 let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;
34 34
35 // We want to only apply this to non-union structs with named fields 35 // We want to only apply this to non-union structs with named fields
@@ -42,7 +42,7 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
42 let impl_def = find_struct_impl(&ctx, &strukt)?; 42 let impl_def = find_struct_impl(&ctx, &strukt)?;
43 43
44 let target = strukt.syntax().text_range(); 44 let target = strukt.syntax().text_range();
45 ctx.add_assist(AssistId("add_new"), "Add default constructor", target, |edit| { 45 acc.add(AssistId("add_new"), "Add default constructor", target, |edit| {
46 let mut buf = String::with_capacity(512); 46 let mut buf = String::with_capacity(512);
47 47
48 if impl_def.is_some() { 48 if impl_def.is_some() {
@@ -123,7 +123,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
123// 123//
124// FIXME: change the new fn checking to a more semantic approach when that's more 124// FIXME: change the new fn checking to a more semantic approach when that's more
125// viable (e.g. we process proc macros, etc) 125// viable (e.g. we process proc macros, etc)
126fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { 126fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> {
127 let db = ctx.db; 127 let db = ctx.db;
128 let module = strukt.syntax().ancestors().find(|node| { 128 let module = strukt.syntax().ancestors().find(|node| {
129 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) 129 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs
index a5b26e5b9..0feba5e11 100644
--- a/crates/ra_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ra_assists/src/handlers/apply_demorgan.rs
@@ -1,6 +1,6 @@
1use ra_syntax::ast::{self, AstNode}; 1use ra_syntax::ast::{self, AstNode};
2 2
3use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; 3use crate::{utils::invert_boolean_expression, AssistContext, AssistId, Assists};
4 4
5// Assist: apply_demorgan 5// Assist: apply_demorgan
6// 6//
@@ -21,7 +21,7 @@ use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId};
21// if !(x == 4 && y) {} 21// if !(x == 4 && y) {}
22// } 22// }
23// ``` 23// ```
24pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> { 24pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let expr = ctx.find_node_at_offset::<ast::BinExpr>()?; 25 let expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
26 let op = expr.op_kind()?; 26 let op = expr.op_kind()?;
27 let op_range = expr.op_token()?.text_range(); 27 let op_range = expr.op_token()?.text_range();
@@ -39,7 +39,7 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> {
39 let rhs_range = rhs.syntax().text_range(); 39 let rhs_range = rhs.syntax().text_range();
40 let not_rhs = invert_boolean_expression(rhs); 40 let not_rhs = invert_boolean_expression(rhs);
41 41
42 ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { 42 acc.add(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| {
43 edit.replace(op_range, opposite_op); 43 edit.replace(op_range, opposite_op);
44 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); 44 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
45 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); 45 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index 2224b9714..78d23150d 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -1,5 +1,6 @@
1use std::collections::BTreeSet; 1use std::collections::BTreeSet;
2 2
3use either::Either;
3use hir::{ 4use hir::{
4 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, 5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait,
5 Type, 6 Type,
@@ -12,12 +13,7 @@ use ra_syntax::{
12}; 13};
13use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
14 15
15use crate::{ 16use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, GroupLabel};
16 assist_ctx::{Assist, AssistCtx},
17 utils::insert_use_statement,
18 AssistId,
19};
20use either::Either;
21 17
22// Assist: auto_import 18// Assist: auto_import
23// 19//
@@ -38,7 +34,7 @@ use either::Either;
38// } 34// }
39// # pub mod std { pub mod collections { pub struct HashMap { } } } 35// # pub mod std { pub mod collections { pub struct HashMap { } } }
40// ``` 36// ```
41pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { 37pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
42 let auto_import_assets = AutoImportAssets::new(&ctx)?; 38 let auto_import_assets = AutoImportAssets::new(&ctx)?;
43 let proposed_imports = auto_import_assets.search_for_imports(ctx.db); 39 let proposed_imports = auto_import_assets.search_for_imports(ctx.db);
44 if proposed_imports.is_empty() { 40 if proposed_imports.is_empty() {
@@ -46,13 +42,19 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
46 } 42 }
47 43
48 let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; 44 let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range;
49 let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); 45 let group = auto_import_assets.get_import_group_message();
50 for import in proposed_imports { 46 for import in proposed_imports {
51 group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), range, |edit| { 47 acc.add_group(
52 insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); 48 &group,
53 }); 49 AssistId("auto_import"),
50 format!("Import `{}`", &import),
51 range,
52 |builder| {
53 insert_use_statement(&auto_import_assets.syntax_under_caret, &import, ctx, builder);
54 },
55 );
54 } 56 }
55 group.finish() 57 Some(())
56} 58}
57 59
58#[derive(Debug)] 60#[derive(Debug)]
@@ -63,7 +65,7 @@ struct AutoImportAssets {
63} 65}
64 66
65impl AutoImportAssets { 67impl AutoImportAssets {
66 fn new(ctx: &AssistCtx) -> Option<Self> { 68 fn new(ctx: &AssistContext) -> Option<Self> {
67 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { 69 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
68 Self::for_regular_path(path_under_caret, &ctx) 70 Self::for_regular_path(path_under_caret, &ctx)
69 } else { 71 } else {
@@ -71,7 +73,7 @@ impl AutoImportAssets {
71 } 73 }
72 } 74 }
73 75
74 fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistCtx) -> Option<Self> { 76 fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistContext) -> Option<Self> {
75 let syntax_under_caret = method_call.syntax().to_owned(); 77 let syntax_under_caret = method_call.syntax().to_owned();
76 let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; 78 let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?;
77 Some(Self { 79 Some(Self {
@@ -81,7 +83,7 @@ impl AutoImportAssets {
81 }) 83 })
82 } 84 }
83 85
84 fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistCtx) -> Option<Self> { 86 fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> {
85 let syntax_under_caret = path_under_caret.syntax().to_owned(); 87 let syntax_under_caret = path_under_caret.syntax().to_owned();
86 if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { 88 if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() {
87 return None; 89 return None;
@@ -104,8 +106,8 @@ impl AutoImportAssets {
104 } 106 }
105 } 107 }
106 108
107 fn get_import_group_message(&self) -> String { 109 fn get_import_group_message(&self) -> GroupLabel {
108 match &self.import_candidate { 110 let name = match &self.import_candidate {
109 ImportCandidate::UnqualifiedName(name) => format!("Import {}", name), 111 ImportCandidate::UnqualifiedName(name) => format!("Import {}", name),
110 ImportCandidate::QualifierStart(qualifier_start) => { 112 ImportCandidate::QualifierStart(qualifier_start) => {
111 format!("Import {}", qualifier_start) 113 format!("Import {}", qualifier_start)
@@ -116,7 +118,8 @@ impl AutoImportAssets {
116 ImportCandidate::TraitMethod(_, trait_method_name) => { 118 ImportCandidate::TraitMethod(_, trait_method_name) => {
117 format!("Import a trait for method {}", trait_method_name) 119 format!("Import a trait for method {}", trait_method_name)
118 } 120 }
119 } 121 };
122 GroupLabel(name)
120 } 123 }
121 124
122 fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { 125 fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> {
@@ -383,7 +386,7 @@ mod tests {
383 } 386 }
384 ", 387 ",
385 r" 388 r"
386 use PubMod1::PubStruct; 389 use PubMod3::PubStruct;
387 390
388 PubSt<|>ruct 391 PubSt<|>ruct
389 392
diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs
index 1e8d986cd..5c907097e 100644
--- a/crates/ra_assists/src/handlers/change_return_type_to_result.rs
+++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs
@@ -1,11 +1,11 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast, AstNode, 2 ast::{self, BlockExpr, Expr, LoopBodyOwner},
3 AstNode,
3 SyntaxKind::{COMMENT, WHITESPACE}, 4 SyntaxKind::{COMMENT, WHITESPACE},
4 SyntaxNode, TextSize, 5 SyntaxNode, TextSize,
5}; 6};
6 7
7use crate::{Assist, AssistCtx, AssistId}; 8use crate::{AssistContext, AssistId, Assists};
8use ast::{BlockExpr, Expr, LoopBodyOwner};
9 9
10// Assist: change_return_type_to_result 10// Assist: change_return_type_to_result
11// 11//
@@ -18,7 +18,7 @@ use ast::{BlockExpr, Expr, LoopBodyOwner};
18// ``` 18// ```
19// fn foo() -> Result<i32, > { Ok(42i32) } 19// fn foo() -> Result<i32, > { Ok(42i32) }
20// ``` 20// ```
21pub(crate) fn change_return_type_to_result(ctx: AssistCtx) -> Option<Assist> { 21pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
22 let fn_def = ctx.find_node_at_offset::<ast::FnDef>(); 22 let fn_def = ctx.find_node_at_offset::<ast::FnDef>();
23 let fn_def = &mut fn_def?; 23 let fn_def = &mut fn_def?;
24 let ret_type = &fn_def.ret_type()?.type_ref()?; 24 let ret_type = &fn_def.ret_type()?.type_ref()?;
@@ -33,7 +33,7 @@ pub(crate) fn change_return_type_to_result(ctx: AssistCtx) -> Option<Assist> {
33 return None; 33 return None;
34 } 34 }
35 35
36 ctx.add_assist( 36 acc.add(
37 AssistId("change_return_type_to_result"), 37 AssistId("change_return_type_to_result"),
38 "Change return type to Result", 38 "Change return type to Result",
39 ret_type.syntax().text_range(), 39 ret_type.syntax().text_range(),
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index 489db83e6..e631766ef 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -7,10 +7,10 @@ use ra_syntax::{
7 }, 7 },
8 SyntaxNode, TextSize, T, 8 SyntaxNode, TextSize, T,
9}; 9};
10
11use crate::{Assist, AssistCtx, AssistId};
12use test_utils::tested_by; 10use test_utils::tested_by;
13 11
12use crate::{AssistContext, AssistId, Assists};
13
14// Assist: change_visibility 14// Assist: change_visibility
15// 15//
16// Adds or changes existing visibility specifier. 16// Adds or changes existing visibility specifier.
@@ -22,14 +22,14 @@ use test_utils::tested_by;
22// ``` 22// ```
23// pub(crate) fn frobnicate() {} 23// pub(crate) fn frobnicate() {}
24// ``` 24// ```
25pub(crate) fn change_visibility(ctx: AssistCtx) -> Option<Assist> { 25pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() { 26 if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
27 return change_vis(ctx, vis); 27 return change_vis(acc, vis);
28 } 28 }
29 add_vis(ctx) 29 add_vis(acc, ctx)
30} 30}
31 31
32fn add_vis(ctx: AssistCtx) -> Option<Assist> { 32fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { 33 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
34 T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, 34 T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
35 _ => false, 35 _ => false,
@@ -66,15 +66,10 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> {
66 return None; 66 return None;
67 }; 67 };
68 68
69 ctx.add_assist( 69 acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| {
70 AssistId("change_visibility"), 70 edit.insert(offset, "pub(crate) ");
71 "Change visibility to pub(crate)", 71 edit.set_cursor(offset);
72 target, 72 })
73 |edit| {
74 edit.insert(offset, "pub(crate) ");
75 edit.set_cursor(offset);
76 },
77 )
78} 73}
79 74
80fn vis_offset(node: &SyntaxNode) -> TextSize { 75fn vis_offset(node: &SyntaxNode) -> TextSize {
@@ -88,10 +83,10 @@ fn vis_offset(node: &SyntaxNode) -> TextSize {
88 .unwrap_or_else(|| node.text_range().start()) 83 .unwrap_or_else(|| node.text_range().start())
89} 84}
90 85
91fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { 86fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
92 if vis.syntax().text() == "pub" { 87 if vis.syntax().text() == "pub" {
93 let target = vis.syntax().text_range(); 88 let target = vis.syntax().text_range();
94 return ctx.add_assist( 89 return acc.add(
95 AssistId("change_visibility"), 90 AssistId("change_visibility"),
96 "Change Visibility to pub(crate)", 91 "Change Visibility to pub(crate)",
97 target, 92 target,
@@ -103,7 +98,7 @@ fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> {
103 } 98 }
104 if vis.syntax().text() == "pub(crate)" { 99 if vis.syntax().text() == "pub(crate)" {
105 let target = vis.syntax().text_range(); 100 let target = vis.syntax().text_range();
106 return ctx.add_assist( 101 return acc.add(
107 AssistId("change_visibility"), 102 AssistId("change_visibility"),
108 "Change visibility to pub", 103 "Change visibility to pub",
109 target, 104 target,
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index 4bd6040b2..ccf91797c 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9}; 9};
10 10
11use crate::{ 11use crate::{
12 assist_ctx::{Assist, AssistCtx}, 12 assist_context::{AssistContext, Assists},
13 utils::invert_boolean_expression, 13 utils::invert_boolean_expression,
14 AssistId, 14 AssistId,
15}; 15};
@@ -36,7 +36,7 @@ use crate::{
36// bar(); 36// bar();
37// } 37// }
38// ``` 38// ```
39pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { 39pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; 40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
41 if if_expr.else_branch().is_some() { 41 if if_expr.else_branch().is_some() {
42 return None; 42 return None;
@@ -96,93 +96,88 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
96 let cursor_position = ctx.frange.range.start(); 96 let cursor_position = ctx.frange.range.start();
97 97
98 let target = if_expr.syntax().text_range(); 98 let target = if_expr.syntax().text_range();
99 ctx.add_assist( 99 acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| {
100 AssistId("convert_to_guarded_return"), 100 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
101 "Convert to guarded return", 101 let new_block = match if_let_pat {
102 target, 102 None => {
103 |edit| { 103 // If.
104 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 104 let new_expr = {
105 let new_block = match if_let_pat { 105 let then_branch =
106 None => { 106 make::block_expr(once(make::expr_stmt(early_expression).into()), None);
107 // If. 107 let cond = invert_boolean_expression(cond_expr);
108 let new_expr = { 108 let e = make::expr_if(make::condition(cond, None), then_branch);
109 let then_branch = 109 if_indent_level.increase_indent(e)
110 make::block_expr(once(make::expr_stmt(early_expression).into()), None); 110 };
111 let cond = invert_boolean_expression(cond_expr); 111 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
112 let e = make::expr_if(make::condition(cond, None), then_branch); 112 }
113 if_indent_level.increase_indent(e) 113 Some((path, bound_ident)) => {
114 }; 114 // If-let.
115 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) 115 let match_expr = {
116 } 116 let happy_arm = {
117 Some((path, bound_ident)) => { 117 let pat = make::tuple_struct_pat(
118 // If-let. 118 path,
119 let match_expr = { 119 once(make::bind_pat(make::name("it")).into()),
120 let happy_arm = {
121 let pat = make::tuple_struct_pat(
122 path,
123 once(make::bind_pat(make::name("it")).into()),
124 );
125 let expr = {
126 let name_ref = make::name_ref("it");
127 let segment = make::path_segment(name_ref);
128 let path = make::path_unqualified(segment);
129 make::expr_path(path)
130 };
131 make::match_arm(once(pat.into()), expr)
132 };
133
134 let sad_arm = make::match_arm(
135 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
136 once(make::placeholder_pat().into()),
137 early_expression,
138 ); 120 );
139 121 let expr = {
140 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) 122 let name_ref = make::name_ref("it");
123 let segment = make::path_segment(name_ref);
124 let path = make::path_unqualified(segment);
125 make::expr_path(path)
126 };
127 make::match_arm(once(pat.into()), expr)
141 }; 128 };
142 129
143 let let_stmt = make::let_stmt( 130 let sad_arm = make::match_arm(
144 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), 131 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
145 Some(match_expr), 132 once(make::placeholder_pat().into()),
133 early_expression,
146 ); 134 );
147 let let_stmt = if_indent_level.increase_indent(let_stmt); 135
148 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) 136 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
149 } 137 };
150 }; 138
151 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); 139 let let_stmt = make::let_stmt(
152 edit.set_cursor(cursor_position); 140 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
153 141 Some(match_expr),
154 fn replace(
155 new_expr: &SyntaxNode,
156 then_block: &ast::BlockExpr,
157 parent_block: &ast::BlockExpr,
158 if_expr: &ast::IfExpr,
159 ) -> SyntaxNode {
160 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
161 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
162 let end_of_then =
163 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
164 end_of_then.prev_sibling_or_token().unwrap()
165 } else {
166 end_of_then
167 };
168 let mut then_statements = new_expr.children_with_tokens().chain(
169 then_block_items
170 .syntax()
171 .children_with_tokens()
172 .skip(1)
173 .take_while(|i| *i != end_of_then),
174 ); 142 );
175 replace_children( 143 let let_stmt = if_indent_level.increase_indent(let_stmt);
176 &parent_block.syntax(), 144 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
177 RangeInclusive::new(
178 if_expr.clone().syntax().clone().into(),
179 if_expr.syntax().clone().into(),
180 ),
181 &mut then_statements,
182 )
183 } 145 }
184 }, 146 };
185 ) 147 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
148 edit.set_cursor(cursor_position);
149
150 fn replace(
151 new_expr: &SyntaxNode,
152 then_block: &ast::BlockExpr,
153 parent_block: &ast::BlockExpr,
154 if_expr: &ast::IfExpr,
155 ) -> SyntaxNode {
156 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
157 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
158 let end_of_then =
159 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
160 end_of_then.prev_sibling_or_token().unwrap()
161 } else {
162 end_of_then
163 };
164 let mut then_statements = new_expr.children_with_tokens().chain(
165 then_block_items
166 .syntax()
167 .children_with_tokens()
168 .skip(1)
169 .take_while(|i| *i != end_of_then),
170 );
171 replace_children(
172 &parent_block.syntax(),
173 RangeInclusive::new(
174 if_expr.clone().syntax().clone().into(),
175 if_expr.syntax().clone().into(),
176 ),
177 &mut then_statements,
178 )
179 }
180 })
186} 181}
187 182
188#[cfg(test)] 183#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 7c8f8bdf2..13c1e7e80 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -5,7 +5,7 @@ use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{AssistContext, AssistId, Assists};
9 9
10// Assist: fill_match_arms 10// Assist: fill_match_arms
11// 11//
@@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId};
31// } 31// }
32// } 32// }
33// ``` 33// ```
34pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { 34pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
35 let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; 35 let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
36 let match_arm_list = match_expr.match_arm_list()?; 36 let match_arm_list = match_expr.match_arm_list()?;
37 37
@@ -93,7 +93,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
93 } 93 }
94 94
95 let target = match_expr.syntax().text_range(); 95 let target = match_expr.syntax().text_range();
96 ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { 96 acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |edit| {
97 let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); 97 let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms);
98 edit.set_cursor(expr.syntax().text_range().start()); 98 edit.set_cursor(expr.syntax().text_range().start());
99 edit.replace_ast(match_arm_list, new_arm_list); 99 edit.replace_ast(match_arm_list, new_arm_list);
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs
index cb7264d7b..692ba4895 100644
--- a/crates/ra_assists/src/handlers/flip_binexpr.rs
+++ b/crates/ra_assists/src/handlers/flip_binexpr.rs
@@ -1,6 +1,6 @@
1use ra_syntax::ast::{AstNode, BinExpr, BinOp}; 1use ra_syntax::ast::{AstNode, BinExpr, BinOp};
2 2
3use crate::{Assist, AssistCtx, AssistId}; 3use crate::{AssistContext, AssistId, Assists};
4 4
5// Assist: flip_binexpr 5// Assist: flip_binexpr
6// 6//
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
17// let _ = 2 + 90; 17// let _ = 2 + 90;
18// } 18// }
19// ``` 19// ```
20pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> { 20pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
21 let expr = ctx.find_node_at_offset::<BinExpr>()?; 21 let expr = ctx.find_node_at_offset::<BinExpr>()?;
22 let lhs = expr.lhs()?.syntax().clone(); 22 let lhs = expr.lhs()?.syntax().clone();
23 let rhs = expr.rhs()?.syntax().clone(); 23 let rhs = expr.rhs()?.syntax().clone();
@@ -33,7 +33,7 @@ pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> {
33 return None; 33 return None;
34 } 34 }
35 35
36 ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { 36 acc.add(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| {
37 if let FlipAction::FlipAndReplaceOp(new_op) = action { 37 if let FlipAction::FlipAndReplaceOp(new_op) = action {
38 edit.replace(op_range, new_op); 38 edit.replace(op_range, new_op);
39 } 39 }
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs
index 24982ae22..dfe2a7fed 100644
--- a/crates/ra_assists/src/handlers/flip_comma.rs
+++ b/crates/ra_assists/src/handlers/flip_comma.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{algo::non_trivia_sibling, Direction, T}; 1use ra_syntax::{algo::non_trivia_sibling, Direction, T};
2 2
3use crate::{Assist, AssistCtx, AssistId}; 3use crate::{AssistContext, AssistId, Assists};
4 4
5// Assist: flip_comma 5// Assist: flip_comma
6// 6//
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
17// ((3, 4), (1, 2)); 17// ((3, 4), (1, 2));
18// } 18// }
19// ``` 19// ```
20pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> { 20pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
21 let comma = ctx.find_token_at_offset(T![,])?; 21 let comma = ctx.find_token_at_offset(T![,])?;
22 let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; 22 let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
23 let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; 23 let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;
@@ -28,7 +28,7 @@ pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> {
28 return None; 28 return None;
29 } 29 }
30 30
31 ctx.add_assist(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { 31 acc.add(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| {
32 edit.replace(prev.text_range(), next.to_string()); 32 edit.replace(prev.text_range(), next.to_string());
33 edit.replace(next.text_range(), prev.to_string()); 33 edit.replace(next.text_range(), prev.to_string());
34 }) 34 })
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs
index 6a3b2df67..8a08702ab 100644
--- a/crates/ra_assists/src/handlers/flip_trait_bound.rs
+++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 Direction, T, 4 Direction, T,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{AssistContext, AssistId, Assists};
8 8
9// Assist: flip_trait_bound 9// Assist: flip_trait_bound
10// 10//
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
17// ``` 17// ```
18// fn foo<T: Copy + Clone>() { } 18// fn foo<T: Copy + Clone>() { }
19// ``` 19// ```
20pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> { 20pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
21 // We want to replicate the behavior of `flip_binexpr` by only suggesting 21 // We want to replicate the behavior of `flip_binexpr` by only suggesting
22 // the assist when the cursor is on a `+` 22 // the assist when the cursor is on a `+`
23 let plus = ctx.find_token_at_offset(T![+])?; 23 let plus = ctx.find_token_at_offset(T![+])?;
@@ -33,7 +33,7 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> {
33 ); 33 );
34 34
35 let target = plus.text_range(); 35 let target = plus.text_range();
36 ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| { 36 acc.add(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| {
37 edit.replace(before.text_range(), after.to_string()); 37 edit.replace(before.text_range(), after.to_string());
38 edit.replace(after.text_range(), before.to_string()); 38 edit.replace(after.text_range(), before.to_string());
39 }) 39 })
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index e5765c845..5b26814d3 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -5,7 +5,10 @@ use ra_syntax::{
5}; 5};
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::{assist_ctx::ActionBuilder, Assist, AssistCtx, AssistId}; 8use crate::{
9 assist_context::{AssistContext, Assists},
10 AssistId,
11};
9 12
10// Assist: inline_local_variable 13// Assist: inline_local_variable
11// 14//
@@ -23,7 +26,7 @@ use crate::{assist_ctx::ActionBuilder, Assist, AssistCtx, AssistId};
23// (1 + 2) * 4; 26// (1 + 2) * 4;
24// } 27// }
25// ``` 28// ```
26pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { 29pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
27 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; 30 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
28 let bind_pat = match let_stmt.pat()? { 31 let bind_pat = match let_stmt.pat()? {
29 ast::Pat::BindPat(pat) => pat, 32 ast::Pat::BindPat(pat) => pat,
@@ -33,7 +36,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
33 tested_by!(test_not_inline_mut_variable); 36 tested_by!(test_not_inline_mut_variable);
34 return None; 37 return None;
35 } 38 }
36 if !bind_pat.syntax().text_range().contains_inclusive(ctx.frange.range.start()) { 39 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
37 tested_by!(not_applicable_outside_of_bind_pat); 40 tested_by!(not_applicable_outside_of_bind_pat);
38 return None; 41 return None;
39 } 42 }
@@ -107,20 +110,14 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
107 let init_in_paren = format!("({})", &init_str); 110 let init_in_paren = format!("({})", &init_str);
108 111
109 let target = bind_pat.syntax().text_range(); 112 let target = bind_pat.syntax().text_range();
110 ctx.add_assist( 113 acc.add(AssistId("inline_local_variable"), "Inline variable", target, move |builder| {
111 AssistId("inline_local_variable"), 114 builder.delete(delete_range);
112 "Inline variable", 115 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
113 target, 116 let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() };
114 move |edit: &mut ActionBuilder| { 117 builder.replace(desc.file_range.range, replacement)
115 edit.delete(delete_range); 118 }
116 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 119 builder.set_cursor(delete_range.start())
117 let replacement = 120 })
118 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
119 edit.replace(desc.file_range.range, replacement)
120 }
121 edit.set_cursor(delete_range.start())
122 },
123 )
124} 121}
125 122
126#[cfg(test)] 123#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index 3c340ff3b..fdf3ada0d 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9use stdx::format_to; 9use stdx::format_to;
10use test_utils::tested_by; 10use test_utils::tested_by;
11 11
12use crate::{Assist, AssistCtx, AssistId}; 12use crate::{AssistContext, AssistId, Assists};
13 13
14// Assist: introduce_variable 14// Assist: introduce_variable
15// 15//
@@ -27,7 +27,7 @@ use crate::{Assist, AssistCtx, AssistId};
27// var_name * 4; 27// var_name * 4;
28// } 28// }
29// ``` 29// ```
30pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { 30pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
31 if ctx.frange.range.is_empty() { 31 if ctx.frange.range.is_empty() {
32 return None; 32 return None;
33 } 33 }
@@ -43,7 +43,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
43 return None; 43 return None;
44 } 44 }
45 let target = expr.syntax().text_range(); 45 let target = expr.syntax().text_range();
46 ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { 46 acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| {
47 let mut buf = String::new(); 47 let mut buf = String::new();
48 48
49 let cursor_offset = if wrap_in_block { 49 let cursor_offset = if wrap_in_block {
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs
index b16271443..527c7caef 100644
--- a/crates/ra_assists/src/handlers/invert_if.rs
+++ b/crates/ra_assists/src/handlers/invert_if.rs
@@ -3,7 +3,11 @@ use ra_syntax::{
3 T, 3 T,
4}; 4};
5 5
6use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId}; 6use crate::{
7 assist_context::{AssistContext, Assists},
8 utils::invert_boolean_expression,
9 AssistId,
10};
7 11
8// Assist: invert_if 12// Assist: invert_if
9// 13//
@@ -24,7 +28,7 @@ use crate::{utils::invert_boolean_expression, Assist, AssistCtx, AssistId};
24// } 28// }
25// ``` 29// ```
26 30
27pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { 31pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 let if_keyword = ctx.find_token_at_offset(T![if])?; 32 let if_keyword = ctx.find_token_at_offset(T![if])?;
29 let expr = ast::IfExpr::cast(if_keyword.parent())?; 33 let expr = ast::IfExpr::cast(if_keyword.parent())?;
30 let if_range = if_keyword.text_range(); 34 let if_range = if_keyword.text_range();
@@ -40,21 +44,21 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
40 44
41 let cond = expr.condition()?.expr()?; 45 let cond = expr.condition()?.expr()?;
42 let then_node = expr.then_branch()?.syntax().clone(); 46 let then_node = expr.then_branch()?.syntax().clone();
47 let else_block = match expr.else_branch()? {
48 ast::ElseBranch::Block(it) => it,
49 ast::ElseBranch::IfExpr(_) => return None,
50 };
43 51
44 if let ast::ElseBranch::Block(else_block) = expr.else_branch()? { 52 let cond_range = cond.syntax().text_range();
45 let cond_range = cond.syntax().text_range(); 53 let flip_cond = invert_boolean_expression(cond);
46 let flip_cond = invert_boolean_expression(cond); 54 let else_node = else_block.syntax();
47 let else_node = else_block.syntax(); 55 let else_range = else_node.text_range();
48 let else_range = else_node.text_range(); 56 let then_range = then_node.text_range();
49 let then_range = then_node.text_range(); 57 acc.add(AssistId("invert_if"), "Invert if", if_range, |edit| {
50 return ctx.add_assist(AssistId("invert_if"), "Invert if", if_range, |edit| { 58 edit.replace(cond_range, flip_cond.syntax().text());
51 edit.replace(cond_range, flip_cond.syntax().text()); 59 edit.replace(else_range, then_node.text());
52 edit.replace(else_range, then_node.text()); 60 edit.replace(then_range, else_node.text());
53 edit.replace(then_range, else_node.text()); 61 })
54 });
55 }
56
57 None
58} 62}
59 63
60#[cfg(test)] 64#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs
index de74d83d8..8e1d93312 100644
--- a/crates/ra_assists/src/handlers/merge_imports.rs
+++ b/crates/ra_assists/src/handlers/merge_imports.rs
@@ -6,7 +6,10 @@ use ra_syntax::{
6 AstNode, Direction, InsertPosition, SyntaxElement, T, 6 AstNode, Direction, InsertPosition, SyntaxElement, T,
7}; 7};
8 8
9use crate::{Assist, AssistCtx, AssistId}; 9use crate::{
10 assist_context::{AssistContext, Assists},
11 AssistId,
12};
10 13
11// Assist: merge_imports 14// Assist: merge_imports
12// 15//
@@ -20,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId};
20// ``` 23// ```
21// use std::{fmt::Formatter, io}; 24// use std::{fmt::Formatter, io};
22// ``` 25// ```
23pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { 26pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let tree: ast::UseTree = ctx.find_node_at_offset()?; 27 let tree: ast::UseTree = ctx.find_node_at_offset()?;
25 let mut rewriter = SyntaxRewriter::default(); 28 let mut rewriter = SyntaxRewriter::default();
26 let mut offset = ctx.frange.range.start(); 29 let mut offset = ctx.frange.range.start();
@@ -53,10 +56,10 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> {
53 }; 56 };
54 57
55 let target = tree.syntax().text_range(); 58 let target = tree.syntax().text_range();
56 ctx.add_assist(AssistId("merge_imports"), "Merge imports", target, |edit| { 59 acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| {
57 edit.rewrite(rewriter); 60 builder.rewrite(rewriter);
58 // FIXME: we only need because our diff is imprecise 61 // FIXME: we only need because our diff is imprecise
59 edit.set_cursor(offset); 62 builder.set_cursor(offset);
60 }) 63 })
61} 64}
62 65
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index 7c4d9d55d..cfe4df47b 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -6,7 +6,7 @@ use ra_syntax::{
6 Direction, TextSize, 6 Direction, TextSize,
7}; 7};
8 8
9use crate::{Assist, AssistCtx, AssistId, TextRange}; 9use crate::{AssistContext, AssistId, Assists, TextRange};
10 10
11// Assist: merge_match_arms 11// Assist: merge_match_arms
12// 12//
@@ -32,7 +32,7 @@ use crate::{Assist, AssistCtx, AssistId, TextRange};
32// } 32// }
33// } 33// }
34// ``` 34// ```
35pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> { 35pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?; 36 let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?;
37 // Don't try to handle arms with guards for now - can add support for this later 37 // Don't try to handle arms with guards for now - can add support for this later
38 if current_arm.guard().is_some() { 38 if current_arm.guard().is_some() {
@@ -70,7 +70,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
70 return None; 70 return None;
71 } 71 }
72 72
73 ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| { 73 acc.add(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| {
74 let pats = if arms_to_merge.iter().any(contains_placeholder) { 74 let pats = if arms_to_merge.iter().any(contains_placeholder) {
75 "_".into() 75 "_".into()
76 } else { 76 } else {
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs
index 44e50cb6e..a41aacfc3 100644
--- a/crates/ra_assists/src/handlers/move_bounds.rs
+++ b/crates/ra_assists/src/handlers/move_bounds.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 T, 5 T,
6}; 6};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{AssistContext, AssistId, Assists};
9 9
10// Assist: move_bounds_to_where_clause 10// Assist: move_bounds_to_where_clause
11// 11//
@@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId};
22// f(x) 22// f(x)
23// } 23// }
24// ``` 24// ```
25pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { 25pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; 26 let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?;
27 27
28 let mut type_params = type_param_list.type_params(); 28 let mut type_params = type_param_list.type_params();
@@ -50,36 +50,29 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> {
50 }; 50 };
51 51
52 let target = type_param_list.syntax().text_range(); 52 let target = type_param_list.syntax().text_range();
53 ctx.add_assist( 53 acc.add(AssistId("move_bounds_to_where_clause"), "Move to where clause", target, |edit| {
54 AssistId("move_bounds_to_where_clause"), 54 let new_params = type_param_list
55 "Move to where clause", 55 .type_params()
56 target, 56 .filter(|it| it.type_bound_list().is_some())
57 |edit| { 57 .map(|type_param| {
58 let new_params = type_param_list 58 let without_bounds = type_param.remove_bounds();
59 .type_params() 59 (type_param, without_bounds)
60 .filter(|it| it.type_bound_list().is_some()) 60 });
61 .map(|type_param| { 61
62 let without_bounds = type_param.remove_bounds(); 62 let new_type_param_list = type_param_list.replace_descendants(new_params);
63 (type_param, without_bounds) 63 edit.replace_ast(type_param_list.clone(), new_type_param_list);
64 }); 64
65 65 let where_clause = {
66 let new_type_param_list = type_param_list.replace_descendants(new_params); 66 let predicates = type_param_list.type_params().filter_map(build_predicate);
67 edit.replace_ast(type_param_list.clone(), new_type_param_list); 67 make::where_clause(predicates)
68 68 };
69 let where_clause = { 69
70 let predicates = type_param_list.type_params().filter_map(build_predicate); 70 let to_insert = match anchor.prev_sibling_or_token() {
71 make::where_clause(predicates) 71 Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()),
72 }; 72 _ => format!(" {}", where_clause.syntax()),
73 73 };
74 let to_insert = match anchor.prev_sibling_or_token() { 74 edit.insert(anchor.text_range().start(), to_insert);
75 Some(ref elem) if elem.kind() == WHITESPACE => { 75 })
76 format!("{} ", where_clause.syntax())
77 }
78 _ => format!(" {}", where_clause.syntax()),
79 };
80 edit.insert(anchor.text_range().start(), to_insert);
81 },
82 )
83} 76}
84 77
85fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { 78fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs
index 29bc9a9ff..fc0335b57 100644
--- a/crates/ra_assists/src/handlers/move_guard.rs
+++ b/crates/ra_assists/src/handlers/move_guard.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 TextSize, 4 TextSize,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{AssistContext, AssistId, Assists};
8 8
9// Assist: move_guard_to_arm_body 9// Assist: move_guard_to_arm_body
10// 10//
@@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId};
31// } 31// }
32// } 32// }
33// ``` 33// ```
34pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> { 34pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
35 let match_arm = ctx.find_node_at_offset::<MatchArm>()?; 35 let match_arm = ctx.find_node_at_offset::<MatchArm>()?;
36 let guard = match_arm.guard()?; 36 let guard = match_arm.guard()?;
37 let space_before_guard = guard.syntax().prev_sibling_or_token(); 37 let space_before_guard = guard.syntax().prev_sibling_or_token();
@@ -41,7 +41,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
41 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); 41 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text());
42 42
43 let target = guard.syntax().text_range(); 43 let target = guard.syntax().text_range();
44 ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { 44 acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| {
45 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { 45 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) {
46 Some(tok) => { 46 Some(tok) => {
47 if ast::Whitespace::cast(tok.clone()).is_some() { 47 if ast::Whitespace::cast(tok.clone()).is_some() {
@@ -88,7 +88,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
88// } 88// }
89// } 89// }
90// ``` 90// ```
91pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { 91pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
92 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; 92 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
93 let match_pat = match_arm.pat()?; 93 let match_pat = match_arm.pat()?;
94 94
@@ -109,7 +109,7 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
109 let buf = format!(" if {}", cond.syntax().text()); 109 let buf = format!(" if {}", cond.syntax().text());
110 110
111 let target = if_expr.syntax().text_range(); 111 let target = if_expr.syntax().text_range();
112 ctx.add_assist( 112 acc.add(
113 AssistId("move_arm_cond_to_match_guard"), 113 AssistId("move_arm_cond_to_match_guard"),
114 "Move condition to match guard", 114 "Move condition to match guard",
115 target, 115 target,
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index 155c679b4..c20ffe0b3 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 TextSize, 5 TextSize,
6}; 6};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{AssistContext, AssistId, Assists};
9 9
10// Assist: make_raw_string 10// Assist: make_raw_string
11// 11//
@@ -22,11 +22,11 @@ use crate::{Assist, AssistCtx, AssistId};
22// r#"Hello, World!"#; 22// r#"Hello, World!"#;
23// } 23// }
24// ``` 24// ```
25pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { 25pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; 26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
27 let value = token.value()?; 27 let value = token.value()?;
28 let target = token.syntax().text_range(); 28 let target = token.syntax().text_range();
29 ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| { 29 acc.add(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| {
30 let max_hash_streak = count_hashes(&value); 30 let max_hash_streak = count_hashes(&value);
31 let mut hashes = String::with_capacity(max_hash_streak + 1); 31 let mut hashes = String::with_capacity(max_hash_streak + 1);
32 for _ in 0..hashes.capacity() { 32 for _ in 0..hashes.capacity() {
@@ -51,11 +51,11 @@ pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> {
51// "Hello, \"World!\""; 51// "Hello, \"World!\"";
52// } 52// }
53// ``` 53// ```
54pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { 54pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; 55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
56 let value = token.value()?; 56 let value = token.value()?;
57 let target = token.syntax().text_range(); 57 let target = token.syntax().text_range();
58 ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| { 58 acc.add(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| {
59 // parse inside string to escape `"` 59 // parse inside string to escape `"`
60 let escaped = value.escape_default().to_string(); 60 let escaped = value.escape_default().to_string();
61 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); 61 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
@@ -77,10 +77,10 @@ pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> {
77// r##"Hello, World!"##; 77// r##"Hello, World!"##;
78// } 78// }
79// ``` 79// ```
80pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { 80pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
81 let token = ctx.find_token_at_offset(RAW_STRING)?; 81 let token = ctx.find_token_at_offset(RAW_STRING)?;
82 let target = token.text_range(); 82 let target = token.text_range();
83 ctx.add_assist(AssistId("add_hash"), "Add # to raw string", target, |edit| { 83 acc.add(AssistId("add_hash"), "Add # to raw string", target, |edit| {
84 edit.insert(token.text_range().start() + TextSize::of('r'), "#"); 84 edit.insert(token.text_range().start() + TextSize::of('r'), "#");
85 edit.insert(token.text_range().end(), "#"); 85 edit.insert(token.text_range().end(), "#");
86 }) 86 })
@@ -101,7 +101,7 @@ pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> {
101// r"Hello, World!"; 101// r"Hello, World!";
102// } 102// }
103// ``` 103// ```
104pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> { 104pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
105 let token = ctx.find_token_at_offset(RAW_STRING)?; 105 let token = ctx.find_token_at_offset(RAW_STRING)?;
106 let text = token.text().as_str(); 106 let text = token.text().as_str();
107 if text.starts_with("r\"") { 107 if text.starts_with("r\"") {
@@ -109,7 +109,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> {
109 return None; 109 return None;
110 } 110 }
111 let target = token.text_range(); 111 let target = token.text_range();
112 ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| { 112 acc.add(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| {
113 let result = &text[2..text.len() - 1]; 113 let result = &text[2..text.len() - 1];
114 let result = if result.starts_with('\"') { 114 let result = if result.starts_with('\"') {
115 // FIXME: this logic is wrong, not only the last has has to handled specially 115 // FIXME: this logic is wrong, not only the last has has to handled specially
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs
index e6e02f2ae..8eef578cf 100644
--- a/crates/ra_assists/src/handlers/remove_dbg.rs
+++ b/crates/ra_assists/src/handlers/remove_dbg.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 TextSize, T, 3 TextSize, T,
4}; 4};
5 5
6use crate::{Assist, AssistCtx, AssistId}; 6use crate::{AssistContext, AssistId, Assists};
7 7
8// Assist: remove_dbg 8// Assist: remove_dbg
9// 9//
@@ -20,7 +20,7 @@ use crate::{Assist, AssistCtx, AssistId};
20// 92; 20// 92;
21// } 21// }
22// ``` 22// ```
23pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> { 23pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; 24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
25 25
26 if !is_valid_macrocall(&macro_call, "dbg")? { 26 if !is_valid_macrocall(&macro_call, "dbg")? {
@@ -58,7 +58,7 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> {
58 }; 58 };
59 59
60 let target = macro_call.syntax().text_range(); 60 let target = macro_call.syntax().text_range();
61 ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { 61 acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| {
62 edit.replace(macro_range, macro_content); 62 edit.replace(macro_range, macro_content);
63 edit.set_cursor(cursor_pos); 63 edit.set_cursor(cursor_pos);
64 }) 64 })
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs
index 9f72f879d..dce546db7 100644
--- a/crates/ra_assists/src/handlers/remove_mut.rs
+++ b/crates/ra_assists/src/handlers/remove_mut.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{SyntaxKind, TextRange, T}; 1use ra_syntax::{SyntaxKind, TextRange, T};
2 2
3use crate::{Assist, AssistCtx, AssistId}; 3use crate::{AssistContext, AssistId, Assists};
4 4
5// Assist: remove_mut 5// Assist: remove_mut
6// 6//
@@ -17,7 +17,7 @@ use crate::{Assist, AssistCtx, AssistId};
17// fn feed(&self, amount: u32) {} 17// fn feed(&self, amount: u32) {}
18// } 18// }
19// ``` 19// ```
20pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> { 20pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
21 let mut_token = ctx.find_token_at_offset(T![mut])?; 21 let mut_token = ctx.find_token_at_offset(T![mut])?;
22 let delete_from = mut_token.text_range().start(); 22 let delete_from = mut_token.text_range().start();
23 let delete_to = match mut_token.next_token() { 23 let delete_to = match mut_token.next_token() {
@@ -26,7 +26,7 @@ pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> {
26 }; 26 };
27 27
28 let target = mut_token.text_range(); 28 let target = mut_token.text_range();
29 ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { 29 acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| {
30 edit.set_cursor(delete_from); 30 edit.set_cursor(delete_from);
31 edit.delete(TextRange::new(delete_from, delete_to)); 31 edit.delete(TextRange::new(delete_from, delete_to));
32 }) 32 })
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index 0b930dea2..757f6406e 100644
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -3,18 +3,9 @@ use std::collections::HashMap;
3use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; 3use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};
7 algo, 7
8 ast::{self, Path, RecordLit, RecordPat}, 8use crate::{AssistContext, AssistId, Assists};
9 match_ast, AstNode, SyntaxKind,
10 SyntaxKind::*,
11 SyntaxNode,
12};
13
14use crate::{
15 assist_ctx::{Assist, AssistCtx},
16 AssistId,
17};
18 9
19// Assist: reorder_fields 10// Assist: reorder_fields
20// 11//
@@ -31,13 +22,13 @@ use crate::{
31// const test: Foo = Foo {foo: 1, bar: 0} 22// const test: Foo = Foo {foo: 1, bar: 0}
32// ``` 23// ```
33// 24//
34pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> { 25pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
35 reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx)) 26 reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx))
36} 27}
37 28
38fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { 29fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 let record = ctx.find_node_at_offset::<R>()?; 30 let record = ctx.find_node_at_offset::<R>()?;
40 let path = record.syntax().children().find_map(Path::cast)?; 31 let path = record.syntax().children().find_map(ast::Path::cast)?;
41 32
42 let ranks = compute_fields_ranks(&path, &ctx)?; 33 let ranks = compute_fields_ranks(&path, &ctx)?;
43 34
@@ -51,7 +42,7 @@ fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
51 } 42 }
52 43
53 let target = record.syntax().text_range(); 44 let target = record.syntax().text_range();
54 ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { 45 acc.add(AssistId("reorder_fields"), "Reorder record fields", target, |edit| {
55 for (old, new) in fields.iter().zip(&sorted_fields) { 46 for (old, new) in fields.iter().zip(&sorted_fields) {
56 algo::diff(old, new).into_text_edit(edit.text_edit_builder()); 47 algo::diff(old, new).into_text_edit(edit.text_edit_builder());
57 } 48 }
@@ -96,9 +87,9 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option
96 } 87 }
97} 88}
98 89
99fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> { 90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> {
100 Some( 91 Some(
101 struct_definition(path, ctx.sema)? 92 struct_definition(path, &ctx.sema)?
102 .fields(ctx.db) 93 .fields(ctx.db)
103 .iter() 94 .iter()
104 .enumerate() 95 .enumerate()
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index 2eb8348f8..a59a06efa 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 AstNode, 4 AstNode,
5}; 5};
6 6
7use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; 7use crate::{utils::TryEnum, AssistContext, AssistId, Assists};
8 8
9// Assist: replace_if_let_with_match 9// Assist: replace_if_let_with_match
10// 10//
@@ -32,7 +32,7 @@ use crate::{utils::TryEnum, Assist, AssistCtx, AssistId};
32// } 32// }
33// } 33// }
34// ``` 34// ```
35pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { 35pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; 36 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
37 let cond = if_expr.condition()?; 37 let cond = if_expr.condition()?;
38 let pat = cond.pat()?; 38 let pat = cond.pat()?;
@@ -43,36 +43,31 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
43 ast::ElseBranch::IfExpr(_) => return None, 43 ast::ElseBranch::IfExpr(_) => return None,
44 }; 44 };
45 45
46 let sema = ctx.sema;
47 let target = if_expr.syntax().text_range(); 46 let target = if_expr.syntax().text_range();
48 ctx.add_assist( 47 acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| {
49 AssistId("replace_if_let_with_match"), 48 let match_expr = {
50 "Replace with match", 49 let then_arm = {
51 target, 50 let then_expr = unwrap_trivial_block(then_block);
52 move |edit| { 51 make::match_arm(vec![pat.clone()], then_expr)
53 let match_expr = {
54 let then_arm = {
55 let then_expr = unwrap_trivial_block(then_block);
56 make::match_arm(vec![pat.clone()], then_expr)
57 };
58 let else_arm = {
59 let pattern = sema
60 .type_of_pat(&pat)
61 .and_then(|ty| TryEnum::from_ty(sema, &ty))
62 .map(|it| it.sad_pattern())
63 .unwrap_or_else(|| make::placeholder_pat().into());
64 let else_expr = unwrap_trivial_block(else_block);
65 make::match_arm(vec![pattern], else_expr)
66 };
67 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
68 }; 52 };
53 let else_arm = {
54 let pattern = ctx
55 .sema
56 .type_of_pat(&pat)
57 .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty))
58 .map(|it| it.sad_pattern())
59 .unwrap_or_else(|| make::placeholder_pat().into());
60 let else_expr = unwrap_trivial_block(else_block);
61 make::match_arm(vec![pattern], else_expr)
62 };
63 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
64 };
69 65
70 let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); 66 let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr);
71 67
72 edit.set_cursor(if_expr.syntax().text_range().start()); 68 edit.set_cursor(if_expr.syntax().text_range().start());
73 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); 69 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
74 }, 70 })
75 )
76} 71}
77 72
78#[cfg(test)] 73#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
index a5509a567..d3f214591 100644
--- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
@@ -9,11 +9,7 @@ use ra_syntax::{
9 AstNode, T, 9 AstNode, T,
10}; 10};
11 11
12use crate::{ 12use crate::{utils::TryEnum, AssistContext, AssistId, Assists};
13 assist_ctx::{Assist, AssistCtx},
14 utils::TryEnum,
15 AssistId,
16};
17 13
18// Assist: replace_let_with_if_let 14// Assist: replace_let_with_if_let
19// 15//
@@ -39,16 +35,16 @@ use crate::{
39// 35//
40// fn compute() -> Option<i32> { None } 36// fn compute() -> Option<i32> { None }
41// ``` 37// ```
42pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { 38pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
43 let let_kw = ctx.find_token_at_offset(T![let])?; 39 let let_kw = ctx.find_token_at_offset(T![let])?;
44 let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?; 40 let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?;
45 let init = let_stmt.initializer()?; 41 let init = let_stmt.initializer()?;
46 let original_pat = let_stmt.pat()?; 42 let original_pat = let_stmt.pat()?;
47 let ty = ctx.sema.type_of_expr(&init)?; 43 let ty = ctx.sema.type_of_expr(&init)?;
48 let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); 44 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty).map(|it| it.happy_case());
49 45
50 let target = let_kw.text_range(); 46 let target = let_kw.text_range();
51 ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { 47 acc.add(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| {
52 let with_placeholder: ast::Pat = match happy_variant { 48 let with_placeholder: ast::Pat = match happy_variant {
53 None => make::placeholder_pat().into(), 49 None => make::placeholder_pat().into(),
54 Some(var_name) => make::tuple_struct_pat( 50 Some(var_name) => make::tuple_struct_pat(
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index fd41da64b..1a81d8a0e 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,11 +1,7 @@
1use hir; 1use hir;
2use ra_syntax::{ast, AstNode, SmolStr, TextRange}; 2use ra_syntax::{ast, AstNode, SmolStr, TextRange};
3 3
4use crate::{ 4use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists};
5 assist_ctx::{Assist, AssistCtx},
6 utils::insert_use_statement,
7 AssistId,
8};
9 5
10// Assist: replace_qualified_name_with_use 6// Assist: replace_qualified_name_with_use
11// 7//
@@ -20,7 +16,10 @@ use crate::{
20// 16//
21// fn process(map: HashMap<String, String>) {} 17// fn process(map: HashMap<String, String>) {}
22// ``` 18// ```
23pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> { 19pub(crate) fn replace_qualified_name_with_use(
20 acc: &mut Assists,
21 ctx: &AssistContext,
22) -> Option<()> {
24 let path: ast::Path = ctx.find_node_at_offset()?; 23 let path: ast::Path = ctx.find_node_at_offset()?;
25 // We don't want to mess with use statements 24 // We don't want to mess with use statements
26 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 25 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
@@ -34,18 +33,18 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist>
34 } 33 }
35 34
36 let target = path.syntax().text_range(); 35 let target = path.syntax().text_range();
37 ctx.add_assist( 36 acc.add(
38 AssistId("replace_qualified_name_with_use"), 37 AssistId("replace_qualified_name_with_use"),
39 "Replace qualified path with use", 38 "Replace qualified path with use",
40 target, 39 target,
41 |edit| { 40 |builder| {
42 let path_to_import = hir_path.mod_path().clone(); 41 let path_to_import = hir_path.mod_path().clone();
43 insert_use_statement(path.syntax(), &path_to_import, edit); 42 insert_use_statement(path.syntax(), &path_to_import, ctx, builder);
44 43
45 if let Some(last) = path.segment() { 44 if let Some(last) = path.segment() {
46 // Here we are assuming the assist will provide a correct use statement 45 // Here we are assuming the assist will provide a correct use statement
47 // so we can delete the path qualifier 46 // so we can delete the path qualifier
48 edit.delete(TextRange::new( 47 builder.delete(TextRange::new(
49 path.syntax().text_range().start(), 48 path.syntax().text_range().start(),
50 last.syntax().text_range().start(), 49 last.syntax().text_range().start(),
51 )); 50 ));
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
index c6b73da67..a46998b8e 100644
--- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 AstNode, 5 AstNode,
6}; 6};
7 7
8use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; 8use crate::{utils::TryEnum, AssistContext, AssistId, Assists};
9 9
10// Assist: replace_unwrap_with_match 10// Assist: replace_unwrap_with_match
11// 11//
@@ -29,7 +29,7 @@ use crate::{utils::TryEnum, Assist, AssistCtx, AssistId};
29// }; 29// };
30// } 30// }
31// ``` 31// ```
32pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { 32pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?; 33 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
34 let name = method_call.name_ref()?; 34 let name = method_call.name_ref()?;
35 if name.text() != "unwrap" { 35 if name.text() != "unwrap" {
@@ -37,33 +37,26 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> {
37 } 37 }
38 let caller = method_call.expr()?; 38 let caller = method_call.expr()?;
39 let ty = ctx.sema.type_of_expr(&caller)?; 39 let ty = ctx.sema.type_of_expr(&caller)?;
40 let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case(); 40 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case();
41 let target = method_call.syntax().text_range(); 41 let target = method_call.syntax().text_range();
42 ctx.add_assist( 42 acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |edit| {
43 AssistId("replace_unwrap_with_match"), 43 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
44 "Replace unwrap with match", 44 let it = make::bind_pat(make::name("a")).into();
45 target, 45 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
46 |edit| {
47 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
48 let it = make::bind_pat(make::name("a")).into();
49 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
50 46
51 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); 47 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
52 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); 48 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
53 49
54 let unreachable_call = make::unreachable_macro_call().into(); 50 let unreachable_call = make::unreachable_macro_call().into();
55 let err_arm = 51 let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
56 make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
57 52
58 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); 53 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
59 let match_expr = make::expr_match(caller.clone(), match_arm_list); 54 let match_expr = make::expr_match(caller.clone(), match_arm_list);
60 let match_expr = 55 let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
61 IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
62 56
63 edit.set_cursor(caller.syntax().text_range().start()); 57 edit.set_cursor(caller.syntax().text_range().start());
64 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); 58 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
65 }, 59 })
66 )
67} 60}
68 61
69#[cfg(test)] 62#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs
index d49563974..159033731 100644
--- a/crates/ra_assists/src/handlers/split_import.rs
+++ b/crates/ra_assists/src/handlers/split_import.rs
@@ -2,7 +2,7 @@ use std::iter::successors;
2 2
3use ra_syntax::{ast, AstNode, T}; 3use ra_syntax::{ast, AstNode, T};
4 4
5use crate::{Assist, AssistCtx, AssistId}; 5use crate::{AssistContext, AssistId, Assists};
6 6
7// Assist: split_import 7// Assist: split_import
8// 8//
@@ -15,7 +15,7 @@ use crate::{Assist, AssistCtx, AssistId};
15// ``` 15// ```
16// use std::{collections::HashMap}; 16// use std::{collections::HashMap};
17// ``` 17// ```
18pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> { 18pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
19 let colon_colon = ctx.find_token_at_offset(T![::])?; 19 let colon_colon = ctx.find_token_at_offset(T![::])?;
20 let path = ast::Path::cast(colon_colon.parent())?.qualifier()?; 20 let path = ast::Path::cast(colon_colon.parent())?.qualifier()?;
21 let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; 21 let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?;
@@ -29,7 +29,7 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> {
29 let cursor = ctx.frange.range.start(); 29 let cursor = ctx.frange.range.start();
30 30
31 let target = colon_colon.text_range(); 31 let target = colon_colon.text_range();
32 ctx.add_assist(AssistId("split_import"), "Split import", target, |edit| { 32 acc.add(AssistId("split_import"), "Split import", target, |edit| {
33 edit.replace_ast(use_tree, new_tree); 33 edit.replace_ast(use_tree, new_tree);
34 edit.set_cursor(cursor); 34 edit.set_cursor(cursor);
35 }) 35 })
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs
index 6df927abb..eba0631a4 100644
--- a/crates/ra_assists/src/handlers/unwrap_block.rs
+++ b/crates/ra_assists/src/handlers/unwrap_block.rs
@@ -1,4 +1,4 @@
1use crate::{Assist, AssistCtx, AssistId}; 1use crate::{AssistContext, AssistId, Assists};
2 2
3use ast::LoopBodyOwner; 3use ast::LoopBodyOwner;
4use ra_fmt::unwrap_trivial_block; 4use ra_fmt::unwrap_trivial_block;
@@ -21,7 +21,7 @@ use ra_syntax::{ast, match_ast, AstNode, TextRange, T};
21// println!("foo"); 21// println!("foo");
22// } 22// }
23// ``` 23// ```
24pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { 24pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let l_curly_token = ctx.find_token_at_offset(T!['{'])?; 25 let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
26 let block = ast::BlockExpr::cast(l_curly_token.parent())?; 26 let block = ast::BlockExpr::cast(l_curly_token.parent())?;
27 let parent = block.syntax().parent()?; 27 let parent = block.syntax().parent()?;
@@ -58,7 +58,7 @@ pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> {
58 }; 58 };
59 59
60 let target = expr_to_unwrap.syntax().text_range(); 60 let target = expr_to_unwrap.syntax().text_range();
61 ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", target, |edit| { 61 acc.add(AssistId("unwrap_block"), "Unwrap block", target, |edit| {
62 edit.set_cursor(expr.syntax().text_range().start()); 62 edit.set_cursor(expr.syntax().text_range().start());
63 63
64 let pat_start: &[_] = &[' ', '{', '\n']; 64 let pat_start: &[_] = &[' ', '{', '\n'];