Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ffb6531

Browse files
committed
Even better chained calls
1 parent b7c0232 commit ffb6531

File tree

1 file changed

+90
-9
lines changed

1 file changed

+90
-9
lines changed

lib/syntax_tree/node.rb

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)