1
1
use ide_db:: { famous_defs:: FamousDefs , source_change:: SourceChangeBuilder } ;
2
2
use stdx:: { format_to, to_lower_snake_case} ;
3
3
use syntax:: {
4
- ast:: { self , AstNode , HasName , HasVisibility } ,
5
- TextRange ,
4
+ ast:: { self , edit_in_place :: Indent , make , AstNode , HasName , HasVisibility } ,
5
+ ted , TextRange ,
6
6
} ;
7
7
8
8
use crate :: {
9
- utils:: { convert_reference_type, find_impl_block_end , find_struct_impl, generate_impl_text } ,
9
+ utils:: { convert_reference_type, find_struct_impl, generate_impl } ,
10
10
AssistContext , AssistId , AssistKind , Assists , GroupLabel ,
11
11
} ;
12
12
@@ -200,14 +200,14 @@ fn generate_getter_from_info(
200
200
ctx : & AssistContext < ' _ > ,
201
201
info : & AssistInfo ,
202
202
record_field_info : & RecordFieldInfo ,
203
- ) -> String {
204
- let mut buf = String :: with_capacity ( 512 ) ;
205
-
206
- let vis = info. strukt . visibility ( ) . map_or ( String :: new ( ) , |v| format ! ( "{v} " ) ) ;
203
+ ) -> ast:: Fn {
207
204
let ( ty, body) = if matches ! ( info. assist_type, AssistType :: MutGet ) {
208
205
(
209
- format ! ( "&mut {}" , record_field_info. field_ty) ,
210
- format ! ( "&mut self.{}" , record_field_info. field_name) ,
206
+ make:: ty_ref ( record_field_info. field_ty . clone ( ) , true ) ,
207
+ make:: expr_ref (
208
+ make:: expr_field ( make:: ext:: expr_self ( ) , & record_field_info. field_name . text ( ) ) ,
209
+ true ,
210
+ ) ,
211
211
)
212
212
} else {
213
213
( || {
@@ -226,41 +226,52 @@ fn generate_getter_from_info(
226
226
} ) ( )
227
227
. unwrap_or_else ( || {
228
228
(
229
- format ! ( "&{}" , record_field_info. field_ty) ,
230
- format ! ( "&self.{}" , record_field_info. field_name) ,
229
+ make:: ty_ref ( record_field_info. field_ty . clone ( ) , false ) ,
230
+ make:: expr_ref (
231
+ make:: expr_field ( make:: ext:: expr_self ( ) , & record_field_info. field_name . text ( ) ) ,
232
+ false ,
233
+ ) ,
231
234
)
232
235
} )
233
236
} ;
234
237
235
- format_to ! (
236
- buf,
237
- " {}fn {}(&{}self) -> {} {{
238
- {}
239
- }}" ,
240
- vis,
241
- record_field_info. fn_name,
242
- matches!( info. assist_type, AssistType :: MutGet ) . then_some( "mut " ) . unwrap_or_default( ) ,
243
- ty,
244
- body,
245
- ) ;
238
+ let self_param = if matches ! ( info. assist_type, AssistType :: MutGet ) {
239
+ make:: mut_self_param ( )
240
+ } else {
241
+ make:: self_param ( )
242
+ } ;
246
243
247
- buf
244
+ let strukt = & info. strukt ;
245
+ let fn_name = make:: name ( & record_field_info. fn_name ) ;
246
+ let params = make:: param_list ( Some ( self_param) , [ ] ) ;
247
+ let ret_type = Some ( make:: ret_type ( ty) ) ;
248
+ let body = make:: block_expr ( [ ] , Some ( body) ) ;
249
+
250
+ make:: fn_ ( strukt. visibility ( ) , fn_name, None , None , params, body, ret_type, false , false , false )
248
251
}
249
252
250
- fn generate_setter_from_info ( info : & AssistInfo , record_field_info : & RecordFieldInfo ) -> String {
251
- let mut buf = String :: with_capacity ( 512 ) ;
253
+ fn generate_setter_from_info ( info : & AssistInfo , record_field_info : & RecordFieldInfo ) -> ast:: Fn {
252
254
let strukt = & info. strukt ;
253
- let fn_name = & record_field_info. fn_name ;
255
+ let field_name = & record_field_info. fn_name ;
256
+ let fn_name = make:: name ( & format ! ( "set_{field_name}" ) ) ;
254
257
let field_ty = & record_field_info. field_ty ;
255
- let vis = strukt. visibility ( ) . map_or ( String :: new ( ) , |v| format ! ( "{v} " ) ) ;
256
- format_to ! (
257
- buf,
258
- " {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{
259
- self.{fn_name} = {fn_name};
260
- }}"
261
- ) ;
262
258
263
- buf
259
+ // Make the param list
260
+ // `(&mut self, $field_name: $field_ty)`
261
+ let field_param =
262
+ make:: param ( make:: ident_pat ( false , false , make:: name ( field_name) ) . into ( ) , field_ty. clone ( ) ) ;
263
+ let params = make:: param_list ( Some ( make:: mut_self_param ( ) ) , [ field_param] ) ;
264
+
265
+ // Make the assignment body
266
+ // `self.$field_name = $field_name`
267
+ let self_expr = make:: ext:: expr_self ( ) ;
268
+ let lhs = make:: expr_field ( self_expr, field_name) ;
269
+ let rhs = make:: expr_path ( make:: ext:: ident_path ( field_name) ) ;
270
+ let assign_stmt = make:: expr_stmt ( make:: expr_assignment ( lhs, rhs) ) ;
271
+ let body = make:: block_expr ( [ assign_stmt. into ( ) ] , None ) ;
272
+
273
+ // Make the setter fn
274
+ make:: fn_ ( strukt. visibility ( ) , fn_name, None , None , params, body, None , false , false , false )
264
275
}
265
276
266
277
fn extract_and_parse (
@@ -353,74 +364,45 @@ fn build_source_change(
353
364
) {
354
365
let record_fields_count = info_of_record_fields. len ( ) ;
355
366
356
- let mut buf = String :: with_capacity ( 512 ) ;
367
+ let impl_def = if let Some ( impl_def) = & assist_info. impl_def {
368
+ // We have an existing impl to add to
369
+ builder. make_mut ( impl_def. clone ( ) )
370
+ } else {
371
+ // Generate a new impl to add the methods to
372
+ let impl_def = generate_impl ( & ast:: Adt :: Struct ( assist_info. strukt . clone ( ) ) ) ;
357
373
358
- // Check if an impl exists
359
- if let Some ( impl_def) = & assist_info. impl_def {
360
- // Check if impl is empty
361
- if let Some ( assoc_item_list) = impl_def. assoc_item_list ( ) {
362
- if assoc_item_list. assoc_items ( ) . next ( ) . is_some ( ) {
363
- // If not empty then only insert a new line
364
- buf. push ( '\n' ) ;
365
- }
366
- }
367
- }
374
+ // Insert it after the adt
375
+ let strukt = builder. make_mut ( assist_info. strukt . clone ( ) ) ;
376
+
377
+ ted:: insert_all_raw (
378
+ ted:: Position :: after ( strukt. syntax ( ) ) ,
379
+ vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
380
+ ) ;
381
+
382
+ impl_def
383
+ } ;
384
+
385
+ let assoc_item_list = impl_def. get_or_create_assoc_item_list ( ) ;
368
386
369
387
for ( i, record_field_info) in info_of_record_fields. iter ( ) . enumerate ( ) {
370
- // this buf inserts a newline at the end of a getter
371
- // automatically, if one wants to add one more newline
372
- // for separating it from other assoc items, that needs
373
- // to be handled separately
374
- let mut getter_buf = match assist_info. assist_type {
388
+ // Make the new getter or setter fn
389
+ let new_fn = match assist_info. assist_type {
375
390
AssistType :: Set => generate_setter_from_info ( & assist_info, record_field_info) ,
376
391
_ => generate_getter_from_info ( ctx, & assist_info, record_field_info) ,
377
- } ;
378
-
379
- // Insert `$0` only for last getter we generate
380
- if i == record_fields_count - 1 && ctx. config . snippet_cap . is_some ( ) {
381
- getter_buf = getter_buf. replacen ( "fn " , "fn $0" , 1 ) ;
382
392
}
383
-
384
- // For first element we do not merge with '\n', as
385
- // that can be inserted by impl_def check defined
386
- // above, for other cases which are:
387
- //
388
- // - impl exists but it empty, here we would ideally
389
- // not want to keep newline between impl <struct> {
390
- // and fn <fn-name>() { line
391
- //
392
- // - next if impl itself does not exist, in this
393
- // case we ourselves generate a new impl and that
394
- // again ends up with the same reasoning as above
395
- // for not keeping newline
396
- if i == 0 {
397
- buf = buf + & getter_buf;
398
- } else {
399
- buf = buf + "\n " + & getter_buf;
400
- }
401
-
402
- // We don't insert a new line at the end of
403
- // last getter as it will end up in the end
404
- // of an impl where we would not like to keep
405
- // getter and end of impl ( i.e. `}` ) with an
406
- // extra line for no reason
407
- if i < record_fields_count - 1 {
408
- buf += "\n " ;
393
+ . clone_for_update ( ) ;
394
+ new_fn. indent ( 1 . into ( ) ) ;
395
+
396
+ // Insert a tabstop only for last method we generate
397
+ if i == record_fields_count - 1 {
398
+ if let Some ( cap) = ctx. config . snippet_cap {
399
+ if let Some ( name) = new_fn. name ( ) {
400
+ builder. add_tabstop_before ( cap, name) ;
401
+ }
402
+ }
409
403
}
410
- }
411
-
412
- let start_offset = assist_info
413
- . impl_def
414
- . as_ref ( )
415
- . and_then ( |impl_def| find_impl_block_end ( impl_def. to_owned ( ) , & mut buf) )
416
- . unwrap_or_else ( || {
417
- buf = generate_impl_text ( & ast:: Adt :: Struct ( assist_info. strukt . clone ( ) ) , & buf) ;
418
- assist_info. strukt . syntax ( ) . text_range ( ) . end ( )
419
- } ) ;
420
404
421
- match ctx. config . snippet_cap {
422
- Some ( cap) => builder. insert_snippet ( cap, start_offset, buf) ,
423
- None => builder. insert ( start_offset, buf) ,
405
+ assoc_item_list. add_item ( new_fn. clone ( ) . into ( ) ) ;
424
406
}
425
407
}
426
408
0 commit comments