11use either:: Either ;
22use ide_db:: defs:: { Definition , NameRefClass } ;
33use syntax:: {
4- ast:: { self , make, HasArgList , HasGenericArgs } ,
5- ted, AstNode ,
4+ ast:: { self , make, syntax_factory:: SyntaxFactory , HasArgList , HasGenericArgs } ,
5+ syntax_editor:: Position ,
6+ AstNode ,
67} ;
78
89use crate :: {
@@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
9192 AssistId ( "add_type_ascription" , AssistKind :: RefactorRewrite ) ,
9293 "Add `: _` before assignment operator" ,
9394 ident. text_range ( ) ,
94- |edit | {
95- let let_stmt = edit . make_mut ( let_stmt) ;
95+ |builder | {
96+ let mut editor = builder . make_editor ( let_stmt. syntax ( ) ) ;
9697
9798 if let_stmt. semicolon_token ( ) . is_none ( ) {
98- ted:: append_child ( let_stmt. syntax ( ) , make:: tokens:: semicolon ( ) ) ;
99+ editor. insert (
100+ Position :: last_child_of ( let_stmt. syntax ( ) ) ,
101+ make:: tokens:: semicolon ( ) ,
102+ ) ;
99103 }
100104
101105 let placeholder_ty = make:: ty_placeholder ( ) . clone_for_update ( ) ;
102106
103- let_stmt. set_ty ( Some ( placeholder_ty. clone ( ) ) ) ;
104-
105- if let Some ( cap) = ctx. config . snippet_cap {
106- edit. add_placeholder_snippet ( cap, placeholder_ty) ;
107+ if let Some ( pat) = let_stmt. pat ( ) {
108+ let elements = vec ! [
109+ make:: token( syntax:: SyntaxKind :: COLON ) . into( ) ,
110+ make:: token( syntax:: SyntaxKind :: WHITESPACE ) . into( ) ,
111+ placeholder_ty. syntax( ) . clone( ) . into( ) ,
112+ ] ;
113+ editor. insert_all ( Position :: after ( pat. syntax ( ) ) , elements) ;
114+ if let Some ( cap) = ctx. config . snippet_cap {
115+ editor. add_annotation (
116+ placeholder_ty. syntax ( ) ,
117+ builder. make_placeholder_snippet ( cap) ,
118+ ) ;
119+ }
107120 }
121+
122+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
108123 } ,
109124 ) ?
110125 } else {
@@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
123138 AssistId ( "add_turbo_fish" , AssistKind :: RefactorRewrite ) ,
124139 "Add `::<>`" ,
125140 ident. text_range ( ) ,
126- |edit| {
127- edit. trigger_parameter_hints ( ) ;
141+ |builder| {
142+ builder. trigger_parameter_hints ( ) ;
143+
144+ let make = SyntaxFactory :: new ( ) ;
145+ let mut editor = match & turbofish_target {
146+ Either :: Left ( it) => builder. make_editor ( it. syntax ( ) ) ,
147+ Either :: Right ( it) => builder. make_editor ( it. syntax ( ) ) ,
148+ } ;
149+
150+ let fish_head = get_fish_head ( & make, number_of_arguments) ;
128151
129- let new_arg_list = match turbofish_target {
152+ match turbofish_target {
130153 Either :: Left ( path_segment) => {
131- edit. make_mut ( path_segment) . get_or_create_generic_arg_list ( )
154+ if let Some ( generic_arg_list) = path_segment. generic_arg_list ( ) {
155+ editor. replace ( generic_arg_list. syntax ( ) , fish_head. syntax ( ) ) ;
156+ } else {
157+ editor. insert (
158+ Position :: last_child_of ( path_segment. syntax ( ) ) ,
159+ fish_head. syntax ( ) ,
160+ ) ;
161+ }
132162 }
133163 Either :: Right ( method_call) => {
134- edit. make_mut ( method_call) . get_or_create_generic_arg_list ( )
164+ if let Some ( generic_arg_list) = method_call. generic_arg_list ( ) {
165+ editor. replace ( generic_arg_list. syntax ( ) , fish_head. syntax ( ) ) ;
166+ } else {
167+ let position = if let Some ( arg_list) = method_call. arg_list ( ) {
168+ Position :: before ( arg_list. syntax ( ) )
169+ } else {
170+ Position :: last_child_of ( method_call. syntax ( ) )
171+ } ;
172+ editor. insert ( position, fish_head. syntax ( ) ) ;
173+ }
135174 }
136175 } ;
137176
138- let fish_head = get_fish_head ( number_of_arguments) . clone_for_update ( ) ;
139-
140- // Note: we need to replace the `new_arg_list` instead of being able to use something like
141- // `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list`
142- // always creates a non-turbofish form generic arg list.
143- ted:: replace ( new_arg_list. syntax ( ) , fish_head. syntax ( ) ) ;
144-
145177 if let Some ( cap) = ctx. config . snippet_cap {
146178 for arg in fish_head. generic_args ( ) {
147- edit . add_placeholder_snippet ( cap , arg )
179+ editor . add_annotation ( arg . syntax ( ) , builder . make_placeholder_snippet ( cap ) ) ;
148180 }
149181 }
182+
183+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
184+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
150185 } ,
151186 )
152187}
153188
154189/// This will create a turbofish generic arg list corresponding to the number of arguments
155- fn get_fish_head ( number_of_arguments : usize ) -> ast:: GenericArgList {
190+ fn get_fish_head ( make : & SyntaxFactory , number_of_arguments : usize ) -> ast:: GenericArgList {
156191 let args = ( 0 ..number_of_arguments) . map ( |_| make:: type_arg ( make:: ty_placeholder ( ) ) . into ( ) ) ;
157- make:: turbofish_generic_arg_list ( args)
192+ make. turbofish_generic_arg_list ( args)
158193}
159194
160195#[ cfg( test) ]
0 commit comments