1
1
use std:: collections:: HashSet ;
2
2
3
3
use 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
+ } ;
5
10
6
11
use 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} ,
8
13
AssistContext , AssistId , AssistKind , Assists , GroupLabel ,
9
14
} ;
10
- use syntax:: ast:: edit:: AstNodeEdit ;
11
15
12
16
// Assist: generate_delegate_methods
13
17
//
@@ -96,7 +100,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
96
100
AssistId ( "generate_delegate_methods" , AssistKind :: Generate ) ,
97
101
format ! ( "Generate delegate for `{field_name}.{name}()`" , ) ,
98
102
target,
99
- |builder | {
103
+ |edit | {
100
104
// Create the function
101
105
let method_source = match method. source ( ctx. db ( ) ) {
102
106
Some ( source) => source. value ,
@@ -135,36 +139,12 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
135
139
is_const,
136
140
is_unsafe,
137
141
)
138
- . indent ( ast:: edit:: IndentLevel ( 1 ) )
139
142
. clone_for_update ( ) ;
140
143
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) ,
166
147
None => {
167
- // Attach the function to the impl block
168
148
let name = & strukt_name. to_string ( ) ;
169
149
let params = strukt. generic_param_list ( ) ;
170
150
let ty_params = params. clone ( ) ;
@@ -178,24 +158,34 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
178
158
None ,
179
159
)
180
160
. 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) ;
183
165
184
166
// 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
198
177
}
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)
199
189
}
200
190
} ,
201
191
) ?;
@@ -244,6 +234,45 @@ impl Person {
244
234
) ;
245
235
}
246
236
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
+
247
276
#[ test]
248
277
fn test_generate_delegate_update_impl_block ( ) {
249
278
check_assist (
@@ -281,6 +310,47 @@ impl Person {
281
310
) ;
282
311
}
283
312
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
+
284
354
#[ test]
285
355
fn test_generate_delegate_tuple_struct ( ) {
286
356
check_assist (
0 commit comments