aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/add_function.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/add_function.rs')
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs145
1 files changed, 87 insertions, 58 deletions
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index de016ae4e..24f931a85 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -4,13 +4,17 @@ use ra_syntax::{
4 ast::{ 4 ast::{
5 self, 5 self,
6 edit::{AstNodeEdit, IndentLevel}, 6 edit::{AstNodeEdit, IndentLevel},
7 ArgListOwner, AstNode, ModuleItemOwner, 7 make, ArgListOwner, AstNode, ModuleItemOwner,
8 }, 8 },
9 SyntaxKind, SyntaxNode, TextSize, 9 SyntaxKind, SyntaxNode, TextSize,
10}; 10};
11use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap, FxHashSet};
12 12
13use crate::{AssistContext, AssistId, Assists}; 13use crate::{
14 assist_config::SnippetCap,
15 utils::{render_snippet, Cursor},
16 AssistContext, AssistId, Assists,
17};
14 18
15// Assist: add_function 19// Assist: add_function
16// 20//
@@ -33,7 +37,7 @@ use crate::{AssistContext, AssistId, Assists};
33// } 37// }
34// 38//
35// fn bar(arg: &str, baz: Baz) { 39// fn bar(arg: &str, baz: Baz) {
36// todo!() 40// ${0:todo!()}
37// } 41// }
38// 42//
39// ``` 43// ```
@@ -58,21 +62,40 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
58 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; 62 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
59 63
60 let target = call.syntax().text_range(); 64 let target = call.syntax().text_range();
61 acc.add(AssistId("add_function"), "Add function", target, |edit| { 65 acc.add(AssistId("add_function"), "Add function", target, |builder| {
62 let function_template = function_builder.render(); 66 let function_template = function_builder.render();
63 edit.set_file(function_template.file); 67 builder.set_file(function_template.file);
64 edit.set_cursor(function_template.cursor_offset); 68 let new_fn = function_template.to_string(ctx.config.snippet_cap);
65 edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); 69 match ctx.config.snippet_cap {
70 Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
71 None => builder.insert(function_template.insert_offset, new_fn),
72 }
66 }) 73 })
67} 74}
68 75
69struct FunctionTemplate { 76struct FunctionTemplate {
70 insert_offset: TextSize, 77 insert_offset: TextSize,
71 cursor_offset: TextSize, 78 placeholder_expr: ast::MacroCall,
72 fn_def: ast::SourceFile, 79 leading_ws: String,
80 fn_def: ast::FnDef,
81 trailing_ws: String,
73 file: FileId, 82 file: FileId,
74} 83}
75 84
85impl FunctionTemplate {
86 fn to_string(&self, cap: Option<SnippetCap>) -> String {
87 let f = match cap {
88 Some(cap) => render_snippet(
89 cap,
90 self.fn_def.syntax(),
91 Cursor::Replace(self.placeholder_expr.syntax()),
92 ),
93 None => self.fn_def.to_string(),
94 };
95 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
96 }
97}
98
76struct FunctionBuilder { 99struct FunctionBuilder {
77 target: GeneratedFunctionTarget, 100 target: GeneratedFunctionTarget,
78 fn_name: ast::Name, 101 fn_name: ast::Name,
@@ -110,35 +133,41 @@ impl FunctionBuilder {
110 } 133 }
111 134
112 fn render(self) -> FunctionTemplate { 135 fn render(self) -> FunctionTemplate {
113 let placeholder_expr = ast::make::expr_todo(); 136 let placeholder_expr = make::expr_todo();
114 let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); 137 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
115 let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); 138 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
116 if self.needs_pub { 139 let mut fn_def =
117 fn_def = ast::make::add_pub_crate_modifier(fn_def); 140 make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body);
118 } 141 let leading_ws;
119 142 let trailing_ws;
120 let (fn_def, insert_offset) = match self.target { 143
144 let insert_offset = match self.target {
121 GeneratedFunctionTarget::BehindItem(it) => { 145 GeneratedFunctionTarget::BehindItem(it) => {
122 let with_leading_blank_line = ast::make::add_leading_newlines(2, fn_def); 146 let indent = IndentLevel::from_node(&it);
123 let indented = with_leading_blank_line.indent(IndentLevel::from_node(&it)); 147 leading_ws = format!("\n\n{}", indent);
124 (indented, it.text_range().end()) 148 fn_def = fn_def.indent(indent);
149 trailing_ws = String::new();
150 it.text_range().end()
125 } 151 }
126 GeneratedFunctionTarget::InEmptyItemList(it) => { 152 GeneratedFunctionTarget::InEmptyItemList(it) => {
127 let indent_once = IndentLevel(1);
128 let indent = IndentLevel::from_node(it.syntax()); 153 let indent = IndentLevel::from_node(it.syntax());
129 let fn_def = ast::make::add_leading_newlines(1, fn_def); 154 leading_ws = format!("\n{}", indent + 1);
130 let fn_def = fn_def.indent(indent_once); 155 fn_def = fn_def.indent(indent + 1);
131 let fn_def = ast::make::add_trailing_newlines(1, fn_def); 156 trailing_ws = format!("\n{}", indent);
132 let fn_def = fn_def.indent(indent); 157 it.syntax().text_range().start() + TextSize::of('{')
133 (fn_def, it.syntax().text_range().start() + TextSize::of('{'))
134 } 158 }
135 }; 159 };
136 160
137 let placeholder_expr = 161 let placeholder_expr =
138 fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 162 fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
139 let cursor_offset_from_fn_start = placeholder_expr.syntax().text_range().start(); 163 FunctionTemplate {
140 let cursor_offset = insert_offset + cursor_offset_from_fn_start; 164 insert_offset,
141 FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file } 165 placeholder_expr,
166 leading_ws,
167 fn_def,
168 trailing_ws,
169 file: self.file,
170 }
142 } 171 }
143} 172}
144 173
@@ -158,7 +187,7 @@ impl GeneratedFunctionTarget {
158 187
159fn fn_name(call: &ast::Path) -> Option<ast::Name> { 188fn fn_name(call: &ast::Path) -> Option<ast::Name> {
160 let name = call.segment()?.syntax().to_string(); 189 let name = call.segment()?.syntax().to_string();
161 Some(ast::make::name(&name)) 190 Some(make::name(&name))
162} 191}
163 192
164/// Computes the type variables and arguments required for the generated function 193/// Computes the type variables and arguments required for the generated function
@@ -180,8 +209,8 @@ fn fn_args(
180 }); 209 });
181 } 210 }
182 deduplicate_arg_names(&mut arg_names); 211 deduplicate_arg_names(&mut arg_names);
183 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| ast::make::param(name, ty)); 212 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| make::param(name, ty));
184 Some((None, ast::make::param_list(params))) 213 Some((None, make::param_list(params)))
185} 214}
186 215
187/// Makes duplicate argument names unique by appending incrementing numbers. 216/// Makes duplicate argument names unique by appending incrementing numbers.
@@ -316,7 +345,7 @@ fn foo() {
316} 345}
317 346
318fn bar() { 347fn bar() {
319 <|>todo!() 348 ${0:todo!()}
320} 349}
321", 350",
322 ) 351 )
@@ -343,7 +372,7 @@ impl Foo {
343} 372}
344 373
345fn bar() { 374fn bar() {
346 <|>todo!() 375 ${0:todo!()}
347} 376}
348", 377",
349 ) 378 )
@@ -367,7 +396,7 @@ fn foo1() {
367} 396}
368 397
369fn bar() { 398fn bar() {
370 <|>todo!() 399 ${0:todo!()}
371} 400}
372 401
373fn foo2() {} 402fn foo2() {}
@@ -393,7 +422,7 @@ mod baz {
393 } 422 }
394 423
395 fn bar() { 424 fn bar() {
396 <|>todo!() 425 ${0:todo!()}
397 } 426 }
398} 427}
399", 428",
@@ -419,7 +448,7 @@ fn foo() {
419} 448}
420 449
421fn bar(baz: Baz) { 450fn bar(baz: Baz) {
422 <|>todo!() 451 ${0:todo!()}
423} 452}
424", 453",
425 ); 454 );
@@ -452,7 +481,7 @@ impl Baz {
452} 481}
453 482
454fn bar(baz: Baz) { 483fn bar(baz: Baz) {
455 <|>todo!() 484 ${0:todo!()}
456} 485}
457", 486",
458 ) 487 )
@@ -473,7 +502,7 @@ fn foo() {
473} 502}
474 503
475fn bar(arg: &str) { 504fn bar(arg: &str) {
476 <|>todo!() 505 ${0:todo!()}
477} 506}
478"#, 507"#,
479 ) 508 )
@@ -494,7 +523,7 @@ fn foo() {
494} 523}
495 524
496fn bar(arg: char) { 525fn bar(arg: char) {
497 <|>todo!() 526 ${0:todo!()}
498} 527}
499"#, 528"#,
500 ) 529 )
@@ -515,7 +544,7 @@ fn foo() {
515} 544}
516 545
517fn bar(arg: i32) { 546fn bar(arg: i32) {
518 <|>todo!() 547 ${0:todo!()}
519} 548}
520", 549",
521 ) 550 )
@@ -536,7 +565,7 @@ fn foo() {
536} 565}
537 566
538fn bar(arg: u8) { 567fn bar(arg: u8) {
539 <|>todo!() 568 ${0:todo!()}
540} 569}
541", 570",
542 ) 571 )
@@ -561,7 +590,7 @@ fn foo() {
561} 590}
562 591
563fn bar(x: u8) { 592fn bar(x: u8) {
564 <|>todo!() 593 ${0:todo!()}
565} 594}
566", 595",
567 ) 596 )
@@ -584,7 +613,7 @@ fn foo() {
584} 613}
585 614
586fn bar(worble: ()) { 615fn bar(worble: ()) {
587 <|>todo!() 616 ${0:todo!()}
588} 617}
589", 618",
590 ) 619 )
@@ -613,7 +642,7 @@ fn baz() {
613} 642}
614 643
615fn bar(foo: impl Foo) { 644fn bar(foo: impl Foo) {
616 <|>todo!() 645 ${0:todo!()}
617} 646}
618", 647",
619 ) 648 )
@@ -640,7 +669,7 @@ fn foo() {
640} 669}
641 670
642fn bar(baz: &Baz) { 671fn bar(baz: &Baz) {
643 <|>todo!() 672 ${0:todo!()}
644} 673}
645", 674",
646 ) 675 )
@@ -669,7 +698,7 @@ fn foo() {
669} 698}
670 699
671fn bar(baz: Baz::Bof) { 700fn bar(baz: Baz::Bof) {
672 <|>todo!() 701 ${0:todo!()}
673} 702}
674", 703",
675 ) 704 )
@@ -692,7 +721,7 @@ fn foo<T>(t: T) {
692} 721}
693 722
694fn bar<T>(t: T) { 723fn bar<T>(t: T) {
695 <|>todo!() 724 ${0:todo!()}
696} 725}
697", 726",
698 ) 727 )
@@ -723,7 +752,7 @@ fn foo() {
723} 752}
724 753
725fn bar(arg: fn() -> Baz) { 754fn bar(arg: fn() -> Baz) {
726 <|>todo!() 755 ${0:todo!()}
727} 756}
728", 757",
729 ) 758 )
@@ -748,7 +777,7 @@ fn foo() {
748} 777}
749 778
750fn bar(closure: impl Fn(i64) -> i64) { 779fn bar(closure: impl Fn(i64) -> i64) {
751 <|>todo!() 780 ${0:todo!()}
752} 781}
753", 782",
754 ) 783 )
@@ -769,7 +798,7 @@ fn foo() {
769} 798}
770 799
771fn bar(baz: ()) { 800fn bar(baz: ()) {
772 <|>todo!() 801 ${0:todo!()}
773} 802}
774", 803",
775 ) 804 )
@@ -794,7 +823,7 @@ fn foo() {
794} 823}
795 824
796fn bar(baz_1: Baz, baz_2: Baz) { 825fn bar(baz_1: Baz, baz_2: Baz) {
797 <|>todo!() 826 ${0:todo!()}
798} 827}
799", 828",
800 ) 829 )
@@ -819,7 +848,7 @@ fn foo() {
819} 848}
820 849
821fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { 850fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
822 <|>todo!() 851 ${0:todo!()}
823} 852}
824"#, 853"#,
825 ) 854 )
@@ -839,7 +868,7 @@ fn foo() {
839 r" 868 r"
840mod bar { 869mod bar {
841 pub(crate) fn my_fn() { 870 pub(crate) fn my_fn() {
842 <|>todo!() 871 ${0:todo!()}
843 } 872 }
844} 873}
845 874
@@ -878,7 +907,7 @@ fn bar() {
878} 907}
879 908
880fn baz(foo: foo::Foo) { 909fn baz(foo: foo::Foo) {
881 <|>todo!() 910 ${0:todo!()}
882} 911}
883", 912",
884 ) 913 )
@@ -902,7 +931,7 @@ mod bar {
902 fn something_else() {} 931 fn something_else() {}
903 932
904 pub(crate) fn my_fn() { 933 pub(crate) fn my_fn() {
905 <|>todo!() 934 ${0:todo!()}
906 } 935 }
907} 936}
908 937
@@ -930,7 +959,7 @@ fn foo() {
930mod bar { 959mod bar {
931 mod baz { 960 mod baz {
932 pub(crate) fn my_fn() { 961 pub(crate) fn my_fn() {
933 <|>todo!() 962 ${0:todo!()}
934 } 963 }
935 } 964 }
936} 965}
@@ -959,7 +988,7 @@ fn main() {
959 988
960 989
961pub(crate) fn bar() { 990pub(crate) fn bar() {
962 <|>todo!() 991 ${0:todo!()}
963}", 992}",
964 ) 993 )
965 } 994 }