@@ -78,25 +78,7 @@ def switch_block_style
78
78
node = target . block
79
79
return Error ::InvalidTargetRange unless node . is_a? ( Prism ::BlockNode )
80
80
81
- parameters = node . parameters
82
- body = node . body
83
-
84
- # If the block is using `do...end` style, we change it to a single line brace block. Newlines are turned into
85
- # semi colons, so that the result is valid Ruby code and still a one liner. If the block is using brace style,
86
- # we do the opposite and turn it into a `do...end` block, making all semi colons into newlines.
87
- new_source = if node . opening_loc . slice == "do"
88
- source = +"{ "
89
- source << "#{ parameters . slice } " if parameters
90
- source << "#{ body . slice . gsub ( "\n " , ";" ) } " if body
91
- source << "}"
92
- else
93
- indentation = " " * target . location . start_column
94
- source = +"do"
95
- source << " #{ parameters . slice } " if parameters
96
- source << "\n #{ indentation } "
97
- source << body . slice . gsub ( ";" , "\n " ) if body
98
- source << "\n #{ indentation } end"
99
- end
81
+ indentation = " " * target . location . start_column unless node . opening_loc . slice == "do"
100
82
101
83
Interface ::CodeAction . new (
102
84
title : CodeActions ::SWITCH_BLOCK_STYLE_TITLE ,
@@ -108,7 +90,10 @@ def switch_block_style
108
90
version : nil ,
109
91
) ,
110
92
edits : [
111
- Interface ::TextEdit . new ( range : range_from_location ( node . location ) , new_text : new_source ) ,
93
+ Interface ::TextEdit . new (
94
+ range : range_from_location ( node . location ) ,
95
+ new_text : recursively_switch_nested_block_styles ( node , indentation ) ,
96
+ ) ,
112
97
] ,
113
98
) ,
114
99
] ,
@@ -277,6 +262,64 @@ def create_text_edit(range, new_text)
277
262
new_text : new_text ,
278
263
)
279
264
end
265
+
266
+ sig { params ( node : Prism ::BlockNode , indentation : T . nilable ( String ) ) . returns ( String ) }
267
+ def recursively_switch_nested_block_styles ( node , indentation )
268
+ parameters = node . parameters
269
+ body = node . body
270
+
271
+ # We use the indentation to differentiate between do...end and brace style blocks because only the do...end
272
+ # style requires the indentation to build the edit.
273
+ #
274
+ # If the block is using `do...end` style, we change it to a single line brace block. Newlines are turned into
275
+ # semi colons, so that the result is valid Ruby code and still a one liner. If the block is using brace style,
276
+ # we do the opposite and turn it into a `do...end` block, making all semi colons into newlines.
277
+ source = +""
278
+
279
+ if indentation
280
+ source << "do"
281
+ source << " #{ parameters . slice } " if parameters
282
+ source << "\n #{ indentation } "
283
+ source << switch_block_body ( body , indentation ) if body
284
+ source << "\n #{ indentation } end"
285
+ else
286
+ source << "{ "
287
+ source << "#{ parameters . slice } " if parameters
288
+ source << switch_block_body ( body , nil ) if body
289
+ source << "}"
290
+ end
291
+
292
+ source
293
+ end
294
+
295
+ sig { params ( body : Prism ::Node , indentation : T . nilable ( String ) ) . returns ( String ) }
296
+ def switch_block_body ( body , indentation )
297
+ # Check if there are any nested blocks inside of the current block
298
+ body_loc = body . location
299
+ nested_block = @document . locate_first_within_range (
300
+ {
301
+ start : { line : body_loc . start_line - 1 , character : body_loc . start_column } ,
302
+ end : { line : body_loc . end_line - 1 , character : body_loc . end_column } ,
303
+ } ,
304
+ node_types : [ Prism ::BlockNode ] ,
305
+ )
306
+
307
+ body_content = body . slice . dup
308
+
309
+ # If there are nested blocks, then we change their style too and we have to mutate the string using the
310
+ # relative position in respect to the beginning of the body
311
+ if nested_block . is_a? ( Prism ::BlockNode )
312
+ location = nested_block . location
313
+ correction_start = location . start_offset - body_loc . start_offset
314
+ correction_end = location . end_offset - body_loc . start_offset
315
+ next_indentation = indentation ? "#{ indentation } " : nil
316
+
317
+ body_content [ correction_start ...correction_end ] =
318
+ recursively_switch_nested_block_styles ( nested_block , next_indentation )
319
+ end
320
+
321
+ indentation ? body_content . gsub ( ";" , "\n " ) : "#{ body_content . gsub ( "\n " , ";" ) } "
322
+ end
280
323
end
281
324
end
282
325
end
0 commit comments