@@ -54,6 +54,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
5454 /// moved past these tokens.
5555 private var closingDelimiterTokens = Set < TokenSyntax > ( )
5656
57+ /// Tracks closures that are never allowed to be laid out entirely on one line (e.g., closures
58+ /// in a function call containing multiple trailing closures).
59+ private var forcedBreakingClosures = Set < SyntaxIdentifier > ( )
60+
5761 init ( configuration: Configuration , operatorContext: OperatorContext ) {
5862 self . config = configuration
5963 self . operatorContext = operatorContext
@@ -870,6 +874,16 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
870874 override func visit( _ node: FunctionCallExprSyntax ) -> SyntaxVisitorContinueKind {
871875 preVisitInsertingContextualBreaks ( node)
872876
877+ // If there are multiple trailing closures, force all the closures in the call to break.
878+ if let additionalTrailingClosures = node. additionalTrailingClosures {
879+ if let closure = node. trailingClosure {
880+ forcedBreakingClosures. insert ( closure. id)
881+ }
882+ for additionalTrailingClosure in additionalTrailingClosures {
883+ forcedBreakingClosures. insert ( additionalTrailingClosure. closure. id)
884+ }
885+ }
886+
873887 if let calledMemberAccessExpr = node. calledExpression. as ( MemberAccessExprSyntax . self) {
874888 if let base = calledMemberAccessExpr. base, base. is ( IdentifierExprSyntax . self) {
875889 // When this function call is wrapped by a try-expr, the group applied when visiting the
@@ -907,6 +921,14 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
907921 clearContextualBreakState ( node)
908922 }
909923
924+ override func visit( _ node: MultipleTrailingClosureElementSyntax )
925+ -> SyntaxVisitorContinueKind
926+ {
927+ before ( node. label, tokens: . space)
928+ after ( node. colon, tokens: . space)
929+ return . visitChildren
930+ }
931+
910932 /// Arrange the given argument list (or equivalently, tuple expression list) as a list of function
911933 /// arguments.
912934 ///
@@ -979,12 +1001,19 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
9791001 }
9801002
9811003 override func visit( _ node: ClosureExprSyntax ) -> SyntaxVisitorContinueKind {
1004+ let newlineBehavior : NewlineBehavior
1005+ if forcedBreakingClosures. remove ( node. id) != nil {
1006+ newlineBehavior = . soft
1007+ } else {
1008+ newlineBehavior = . elective
1009+ }
1010+
9821011 if let signature = node. signature {
9831012 after ( node. leftBrace, tokens: . break( . open) )
9841013 if node. statements. count > 0 {
985- after ( signature. inTok, tokens: . break( . same) )
1014+ after ( signature. inTok, tokens: . break( . same, newlines : newlineBehavior ) )
9861015 } else {
987- after ( signature. inTok, tokens: . break( . same, size: 0 ) )
1016+ after ( signature. inTok, tokens: . break( . same, size: 0 , newlines : newlineBehavior ) )
9881017 }
9891018 before ( node. rightBrace, tokens: . break( . close) )
9901019 } else {
@@ -994,7 +1023,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
9941023 // or part of some other expression (where we want that expression's same/continue behavior to
9951024 // apply).
9961025 arrangeBracesAndContents (
997- of: node, contentsKeyPath: \. statements, shouldResetBeforeLeftBrace: false )
1026+ of: node,
1027+ contentsKeyPath: \. statements,
1028+ shouldResetBeforeLeftBrace: false ,
1029+ openBraceNewlineBehavior: newlineBehavior)
9981030 }
9991031 return . visitChildren
10001032 }
@@ -2537,10 +2569,13 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
25372569 /// if you have already placed a `reset` elsewhere (for example, in a `guard` statement, the
25382570 /// `reset` is inserted before the `else` keyword to force both it and the brace down to the
25392571 /// next line).
2572+ /// - openBraceNewlineBehavior: The newline behavior to apply to the break following the open
2573+ /// brace; defaults to `.elective`.
25402574 private func arrangeBracesAndContents< Node: BracedSyntax , BodyContents: SyntaxCollection > (
25412575 of node: Node ? ,
25422576 contentsKeyPath: KeyPath < Node , BodyContents > ? ,
2543- shouldResetBeforeLeftBrace: Bool = true
2577+ shouldResetBeforeLeftBrace: Bool = true ,
2578+ openBraceNewlineBehavior: NewlineBehavior = . elective
25442579 ) where BodyContents. Element: SyntaxProtocol {
25452580 guard let node = node, let contentsKeyPath = contentsKeyPath else { return }
25462581
@@ -2550,10 +2585,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
25502585 tokens: . break( . reset, size: 1 , newlines: . elective( ignoresDiscretionary: true ) ) )
25512586 }
25522587 if !areBracesCompletelyEmpty( node, contentsKeyPath: contentsKeyPath) {
2553- after ( node. leftBrace, tokens: . break( . open, size: 1 ) , . open)
2588+ after (
2589+ node. leftBrace, tokens: . break( . open, size: 1 , newlines: openBraceNewlineBehavior) , . open)
25542590 before ( node. rightBrace, tokens: . break( . close, size: 1 ) , . close)
25552591 } else {
2556- after ( node. leftBrace, tokens: . break( . open, size: 0 ) )
2592+ after ( node. leftBrace, tokens: . break( . open, size: 0 , newlines : openBraceNewlineBehavior ) )
25572593 before ( node. rightBrace, tokens: . break( . close, size: 0 ) )
25582594 }
25592595 }
0 commit comments