diff options
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 8 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_function.rs | 71 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 15 | ||||
-rw-r--r-- | crates/ra_ide/src/assists.rs | 4 |
4 files changed, 82 insertions, 16 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index c3e653299..279163257 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | }; | 10 | }; |
11 | use ra_text_edit::TextEditBuilder; | 11 | use ra_text_edit::TextEditBuilder; |
12 | 12 | ||
13 | use crate::{AssistAction, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; | 13 | use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; |
14 | use algo::SyntaxRewriter; | 14 | use algo::SyntaxRewriter; |
15 | 15 | ||
16 | #[derive(Clone, Debug)] | 16 | #[derive(Clone, Debug)] |
@@ -180,6 +180,7 @@ pub(crate) struct ActionBuilder { | |||
180 | edit: TextEditBuilder, | 180 | edit: TextEditBuilder, |
181 | cursor_position: Option<TextUnit>, | 181 | cursor_position: Option<TextUnit>, |
182 | target: Option<TextRange>, | 182 | target: Option<TextRange>, |
183 | file: AssistFile, | ||
183 | } | 184 | } |
184 | 185 | ||
185 | impl ActionBuilder { | 186 | impl ActionBuilder { |
@@ -241,11 +242,16 @@ impl ActionBuilder { | |||
241 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | 242 | algo::diff(&node, &new).into_text_edit(&mut self.edit) |
242 | } | 243 | } |
243 | 244 | ||
245 | pub(crate) fn set_file(&mut self, assist_file: AssistFile) { | ||
246 | self.file = assist_file | ||
247 | } | ||
248 | |||
244 | fn build(self) -> AssistAction { | 249 | fn build(self) -> AssistAction { |
245 | AssistAction { | 250 | AssistAction { |
246 | edit: self.edit.finish(), | 251 | edit: self.edit.finish(), |
247 | cursor_position: self.cursor_position, | 252 | cursor_position: self.cursor_position, |
248 | target: self.target, | 253 | target: self.target, |
254 | file: self.file, | ||
249 | } | 255 | } |
250 | } | 256 | } |
251 | } | 257 | } |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index a1261fe15..b65ded871 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -3,7 +3,7 @@ use ra_syntax::{ | |||
3 | SyntaxKind, SyntaxNode, TextUnit, | 3 | SyntaxKind, SyntaxNode, TextUnit, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 6 | use crate::{Assist, AssistCtx, AssistFile, AssistId}; |
7 | use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner}; | 7 | use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner}; |
8 | use hir::HirDisplay; | 8 | use hir::HirDisplay; |
9 | use rustc_hash::{FxHashMap, FxHashSet}; | 9 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -44,10 +44,10 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { | |||
44 | } | 44 | } |
45 | 45 | ||
46 | let target_module = if let Some(qualifier) = path.qualifier() { | 46 | let target_module = if let Some(qualifier) = path.qualifier() { |
47 | if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(resolved))) = | 47 | if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = |
48 | ctx.sema.resolve_path(&qualifier) | 48 | ctx.sema.resolve_path(&qualifier) |
49 | { | 49 | { |
50 | Some(resolved.definition_source(ctx.sema.db).value) | 50 | Some(module.definition_source(ctx.sema.db)) |
51 | } else { | 51 | } else { |
52 | return None; | 52 | return None; |
53 | } | 53 | } |
@@ -61,6 +61,7 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { | |||
61 | edit.target(call.syntax().text_range()); | 61 | edit.target(call.syntax().text_range()); |
62 | 62 | ||
63 | if let Some(function_template) = function_builder.render() { | 63 | if let Some(function_template) = function_builder.render() { |
64 | edit.set_file(function_template.file); | ||
64 | edit.set_cursor(function_template.cursor_offset); | 65 | edit.set_cursor(function_template.cursor_offset); |
65 | edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); | 66 | edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); |
66 | } | 67 | } |
@@ -71,6 +72,7 @@ struct FunctionTemplate { | |||
71 | insert_offset: TextUnit, | 72 | insert_offset: TextUnit, |
72 | cursor_offset: TextUnit, | 73 | cursor_offset: TextUnit, |
73 | fn_def: ast::SourceFile, | 74 | fn_def: ast::SourceFile, |
75 | file: AssistFile, | ||
74 | } | 76 | } |
75 | 77 | ||
76 | struct FunctionBuilder { | 78 | struct FunctionBuilder { |
@@ -78,6 +80,7 @@ struct FunctionBuilder { | |||
78 | fn_name: ast::Name, | 80 | fn_name: ast::Name, |
79 | type_params: Option<ast::TypeParamList>, | 81 | type_params: Option<ast::TypeParamList>, |
80 | params: ast::ParamList, | 82 | params: ast::ParamList, |
83 | file: AssistFile, | ||
81 | } | 84 | } |
82 | 85 | ||
83 | impl FunctionBuilder { | 86 | impl FunctionBuilder { |
@@ -87,16 +90,19 @@ impl FunctionBuilder { | |||
87 | ctx: &AssistCtx, | 90 | ctx: &AssistCtx, |
88 | call: &ast::CallExpr, | 91 | call: &ast::CallExpr, |
89 | path: &ast::Path, | 92 | path: &ast::Path, |
90 | generate_in: Option<hir::ModuleSource>, | 93 | generate_in: Option<hir::InFile<hir::ModuleSource>>, |
91 | ) -> Option<Self> { | 94 | ) -> Option<Self> { |
95 | let mut file = AssistFile::default(); | ||
92 | let target = if let Some(generate_in_module) = generate_in { | 96 | let target = if let Some(generate_in_module) = generate_in { |
93 | next_space_for_fn_in_module(generate_in_module)? | 97 | let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, generate_in_module)?; |
98 | file = in_file; | ||
99 | target | ||
94 | } else { | 100 | } else { |
95 | next_space_for_fn_after_call_site(&call)? | 101 | next_space_for_fn_after_call_site(&call)? |
96 | }; | 102 | }; |
97 | let fn_name = fn_name(&path)?; | 103 | let fn_name = fn_name(&path)?; |
98 | let (type_params, params) = fn_args(ctx, &call)?; | 104 | let (type_params, params) = fn_args(ctx, &call)?; |
99 | Some(Self { target, fn_name, type_params, params }) | 105 | Some(Self { target, fn_name, type_params, params, file }) |
100 | } | 106 | } |
101 | fn render(self) -> Option<FunctionTemplate> { | 107 | fn render(self) -> Option<FunctionTemplate> { |
102 | let placeholder_expr = ast::make::expr_todo(); | 108 | let placeholder_expr = ast::make::expr_todo(); |
@@ -130,7 +136,7 @@ impl FunctionBuilder { | |||
130 | .text_range() | 136 | .text_range() |
131 | .start(); | 137 | .start(); |
132 | let cursor_offset = insert_offset + cursor_offset_from_fn_start; | 138 | let cursor_offset = insert_offset + cursor_offset_from_fn_start; |
133 | Some(FunctionTemplate { insert_offset, cursor_offset, fn_def }) | 139 | Some(FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file }) |
134 | } | 140 | } |
135 | } | 141 | } |
136 | 142 | ||
@@ -250,23 +256,29 @@ fn next_space_for_fn_after_call_site(expr: &ast::CallExpr) -> Option<GeneratedFu | |||
250 | last_ancestor.map(GeneratedFunctionTarget::BehindItem) | 256 | last_ancestor.map(GeneratedFunctionTarget::BehindItem) |
251 | } | 257 | } |
252 | 258 | ||
253 | fn next_space_for_fn_in_module(module: hir::ModuleSource) -> Option<GeneratedFunctionTarget> { | 259 | fn next_space_for_fn_in_module( |
254 | match module { | 260 | db: &dyn hir::db::AstDatabase, |
261 | module: hir::InFile<hir::ModuleSource>, | ||
262 | ) -> Option<(AssistFile, GeneratedFunctionTarget)> { | ||
263 | let file = module.file_id.original_file(db); | ||
264 | let assist_file = AssistFile::TargetFile(file); | ||
265 | let assist_item = match module.value { | ||
255 | hir::ModuleSource::SourceFile(it) => { | 266 | hir::ModuleSource::SourceFile(it) => { |
256 | if let Some(last_item) = it.items().last() { | 267 | if let Some(last_item) = it.items().last() { |
257 | Some(GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())) | 268 | GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) |
258 | } else { | 269 | } else { |
259 | Some(GeneratedFunctionTarget::BehindItem(it.syntax().clone())) | 270 | GeneratedFunctionTarget::BehindItem(it.syntax().clone()) |
260 | } | 271 | } |
261 | } | 272 | } |
262 | hir::ModuleSource::Module(it) => { | 273 | hir::ModuleSource::Module(it) => { |
263 | if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) { | 274 | if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) { |
264 | Some(GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())) | 275 | GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) |
265 | } else { | 276 | } else { |
266 | it.item_list().map(GeneratedFunctionTarget::InEmptyItemList) | 277 | GeneratedFunctionTarget::InEmptyItemList(it.item_list()?) |
267 | } | 278 | } |
268 | } | 279 | } |
269 | } | 280 | }; |
281 | Some((assist_file, assist_item)) | ||
270 | } | 282 | } |
271 | 283 | ||
272 | #[cfg(test)] | 284 | #[cfg(test)] |
@@ -885,6 +897,37 @@ fn foo() { | |||
885 | } | 897 | } |
886 | 898 | ||
887 | #[test] | 899 | #[test] |
900 | fn add_function_in_another_file() { | ||
901 | check_assist( | ||
902 | add_function, | ||
903 | r" | ||
904 | //- /main.rs | ||
905 | mod foo; | ||
906 | |||
907 | fn main() { | ||
908 | foo::bar<|>() | ||
909 | } | ||
910 | |||
911 | //- /foo.rs | ||
912 | |||
913 | ", | ||
914 | r" | ||
915 | //- /main.rs | ||
916 | mod foo; | ||
917 | |||
918 | fn main() { | ||
919 | foo::bar() | ||
920 | } | ||
921 | |||
922 | //- /foo.rs | ||
923 | fn bar() { | ||
924 | <|>todo!() | ||
925 | } | ||
926 | ", | ||
927 | ) | ||
928 | } | ||
929 | |||
930 | #[test] | ||
888 | fn add_function_not_applicable_if_function_already_exists() { | 931 | fn add_function_not_applicable_if_function_already_exists() { |
889 | check_assist_not_applicable( | 932 | check_assist_not_applicable( |
890 | add_function, | 933 | add_function, |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index a00136da1..fb57486cb 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -17,7 +17,7 @@ mod doc_tests; | |||
17 | pub mod utils; | 17 | pub mod utils; |
18 | pub mod ast_transform; | 18 | pub mod ast_transform; |
19 | 19 | ||
20 | use ra_db::FileRange; | 20 | use ra_db::{FileId, FileRange}; |
21 | use ra_ide_db::RootDatabase; | 21 | use ra_ide_db::RootDatabase; |
22 | use ra_syntax::{TextRange, TextUnit}; | 22 | use ra_syntax::{TextRange, TextUnit}; |
23 | use ra_text_edit::TextEdit; | 23 | use ra_text_edit::TextEdit; |
@@ -54,6 +54,7 @@ pub struct AssistAction { | |||
54 | pub cursor_position: Option<TextUnit>, | 54 | pub cursor_position: Option<TextUnit>, |
55 | // FIXME: This belongs to `AssistLabel` | 55 | // FIXME: This belongs to `AssistLabel` |
56 | pub target: Option<TextRange>, | 56 | pub target: Option<TextRange>, |
57 | pub file: AssistFile, | ||
57 | } | 58 | } |
58 | 59 | ||
59 | #[derive(Debug, Clone)] | 60 | #[derive(Debug, Clone)] |
@@ -63,6 +64,18 @@ pub struct ResolvedAssist { | |||
63 | pub action: AssistAction, | 64 | pub action: AssistAction, |
64 | } | 65 | } |
65 | 66 | ||
67 | #[derive(Debug, Clone, Copy)] | ||
68 | pub enum AssistFile { | ||
69 | CurrentFile, | ||
70 | TargetFile(FileId), | ||
71 | } | ||
72 | |||
73 | impl Default for AssistFile { | ||
74 | fn default() -> Self { | ||
75 | Self::CurrentFile | ||
76 | } | ||
77 | } | ||
78 | |||
66 | /// Return all the assists applicable at the given position. | 79 | /// Return all the assists applicable at the given position. |
67 | /// | 80 | /// |
68 | /// Assists are returned in the "unresolved" state, that is only labels are | 81 | /// Assists are returned in the "unresolved" state, that is only labels are |
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs index 40d56a4f7..2b5d11681 100644 --- a/crates/ra_ide/src/assists.rs +++ b/crates/ra_ide/src/assists.rs | |||
@@ -37,6 +37,10 @@ fn action_to_edit( | |||
37 | file_id: FileId, | 37 | file_id: FileId, |
38 | assist_label: &AssistLabel, | 38 | assist_label: &AssistLabel, |
39 | ) -> SourceChange { | 39 | ) -> SourceChange { |
40 | let file_id = match action.file { | ||
41 | ra_assists::AssistFile::TargetFile(it) => it, | ||
42 | _ => file_id, | ||
43 | }; | ||
40 | let file_edit = SourceFileEdit { file_id, edit: action.edit }; | 44 | let file_edit = SourceFileEdit { file_id, edit: action.edit }; |
41 | SourceChange::source_file_edit(assist_label.label.clone(), file_edit) | 45 | SourceChange::source_file_edit(assist_label.label.clone(), file_edit) |
42 | .with_cursor_opt(action.cursor_position.map(|offset| FilePosition { offset, file_id })) | 46 | .with_cursor_opt(action.cursor_position.map(|offset| FilePosition { offset, file_id })) |