Skip to content

Commit 8c121bf

Browse files
committed
Add new tokens to append trailing commas.
1 parent 818c7c6 commit 8c121bf

13 files changed

+116
-172
lines changed

Sources/SwiftFormat/Pipelines+Generated.swift

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ import SwiftSyntax
1818

1919
extension LintPipeline {
2020

21-
func visit(_ node: ArrayExprSyntax) -> SyntaxVisitorContinueKind {
22-
visitIfEnabled(MultiLineTrailingCommas.visit, in: context, for: node)
23-
return .visitChildren
24-
}
25-
2621
func visit(_ node: AsExprSyntax) -> SyntaxVisitorContinueKind {
2722
visitIfEnabled(NeverForceUnwrap.visit, in: context, for: node)
2823
return .visitChildren
@@ -71,11 +66,6 @@ extension LintPipeline {
7166
return .visitChildren
7267
}
7368

74-
func visit(_ node: DictionaryExprSyntax) -> SyntaxVisitorContinueKind {
75-
visitIfEnabled(MultiLineTrailingCommas.visit, in: context, for: node)
76-
return .visitChildren
77-
}
78-
7969
func visit(_ node: EnumCaseElementSyntax) -> SyntaxVisitorContinueKind {
8070
visitIfEnabled(AlwaysUseLowerCamelCase.visit, in: context, for: node)
8171
visitIfEnabled(NoLeadingUnderscores.visit, in: context, for: node)
@@ -243,8 +233,12 @@ extension LintPipeline {
243233
return .visitChildren
244234
}
245235

246-
func visit(_ node: SwitchStmtSyntax) -> SyntaxVisitorContinueKind {
236+
func visit(_ node: SwitchCaseListSyntax) -> SyntaxVisitorContinueKind {
247237
visitIfEnabled(NoCasesWithOnlyFallthrough.visit, in: context, for: node)
238+
return .visitChildren
239+
}
240+
241+
func visit(_ node: SwitchStmtSyntax) -> SyntaxVisitorContinueKind {
248242
visitIfEnabled(NoParensAroundConditions.visit, in: context, for: node)
249243
return .visitChildren
250244
}
@@ -285,7 +279,6 @@ extension FormatPipeline {
285279
node = DoNotUseSemicolons(context: context).visit(node)
286280
node = FullyIndirectEnum(context: context).visit(node)
287281
node = GroupNumericLiterals(context: context).visit(node)
288-
node = MultiLineTrailingCommas(context: context).visit(node)
289282
node = NoAccessLevelOnExtensionDeclaration(context: context).visit(node)
290283
node = NoBlockComments(context: context).visit(node)
291284
node = NoCasesWithOnlyFallthrough(context: context).visit(node)

Sources/SwiftFormatConfiguration/RuleRegistry+Generated.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ enum RuleRegistry {
2424
"FullyIndirectEnum": true,
2525
"GroupNumericLiterals": true,
2626
"IdentifiersMustBeASCII": true,
27-
"MultiLineTrailingCommas": true,
2827
"NeverForceUnwrap": true,
2928
"NeverUseForceTry": true,
3029
"NeverUseImplicitlyUnwrappedOptionals": true,

Sources/SwiftFormatPrettyPrint/PrettyPrint.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public class PrettyPrinter {
7979
/// Keeps track of the continuation line state as you go into and out of open-close break groups.
8080
private var continuationStack: [Bool] = []
8181

82+
/// Keeps track of the line number where comma regions started. Line numbers are removed as their
83+
/// corresponding end token are encountered.
84+
private var commaDelimitedRegionStack: [Int] = []
85+
8286
/// Keeps track of the most recent number of consecutive newlines that have been printed.
8387
///
8488
/// This value is reset to zero whenever non-newline content is printed.
@@ -443,6 +447,18 @@ public class PrettyPrinter {
443447
case .enableBreaking:
444448
activeBreakSuppressionCount -= 1
445449
}
450+
451+
case .commaDelimitedRegionStart:
452+
commaDelimitedRegionStack.append(openCloseBreakCompensatingLineNumber)
453+
454+
case .commaDelimitedRegionEnd:
455+
guard let startLineNumber = commaDelimitedRegionStack.popLast() else {
456+
fatalError("Found trailing comma end with no corresponding start.")
457+
}
458+
459+
if startLineNumber != openCloseBreakCompensatingLineNumber {
460+
write(",")
461+
}
446462
}
447463
}
448464

@@ -535,6 +551,21 @@ public class PrettyPrinter {
535551
case .printerControl:
536552
// Control tokens have no length. They aren't printed.
537553
lengths.append(0)
554+
555+
case .commaDelimitedRegionStart:
556+
lengths.append(0)
557+
558+
case .commaDelimitedRegionEnd:
559+
// The trailing comma needs to be included in the length of the preceding break, but is not
560+
// included in the length of the enclosing group. A trailing comma cannot cause the group
561+
// to break onto multiple lines, because the comma isn't printed for a single line group.
562+
if let index = delimIndexStack.last, case .break = tokens[index] {
563+
lengths[index] += 1
564+
}
565+
// If the closest delimiter token is an open, instead of a break, then adding the comma's
566+
// length isn't necessary. In that case, the comma is printed if the preceding break fires.
567+
568+
lengths.append(1)
538569
}
539570
}
540571

@@ -621,6 +652,14 @@ public class PrettyPrinter {
621652
case .printerControl(let kind):
622653
printDebugIndent()
623654
print("[PRINTER CONTROL Kind: \(kind) Idx: \(idx)]")
655+
656+
case .commaDelimitedRegionStart:
657+
printDebugIndent()
658+
print("[COMMA DELIMITED START Idx: \(idx)]")
659+
660+
case .commaDelimitedRegionEnd:
661+
printDebugIndent()
662+
print("[COMMA DELIMITED END Idx: \(idx)]")
624663
}
625664
}
626665

Sources/SwiftFormatPrettyPrint/Token.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ enum Token {
171171
case verbatim(Verbatim)
172172
case printerControl(kind: PrinterControlKind)
173173

174+
/// Marks the beginning of a comma delimited collection, where a trailing comma should be inserted
175+
/// at `commaDelimitedRegionEnd` if and only if the collection spans multiple lines.
176+
case commaDelimitedRegionStart
177+
178+
/// Marks the end of a comma delimited collection, where a trailing comma should be inserted
179+
/// if and only if the collection spans multiple lines.
180+
case commaDelimitedRegionEnd
181+
174182
// Convenience overloads for the enum types
175183
static let open = Token.open(.inconsistent, 0)
176184

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ private final class TokenStreamCreator: SyntaxVisitor {
4747
/// stream.
4848
private var pendingMultilineStringSegmentPrefixLengths = [TokenSyntax: Int]()
4949

50+
/// Lists tokens that shouldn't be appended to the token stream as `syntax` tokens. They will be
51+
/// printed conditionally using a different type of token.
52+
private var ignoredTokens = [TokenSyntax]()
53+
5054
init(configuration: Configuration, operatorContext: OperatorContext) {
5155
self.config = configuration
5256
self.operatorContext = operatorContext
@@ -698,6 +702,13 @@ private final class TokenStreamCreator: SyntaxVisitor {
698702

699703
func visit(_ node: ArrayElementListSyntax) -> SyntaxVisitorContinueKind {
700704
insertTokens(.break(.same), betweenElementsOf: node)
705+
if let firstElement = node.first, let lastElement = node.last {
706+
before(firstElement.firstToken, tokens: .commaDelimitedRegionStart)
707+
after(lastElement.lastToken, tokens: .commaDelimitedRegionEnd)
708+
if let existingTrailingComma = lastElement.trailingComma {
709+
ignoredTokens.append(existingTrailingComma)
710+
}
711+
}
701712
return .visitChildren
702713
}
703714

@@ -715,6 +726,13 @@ private final class TokenStreamCreator: SyntaxVisitor {
715726

716727
func visit(_ node: DictionaryElementListSyntax) -> SyntaxVisitorContinueKind {
717728
insertTokens(.break(.same), betweenElementsOf: node)
729+
if let firstElement = node.first, let lastElement = node.last {
730+
before(firstElement.firstToken, tokens: .commaDelimitedRegionStart)
731+
after(lastElement.lastToken, tokens: .commaDelimitedRegionEnd)
732+
if let existingTrailingComma = lastElement.trailingComma {
733+
ignoredTokens.append(existingTrailingComma)
734+
}
735+
}
718736
return .visitChildren
719737
}
720738

@@ -1936,7 +1954,7 @@ private final class TokenStreamCreator: SyntaxVisitor {
19361954

19371955
if let pendingSegmentIndex = pendingMultilineStringSegmentPrefixLengths.index(forKey: token) {
19381956
appendMultilineStringSegments(at: pendingSegmentIndex)
1939-
} else {
1957+
} else if !ignoredTokens.contains(token) {
19401958
// Otherwise, it's just a regular token, so add the text as-is.
19411959
appendToken(.syntax(token.text))
19421960
}

Sources/SwiftFormatRules/MultiLineTrailingCommas.swift

Lines changed: 0 additions & 88 deletions
This file was deleted.

Tests/SwiftFormatPrettyPrintTests/ArrayDeclTests.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,42 @@ public class ArrayDeclTests: PrettyPrintTestCase {
22
public func testBasicArrays() {
33
let input =
44
"""
5-
let a = [1, 2, 3]
5+
let a = [1, 2, 3,]
66
let a: [Bool] = [false, true, true, false]
7+
let a = [11111111, 2222222, 33333333, 444444]
78
let a = [11111111, 2222222, 33333333, 4444444]
89
let a: [String] = ["One", "Two", "Three", "Four"]
910
let a: [String] = ["One", "Two", "Three", "Four", "Five", "Six", "Seven"]
1011
let a: [String] = ["One", "Two", "Three", "Four", "Five", "Six", "Seven",]
12+
let a: [String] = [
13+
"One", "Two", "Three", "Four", "Five",
14+
"Six", "Seven", "Eight",
15+
]
1116
"""
1217

1318
let expected =
1419
"""
1520
let a = [1, 2, 3]
1621
let a: [Bool] = [false, true, true, false]
22+
let a = [11111111, 2222222, 33333333, 444444]
1723
let a = [
18-
11111111, 2222222, 33333333, 4444444
24+
11111111, 2222222, 33333333, 4444444,
1925
]
2026
let a: [String] = [
21-
"One", "Two", "Three", "Four"
27+
"One", "Two", "Three", "Four",
2228
]
2329
let a: [String] = [
2430
"One", "Two", "Three", "Four", "Five",
25-
"Six", "Seven"
31+
"Six", "Seven",
2632
]
2733
let a: [String] = [
2834
"One", "Two", "Three", "Four", "Five",
2935
"Six", "Seven",
3036
]
37+
let a: [String] = [
38+
"One", "Two", "Three", "Four", "Five",
39+
"Six", "Seven", "Eight",
40+
]
3141
3242
"""
3343

Tests/SwiftFormatPrettyPrintTests/CommentTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,30 +220,30 @@ public class CommentTests: PrettyPrintTestCase {
220220
// Array comment
221221
let a = [
222222
456, // small comment
223-
789
223+
789,
224224
]
225225
226226
// Dictionary comment
227227
let b = [
228228
"abc": 456, // small comment
229-
"def": 789
229+
"def": 789,
230230
]
231231
232232
// Trailing comment
233233
let c = [
234-
123, 456 // small comment
234+
123, 456, // small comment
235235
]
236236
237237
/* Array comment */
238238
let a = [
239239
456, /* small comment */
240-
789
240+
789,
241241
]
242242
243243
/* Dictionary comment */
244244
let b = [
245245
"abc": 456, /* small comment */
246-
"def": 789
246+
"def": 789,
247247
]
248248
249249
"""

0 commit comments

Comments
 (0)