@@ -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
}
@@ -2537,10 +2569,13 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2537
2569
/// if you have already placed a `reset` elsewhere (for example, in a `guard` statement, the
2538
2570
/// `reset` is inserted before the `else` keyword to force both it and the brace down to the
2539
2571
/// next line).
2572
+ /// - openBraceNewlineBehavior: The newline behavior to apply to the break following the open
2573
+ /// brace; defaults to `.elective`.
2540
2574
private func arrangeBracesAndContents< Node: BracedSyntax , BodyContents: SyntaxCollection > (
2541
2575
of node: Node ? ,
2542
2576
contentsKeyPath: KeyPath < Node , BodyContents > ? ,
2543
- shouldResetBeforeLeftBrace: Bool = true
2577
+ shouldResetBeforeLeftBrace: Bool = true ,
2578
+ openBraceNewlineBehavior: NewlineBehavior = . elective
2544
2579
) where BodyContents. Element: SyntaxProtocol {
2545
2580
guard let node = node, let contentsKeyPath = contentsKeyPath else { return }
2546
2581
@@ -2550,10 +2585,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
2550
2585
tokens: . break( . reset, size: 1 , newlines: . elective( ignoresDiscretionary: true ) ) )
2551
2586
}
2552
2587
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)
2554
2590
before ( node. rightBrace, tokens: . break( . close, size: 1 ) , . close)
2555
2591
} else {
2556
- after ( node. leftBrace, tokens: . break( . open, size: 0 ) )
2592
+ after ( node. leftBrace, tokens: . break( . open, size: 0 , newlines : openBraceNewlineBehavior ) )
2557
2593
before ( node. rightBrace, tokens: . break( . close, size: 0 ) )
2558
2594
}
2559
2595
}
0 commit comments