@@ -2,13 +2,16 @@ use ide_db::{famous_defs::FamousDefs, source_change::SourceChangeBuilder};
22use stdx:: { format_to, to_lower_snake_case} ;
33use syntax:: {
44 TextRange ,
5- ast:: { self , AstNode , HasName , HasVisibility , edit_in_place:: Indent , make} ,
6- ted,
5+ ast:: {
6+ self , AstNode , HasGenericParams , HasName , HasVisibility , edit_in_place:: Indent ,
7+ syntax_factory:: SyntaxFactory ,
8+ } ,
9+ syntax_editor:: Position ,
710} ;
811
912use crate :: {
1013 AssistContext , AssistId , Assists , GroupLabel ,
11- utils:: { convert_reference_type, find_struct_impl, generate_impl } ,
14+ utils:: { convert_reference_type, find_struct_impl} ,
1215} ;
1316
1417// Assist: generate_setter
@@ -216,11 +219,14 @@ fn generate_getter_from_info(
216219 info : & AssistInfo ,
217220 record_field_info : & RecordFieldInfo ,
218221) -> ast:: Fn {
222+ let make = SyntaxFactory :: without_mappings ( ) ;
223+
219224 let ( ty, body) = if matches ! ( info. assist_type, AssistType :: MutGet ) {
225+ let self_expr = make. expr_path ( make. ident_path ( "self" ) ) ;
220226 (
221- make:: ty_ref ( record_field_info. field_ty . clone ( ) , true ) ,
222- make:: expr_ref (
223- make:: expr_field ( make :: ext :: expr_self ( ) , & record_field_info. field_name . text ( ) ) ,
227+ make. ty_ref ( record_field_info. field_ty . clone ( ) , true ) ,
228+ make. expr_ref (
229+ make. expr_field ( self_expr , & record_field_info. field_name . text ( ) ) . into ( ) ,
224230 true ,
225231 ) ,
226232 )
@@ -240,29 +246,30 @@ fn generate_getter_from_info(
240246 } )
241247 } ) ( )
242248 . unwrap_or_else ( || {
249+ let self_expr = make. expr_path ( make. ident_path ( "self" ) ) ;
243250 (
244- make:: ty_ref ( record_field_info. field_ty . clone ( ) , false ) ,
245- make:: expr_ref (
246- make:: expr_field ( make :: ext :: expr_self ( ) , & record_field_info. field_name . text ( ) ) ,
251+ make. ty_ref ( record_field_info. field_ty . clone ( ) , false ) ,
252+ make. expr_ref (
253+ make. expr_field ( self_expr , & record_field_info. field_name . text ( ) ) . into ( ) ,
247254 false ,
248255 ) ,
249256 )
250257 } )
251258 } ;
252259
253260 let self_param = if matches ! ( info. assist_type, AssistType :: MutGet ) {
254- make:: mut_self_param ( )
261+ make. mut_self_param ( )
255262 } else {
256- make:: self_param ( )
263+ make. self_param ( )
257264 } ;
258265
259266 let strukt = & info. strukt ;
260- let fn_name = make:: name ( & record_field_info. fn_name ) ;
261- let params = make:: param_list ( Some ( self_param) , [ ] ) ;
262- let ret_type = Some ( make:: ret_type ( ty) ) ;
263- let body = make:: block_expr ( [ ] , Some ( body) ) ;
267+ let fn_name = make. name ( & record_field_info. fn_name ) ;
268+ let params = make. param_list ( Some ( self_param) , [ ] ) ;
269+ let ret_type = Some ( make. ret_type ( ty) ) ;
270+ let body = make. block_expr ( [ ] , Some ( body) ) ;
264271
265- make:: fn_ (
272+ make. fn_ (
266273 None ,
267274 strukt. visibility ( ) ,
268275 fn_name,
@@ -277,29 +284,30 @@ fn generate_getter_from_info(
277284 false ,
278285 )
279286}
280-
281287fn generate_setter_from_info ( info : & AssistInfo , record_field_info : & RecordFieldInfo ) -> ast:: Fn {
288+ let make = SyntaxFactory :: without_mappings ( ) ;
289+
282290 let strukt = & info. strukt ;
283291 let field_name = & record_field_info. fn_name ;
284- let fn_name = make:: name ( & format ! ( "set_{field_name}" ) ) ;
292+ let fn_name = make. name ( & format ! ( "set_{field_name}" ) ) ;
285293 let field_ty = & record_field_info. field_ty ;
286294
287295 // Make the param list
288296 // `(&mut self, $field_name: $field_ty)`
289297 let field_param =
290- make:: param ( make:: ident_pat ( false , false , make:: name ( field_name) ) . into ( ) , field_ty. clone ( ) ) ;
291- let params = make:: param_list ( Some ( make:: mut_self_param ( ) ) , [ field_param] ) ;
298+ make. param ( make. ident_pat ( false , false , make. name ( field_name) ) . into ( ) , field_ty. clone ( ) ) ;
299+ let params = make. param_list ( Some ( make. mut_self_param ( ) ) , [ field_param] ) ;
292300
293301 // Make the assignment body
294302 // `self.$field_name = $field_name`
295- let self_expr = make:: ext :: expr_self ( ) ;
296- let lhs = make:: expr_field ( self_expr, field_name) ;
297- let rhs = make:: expr_path ( make:: ext :: ident_path ( field_name) ) ;
298- let assign_stmt = make:: expr_stmt ( make:: expr_assignment ( lhs, rhs) . into ( ) ) ;
299- let body = make:: block_expr ( [ assign_stmt. into ( ) ] , None ) ;
303+ let self_expr = make. expr_path ( make . ident_path ( "self" ) ) ;
304+ let lhs = make. expr_field ( self_expr, field_name) ;
305+ let rhs = make. expr_path ( make. ident_path ( field_name) ) ;
306+ let assign_stmt = make. expr_stmt ( make. expr_assignment ( lhs. into ( ) , rhs) . into ( ) ) ;
307+ let body = make. block_expr ( [ assign_stmt. into ( ) ] , None ) ;
300308
301309 // Make the setter fn
302- make:: fn_ (
310+ make. fn_ (
303311 None ,
304312 strukt. visibility ( ) ,
305313 fn_name,
@@ -403,46 +411,70 @@ fn build_source_change(
403411 info_of_record_fields : Vec < RecordFieldInfo > ,
404412 assist_info : AssistInfo ,
405413) {
406- let record_fields_count = info_of_record_fields. len ( ) ;
414+ let items: Vec < ast:: AssocItem > = info_of_record_fields
415+ . iter ( )
416+ . map ( |record_field_info| {
417+ let method = match assist_info. assist_type {
418+ AssistType :: Set => generate_setter_from_info ( & assist_info, record_field_info) ,
419+ _ => generate_getter_from_info ( ctx, & assist_info, record_field_info) ,
420+ } ;
421+ let new_fn = method. clone_for_update ( ) ;
422+ new_fn. indent ( 1 . into ( ) ) ;
423+ new_fn. into ( )
424+ } )
425+ . collect ( ) ;
407426
408- let impl_def = if let Some ( impl_def) = & assist_info. impl_def {
427+ if let Some ( impl_def) = & assist_info. impl_def {
409428 // We have an existing impl to add to
410- builder. make_mut ( impl_def. clone ( ) )
411- } else {
412- // Generate a new impl to add the methods to
413- let impl_def = generate_impl ( & ast:: Adt :: Struct ( assist_info. strukt . clone ( ) ) ) ;
414-
415- // Insert it after the adt
416- let strukt = builder. make_mut ( assist_info. strukt . clone ( ) ) ;
429+ let mut editor = builder. make_editor ( impl_def. syntax ( ) ) ;
430+
431+ let assoc_item_list = impl_def. assoc_item_list ( ) . unwrap ( ) ;
432+ assoc_item_list. add_items ( & mut editor, items. clone ( ) ) ;
433+
434+ // Add tabstop for last method
435+ if let Some ( cap) = ctx. config . snippet_cap {
436+ if let Some ( ast:: AssocItem :: Fn ( fn_) ) = items. last ( ) {
437+ if let Some ( name) = fn_. name ( ) {
438+ let tabstop = builder. make_tabstop_before ( cap) ;
439+ editor. add_annotation ( name. syntax ( ) . clone ( ) , tabstop) ;
440+ }
441+ }
442+ }
417443
418- ted:: insert_all_raw (
419- ted:: Position :: after ( strukt. syntax ( ) ) ,
420- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
444+ builder. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
445+ } else {
446+ let make = SyntaxFactory :: without_mappings ( ) ;
447+ let ty_params = assist_info. strukt . generic_param_list ( ) ;
448+ let ty_args = ty_params. as_ref ( ) . map ( |it| it. to_generic_args ( ) ) ;
449+ let impl_def = make. impl_ (
450+ None ,
451+ ty_params,
452+ ty_args,
453+ make. ty_path ( make. ident_path ( & assist_info. strukt . name ( ) . unwrap ( ) . to_string ( ) ) ) . into ( ) ,
454+ None ,
455+ Some ( make. assoc_item_list ( items) ) ,
421456 ) ;
422457
423- impl_def
424- } ;
425-
426- let assoc_item_list = impl_def. get_or_create_assoc_item_list ( ) ;
458+ let mut editor = builder. make_editor ( assist_info. strukt . syntax ( ) ) ;
459+ // Insert impl after the struct
460+ editor. insert_all (
461+ Position :: after ( assist_info. strukt . syntax ( ) ) ,
462+ vec ! [ make. whitespace( "\n \n " ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
463+ ) ;
427464
428- for ( i, record_field_info) in info_of_record_fields. iter ( ) . enumerate ( ) {
429- // Make the new getter or setter fn
430- let new_fn = match assist_info. assist_type {
431- AssistType :: Set => generate_setter_from_info ( & assist_info, record_field_info) ,
432- _ => generate_getter_from_info ( ctx, & assist_info, record_field_info) ,
433- }
434- . clone_for_update ( ) ;
435- new_fn. indent ( 1 . into ( ) ) ;
436-
437- // Insert a tabstop only for last method we generate
438- if i == record_fields_count - 1
439- && let Some ( cap) = ctx. config . snippet_cap
440- && let Some ( name) = new_fn. name ( )
441- {
442- builder. add_tabstop_before ( cap, name) ;
465+ // Add tabstop for last method
466+ if let Some ( cap) = ctx. config . snippet_cap {
467+ if let Some ( assoc_list) = impl_def. assoc_item_list ( ) {
468+ if let Some ( ast:: AssocItem :: Fn ( fn_) ) = assoc_list. assoc_items ( ) . last ( ) {
469+ if let Some ( name) = fn_. name ( ) {
470+ let tabstop = builder. make_tabstop_before ( cap) ;
471+ editor. add_annotation ( name. syntax ( ) . clone ( ) , tabstop) ;
472+ }
473+ }
474+ }
443475 }
444476
445- assoc_item_list . add_item ( new_fn . clone ( ) . into ( ) ) ;
477+ builder . add_file_edits ( ctx . vfs_file_id ( ) , editor ) ;
446478 }
447479}
448480
0 commit comments