@@ -2212,6 +2212,68 @@ def format(q)
2212
2212
end
2213
2213
end
2214
2214
2215
+ class CallChainFormatter
2216
+ # [Call] the top of the call chain
2217
+ attr_reader :node
2218
+
2219
+ def initialize ( node )
2220
+ @node = node
2221
+ end
2222
+
2223
+ def format ( q )
2224
+ children = [ node ]
2225
+ children << children . last . receiver while children . last . receiver . is_a? ( Call )
2226
+ q . format ( children . last . receiver )
2227
+
2228
+ q . group do
2229
+ format_child ( q , children . pop ) if attach_directly? ( children . last )
2230
+
2231
+ q . indent do
2232
+ children . reverse_each do |child |
2233
+ case child
2234
+ in { receiver : Call [ message : { value : "where" } ] , message : { value : "not" } }
2235
+ # This is very specialized behavior wherein we group
2236
+ # .where.not calls together because it looks better. For more
2237
+ # information, see
2238
+ # https://github.com/prettier/plugin-ruby/issues/862.
2239
+ else
2240
+ q . breakable ( "" )
2241
+ end
2242
+
2243
+ format_child ( q , child )
2244
+ end
2245
+ end
2246
+ end
2247
+ end
2248
+
2249
+ private
2250
+
2251
+ # For certain nodes, we want to attach directly to the end and don't
2252
+ # want to indent the first call. So we'll pop off the first children and
2253
+ # format it separately here.
2254
+ def attach_directly? ( child )
2255
+ [ ArrayLiteral , HashLiteral , Heredoc , If , Unless , XStringLiteral ]
2256
+ . include? ( child . receiver . class )
2257
+ end
2258
+
2259
+ def format_child ( q , child )
2260
+ q . format ( CallOperatorFormatter . new ( child . operator ) )
2261
+ q . format ( child . message ) if child . message != :call
2262
+ child . format_arguments ( q )
2263
+
2264
+ # If there are any comments on this node then we need to explicitly print
2265
+ # them out here since we're bypassing the normal comment printing.
2266
+ if child . comments . any?
2267
+ child . comments . each do |comment |
2268
+ comment . inline? ? q . text ( " " ) : q . breakable
2269
+ comment . format ( q )
2270
+ end
2271
+
2272
+ q . break_parent
2273
+ end
2274
+ end
2275
+ end
2276
+
2215
2277
# Call represents a method call.
2216
2278
#
2217
2279
# receiver.message
@@ -2277,6 +2339,33 @@ def deconstruct_keys(keys)
2277
2339
def format ( q )
2278
2340
call_operator = CallOperatorFormatter . new ( operator )
2279
2341
2342
+ # If we're at the top of a call chain, then we're going to do some
2343
+ # specialized printing in case we can print it nicely. We _only_ do this
2344
+ # at the top of the chain to avoid weird recursion issues.
2345
+ if !q . parent . is_a? ( Call ) && receiver . is_a? ( Call )
2346
+ q . group { q . if_break { CallChainFormatter . new ( self ) . format ( q ) } . if_flat { format_contents ( q ) } }
2347
+ else
2348
+ format_contents ( q )
2349
+ end
2350
+ end
2351
+
2352
+ def format_arguments ( q )
2353
+ case arguments
2354
+ in ArgParen
2355
+ q . format ( arguments )
2356
+ in Args
2357
+ q . text ( " " )
2358
+ q . format ( arguments )
2359
+ else
2360
+ # Do nothing if there are no arguments.
2361
+ end
2362
+ end
2363
+
2364
+ private
2365
+
2366
+ def format_contents ( q )
2367
+ call_operator = CallOperatorFormatter . new ( operator )
2368
+
2280
2369
q . group do
2281
2370
q . format ( receiver )
2282
2371
@@ -2297,15 +2386,7 @@ def format(q)
2297
2386
q . format ( message ) if message != :call
2298
2387
end
2299
2388
2300
- case arguments
2301
- in ArgParen
2302
- q . format ( arguments )
2303
- in Args
2304
- q . text ( " " )
2305
- q . format ( arguments )
2306
- else
2307
- # Do nothing if there are no arguments.
2308
- end
2389
+ format_arguments ( q )
2309
2390
end
2310
2391
end
2311
2392
end
0 commit comments