diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 30 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 42 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/unwrap_block.rs | 67 | ||||
-rw-r--r-- | crates/ra_assists/src/utils.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/utils/insert_use.rs | 9 |
6 files changed, 100 insertions, 52 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 2fe7c3de3..da2880037 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -105,7 +105,7 @@ impl<'a> AssistCtx<'a> { | |||
105 | let mut info = AssistInfo::new(label); | 105 | let mut info = AssistInfo::new(label); |
106 | if self.should_compute_edit { | 106 | if self.should_compute_edit { |
107 | let action = { | 107 | let action = { |
108 | let mut edit = ActionBuilder::default(); | 108 | let mut edit = ActionBuilder::new(&self); |
109 | f(&mut edit); | 109 | f(&mut edit); |
110 | edit.build() | 110 | edit.build() |
111 | }; | 111 | }; |
@@ -130,6 +130,12 @@ impl<'a> AssistCtx<'a> { | |||
130 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { | 130 | pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { |
131 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) | 131 | find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) |
132 | } | 132 | } |
133 | |||
134 | pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { | ||
135 | self.sema | ||
136 | .find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start()) | ||
137 | } | ||
138 | |||
133 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 139 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
134 | find_covering_element(self.source_file.syntax(), self.frange.range) | 140 | find_covering_element(self.source_file.syntax(), self.frange.range) |
135 | } | 141 | } |
@@ -156,7 +162,7 @@ impl<'a> AssistGroup<'a> { | |||
156 | let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone())); | 162 | let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone())); |
157 | if self.ctx.should_compute_edit { | 163 | if self.ctx.should_compute_edit { |
158 | let action = { | 164 | let action = { |
159 | let mut edit = ActionBuilder::default(); | 165 | let mut edit = ActionBuilder::new(&self.ctx); |
160 | f(&mut edit); | 166 | f(&mut edit); |
161 | edit.build() | 167 | edit.build() |
162 | }; | 168 | }; |
@@ -175,15 +181,29 @@ impl<'a> AssistGroup<'a> { | |||
175 | } | 181 | } |
176 | } | 182 | } |
177 | 183 | ||
178 | #[derive(Default)] | 184 | pub(crate) struct ActionBuilder<'a, 'b> { |
179 | pub(crate) struct ActionBuilder { | ||
180 | edit: TextEditBuilder, | 185 | edit: TextEditBuilder, |
181 | cursor_position: Option<TextSize>, | 186 | cursor_position: Option<TextSize>, |
182 | target: Option<TextRange>, | 187 | target: Option<TextRange>, |
183 | file: AssistFile, | 188 | file: AssistFile, |
189 | ctx: &'a AssistCtx<'b>, | ||
184 | } | 190 | } |
185 | 191 | ||
186 | impl ActionBuilder { | 192 | impl<'a, 'b> ActionBuilder<'a, 'b> { |
193 | fn new(ctx: &'a AssistCtx<'b>) -> Self { | ||
194 | Self { | ||
195 | edit: TextEditBuilder::default(), | ||
196 | cursor_position: None, | ||
197 | target: None, | ||
198 | file: AssistFile::default(), | ||
199 | ctx, | ||
200 | } | ||
201 | } | ||
202 | |||
203 | pub(crate) fn ctx(&self) -> &AssistCtx<'b> { | ||
204 | &self.ctx | ||
205 | } | ||
206 | |||
187 | /// Replaces specified `range` of text with a given string. | 207 | /// Replaces specified `range` of text with a given string. |
188 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { | 208 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { |
189 | self.edit.replace(range, replace_with.into()) | 209 | self.edit.replace(range, replace_with.into()) |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 99682e023..db6c4d2fa 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -45,15 +45,12 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
45 | return None; | 45 | return None; |
46 | } | 46 | } |
47 | 47 | ||
48 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; | ||
48 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); | 49 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); |
49 | for import in proposed_imports { | 50 | for import in proposed_imports { |
50 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { | 51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { |
51 | edit.target(auto_import_assets.syntax_under_caret.text_range()); | 52 | edit.target(range); |
52 | insert_use_statement( | 53 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); |
53 | &auto_import_assets.syntax_under_caret, | ||
54 | &import, | ||
55 | edit.text_edit_builder(), | ||
56 | ); | ||
57 | }); | 54 | }); |
58 | } | 55 | } |
59 | group.finish() | 56 | group.finish() |
@@ -68,10 +65,10 @@ struct AutoImportAssets { | |||
68 | 65 | ||
69 | impl AutoImportAssets { | 66 | impl AutoImportAssets { |
70 | fn new(ctx: &AssistCtx) -> Option<Self> { | 67 | fn new(ctx: &AssistCtx) -> Option<Self> { |
71 | if let Some(path_under_caret) = ctx.find_node_at_offset::<ast::Path>() { | 68 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { |
72 | Self::for_regular_path(path_under_caret, &ctx) | 69 | Self::for_regular_path(path_under_caret, &ctx) |
73 | } else { | 70 | } else { |
74 | Self::for_method_call(ctx.find_node_at_offset()?, &ctx) | 71 | Self::for_method_call(ctx.find_node_at_offset_with_descend()?, &ctx) |
75 | } | 72 | } |
76 | } | 73 | } |
77 | 74 | ||
@@ -306,6 +303,35 @@ mod tests { | |||
306 | } | 303 | } |
307 | 304 | ||
308 | #[test] | 305 | #[test] |
306 | fn applicable_when_found_an_import_in_macros() { | ||
307 | check_assist( | ||
308 | auto_import, | ||
309 | r" | ||
310 | macro_rules! foo { | ||
311 | ($i:ident) => { fn foo(a: $i) {} } | ||
312 | } | ||
313 | foo!(Pub<|>Struct); | ||
314 | |||
315 | pub mod PubMod { | ||
316 | pub struct PubStruct; | ||
317 | } | ||
318 | ", | ||
319 | r" | ||
320 | use PubMod::PubStruct; | ||
321 | |||
322 | macro_rules! foo { | ||
323 | ($i:ident) => { fn foo(a: $i) {} } | ||
324 | } | ||
325 | foo!(Pub<|>Struct); | ||
326 | |||
327 | pub mod PubMod { | ||
328 | pub struct PubStruct; | ||
329 | } | ||
330 | ", | ||
331 | ); | ||
332 | } | ||
333 | |||
334 | #[test] | ||
309 | fn auto_imports_are_merged() { | 335 | fn auto_imports_are_merged() { |
310 | check_assist( | 336 | check_assist( |
311 | auto_import, | 337 | auto_import, |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index 918e8dd8d..ff2463c77 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -38,7 +38,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
38 | "Replace qualified path with use", | 38 | "Replace qualified path with use", |
39 | |edit| { | 39 | |edit| { |
40 | let path_to_import = hir_path.mod_path().clone(); | 40 | let path_to_import = hir_path.mod_path().clone(); |
41 | insert_use_statement(path.syntax(), &path_to_import, edit.text_edit_builder()); | 41 | insert_use_statement(path.syntax(), &path_to_import, edit); |
42 | 42 | ||
43 | if let Some(last) = path.segment() { | 43 | if let Some(last) = path.segment() { |
44 | // Here we are assuming the assist will provide a correct use statement | 44 | // Here we are assuming the assist will provide a correct use statement |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 58649c47e..859c70ad8 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use crate::{Assist, AssistCtx, AssistId}; | 1 | use crate::{Assist, AssistCtx, AssistId}; |
2 | 2 | ||
3 | use ast::{BlockExpr, Expr, ForExpr, IfExpr, LoopBodyOwner, LoopExpr, WhileExpr}; | 3 | use ast::LoopBodyOwner; |
4 | use ra_fmt::unwrap_trivial_block; | 4 | use ra_fmt::unwrap_trivial_block; |
5 | use ra_syntax::{ast, AstNode, TextRange, T}; | 5 | use ra_syntax::{ast, match_ast, AstNode, TextRange, T}; |
6 | 6 | ||
7 | // Assist: unwrap_block | 7 | // Assist: unwrap_block |
8 | // | 8 | // |
@@ -23,39 +23,40 @@ use ra_syntax::{ast, AstNode, TextRange, T}; | |||
23 | // ``` | 23 | // ``` |
24 | pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | 24 | pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { |
25 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | 25 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; |
26 | 26 | let block = ast::BlockExpr::cast(l_curly_token.parent())?; | |
27 | let res = if let Some(if_expr) = l_curly_token.ancestors().find_map(IfExpr::cast) { | 27 | let parent = block.syntax().parent()?; |
28 | // if expression | 28 | let (expr, expr_to_unwrap) = match_ast! { |
29 | let expr_to_unwrap = if_expr.blocks().find_map(|expr| extract_expr(ctx.frange.range, expr)); | 29 | match parent { |
30 | let expr_to_unwrap = expr_to_unwrap?; | 30 | ast::IfExpr(if_expr) => { |
31 | // Find if we are in a else if block | 31 | let expr_to_unwrap = if_expr.blocks().find_map(|expr| extract_expr(ctx.frange.range, expr)); |
32 | let ancestor = if_expr.syntax().ancestors().skip(1).find_map(ast::IfExpr::cast); | 32 | let expr_to_unwrap = expr_to_unwrap?; |
33 | 33 | // Find if we are in a else if block | |
34 | if let Some(ancestor) = ancestor { | 34 | let ancestor = if_expr.syntax().parent().and_then(ast::IfExpr::cast); |
35 | Some((ast::Expr::IfExpr(ancestor), expr_to_unwrap)) | 35 | |
36 | } else { | 36 | match ancestor { |
37 | Some((ast::Expr::IfExpr(if_expr), expr_to_unwrap)) | 37 | None => (ast::Expr::IfExpr(if_expr), expr_to_unwrap), |
38 | Some(ancestor) => (ast::Expr::IfExpr(ancestor), expr_to_unwrap), | ||
39 | } | ||
40 | }, | ||
41 | ast::ForExpr(for_expr) => { | ||
42 | let block_expr = for_expr.loop_body()?; | ||
43 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | ||
44 | (ast::Expr::ForExpr(for_expr), expr_to_unwrap) | ||
45 | }, | ||
46 | ast::WhileExpr(while_expr) => { | ||
47 | let block_expr = while_expr.loop_body()?; | ||
48 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | ||
49 | (ast::Expr::WhileExpr(while_expr), expr_to_unwrap) | ||
50 | }, | ||
51 | ast::LoopExpr(loop_expr) => { | ||
52 | let block_expr = loop_expr.loop_body()?; | ||
53 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | ||
54 | (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap) | ||
55 | }, | ||
56 | _ => return None, | ||
38 | } | 57 | } |
39 | } else if let Some(for_expr) = l_curly_token.ancestors().find_map(ForExpr::cast) { | ||
40 | // for expression | ||
41 | let block_expr = for_expr.loop_body()?; | ||
42 | extract_expr(ctx.frange.range, block_expr) | ||
43 | .map(|expr_to_unwrap| (ast::Expr::ForExpr(for_expr), expr_to_unwrap)) | ||
44 | } else if let Some(while_expr) = l_curly_token.ancestors().find_map(WhileExpr::cast) { | ||
45 | // while expression | ||
46 | let block_expr = while_expr.loop_body()?; | ||
47 | extract_expr(ctx.frange.range, block_expr) | ||
48 | .map(|expr_to_unwrap| (ast::Expr::WhileExpr(while_expr), expr_to_unwrap)) | ||
49 | } else if let Some(loop_expr) = l_curly_token.ancestors().find_map(LoopExpr::cast) { | ||
50 | // loop expression | ||
51 | let block_expr = loop_expr.loop_body()?; | ||
52 | extract_expr(ctx.frange.range, block_expr) | ||
53 | .map(|expr_to_unwrap| (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap)) | ||
54 | } else { | ||
55 | None | ||
56 | }; | 58 | }; |
57 | 59 | ||
58 | let (expr, expr_to_unwrap) = res?; | ||
59 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| { | 60 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| { |
60 | edit.set_cursor(expr.syntax().text_range().start()); | 61 | edit.set_cursor(expr.syntax().text_range().start()); |
61 | edit.target(expr_to_unwrap.syntax().text_range()); | 62 | edit.target(expr_to_unwrap.syntax().text_range()); |
@@ -76,7 +77,7 @@ pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | |||
76 | }) | 77 | }) |
77 | } | 78 | } |
78 | 79 | ||
79 | fn extract_expr(cursor_range: TextRange, block: BlockExpr) -> Option<Expr> { | 80 | fn extract_expr(cursor_range: TextRange, block: ast::BlockExpr) -> Option<ast::Expr> { |
80 | let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range); | 81 | let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range); |
81 | 82 | ||
82 | if cursor_in_range { | 83 | if cursor_in_range { |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index efd988697..6be704ce3 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | }; | 11 | }; |
12 | use rustc_hash::FxHashSet; | 12 | use rustc_hash::FxHashSet; |
13 | 13 | ||
14 | pub use insert_use::insert_use_statement; | 14 | pub(crate) use insert_use::insert_use_statement; |
15 | 15 | ||
16 | pub fn get_missing_impl_items( | 16 | pub fn get_missing_impl_items( |
17 | sema: &Semantics<RootDatabase>, | 17 | sema: &Semantics<RootDatabase>, |
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index c507e71e0..c1f447efe 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | // FIXME: rewrite according to the plan, outlined in | 2 | // FIXME: rewrite according to the plan, outlined in |
3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 | 3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 |
4 | 4 | ||
5 | use crate::assist_ctx::ActionBuilder; | ||
5 | use hir::{self, ModPath}; | 6 | use hir::{self, ModPath}; |
6 | use ra_syntax::{ | 7 | use ra_syntax::{ |
7 | ast::{self, NameOwner}, | 8 | ast::{self, NameOwner}, |
@@ -14,14 +15,14 @@ use ra_text_edit::TextEditBuilder; | |||
14 | /// Creates and inserts a use statement for the given path to import. | 15 | /// Creates and inserts a use statement for the given path to import. |
15 | /// The use statement is inserted in the scope most appropriate to the | 16 | /// The use statement is inserted in the scope most appropriate to the |
16 | /// the cursor position given, additionally merged with the existing use imports. | 17 | /// the cursor position given, additionally merged with the existing use imports. |
17 | pub fn insert_use_statement( | 18 | pub(crate) fn insert_use_statement( |
18 | // Ideally the position of the cursor, used to | 19 | // Ideally the position of the cursor, used to |
19 | position: &SyntaxNode, | 20 | position: &SyntaxNode, |
20 | path_to_import: &ModPath, | 21 | path_to_import: &ModPath, |
21 | edit: &mut TextEditBuilder, | 22 | edit: &mut ActionBuilder, |
22 | ) { | 23 | ) { |
23 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); | 24 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); |
24 | let container = position.ancestors().find_map(|n| { | 25 | let container = edit.ctx().sema.ancestors_with_macros(position.clone()).find_map(|n| { |
25 | if let Some(module) = ast::Module::cast(n.clone()) { | 26 | if let Some(module) = ast::Module::cast(n.clone()) { |
26 | return module.item_list().map(|it| it.syntax().clone()); | 27 | return module.item_list().map(|it| it.syntax().clone()); |
27 | } | 28 | } |
@@ -30,7 +31,7 @@ pub fn insert_use_statement( | |||
30 | 31 | ||
31 | if let Some(container) = container { | 32 | if let Some(container) = container { |
32 | let action = best_action_for_target(container, position.clone(), &target); | 33 | let action = best_action_for_target(container, position.clone(), &target); |
33 | make_assist(&action, &target, edit); | 34 | make_assist(&action, &target, edit.text_edit_builder()); |
34 | } | 35 | } |
35 | } | 36 | } |
36 | 37 | ||