11use ra_syntax:: {
22 ast:: { self , AstNode } ,
3- SmolStr , SyntaxKind , SyntaxNode , TextUnit ,
3+ SyntaxKind , SyntaxNode , TextUnit ,
44} ;
55
66use crate :: { Assist , AssistCtx , AssistId } ;
7- use ast:: { ArgListOwner , CallExpr , Expr } ;
7+ use ast:: { edit :: IndentLevel , ArgListOwner , CallExpr , Expr } ;
88use hir:: HirDisplay ;
9- use ra_fmt:: leading_indent;
109use rustc_hash:: { FxHashMap , FxHashSet } ;
1110
1211// Assist: add_function
@@ -53,73 +52,62 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
5352 ctx. add_assist ( AssistId ( "add_function" ) , "Add function" , |edit| {
5453 edit. target ( call. syntax ( ) . text_range ( ) ) ;
5554
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+ }
5959 } )
6060}
6161
6262struct FunctionTemplate {
6363 insert_offset : TextUnit ,
6464 cursor_offset : TextUnit ,
65- fn_text : String ,
65+ fn_def : ast :: SourceFile ,
6666}
6767
6868struct 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 ,
7473}
7574
7675impl FunctionBuilder {
7776 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) ?;
7978 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 ) > {
123111 let mut arg_names = Vec :: new ( ) ;
124112 let mut arg_types = Vec :: new ( ) ;
125113 for arg in call. arg_list ( ) ?. args ( ) {
@@ -134,15 +122,8 @@ fn fn_args(ctx: &AssistCtx, call: &CallExpr) -> Option<String> {
134122 } ) ;
135123 }
136124 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) ) )
146127}
147128
148129/// Makes duplicate argument names unique by appending incrementing numbers.
@@ -203,7 +184,7 @@ fn fn_arg_type(ctx: &AssistCtx, fn_arg: &Expr) -> Option<String> {
203184/// directly after the current block
204185/// We want to write the generated function directly after
205186/// 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 > {
207188 let mut ancestors = expr. syntax ( ) . ancestors ( ) . peekable ( ) ;
208189 let mut last_ancestor: Option < SyntaxNode > = None ;
209190 while let Some ( next_ancestor) = ancestors. next ( ) {
@@ -220,7 +201,7 @@ fn next_space_for_fn(expr: &CallExpr) -> Option<(TextUnit, Option<SmolStr>)> {
220201 }
221202 last_ancestor = Some ( next_ancestor) ;
222203 }
223- last_ancestor. map ( |a| ( a . text_range ( ) . end ( ) , leading_indent ( & a ) ) )
204+ last_ancestor
224205}
225206
226207#[ cfg( test) ]
0 commit comments