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