1
1
use ra_syntax:: {
2
2
ast:: { self , AstNode } ,
3
- SmolStr , SyntaxKind , SyntaxNode , TextUnit ,
3
+ SyntaxKind , SyntaxNode , TextUnit ,
4
4
} ;
5
5
6
6
use crate :: { Assist , AssistCtx , AssistId } ;
7
- use ast:: { ArgListOwner , CallExpr , Expr } ;
7
+ use ast:: { edit :: IndentLevel , ArgListOwner , CallExpr , Expr } ;
8
8
use hir:: HirDisplay ;
9
- use ra_fmt:: leading_indent;
10
9
use rustc_hash:: { FxHashMap , FxHashSet } ;
11
10
12
11
// Assist: add_function
@@ -53,73 +52,62 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
53
52
ctx. add_assist ( AssistId ( "add_function" ) , "Add function" , |edit| {
54
53
edit. target ( call. syntax ( ) . text_range ( ) ) ;
55
54
56
- let function_template = function_builder. render ( ) ;
57
- edit. set_cursor ( function_template. cursor_offset ) ;
58
- edit. insert ( function_template. insert_offset , function_template. fn_text ) ;
55
+ if let Some ( function_template) = function_builder. render ( ) {
56
+ edit. set_cursor ( function_template. cursor_offset ) ;
57
+ edit. insert ( function_template. insert_offset , function_template. fn_def . to_string ( ) ) ;
58
+ }
59
59
} )
60
60
}
61
61
62
62
struct FunctionTemplate {
63
63
insert_offset : TextUnit ,
64
64
cursor_offset : TextUnit ,
65
- fn_text : String ,
65
+ fn_def : ast :: SourceFile ,
66
66
}
67
67
68
68
struct FunctionBuilder {
69
- start_offset : TextUnit ,
70
- fn_name : String ,
71
- fn_generics : String ,
72
- fn_args : String ,
73
- indent : String ,
69
+ append_fn_at : SyntaxNode ,
70
+ fn_name : ast:: Name ,
71
+ type_params : Option < ast:: TypeParamList > ,
72
+ params : ast:: ParamList ,
74
73
}
75
74
76
75
impl FunctionBuilder {
77
76
fn from_call ( ctx : & AssistCtx , call : & ast:: CallExpr ) -> Option < Self > {
78
- let ( start , indent ) = next_space_for_fn ( & call) ?;
77
+ let append_fn_at = next_space_for_fn ( & call) ?;
79
78
let fn_name = fn_name ( & call) ?;
80
- let fn_generics = fn_generics ( & call) ?;
81
- let fn_args = fn_args ( ctx, & call) ?;
82
- let indent = if let Some ( i) = & indent { i. to_string ( ) } else { String :: new ( ) } ;
83
- Some ( Self { start_offset : start, fn_name, fn_generics, fn_args, indent } )
84
- }
85
- fn render ( & self ) -> FunctionTemplate {
86
- let mut fn_buf = String :: with_capacity ( 128 ) ;
87
- fn_buf. push_str ( "\n \n " ) ;
88
- fn_buf. push_str ( & self . indent ) ;
89
- fn_buf. push_str ( "fn " ) ;
90
- fn_buf. push_str ( & self . fn_name ) ;
91
- fn_buf. push_str ( & self . fn_generics ) ;
92
- fn_buf. push_str ( & self . fn_args ) ;
93
- fn_buf. push_str ( " {\n " ) ;
94
- fn_buf. push_str ( & self . indent ) ;
95
- fn_buf. push_str ( " " ) ;
96
-
97
- // We take the offset here to put the cursor in front of the `unimplemented!()` body
98
- let offset = TextUnit :: of_str ( & fn_buf) ;
99
-
100
- fn_buf. push_str ( "unimplemented!()\n " ) ;
101
- fn_buf. push_str ( & self . indent ) ;
102
- fn_buf. push_str ( "}" ) ;
103
-
104
- let cursor_pos = self . start_offset + offset;
105
- FunctionTemplate {
106
- fn_text : fn_buf,
107
- cursor_offset : cursor_pos,
108
- insert_offset : self . start_offset ,
109
- }
110
- }
111
- }
112
-
113
- fn fn_name ( call : & CallExpr ) -> Option < String > {
114
- Some ( call. expr ( ) ?. syntax ( ) . to_string ( ) )
115
- }
116
-
117
- fn fn_generics ( _call : & CallExpr ) -> Option < String > {
118
- // TODO
119
- Some ( "" . into ( ) )
120
- }
121
-
122
- fn fn_args ( ctx : & AssistCtx , call : & CallExpr ) -> Option < String > {
79
+ let ( type_params, params) = fn_args ( ctx, & call) ?;
80
+ Some ( Self { append_fn_at, fn_name, type_params, params } )
81
+ }
82
+ fn render ( self ) -> Option < FunctionTemplate > {
83
+ let placeholder_expr = ast:: make:: expr_unimplemented ( ) ;
84
+ let fn_body = ast:: make:: block_expr ( vec ! [ ] , Some ( placeholder_expr) ) ;
85
+ let fn_def = ast:: make:: fn_def ( self . fn_name , self . type_params , self . params , fn_body) ;
86
+ let fn_def = ast:: make:: add_newlines ( 2 , fn_def) ;
87
+ let fn_def = IndentLevel :: from_node ( & self . append_fn_at ) . increase_indent ( fn_def) ;
88
+ let insert_offset = self . append_fn_at . text_range ( ) . end ( ) ;
89
+ let cursor_offset_from_fn_start = fn_def
90
+ . syntax ( )
91
+ . descendants ( )
92
+ . find_map ( ast:: MacroCall :: cast) ?
93
+ . syntax ( )
94
+ . text_range ( )
95
+ . start ( ) ;
96
+ let cursor_offset = insert_offset + cursor_offset_from_fn_start;
97
+ Some ( FunctionTemplate { insert_offset, cursor_offset, fn_def } )
98
+ }
99
+ }
100
+
101
+ fn fn_name ( call : & CallExpr ) -> Option < ast:: Name > {
102
+ let name = call. expr ( ) ?. syntax ( ) . to_string ( ) ;
103
+ Some ( ast:: make:: name ( & name) )
104
+ }
105
+
106
+ /// Computes the type variables and arguments required for the generated function
107
+ fn fn_args (
108
+ ctx : & AssistCtx ,
109
+ call : & CallExpr ,
110
+ ) -> Option < ( Option < ast:: TypeParamList > , ast:: ParamList ) > {
123
111
let mut arg_names = Vec :: new ( ) ;
124
112
let mut arg_types = Vec :: new ( ) ;
125
113
for arg in call. arg_list ( ) ?. args ( ) {
@@ -134,15 +122,8 @@ fn fn_args(ctx: &AssistCtx, call: &CallExpr) -> Option<String> {
134
122
} ) ;
135
123
}
136
124
deduplicate_arg_names ( & mut arg_names) ;
137
- Some ( format ! (
138
- "({})" ,
139
- arg_names
140
- . into_iter( )
141
- . zip( arg_types)
142
- . map( |( name, ty) | format!( "{}: {}" , name, ty) )
143
- . collect:: <Vec <_>>( )
144
- . join( ", " )
145
- ) )
125
+ let params = arg_names. into_iter ( ) . zip ( arg_types) . map ( |( name, ty) | ast:: make:: param ( name, ty) ) ;
126
+ Some ( ( None , ast:: make:: param_list ( params) ) )
146
127
}
147
128
148
129
/// Makes duplicate argument names unique by appending incrementing numbers.
@@ -203,7 +184,7 @@ fn fn_arg_type(ctx: &AssistCtx, fn_arg: &Expr) -> Option<String> {
203
184
/// directly after the current block
204
185
/// We want to write the generated function directly after
205
186
/// fns, impls or macro calls, but inside mods
206
- fn next_space_for_fn ( expr : & CallExpr ) -> Option < ( TextUnit , Option < SmolStr > ) > {
187
+ fn next_space_for_fn ( expr : & CallExpr ) -> Option < SyntaxNode > {
207
188
let mut ancestors = expr. syntax ( ) . ancestors ( ) . peekable ( ) ;
208
189
let mut last_ancestor: Option < SyntaxNode > = None ;
209
190
while let Some ( next_ancestor) = ancestors. next ( ) {
@@ -220,7 +201,7 @@ fn next_space_for_fn(expr: &CallExpr) -> Option<(TextUnit, Option<SmolStr>)> {
220
201
}
221
202
last_ancestor = Some ( next_ancestor) ;
222
203
}
223
- last_ancestor. map ( |a| ( a . text_range ( ) . end ( ) , leading_indent ( & a ) ) )
204
+ last_ancestor
224
205
}
225
206
226
207
#[ cfg( test) ]
0 commit comments