diff options
Diffstat (limited to 'crates/ra_assists/src')
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. |
2 | use hir::{db::HirDatabase, InFile, SourceAnalyzer}; | 2 | use either::Either; |
3 | use hir::{db::HirDatabase, InFile, SourceAnalyzer, SourceBinder}; | ||
3 | use ra_db::FileRange; | 4 | use ra_db::FileRange; |
4 | use ra_fmt::{leading_indent, reindent}; | 5 | use ra_fmt::{leading_indent, reindent}; |
5 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -9,12 +10,12 @@ use ra_syntax::{ | |||
9 | }; | 10 | }; |
10 | use ra_text_edit::TextEditBuilder; | 11 | use ra_text_edit::TextEditBuilder; |
11 | 12 | ||
12 | use crate::{AssistAction, AssistId, AssistLabel}; | 13 | use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist}; |
13 | 14 | ||
14 | #[derive(Clone, Debug)] | 15 | #[derive(Clone, Debug)] |
15 | pub(crate) enum Assist { | 16 | pub(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)] |
129 | pub(crate) struct AssistBuilder { | 163 | pub(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 | ||
135 | impl AssistBuilder { | 170 | impl 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}; | |||
28 | pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 28 | pub(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}; | |||
30 | pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 30 | pub(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 @@ | |||
1 | use format_buf::format; | 1 | use format_buf::format; |
2 | use hir::{db::HirDatabase, FromSource, InFile}; | 2 | use hir::{db::HirDatabase, InFile}; |
3 | use join_to_string::join; | 3 | use join_to_string::join; |
4 | use ra_syntax::{ | 4 | use 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 | ||
78 | fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { | 78 | fn 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 | ||
7 | use crate::assist_ctx::AssistBuilder; | 7 | use crate::assist_ctx::ActionBuilder; |
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use 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}; | |||
25 | pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(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 | |||
54 | pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 54 | pub(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 | // ``` |
80 | pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 80 | pub(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 @@ | |||
2 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
3 | 3 | ||
4 | use hir::{db::HirDatabase, InFile, PathResolution}; | 4 | use hir::{db::HirDatabase, InFile, PathResolution}; |
5 | use ra_syntax::ast::{self, make, AstNode}; | 5 | use ra_syntax::ast::{self, AstNode}; |
6 | 6 | ||
7 | pub trait AstTransform<'a> { | 7 | pub 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; | |||
13 | mod test_db; | 13 | mod test_db; |
14 | pub mod ast_transform; | 14 | pub mod ast_transform; |
15 | 15 | ||
16 | use either::Either; | ||
16 | use hir::db::HirDatabase; | 17 | use hir::db::HirDatabase; |
17 | use ra_db::FileRange; | 18 | use ra_db::FileRange; |
18 | use ra_syntax::{TextRange, TextUnit}; | 19 | use ra_syntax::{TextRange, TextUnit}; |
@@ -35,11 +36,27 @@ pub struct AssistLabel { | |||
35 | 36 | ||
36 | #[derive(Debug, Clone)] | 37 | #[derive(Debug, Clone)] |
37 | pub struct AssistAction { | 38 | pub 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)] | ||
46 | pub struct ResolvedAssist { | ||
47 | pub label: AssistLabel, | ||
48 | pub action_data: Either<AssistAction, Vec<AssistAction>>, | ||
49 | } | ||
50 | |||
51 | impl 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. |
67 | pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)> | 84 | pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist> |
68 | where | 85 | where |
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 | } |