aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs60
-rw-r--r--crates/ra_assists/src/assists/add_custom_impl.rs5
-rw-r--r--crates/ra_assists/src/assists/add_derive.rs2
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs12
-rw-r--r--crates/ra_assists/src/assists/add_impl.rs2
-rw-r--r--crates/ra_assists/src/assists/add_import.rs2
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs4
-rw-r--r--crates/ra_assists/src/assists/add_new.rs9
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs2
-rw-r--r--crates/ra_assists/src/assists/change_visibility.rs18
-rw-r--r--crates/ra_assists/src/assists/early_return.rs2
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs2
-rw-r--r--crates/ra_assists/src/assists/flip_binexpr.rs2
-rw-r--r--crates/ra_assists/src/assists/flip_comma.rs2
-rw-r--r--crates/ra_assists/src/assists/flip_trait_bound.rs2
-rw-r--r--crates/ra_assists/src/assists/inline_local_variable.rs6
-rw-r--r--crates/ra_assists/src/assists/introduce_variable.rs2
-rw-r--r--crates/ra_assists/src/assists/invert_if.rs2
-rw-r--r--crates/ra_assists/src/assists/merge_match_arms.rs2
-rw-r--r--crates/ra_assists/src/assists/move_bounds.rs2
-rw-r--r--crates/ra_assists/src/assists/move_guard.rs4
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs8
-rw-r--r--crates/ra_assists/src/assists/remove_dbg.rs2
-rw-r--r--crates/ra_assists/src/assists/replace_if_let_with_match.rs2
-rw-r--r--crates/ra_assists/src/assists/split_import.rs2
-rw-r--r--crates/ra_assists/src/ast_transform.rs13
-rw-r--r--crates/ra_assists/src/doc_tests.rs8
-rw-r--r--crates/ra_assists/src/lib.rs42
28 files changed, 151 insertions, 70 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 28152f724..43f0d664b 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,5 +1,6 @@
1//! This module defines `AssistCtx` -- the API surface that is exposed to assists. 1//! This module defines `AssistCtx` -- the API surface that is exposed to assists.
2use hir::{db::HirDatabase, InFile, SourceAnalyzer}; 2use either::Either;
3use hir::{db::HirDatabase, InFile, SourceAnalyzer, SourceBinder};
3use ra_db::FileRange; 4use ra_db::FileRange;
4use ra_fmt::{leading_indent, reindent}; 5use ra_fmt::{leading_indent, reindent};
5use ra_syntax::{ 6use ra_syntax::{
@@ -9,12 +10,12 @@ use ra_syntax::{
9}; 10};
10use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
11 12
12use crate::{AssistAction, AssistId, AssistLabel}; 13use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist};
13 14
14#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
15pub(crate) enum Assist { 16pub(crate) enum Assist {
16 Unresolved { label: AssistLabel }, 17 Unresolved { label: AssistLabel },
17 Resolved { label: AssistLabel, action: AssistAction }, 18 Resolved { assist: ResolvedAssist },
18} 19}
19 20
20/// `AssistCtx` allows to apply an assist or check if it could be applied. 21/// `AssistCtx` allows to apply an assist or check if it could be applied.
@@ -81,16 +82,45 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
81 self, 82 self,
82 id: AssistId, 83 id: AssistId,
83 label: impl Into<String>, 84 label: impl Into<String>,
84 f: impl FnOnce(&mut AssistBuilder), 85 f: impl FnOnce(&mut ActionBuilder),
85 ) -> Option<Assist> { 86 ) -> Option<Assist> {
86 let label = AssistLabel { label: label.into(), id }; 87 let label = AssistLabel { label: label.into(), id };
88 assert!(label.label.chars().nth(0).unwrap().is_uppercase());
89
87 let assist = if self.should_compute_edit { 90 let assist = if self.should_compute_edit {
88 let action = { 91 let action = {
89 let mut edit = AssistBuilder::default(); 92 let mut edit = ActionBuilder::default();
90 f(&mut edit); 93 f(&mut edit);
91 edit.build() 94 edit.build()
92 }; 95 };
93 Assist::Resolved { label, action } 96 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } }
97 } else {
98 Assist::Unresolved { label }
99 };
100
101 Some(assist)
102 }
103
104 #[allow(dead_code)] // will be used for auto import assist with multiple actions
105 pub(crate) fn add_assist_group(
106 self,
107 id: AssistId,
108 label: impl Into<String>,
109 f: impl FnOnce() -> Vec<ActionBuilder>,
110 ) -> Option<Assist> {
111 let label = AssistLabel { label: label.into(), id };
112 let assist = if self.should_compute_edit {
113 let actions = f();
114 assert!(!actions.is_empty(), "Assist cannot have no");
115
116 Assist::Resolved {
117 assist: ResolvedAssist {
118 label,
119 action_data: Either::Right(
120 actions.into_iter().map(ActionBuilder::build).collect(),
121 ),
122 },
123 }
94 } else { 124 } else {
95 Assist::Unresolved { label } 125 Assist::Unresolved { label }
96 }; 126 };
@@ -112,12 +142,16 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
112 pub(crate) fn covering_element(&self) -> SyntaxElement { 142 pub(crate) fn covering_element(&self) -> SyntaxElement {
113 find_covering_element(self.source_file.syntax(), self.frange.range) 143 find_covering_element(self.source_file.syntax(), self.frange.range)
114 } 144 }
145 pub(crate) fn source_binder(&self) -> SourceBinder<'a, DB> {
146 SourceBinder::new(self.db)
147 }
115 pub(crate) fn source_analyzer( 148 pub(crate) fn source_analyzer(
116 &self, 149 &self,
117 node: &SyntaxNode, 150 node: &SyntaxNode,
118 offset: Option<TextUnit>, 151 offset: Option<TextUnit>,
119 ) -> SourceAnalyzer { 152 ) -> SourceAnalyzer {
120 SourceAnalyzer::new(self.db, InFile::new(self.frange.file_id.into(), node), offset) 153 let src = InFile::new(self.frange.file_id.into(), node);
154 self.source_binder().analyze(src, offset)
121 } 155 }
122 156
123 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { 157 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement {
@@ -126,13 +160,20 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
126} 160}
127 161
128#[derive(Default)] 162#[derive(Default)]
129pub(crate) struct AssistBuilder { 163pub(crate) struct ActionBuilder {
130 edit: TextEditBuilder, 164 edit: TextEditBuilder,
131 cursor_position: Option<TextUnit>, 165 cursor_position: Option<TextUnit>,
132 target: Option<TextRange>, 166 target: Option<TextRange>,
167 label: Option<String>,
133} 168}
134 169
135impl AssistBuilder { 170impl ActionBuilder {
171 #[allow(dead_code)]
172 /// Adds a custom label to the action, if it needs to be different from the assist label
173 pub(crate) fn label(&mut self, label: impl Into<String>) {
174 self.label = Some(label.into())
175 }
176
136 /// Replaces specified `range` of text with a given string. 177 /// Replaces specified `range` of text with a given string.
137 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 178 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
138 self.edit.replace(range, replace_with.into()) 179 self.edit.replace(range, replace_with.into())
@@ -191,6 +232,7 @@ impl AssistBuilder {
191 edit: self.edit.finish(), 232 edit: self.edit.finish(),
192 cursor_position: self.cursor_position, 233 cursor_position: self.cursor_position,
193 target: self.target, 234 target: self.target,
235 label: self.label,
194 } 236 }
195 } 237 }
196} 238}
diff --git a/crates/ra_assists/src/assists/add_custom_impl.rs b/crates/ra_assists/src/assists/add_custom_impl.rs
index 9b8955710..f91034967 100644
--- a/crates/ra_assists/src/assists/add_custom_impl.rs
+++ b/crates/ra_assists/src/assists/add_custom_impl.rs
@@ -49,7 +49,10 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
49 let annotated_name = annotated.syntax().text().to_string(); 49 let annotated_name = annotated.syntax().text().to_string();
50 let start_offset = annotated.syntax().parent()?.text_range().end(); 50 let start_offset = annotated.syntax().parent()?.text_range().end();
51 51
52 ctx.add_assist(AssistId("add_custom_impl"), "add custom impl", |edit| { 52 let label =
53 format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name);
54
55 ctx.add_assist(AssistId("add_custom_impl"), label, |edit| {
53 edit.target(attr.syntax().text_range()); 56 edit.target(attr.syntax().text_range());
54 57
55 let new_attr_input = input 58 let new_attr_input = input
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs
index 764b17bd8..6d9af3905 100644
--- a/crates/ra_assists/src/assists/add_derive.rs
+++ b/crates/ra_assists/src/assists/add_derive.rs
@@ -28,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId};
28pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 28pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; 29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
30 let node_start = derive_insertion_offset(&nominal)?; 30 let node_start = derive_insertion_offset(&nominal)?;
31 ctx.add_assist(AssistId("add_derive"), "add `#[derive]`", |edit| { 31 ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", |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())
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index 2c602a79e..f9f826b88 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -47,10 +47,14 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
47 return None; 47 return None;
48 } 48 }
49 49
50 ctx.add_assist(AssistId("add_explicit_type"), "add explicit type", |edit| { 50 ctx.add_assist(
51 edit.target(pat_range); 51 AssistId("add_explicit_type"),
52 edit.insert(name_range.end(), format!(": {}", ty.display(db))); 52 format!("Insert explicit type '{}'", ty.display(db)),
53 }) 53 |edit| {
54 edit.target(pat_range);
55 edit.insert(name_range.end(), format!(": {}", ty.display(db)));
56 },
57 )
54} 58}
55 59
56#[cfg(test)] 60#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs
index 7da0cfd0d..4b326c837 100644
--- a/crates/ra_assists/src/assists/add_impl.rs
+++ b/crates/ra_assists/src/assists/add_impl.rs
@@ -30,7 +30,7 @@ use crate::{Assist, AssistCtx, AssistId};
30pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 30pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
31 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; 31 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
32 let name = nominal.name()?; 32 let name = nominal.name()?;
33 ctx.add_assist(AssistId("add_impl"), "add impl", |edit| { 33 ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| {
34 edit.target(nominal.syntax().text_range()); 34 edit.target(nominal.syntax().text_range());
35 let type_params = nominal.type_param_list(); 35 let type_params = nominal.type_param_list();
36 let start_offset = nominal.syntax().text_range().end(); 36 let start_offset = nominal.syntax().text_range().end();
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs
index b8752cbad..bf6cfe865 100644
--- a/crates/ra_assists/src/assists/add_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -72,7 +72,7 @@ pub(crate) fn add_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
72 } 72 }
73 }; 73 };
74 74
75 ctx.add_assist(AssistId("add_import"), format!("import {}", fmt_segments(&segments)), |edit| { 75 ctx.add_assist(AssistId("add_import"), format!("Import {}", fmt_segments(&segments)), |edit| {
76 apply_auto_import(&position, &path, &segments, edit.text_edit_builder()); 76 apply_auto_import(&position, &path, &segments, edit.text_edit_builder());
77 }) 77 })
78} 78}
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index bf1136193..5bb937bde 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -48,7 +48,7 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
48 ctx, 48 ctx,
49 AddMissingImplMembersMode::NoDefaultMethods, 49 AddMissingImplMembersMode::NoDefaultMethods,
50 "add_impl_missing_members", 50 "add_impl_missing_members",
51 "add missing impl members", 51 "Implement missing members",
52 ) 52 )
53} 53}
54 54
@@ -89,7 +89,7 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> O
89 ctx, 89 ctx,
90 AddMissingImplMembersMode::DefaultMethodsOnly, 90 AddMissingImplMembersMode::DefaultMethodsOnly,
91 "add_impl_default_members", 91 "add_impl_default_members",
92 "add impl default members", 92 "Implement default members",
93 ) 93 )
94} 94}
95 95
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
index b2f946fac..8db63f762 100644
--- a/crates/ra_assists/src/assists/add_new.rs
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -1,5 +1,5 @@
1use format_buf::format; 1use format_buf::format;
2use hir::{db::HirDatabase, FromSource, InFile}; 2use hir::{db::HirDatabase, InFile};
3use join_to_string::join; 3use join_to_string::join;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{ 5 ast::{
@@ -43,7 +43,7 @@ pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
43 // Return early if we've found an existing new fn 43 // Return early if we've found an existing new fn
44 let impl_block = find_struct_impl(&ctx, &strukt)?; 44 let impl_block = find_struct_impl(&ctx, &strukt)?;
45 45
46 ctx.add_assist(AssistId("add_new"), "add new fn", |edit| { 46 ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| {
47 edit.target(strukt.syntax().text_range()); 47 edit.target(strukt.syntax().text_range());
48 48
49 let mut buf = String::with_capacity(512); 49 let mut buf = String::with_capacity(512);
@@ -136,15 +136,16 @@ fn find_struct_impl(
136 let module = strukt.syntax().ancestors().find(|node| { 136 let module = strukt.syntax().ancestors().find(|node| {
137 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) 137 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
138 })?; 138 })?;
139 let mut sb = ctx.source_binder();
139 140
140 let struct_ty = { 141 let struct_ty = {
141 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() }; 142 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
142 hir::Struct::from_source(db, src)?.ty(db) 143 sb.to_def(src)?.ty(db)
143 }; 144 };
144 145
145 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| { 146 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
146 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() }; 147 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
147 let blk = hir::ImplBlock::from_source(db, src)?; 148 let blk = sb.to_def(src)?;
148 149
149 let same_ty = blk.target_ty(db) == struct_ty; 150 let same_ty = blk.target_ty(db) == struct_ty;
150 let not_trait_impl = blk.target_trait(db).is_none(); 151 let not_trait_impl = blk.target_trait(db).is_none();
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
index 7c57c0560..666dce4e6 100644
--- a/crates/ra_assists/src/assists/apply_demorgan.rs
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -39,7 +39,7 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
39 let not_lhs = invert_boolean_expression(&lhs)?; 39 let not_lhs = invert_boolean_expression(&lhs)?;
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 demorgan's law", |edit| { 42 ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", |edit| {
43 edit.target(op_range); 43 edit.target(op_range);
44 edit.replace(op_range, opposite_op); 44 edit.replace(op_range, opposite_op);
45 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); 45 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs
index 132c9dc1d..fd766bb46 100644
--- a/crates/ra_assists/src/assists/change_visibility.rs
+++ b/crates/ra_assists/src/assists/change_visibility.rs
@@ -57,7 +57,7 @@ fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
57 (vis_offset(field.syntax()), ident.text_range()) 57 (vis_offset(field.syntax()), ident.text_range())
58 }; 58 };
59 59
60 ctx.add_assist(AssistId("change_visibility"), "make pub(crate)", |edit| { 60 ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| {
61 edit.target(target); 61 edit.target(target);
62 edit.insert(offset, "pub(crate) "); 62 edit.insert(offset, "pub(crate) ");
63 edit.set_cursor(offset); 63 edit.set_cursor(offset);
@@ -77,14 +77,18 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
77 77
78fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { 78fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> {
79 if vis.syntax().text() == "pub" { 79 if vis.syntax().text() == "pub" {
80 return ctx.add_assist(AssistId("change_visibility"), "change to pub(crate)", |edit| { 80 return ctx.add_assist(
81 edit.target(vis.syntax().text_range()); 81 AssistId("change_visibility"),
82 edit.replace(vis.syntax().text_range(), "pub(crate)"); 82 "Change Visibility to pub(crate)",
83 edit.set_cursor(vis.syntax().text_range().start()) 83 |edit| {
84 }); 84 edit.target(vis.syntax().text_range());
85 edit.replace(vis.syntax().text_range(), "pub(crate)");
86 edit.set_cursor(vis.syntax().text_range().start())
87 },
88 );
85 } 89 }
86 if vis.syntax().text() == "pub(crate)" { 90 if vis.syntax().text() == "pub(crate)" {
87 return ctx.add_assist(AssistId("change_visibility"), "change to pub", |edit| { 91 return ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub", |edit| {
88 edit.target(vis.syntax().text_range()); 92 edit.target(vis.syntax().text_range());
89 edit.replace(vis.syntax().text_range(), "pub"); 93 edit.replace(vis.syntax().text_range(), "pub");
90 edit.set_cursor(vis.syntax().text_range().start()); 94 edit.set_cursor(vis.syntax().text_range().start());
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index 023917aca..487ee9eef 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -95,7 +95,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
95 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; 95 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
96 let cursor_position = ctx.frange.range.start(); 96 let cursor_position = ctx.frange.range.start();
97 97
98 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { 98 ctx.add_assist(AssistId("convert_to_guarded_return"), "Convert to guarded return", |edit| {
99 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 99 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
100 let new_block = match if_let_pat { 100 let new_block = match if_let_pat {
101 None => { 101 None => {
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs
index 99d80998c..01758d23a 100644
--- a/crates/ra_assists/src/assists/fill_match_arms.rs
+++ b/crates/ra_assists/src/assists/fill_match_arms.rs
@@ -57,7 +57,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
57 57
58 let db = ctx.db; 58 let db = ctx.db;
59 59
60 ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| { 60 ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", |edit| {
61 let indent_level = IndentLevel::from_node(match_arm_list.syntax()); 61 let indent_level = IndentLevel::from_node(match_arm_list.syntax());
62 62
63 let new_arm_list = { 63 let new_arm_list = {
diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs
index 2d91b2a7e..2074087cd 100644
--- a/crates/ra_assists/src/assists/flip_binexpr.rs
+++ b/crates/ra_assists/src/assists/flip_binexpr.rs
@@ -34,7 +34,7 @@ pub(crate) fn flip_binexpr(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
34 return None; 34 return None;
35 } 35 }
36 36
37 ctx.add_assist(AssistId("flip_binexpr"), "flip binary expression", |edit| { 37 ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", |edit| {
38 edit.target(op_range); 38 edit.target(op_range);
39 if let FlipAction::FlipAndReplaceOp(new_op) = action { 39 if let FlipAction::FlipAndReplaceOp(new_op) = action {
40 edit.replace(op_range, new_op); 40 edit.replace(op_range, new_op);
diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs
index 9be1c1dc6..dd0c405ed 100644
--- a/crates/ra_assists/src/assists/flip_comma.rs
+++ b/crates/ra_assists/src/assists/flip_comma.rs
@@ -29,7 +29,7 @@ pub(crate) fn flip_comma(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
29 return None; 29 return None;
30 } 30 }
31 31
32 ctx.add_assist(AssistId("flip_comma"), "flip comma", |edit| { 32 ctx.add_assist(AssistId("flip_comma"), "Flip comma", |edit| {
33 edit.target(comma.text_range()); 33 edit.target(comma.text_range());
34 edit.replace(prev.text_range(), next.to_string()); 34 edit.replace(prev.text_range(), next.to_string());
35 edit.replace(next.text_range(), prev.to_string()); 35 edit.replace(next.text_range(), prev.to_string());
diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs
index 6017b39dd..50b3fa492 100644
--- a/crates/ra_assists/src/assists/flip_trait_bound.rs
+++ b/crates/ra_assists/src/assists/flip_trait_bound.rs
@@ -33,7 +33,7 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
33 non_trivia_sibling(plus.clone().into(), Direction::Next)?, 33 non_trivia_sibling(plus.clone().into(), Direction::Next)?,
34 ); 34 );
35 35
36 ctx.add_assist(AssistId("flip_trait_bound"), "flip trait bound", |edit| { 36 ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", |edit| {
37 edit.target(plus.text_range()); 37 edit.target(plus.text_range());
38 edit.replace(before.text_range(), after.to_string()); 38 edit.replace(before.text_range(), after.to_string());
39 edit.replace(after.text_range(), before.to_string()); 39 edit.replace(after.text_range(), before.to_string());
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs
index 18a34502c..45e0f983f 100644
--- a/crates/ra_assists/src/assists/inline_local_variable.rs
+++ b/crates/ra_assists/src/assists/inline_local_variable.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 TextRange, 4 TextRange,
5}; 5};
6 6
7use crate::assist_ctx::AssistBuilder; 7use crate::assist_ctx::ActionBuilder;
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
9 9
10// Assist: inline_local_variable 10// Assist: inline_local_variable
@@ -93,8 +93,8 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option<
93 93
94 ctx.add_assist( 94 ctx.add_assist(
95 AssistId("inline_local_variable"), 95 AssistId("inline_local_variable"),
96 "inline local variable", 96 "Inline variable",
97 move |edit: &mut AssistBuilder| { 97 move |edit: &mut ActionBuilder| {
98 edit.delete(delete_range); 98 edit.delete(delete_range);
99 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 99 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
100 if should_wrap { 100 if should_wrap {
diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/assists/introduce_variable.rs
index 0623d4475..19e211e0f 100644
--- a/crates/ra_assists/src/assists/introduce_variable.rs
+++ b/crates/ra_assists/src/assists/introduce_variable.rs
@@ -43,7 +43,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Ass
43 if indent.kind() != WHITESPACE { 43 if indent.kind() != WHITESPACE {
44 return None; 44 return None;
45 } 45 }
46 ctx.add_assist(AssistId("introduce_variable"), "introduce variable", move |edit| { 46 ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", 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/assists/invert_if.rs b/crates/ra_assists/src/assists/invert_if.rs
index bababa3e2..16352c040 100644
--- a/crates/ra_assists/src/assists/invert_if.rs
+++ b/crates/ra_assists/src/assists/invert_if.rs
@@ -41,7 +41,7 @@ pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
41 let else_node = else_block.syntax(); 41 let else_node = else_block.syntax();
42 let else_range = else_node.text_range(); 42 let else_range = else_node.text_range();
43 let then_range = then_node.text_range(); 43 let then_range = then_node.text_range();
44 return ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| { 44 return ctx.add_assist(AssistId("invert_if"), "Invert if", |edit| {
45 edit.target(if_range); 45 edit.target(if_range);
46 edit.replace(cond_range, flip_cond.syntax().text()); 46 edit.replace(cond_range, flip_cond.syntax().text());
47 edit.replace(else_range, then_node.text()); 47 edit.replace(else_range, then_node.text());
diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs
index e9f2cae91..aca391155 100644
--- a/crates/ra_assists/src/assists/merge_match_arms.rs
+++ b/crates/ra_assists/src/assists/merge_match_arms.rs
@@ -52,7 +52,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
52 52
53 let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start(); 53 let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start();
54 54
55 ctx.add_assist(AssistId("merge_match_arms"), "merge match arms", |edit| { 55 ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", |edit| {
56 fn contains_placeholder(a: &MatchArm) -> bool { 56 fn contains_placeholder(a: &MatchArm) -> bool {
57 a.pats().any(|x| match x { 57 a.pats().any(|x| match x {
58 ra_syntax::ast::Pat::PlaceholderPat(..) => true, 58 ra_syntax::ast::Pat::PlaceholderPat(..) => true,
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs
index 3145d7625..355adddc3 100644
--- a/crates/ra_assists/src/assists/move_bounds.rs
+++ b/crates/ra_assists/src/assists/move_bounds.rs
@@ -46,7 +46,7 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx<impl HirDatabase>) -> O
46 _ => return None, 46 _ => return None,
47 }; 47 };
48 48
49 ctx.add_assist(AssistId("move_bounds_to_where_clause"), "move_bounds_to_where_clause", |edit| { 49 ctx.add_assist(AssistId("move_bounds_to_where_clause"), "Move to where clause", |edit| {
50 let new_params = type_param_list 50 let new_params = type_param_list
51 .type_params() 51 .type_params()
52 .filter(|it| it.type_bound_list().is_some()) 52 .filter(|it| it.type_bound_list().is_some())
diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs
index b49ec6172..41a31e677 100644
--- a/crates/ra_assists/src/assists/move_guard.rs
+++ b/crates/ra_assists/src/assists/move_guard.rs
@@ -41,7 +41,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx<impl HirDatabase>) -> Option
41 let arm_expr = match_arm.expr()?; 41 let arm_expr = match_arm.expr()?;
42 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); 42 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text());
43 43
44 ctx.add_assist(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { 44 ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", |edit| {
45 edit.target(guard.syntax().text_range()); 45 edit.target(guard.syntax().text_range());
46 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { 46 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) {
47 Some(tok) => { 47 Some(tok) => {
@@ -111,7 +111,7 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx<impl HirDatabase>) ->
111 111
112 ctx.add_assist( 112 ctx.add_assist(
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 |edit| { 115 |edit| {
116 edit.target(if_expr.syntax().text_range()); 116 edit.target(if_expr.syntax().text_range());
117 let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none(); 117 let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none();
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs
index 93912a470..e79c51673 100644
--- a/crates/ra_assists/src/assists/raw_string.rs
+++ b/crates/ra_assists/src/assists/raw_string.rs
@@ -25,7 +25,7 @@ use crate::{Assist, AssistCtx, AssistId};
25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; 26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
27 let value = token.value()?; 27 let value = token.value()?;
28 ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| { 28 ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", |edit| {
29 edit.target(token.syntax().text_range()); 29 edit.target(token.syntax().text_range());
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);
@@ -54,7 +54,7 @@ pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
54pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 54pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; 55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
56 let value = token.value()?; 56 let value = token.value()?;
57 ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { 57 ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", |edit| {
58 edit.target(token.syntax().text_range()); 58 edit.target(token.syntax().text_range());
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();
@@ -79,7 +79,7 @@ pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
79// ``` 79// ```
80pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 80pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
81 let token = ctx.find_token_at_offset(RAW_STRING)?; 81 let token = ctx.find_token_at_offset(RAW_STRING)?;
82 ctx.add_assist(AssistId("add_hash"), "add hash to raw string", |edit| { 82 ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| {
83 edit.target(token.text_range()); 83 edit.target(token.text_range());
84 edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); 84 edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#");
85 edit.insert(token.text_range().end(), "#"); 85 edit.insert(token.text_range().end(), "#");
@@ -108,7 +108,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
108 // no hash to remove 108 // no hash to remove
109 return None; 109 return None;
110 } 110 }
111 ctx.add_assist(AssistId("remove_hash"), "remove hash from raw string", |edit| { 111 ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", |edit| {
112 edit.target(token.text_range()); 112 edit.target(token.text_range());
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('\"') {
diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs
index aedf8747f..cf211ab84 100644
--- a/crates/ra_assists/src/assists/remove_dbg.rs
+++ b/crates/ra_assists/src/assists/remove_dbg.rs
@@ -58,7 +58,7 @@ pub(crate) fn remove_dbg(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
58 text.slice(without_parens).to_string() 58 text.slice(without_parens).to_string()
59 }; 59 };
60 60
61 ctx.add_assist(AssistId("remove_dbg"), "remove dbg!()", |edit| { 61 ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", |edit| {
62 edit.target(macro_call.syntax().text_range()); 62 edit.target(macro_call.syntax().text_range());
63 edit.replace(macro_range, macro_content); 63 edit.replace(macro_range, macro_content);
64 edit.set_cursor(cursor_pos); 64 edit.set_cursor(cursor_pos);
diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs
index 3272801ff..c9b62e5ff 100644
--- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs
@@ -42,7 +42,7 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Opt
42 ast::ElseBranch::IfExpr(_) => return None, 42 ast::ElseBranch::IfExpr(_) => return None,
43 }; 43 };
44 44
45 ctx.add_assist(AssistId("replace_if_let_with_match"), "replace with match", |edit| { 45 ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| {
46 let match_expr = build_match_expr(expr, pat, then_block, else_block); 46 let match_expr = build_match_expr(expr, pat, then_block, else_block);
47 edit.target(if_expr.syntax().text_range()); 47 edit.target(if_expr.syntax().text_range());
48 edit.replace_node_and_indent(if_expr.syntax(), match_expr); 48 edit.replace_node_and_indent(if_expr.syntax(), match_expr);
diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs
index 5f8d6b0be..6038c4858 100644
--- a/crates/ra_assists/src/assists/split_import.rs
+++ b/crates/ra_assists/src/assists/split_import.rs
@@ -32,7 +32,7 @@ pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
32 None => top_path.syntax().text_range().end(), 32 None => top_path.syntax().text_range().end(),
33 }; 33 };
34 34
35 ctx.add_assist(AssistId("split_import"), "split import", |edit| { 35 ctx.add_assist(AssistId("split_import"), "Split import", |edit| {
36 edit.target(colon_colon.text_range()); 36 edit.target(colon_colon.text_range());
37 edit.insert(l_curly, "{"); 37 edit.insert(l_curly, "{");
38 edit.insert(r_curly, "}"); 38 edit.insert(r_curly, "}");
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index eac2903d1..56b7588ef 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -2,7 +2,7 @@
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use hir::{db::HirDatabase, InFile, PathResolution}; 4use hir::{db::HirDatabase, InFile, PathResolution};
5use ra_syntax::ast::{self, make, AstNode}; 5use ra_syntax::ast::{self, AstNode};
6 6
7pub trait AstTransform<'a> { 7pub trait AstTransform<'a> {
8 fn get_substitution( 8 fn get_substitution(
@@ -134,11 +134,18 @@ impl<'a, DB: HirDatabase> QualifyPaths<'a, DB> {
134 match resolution { 134 match resolution {
135 PathResolution::Def(def) => { 135 PathResolution::Def(def) => {
136 let found_path = from.find_use_path(self.db, def)?; 136 let found_path = from.find_use_path(self.db, def)?;
137 let args = p 137 let mut path = path_to_ast(found_path);
138
139 let type_args = p
138 .segment() 140 .segment()
139 .and_then(|s| s.type_arg_list()) 141 .and_then(|s| s.type_arg_list())
140 .map(|arg_list| apply(self, node.with_value(arg_list))); 142 .map(|arg_list| apply(self, node.with_value(arg_list)));
141 Some(make::path_with_type_arg_list(path_to_ast(found_path), args).syntax().clone()) 143 if let Some(type_args) = type_args {
144 let last_segment = path.segment().unwrap();
145 path = path.with_segment(last_segment.with_type_args(type_args))
146 }
147
148 Some(path.syntax().clone())
142 } 149 }
143 PathResolution::Local(_) 150 PathResolution::Local(_)
144 | PathResolution::TypeParam(_) 151 | PathResolution::TypeParam(_)
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index a8f8446cb..5dc1ee233 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -15,21 +15,21 @@ fn check(assist_id: &str, before: &str, after: &str) {
15 let (db, file_id) = TestDB::with_single_file(&before); 15 let (db, file_id) = TestDB::with_single_file(&before);
16 let frange = FileRange { file_id, range: selection.into() }; 16 let frange = FileRange { file_id, range: selection.into() };
17 17
18 let (_assist_id, action) = crate::assists(&db, frange) 18 let assist = crate::assists(&db, frange)
19 .into_iter() 19 .into_iter()
20 .find(|(id, _)| id.id.0 == assist_id) 20 .find(|assist| assist.label.id.0 == assist_id)
21 .unwrap_or_else(|| { 21 .unwrap_or_else(|| {
22 panic!( 22 panic!(
23 "\n\nAssist is not applicable: {}\nAvailable assists: {}", 23 "\n\nAssist is not applicable: {}\nAvailable assists: {}",
24 assist_id, 24 assist_id,
25 crate::assists(&db, frange) 25 crate::assists(&db, frange)
26 .into_iter() 26 .into_iter()
27 .map(|(id, _)| id.id.0) 27 .map(|assist| assist.label.id.0)
28 .collect::<Vec<_>>() 28 .collect::<Vec<_>>()
29 .join(", ") 29 .join(", ")
30 ) 30 )
31 }); 31 });
32 32
33 let actual = action.edit.apply(&before); 33 let actual = assist.get_first_action().edit.apply(&before);
34 assert_eq_text!(after, &actual); 34 assert_eq_text!(after, &actual);
35} 35}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 712ff6f6a..d45b58966 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -13,6 +13,7 @@ mod doc_tests;
13mod test_db; 13mod test_db;
14pub mod ast_transform; 14pub mod ast_transform;
15 15
16use either::Either;
16use hir::db::HirDatabase; 17use hir::db::HirDatabase;
17use ra_db::FileRange; 18use ra_db::FileRange;
18use ra_syntax::{TextRange, TextUnit}; 19use ra_syntax::{TextRange, TextUnit};
@@ -35,11 +36,27 @@ pub struct AssistLabel {
35 36
36#[derive(Debug, Clone)] 37#[derive(Debug, Clone)]
37pub struct AssistAction { 38pub struct AssistAction {
39 pub label: Option<String>,
38 pub edit: TextEdit, 40 pub edit: TextEdit,
39 pub cursor_position: Option<TextUnit>, 41 pub cursor_position: Option<TextUnit>,
40 pub target: Option<TextRange>, 42 pub target: Option<TextRange>,
41} 43}
42 44
45#[derive(Debug, Clone)]
46pub struct ResolvedAssist {
47 pub label: AssistLabel,
48 pub action_data: Either<AssistAction, Vec<AssistAction>>,
49}
50
51impl ResolvedAssist {
52 pub fn get_first_action(&self) -> AssistAction {
53 match &self.action_data {
54 Either::Left(action) => action.clone(),
55 Either::Right(actions) => actions[0].clone(),
56 }
57 }
58}
59
43/// Return all the assists applicable at the given position. 60/// Return all the assists applicable at the given position.
44/// 61///
45/// Assists are returned in the "unresolved" state, that is only labels are 62/// Assists are returned in the "unresolved" state, that is only labels are
@@ -64,7 +81,7 @@ where
64/// 81///
65/// Assists are returned in the "resolved" state, that is with edit fully 82/// Assists are returned in the "resolved" state, that is with edit fully
66/// computed. 83/// computed.
67pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)> 84pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist>
68where 85where
69 H: HirDatabase + 'static, 86 H: HirDatabase + 'static,
70{ 87{
@@ -75,11 +92,11 @@ where
75 .iter() 92 .iter()
76 .filter_map(|f| f(ctx.clone())) 93 .filter_map(|f| f(ctx.clone()))
77 .map(|a| match a { 94 .map(|a| match a {
78 Assist::Resolved { label, action } => (label, action), 95 Assist::Resolved { assist } => assist,
79 Assist::Unresolved { .. } => unreachable!(), 96 Assist::Unresolved { .. } => unreachable!(),
80 }) 97 })
81 .collect::<Vec<_>>(); 98 .collect::<Vec<_>>();
82 a.sort_by(|a, b| match (a.1.target, b.1.target) { 99 a.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) {
83 (Some(a), Some(b)) => a.len().cmp(&b.len()), 100 (Some(a), Some(b)) => a.len().cmp(&b.len()),
84 (Some(_), None) => Ordering::Less, 101 (Some(_), None) => Ordering::Less,
85 (None, Some(_)) => Ordering::Greater, 102 (None, Some(_)) => Ordering::Greater,
@@ -174,7 +191,7 @@ mod helpers {
174 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 191 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
175 let action = match assist { 192 let action = match assist {
176 Assist::Unresolved { .. } => unreachable!(), 193 Assist::Unresolved { .. } => unreachable!(),
177 Assist::Resolved { action, .. } => action, 194 Assist::Resolved { assist } => assist.get_first_action(),
178 }; 195 };
179 196
180 let actual = action.edit.apply(&before); 197 let actual = action.edit.apply(&before);
@@ -201,7 +218,7 @@ mod helpers {
201 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 218 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
202 let action = match assist { 219 let action = match assist {
203 Assist::Unresolved { .. } => unreachable!(), 220 Assist::Unresolved { .. } => unreachable!(),
204 Assist::Resolved { action, .. } => action, 221 Assist::Resolved { assist } => assist.get_first_action(),
205 }; 222 };
206 223
207 let mut actual = action.edit.apply(&before); 224 let mut actual = action.edit.apply(&before);
@@ -224,7 +241,7 @@ mod helpers {
224 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 241 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
225 let action = match assist { 242 let action = match assist {
226 Assist::Unresolved { .. } => unreachable!(), 243 Assist::Unresolved { .. } => unreachable!(),
227 Assist::Resolved { action, .. } => action, 244 Assist::Resolved { assist } => assist.get_first_action(),
228 }; 245 };
229 246
230 let range = action.target.expect("expected target on action"); 247 let range = action.target.expect("expected target on action");
@@ -243,7 +260,7 @@ mod helpers {
243 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 260 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
244 let action = match assist { 261 let action = match assist {
245 Assist::Unresolved { .. } => unreachable!(), 262 Assist::Unresolved { .. } => unreachable!(),
246 Assist::Resolved { action, .. } => action, 263 Assist::Resolved { assist } => assist.get_first_action(),
247 }; 264 };
248 265
249 let range = action.target.expect("expected target on action"); 266 let range = action.target.expect("expected target on action");
@@ -292,8 +309,11 @@ mod tests {
292 let assists = super::assists(&db, frange); 309 let assists = super::assists(&db, frange);
293 let mut assists = assists.iter(); 310 let mut assists = assists.iter();
294 311
295 assert_eq!(assists.next().expect("expected assist").0.label, "make pub(crate)"); 312 assert_eq!(
296 assert_eq!(assists.next().expect("expected assist").0.label, "add `#[derive]`"); 313 assists.next().expect("expected assist").label.label,
314 "Change visibility to pub(crate)"
315 );
316 assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`");
297 } 317 }
298 318
299 #[test] 319 #[test]
@@ -312,7 +332,7 @@ mod tests {
312 let assists = super::assists(&db, frange); 332 let assists = super::assists(&db, frange);
313 let mut assists = assists.iter(); 333 let mut assists = assists.iter();
314 334
315 assert_eq!(assists.next().expect("expected assist").0.label, "introduce variable"); 335 assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable");
316 assert_eq!(assists.next().expect("expected assist").0.label, "replace with match"); 336 assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match");
317 } 337 }
318} 338}