@@ -5,12 +5,12 @@ use syntax::{
55 SyntaxKind :: WHITESPACE ,
66 T ,
77 ast:: { self , AstNode , HasName , make} ,
8- ted :: { self , Position } ,
8+ syntax_editor :: { Position , SyntaxEditor } ,
99} ;
1010
1111use crate :: {
1212 AssistConfig , AssistId ,
13- assist_context:: { AssistContext , Assists , SourceChangeBuilder } ,
13+ assist_context:: { AssistContext , Assists } ,
1414 utils:: {
1515 DefaultMethods , IgnoreAssocItems , add_trait_assoc_items_to_impl, filter_assoc_items,
1616 gen_trait_fn_body, generate_trait_impl,
@@ -126,9 +126,9 @@ fn add_assist(
126126 let label = format ! ( "Convert to manual `impl {replace_trait_path} for {annotated_name}`" ) ;
127127
128128 acc. add ( AssistId :: refactor ( "replace_derive_with_manual_impl" ) , label, target, |builder| {
129- let insert_after = ted :: Position :: after ( builder . make_mut ( adt. clone ( ) ) . syntax ( ) ) ;
129+ let insert_after = Position :: after ( adt. syntax ( ) ) ;
130130 let impl_is_unsafe = trait_. map ( |s| s. is_unsafe ( ctx. db ( ) ) ) . unwrap_or ( false ) ;
131- let impl_def_with_items = impl_def_from_trait (
131+ let impl_def = impl_def_from_trait (
132132 & ctx. sema ,
133133 ctx. config ,
134134 adt,
@@ -137,39 +137,23 @@ fn add_assist(
137137 replace_trait_path,
138138 impl_is_unsafe,
139139 ) ;
140- update_attribute ( builder, old_derives, old_tree, old_trait_path, attr) ;
141140
142- let trait_path = make:: ty_path ( replace_trait_path. clone ( ) ) ;
143-
144- match ( ctx. config . snippet_cap , impl_def_with_items) {
145- ( None , None ) => {
146- let impl_def = generate_trait_impl ( impl_is_unsafe, adt, trait_path) ;
141+ let mut editor = builder. make_editor ( attr. syntax ( ) ) ;
142+ update_attribute ( & mut editor, old_derives, old_tree, old_trait_path, attr) ;
147143
148- ted:: insert_all (
149- insert_after,
150- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
151- ) ;
152- }
153- ( None , Some ( ( impl_def, _) ) ) => {
154- ted:: insert_all (
155- insert_after,
156- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
157- ) ;
158- }
159- ( Some ( cap) , None ) => {
160- let impl_def = generate_trait_impl ( impl_is_unsafe, adt, trait_path) ;
144+ let trait_path = make:: ty_path ( replace_trait_path. clone ( ) ) ;
161145
162- if let Some ( l_curly) = impl_def. assoc_item_list ( ) . and_then ( |it| it. l_curly_token ( ) )
163- {
164- builder. add_tabstop_after_token ( cap, l_curly) ;
165- }
146+ let ( impl_def, first_assoc_item) = if let Some ( impl_def) = impl_def {
147+ (
148+ impl_def. clone ( ) ,
149+ impl_def. assoc_item_list ( ) . and_then ( |list| list. assoc_items ( ) . next ( ) ) ,
150+ )
151+ } else {
152+ ( generate_trait_impl ( impl_is_unsafe, adt, trait_path) , None )
153+ } ;
166154
167- ted:: insert_all (
168- insert_after,
169- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
170- ) ;
171- }
172- ( Some ( cap) , Some ( ( impl_def, first_assoc_item) ) ) => {
155+ if let Some ( cap) = ctx. config . snippet_cap {
156+ if let Some ( first_assoc_item) = first_assoc_item {
173157 if let ast:: AssocItem :: Fn ( ref func) = first_assoc_item
174158 && let Some ( m) = func. syntax ( ) . descendants ( ) . find_map ( ast:: MacroCall :: cast)
175159 && m. syntax ( ) . text ( ) == "todo!()"
@@ -180,13 +164,18 @@ fn add_assist(
180164 // If we haven't already added a snippet, add a tabstop before the generated function
181165 builder. add_tabstop_before ( cap, first_assoc_item) ;
182166 }
183-
184- ted:: insert_all (
185- insert_after,
186- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
187- ) ;
167+ } else if let Some ( l_curly) =
168+ impl_def. assoc_item_list ( ) . and_then ( |it| it. l_curly_token ( ) )
169+ {
170+ builder. add_tabstop_after_token ( cap, l_curly) ;
188171 }
189- } ;
172+ }
173+
174+ editor. insert_all (
175+ insert_after,
176+ vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
177+ ) ;
178+ builder. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
190179 } )
191180}
192181
@@ -198,7 +187,7 @@ fn impl_def_from_trait(
198187 trait_ : Option < hir:: Trait > ,
199188 trait_path : & ast:: Path ,
200189 impl_is_unsafe : bool ,
201- ) -> Option < ( ast:: Impl , ast :: AssocItem ) > {
190+ ) -> Option < ast:: Impl > {
202191 let trait_ = trait_?;
203192 let target_scope = sema. scope ( annotated_name. syntax ( ) ) ?;
204193
@@ -217,23 +206,25 @@ fn impl_def_from_trait(
217206 }
218207 let impl_def = generate_trait_impl ( impl_is_unsafe, adt, make:: ty_path ( trait_path. clone ( ) ) ) ;
219208
220- let first_assoc_item =
209+ let _ =
221210 add_trait_assoc_items_to_impl ( sema, config, & trait_items, trait_, & impl_def, & target_scope) ;
222-
211+ let impl_def = impl_def. clone_subtree ( ) ;
212+ let mut editor = SyntaxEditor :: new ( impl_def. syntax ( ) . clone ( ) ) ;
213+ let first_assoc_item = impl_def. assoc_item_list ( ) . and_then ( |item| item. assoc_items ( ) . next ( ) ) ?;
223214 // Generate a default `impl` function body for the derived trait.
224215 if let ast:: AssocItem :: Fn ( ref func) = first_assoc_item {
225216 if let Some ( body) = gen_trait_fn_body ( func, trait_path, adt, None )
226217 && let Some ( func_body) = func. body ( )
227218 {
228- ted :: replace ( func_body. syntax ( ) , body. syntax ( ) ) ;
219+ editor . replace ( func_body. syntax ( ) , body. syntax ( ) ) ;
229220 }
230221 } ;
231-
232- Some ( ( impl_def, first_assoc_item ) )
222+ let impl_def = ast :: Impl :: cast ( editor . finish ( ) . new_root ( ) . clone ( ) ) ? ;
223+ Some ( impl_def)
233224}
234225
235226fn update_attribute (
236- builder : & mut SourceChangeBuilder ,
227+ editor : & mut SyntaxEditor ,
237228 old_derives : & [ ast:: Path ] ,
238229 old_tree : & ast:: TokenTree ,
239230 old_trait_path : & ast:: Path ,
@@ -246,8 +237,6 @@ fn update_attribute(
246237 let has_more_derives = !new_derives. is_empty ( ) ;
247238
248239 if has_more_derives {
249- let old_tree = builder. make_mut ( old_tree. clone ( ) ) ;
250-
251240 // Make the paths into flat lists of tokens in a vec
252241 let tt = new_derives. iter ( ) . map ( |path| path. syntax ( ) . clone ( ) ) . map ( |node| {
253242 node. descendants_with_tokens ( )
@@ -262,18 +251,17 @@ fn update_attribute(
262251 let tt = tt. collect :: < Vec < _ > > ( ) ;
263252
264253 let new_tree = make:: token_tree ( T ! [ '(' ] , tt) . clone_for_update ( ) ;
265- ted :: replace ( old_tree. syntax ( ) , new_tree. syntax ( ) ) ;
254+ editor . replace ( old_tree. syntax ( ) , new_tree. syntax ( ) ) ;
266255 } else {
267256 // Remove the attr and any trailing whitespace
268- let attr = builder. make_mut ( attr. clone ( ) ) ;
269257
270258 if let Some ( line_break) =
271259 attr. syntax ( ) . next_sibling_or_token ( ) . filter ( |t| t. kind ( ) == WHITESPACE )
272260 {
273- ted :: remove ( line_break)
261+ editor . delete ( line_break)
274262 }
275263
276- ted :: remove ( attr. syntax ( ) )
264+ editor . delete ( attr. syntax ( ) )
277265 }
278266}
279267
0 commit comments