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

Commit 6a74297

Browse files
committed
Better call chain formatting with method add blocks factored in
1 parent 8932ff8 commit 6a74297

File tree

1 file changed

+76
-13
lines changed

1 file changed

+76
-13
lines changed

lib/syntax_tree/node.rb

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,29 +2214,88 @@ def initialize(node)
22142214
end
22152215

22162216
def format(q)
2217+
q.group { q.if_break { format_chain(q) }.if_flat { node.format_contents(q) } }
2218+
end
2219+
2220+
def format_chain(q)
22172221
children = [node]
2218-
children << children.last.receiver while children.last.receiver.is_a?(Call)
2222+
2223+
# First, walk down the chain until we get to the point where we're not
2224+
# longer at a chainable node.
2225+
while true
2226+
case children.last
2227+
in Call[receiver: Call]
2228+
children << children.last.receiver
2229+
in Call[receiver: MethodAddBlock[call: Call]]
2230+
children << children.last.receiver
2231+
in MethodAddBlock[call: Call]
2232+
children << children.last.call
2233+
else
2234+
break
2235+
end
2236+
end
2237+
2238+
# We're going to have some specialized behavior for if it's an entire
2239+
# chain of calls without arguments except for the last one. This is common
2240+
# enough in Ruby source code that it's worth the extra complexity here.
2241+
empty_except_last =
2242+
children.drop(1).all? do |child|
2243+
child.is_a?(Call) && child.arguments.nil?
2244+
end
2245+
2246+
# Here, we're going to add all of the children onto the stack of the
2247+
# formatter so it's as if we had descending normally into them. This is
2248+
# necessary so they can check their parents as normal.
2249+
q.stack.concat(children)
22192250
q.format(children.last.receiver)
22202251

22212252
q.group do
2222-
format_child(q, children.pop) if attach_directly?(children.last)
2253+
if attach_directly?(children.last)
2254+
format_child(q, children.pop)
2255+
q.stack.pop
2256+
end
22232257

22242258
q.indent do
2225-
children.reverse_each do |child|
2259+
while child = children.pop
22262260
case child
2227-
in { receiver: Call[message: { value: "where" }], message: { value: "not" } }
2261+
in Call[receiver: Call[message: { value: "where" }], message: { value: "not" }]
22282262
# This is very specialized behavior wherein we group
22292263
# .where.not calls together because it looks better. For more
22302264
# information, see
22312265
# https://github.com/prettier/plugin-ruby/issues/862.
2232-
else
2266+
in Call
2267+
# If we're at a Call node and not a MethodAddBlock node in the
2268+
# chain then we're going to add a newline so it indents properly.
22332269
q.breakable("")
2270+
else
22342271
end
22352272

2236-
format_child(q, child)
2273+
format_child(q, child, skip_attached: empty_except_last && children.empty?)
2274+
2275+
# Pop off the formatter's stack so that it aligns with what would
2276+
# have happened if we had been formatting normally.
2277+
q.stack.pop
22372278
end
22382279
end
22392280
end
2281+
2282+
if empty_except_last
2283+
case node
2284+
in Call
2285+
node.format_arguments(q)
2286+
in MethodAddBlock[block:]
2287+
q.format(block)
2288+
end
2289+
end
2290+
end
2291+
2292+
def self.chained?(node)
2293+
case node
2294+
in Call | MethodAddBlock[call: Call]
2295+
true
2296+
else
2297+
false
2298+
end
22402299
end
22412300

22422301
private
@@ -2249,10 +2308,16 @@ def attach_directly?(child)
22492308
.include?(child.receiver.class)
22502309
end
22512310

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)
2311+
def format_child(q, child, skip_attached: false)
2312+
# First, format the actual contents of the child.
2313+
case child
2314+
in Call
2315+
q.format(CallOperatorFormatter.new(child.operator))
2316+
q.format(child.message) if child.message != :call
2317+
child.format_arguments(q) unless skip_attached
2318+
in MethodAddBlock
2319+
q.format(child.block) unless skip_attached
2320+
end
22562321

22572322
# If there are any comments on this node then we need to explicitly print
22582323
# them out here since we're bypassing the normal comment printing.
@@ -2335,7 +2400,7 @@ def format(q)
23352400
# If we're at the top of a call chain, then we're going to do some
23362401
# specialized printing in case we can print it nicely. We _only_ do this
23372402
# at the top of the chain to avoid weird recursion issues.
2338-
if !q.parent.is_a?(Call) && receiver.is_a?(Call)
2403+
if !CallChainFormatter.chained?(q.parent) && CallChainFormatter.chained?(receiver)
23392404
q.group { q.if_break { CallChainFormatter.new(self).format(q) }.if_flat { format_contents(q) } }
23402405
else
23412406
format_contents(q)
@@ -2354,8 +2419,6 @@ def format_arguments(q)
23542419
end
23552420
end
23562421

2357-
private
2358-
23592422
def format_contents(q)
23602423
call_operator = CallOperatorFormatter.new(operator)
23612424

0 commit comments

Comments
 (0)