11use std:: collections:: HashSet ;
22
33use hir:: { self , HasCrate , HasSource , HasVisibility } ;
4- use syntax:: ast:: { self , make, AstNode , HasGenericParams , HasName , HasVisibility as _} ;
4+ use syntax:: {
5+ ast:: {
6+ self , edit_in_place:: Indent , make, AstNode , HasGenericParams , HasName , HasVisibility as _,
7+ } ,
8+ ted,
9+ } ;
510
611use crate :: {
7- utils:: { convert_param_list_to_arg_list, find_struct_impl, render_snippet , Cursor } ,
12+ utils:: { convert_param_list_to_arg_list, find_struct_impl} ,
813 AssistContext , AssistId , AssistKind , Assists , GroupLabel ,
914} ;
10- use syntax:: ast:: edit:: AstNodeEdit ;
1115
1216// Assist: generate_delegate_methods
1317//
@@ -96,7 +100,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
96100 AssistId ( "generate_delegate_methods" , AssistKind :: Generate ) ,
97101 format ! ( "Generate delegate for `{field_name}.{name}()`" , ) ,
98102 target,
99- |builder | {
103+ |edit | {
100104 // Create the function
101105 let method_source = match method. source ( ctx. db ( ) ) {
102106 Some ( source) => source. value ,
@@ -135,36 +139,12 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
135139 is_const,
136140 is_unsafe,
137141 )
138- . indent ( ast:: edit:: IndentLevel ( 1 ) )
139142 . clone_for_update ( ) ;
140143
141- let cursor = Cursor :: Before ( f. syntax ( ) ) ;
142-
143- // Create or update an impl block, attach the function to it,
144- // then insert into our code.
145- match impl_def {
146- Some ( impl_def) => {
147- // Remember where in our source our `impl` block lives.
148- let impl_def = impl_def. clone_for_update ( ) ;
149- let old_range = impl_def. syntax ( ) . text_range ( ) ;
150-
151- // Attach the function to the impl block
152- let assoc_items = impl_def. get_or_create_assoc_item_list ( ) ;
153- assoc_items. add_item ( f. clone ( ) . into ( ) ) ;
154-
155- // Update the impl block.
156- match ctx. config . snippet_cap {
157- Some ( cap) => {
158- let snippet = render_snippet ( cap, impl_def. syntax ( ) , cursor) ;
159- builder. replace_snippet ( cap, old_range, snippet) ;
160- }
161- None => {
162- builder. replace ( old_range, impl_def. syntax ( ) . to_string ( ) ) ;
163- }
164- }
165- }
144+ // Get the impl to update, or create one if we need to.
145+ let impl_def = match impl_def {
146+ Some ( impl_def) => edit. make_mut ( impl_def) ,
166147 None => {
167- // Attach the function to the impl block
168148 let name = & strukt_name. to_string ( ) ;
169149 let params = strukt. generic_param_list ( ) ;
170150 let ty_params = params. clone ( ) ;
@@ -178,24 +158,34 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
178158 None ,
179159 )
180160 . clone_for_update ( ) ;
181- let assoc_items = impl_def. get_or_create_assoc_item_list ( ) ;
182- assoc_items. add_item ( f. clone ( ) . into ( ) ) ;
161+
162+ // Fixup impl_def indentation
163+ let indent = strukt. indent_level ( ) ;
164+ impl_def. reindent_to ( indent) ;
183165
184166 // Insert the impl block.
185- match ctx. config . snippet_cap {
186- Some ( cap) => {
187- let offset = strukt. syntax ( ) . text_range ( ) . end ( ) ;
188- let snippet = render_snippet ( cap, impl_def. syntax ( ) , cursor) ;
189- let snippet = format ! ( "\n \n {snippet}" ) ;
190- builder. insert_snippet ( cap, offset, snippet) ;
191- }
192- None => {
193- let offset = strukt. syntax ( ) . text_range ( ) . end ( ) ;
194- let snippet = format ! ( "\n \n {}" , impl_def. syntax( ) ) ;
195- builder. insert ( offset, snippet) ;
196- }
197- }
167+ let strukt = edit. make_mut ( strukt. clone ( ) ) ;
168+ ted:: insert_all (
169+ ted:: Position :: after ( strukt. syntax ( ) ) ,
170+ vec ! [
171+ make:: tokens:: whitespace( & format!( "\n \n {indent}" ) ) . into( ) ,
172+ impl_def. syntax( ) . clone( ) . into( ) ,
173+ ] ,
174+ ) ;
175+
176+ impl_def
198177 }
178+ } ;
179+
180+ // Fixup function indentation.
181+ // FIXME: Should really be handled by `AssocItemList::add_item`
182+ f. reindent_to ( impl_def. indent_level ( ) + 1 ) ;
183+
184+ let assoc_items = impl_def. get_or_create_assoc_item_list ( ) ;
185+ assoc_items. add_item ( f. clone ( ) . into ( ) ) ;
186+
187+ if let Some ( cap) = ctx. config . snippet_cap {
188+ edit. add_tabstop_before ( cap, f)
199189 }
200190 } ,
201191 ) ?;
@@ -244,6 +234,45 @@ impl Person {
244234 ) ;
245235 }
246236
237+ #[ test]
238+ fn test_generate_delegate_create_impl_block_match_indent ( ) {
239+ check_assist (
240+ generate_delegate_methods,
241+ r#"
242+ mod indent {
243+ struct Age(u8);
244+ impl Age {
245+ fn age(&self) -> u8 {
246+ self.0
247+ }
248+ }
249+
250+ struct Person {
251+ ag$0e: Age,
252+ }
253+ }"# ,
254+ r#"
255+ mod indent {
256+ struct Age(u8);
257+ impl Age {
258+ fn age(&self) -> u8 {
259+ self.0
260+ }
261+ }
262+
263+ struct Person {
264+ age: Age,
265+ }
266+
267+ impl Person {
268+ $0fn age(&self) -> u8 {
269+ self.age.age()
270+ }
271+ }
272+ }"# ,
273+ ) ;
274+ }
275+
247276 #[ test]
248277 fn test_generate_delegate_update_impl_block ( ) {
249278 check_assist (
@@ -281,6 +310,47 @@ impl Person {
281310 ) ;
282311 }
283312
313+ #[ test]
314+ fn test_generate_delegate_update_impl_block_match_indent ( ) {
315+ check_assist (
316+ generate_delegate_methods,
317+ r#"
318+ mod indent {
319+ struct Age(u8);
320+ impl Age {
321+ fn age(&self) -> u8 {
322+ self.0
323+ }
324+ }
325+
326+ struct Person {
327+ ag$0e: Age,
328+ }
329+
330+ impl Person {}
331+ }"# ,
332+ r#"
333+ mod indent {
334+ struct Age(u8);
335+ impl Age {
336+ fn age(&self) -> u8 {
337+ self.0
338+ }
339+ }
340+
341+ struct Person {
342+ age: Age,
343+ }
344+
345+ impl Person {
346+ $0fn age(&self) -> u8 {
347+ self.age.age()
348+ }
349+ }
350+ }"# ,
351+ ) ;
352+ }
353+
284354 #[ test]
285355 fn test_generate_delegate_tuple_struct ( ) {
286356 check_assist (
0 commit comments