@@ -54,6 +54,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
54
54
/// moved past these tokens.
55
55
private var closingDelimiterTokens = Set < TokenSyntax > ( )
56
56
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
+
57
61
init ( configuration: Configuration , operatorContext: OperatorContext ) {
58
62
self . config = configuration
59
63
self . operatorContext = operatorContext
@@ -870,6 +874,16 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
870
874
override func visit( _ node: FunctionCallExprSyntax ) -> SyntaxVisitorContinueKind {
871
875
preVisitInsertingContextualBreaks ( node)
872
876
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
+
873
887
if let calledMemberAccessExpr = node. calledExpression. as ( MemberAccessExprSyntax . self) {
874
888
if let base = calledMemberAccessExpr. base, base. is ( IdentifierExprSyntax . self) {
875
889
// 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 {
907
921
clearContextualBreakState ( node)
908
922
}
909
923
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
+
910
932
/// Arrange the given argument list (or equivalently, tuple expression list) as a list of function
911
933
/// arguments.
912
934
///
@@ -979,12 +1001,19 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
979
1001
}
980
1002
981
1003
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
+
982
1011
if let signature = node. signature {
983
1012
after ( node. leftBrace, tokens: . break( . open) )
984
1013
if node. statements. count > 0 {
985
- after ( signature. inTok, tokens: . break( . same) )
1014
+ after ( signature. inTok, tokens: . break( . same, newlines : newlineBehavior ) )
986
1015
} else {
987
- after ( signature. inTok, tokens: . break( . same, size: 0 ) )
1016
+ after ( signature. inTok, tokens: . break( . same, size: 0 , newlines : newlineBehavior ) )
988
1017
}
989
1018
before ( node. rightBrace, tokens: . break( . close) )
990
1019
} else {
@@ -994,7 +1023,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
994
1023
// or part of some other expression (where we want that expression's same/continue behavior to
995
1024
// apply).
996
1025
arrangeBracesAndContents (
997
- of: node, contentsKeyPath: \. statements, shouldResetBeforeLeftBrace: false )
1026
+ of: node,
1027
+ contentsKeyPath: \. statements,
1028
+ shouldResetBeforeLeftBrace: false ,
1029
+ openBraceNewlineBehavior: newlineBehavior)
998
1030
}
999
1031
return . visitChildren
1000
1032
}
@@ -2539,10 +2571,13 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2539
2571
/// if you have already placed a `reset` elsewhere (for example, in a `guard` statement, the
2540
2572
/// `reset` is inserted before the `else` keyword to force both it and the brace down to the
2541
2573
/// next line).
2574
+ /// - openBraceNewlineBehavior: The newline behavior to apply to the break following the open
2575
+ /// brace; defaults to `.elective`.
2542
2576
private func arrangeBracesAndContents< Node: BracedSyntax , BodyContents: SyntaxCollection > (
2543
2577
of node: Node ? ,
2544
2578
contentsKeyPath: KeyPath < Node , BodyContents > ? ,
2545
- shouldResetBeforeLeftBrace: Bool = true
2579
+ shouldResetBeforeLeftBrace: Bool = true ,
2580
+ openBraceNewlineBehavior: NewlineBehavior = . elective
2546
2581
) where BodyContents. Element: SyntaxProtocol {
2547
2582
guard let node = node, let contentsKeyPath = contentsKeyPath else { return }
2548
2583
@@ -2552,10 +2587,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2552
2587
tokens: . break( . reset, size: 1 , newlines: . elective( ignoresDiscretionary: true ) ) )
2553
2588
}
2554
2589
if !areBracesCompletelyEmpty( node, contentsKeyPath: contentsKeyPath) {
2555
- after ( node. leftBrace, tokens: . break( . open, size: 1 ) , . open)
2590
+ after (
2591
+ node. leftBrace, tokens: . break( . open, size: 1 , newlines: openBraceNewlineBehavior) , . open)
2556
2592
before ( node. rightBrace, tokens: . break( . close, size: 1 ) , . close)
2557
2593
} else {
2558
- after ( node. leftBrace, tokens: . break( . open, size: 0 ) )
2594
+ after ( node. leftBrace, tokens: . break( . open, size: 0 , newlines : openBraceNewlineBehavior ) )
2559
2595
before ( node. rightBrace, tokens: . break( . close, size: 0 ) )
2560
2596
}
2561
2597
}
0 commit comments