@@ -2212,6 +2212,68 @@ def format(q)
22122212 end
22132213 end
22142214
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+
22152277 # Call represents a method call.
22162278 #
22172279 # receiver.message
@@ -2277,6 +2339,33 @@ def deconstruct_keys(keys)
22772339 def format ( q )
22782340 call_operator = CallOperatorFormatter . new ( operator )
22792341
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+
22802369 q . group do
22812370 q . format ( receiver )
22822371
@@ -2297,15 +2386,7 @@ def format(q)
22972386 q . format ( message ) if message != :call
22982387 end
22992388
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 )
23092390 end
23102391 end
23112392 end
0 commit comments