Skip to content

Commit

Permalink
Improve multilineEnumCases rule
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Aug 15, 2020
1 parent f911f90 commit 5155557
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 39 deletions.
4 changes: 3 additions & 1 deletion Snapshots/Euclid/Sources/Plane.swift
Expand Up @@ -124,7 +124,9 @@ internal extension Plane {
// An enum of planes along the X, Y and Z axes
// Used internally for flattening 3D paths and polygons
enum FlatteningPlane: RawRepresentable {
case xy, xz, yz
case xy
case xz
case yz

var rawValue: Plane {
switch self {
Expand Down
4 changes: 3 additions & 1 deletion Snapshots/Euclid/Sources/Shapes.swift
Expand Up @@ -68,7 +68,9 @@ public extension Path {
/// Create a quadratic bezier spline
static func curve(_ points: [PathPoint], detail: Int = 4) -> Path {
enum ArcRange {
case lhs, rhs, all
case lhs
case rhs
case all
}

func arc(_ p0: PathPoint, _ p1: PathPoint, _ p2: PathPoint,
Expand Down
9 changes: 6 additions & 3 deletions Snapshots/Layout/LayoutTests/RuntimeTypeTests.swift
Expand Up @@ -255,7 +255,8 @@ class RuntimeTypeTests: XCTestCase {
}

private enum NonRawRepresentableEnum {
case foo, bar
case foo
case bar
}

func testCastNonRawRepresentableEnum() {
Expand All @@ -269,7 +270,8 @@ class RuntimeTypeTests: XCTestCase {
}

private enum NonHashableEnum: RawRepresentable {
case foo, bar
case foo
case bar

var rawValue: RuntimeTypeTests.TestStruct {
return TestStruct(foo: 0)
Expand All @@ -296,7 +298,8 @@ class RuntimeTypeTests: XCTestCase {
}

private enum NonRawRepresentableOrHashableEnum {
case foo, bar(Int)
case foo
case bar(Int)
}

func testCastNonRawRepresentableOrHashableEnum() {
Expand Down
15 changes: 7 additions & 8 deletions Sources/Formatter.swift
Expand Up @@ -241,14 +241,11 @@ public class Formatter: NSObject {
}

/// Replaces the tokens in the specified range with new tokens
public func replaceTokens(inRange range: Range<Int>, with tokens: [Token]) {
if range.count == tokens.count, ArraySlice(tokens) == self.tokens[range] {
return
}
@discardableResult
public func replaceTokens(inRange range: Range<Int>, with tokens: [Token]) -> Int {
let max = min(range.count, tokens.count)
for i in 0 ..< max {
trackChange(at: range.lowerBound + i)
self.tokens[range.lowerBound + i] = tokens[i]
replaceToken(at: range.lowerBound + i, with: tokens[i])
}
if range.count > max {
for _ in max ..< range.count {
Expand All @@ -259,11 +256,13 @@ public class Formatter: NSObject {
insertToken(tokens[i], at: range.lowerBound + i)
}
}
return tokens.count - range.count
}

/// Replaces the tokens in the specified closed range with new tokens
public func replaceTokens(inRange range: ClosedRange<Int>, with tokens: [Token]) {
replaceTokens(inRange: range.lowerBound ..< range.upperBound + 1, with: tokens)
@discardableResult
public func replaceTokens(inRange range: ClosedRange<Int>, with tokens: [Token]) -> Int {
return replaceTokens(inRange: range.lowerBound ..< range.upperBound + 1, with: tokens)
}

/// Removes the token at the specified index
Expand Down
41 changes: 18 additions & 23 deletions Sources/Rules.swift
Expand Up @@ -3453,30 +3453,25 @@ public struct _FormatRules {
options: [],
sharedOptions: ["linebreaks"]
) { formatter in
formatter.forEach(.keyword("enum")) { idx, _ in
if let start = formatter.index(of: .startOfScope("{"), after: idx),
let end = formatter.index(of: .endOfScope("}"), after: start)
formatter.forEach(.keyword("case")) { i, _ in
guard formatter.isEnumCase(at: i),
var end = formatter.index(of: .endOfScope("}"), after: i),
formatter.tokens[i ..< end].contains(where: { $0.isLinebreak })
else {
return
}
var index = i
let indent = formatter.indentForLine(at: i)
while let commaIndex = formatter.index(of: .delimiter(","), in: (index + 1) ..< end),
let nextIndex = formatter.index(of: .nonSpaceOrLinebreak, after: commaIndex)
{
var lastCase = start

while let caseKeywordIndex = formatter.index(of: .keyword("case"), after: lastCase),
let breaklineIndex = formatter.index(of: .linebreak, after: caseKeywordIndex)
{
for jdx in (caseKeywordIndex + 1) ... breaklineIndex {
guard
let token = formatter.token(at: jdx),
token == .delimiter(","),
formatter.index(of: .startOfScope("("), in: lastCase ..< jdx) == nil else { continue }

formatter.removeToken(at: jdx)
formatter.insertLinebreak(at: jdx)
formatter.insertSpace(formatter.indentForLine(at: jdx), at: jdx + 1)
formatter.insertToken(.keyword("case"), at: jdx + 2)
formatter.insertToken(.space(" "), at: jdx + 3)
}

lastCase = breaklineIndex
}
formatter.replaceToken(at: commaIndex, with: .keyword("case"))
let delta = formatter
.replaceTokens(inRange: commaIndex + 1 ..< nextIndex, with: [.space(" ")])
formatter.insertLinebreak(at: commaIndex)
formatter.insertSpace(indent, at: commaIndex + 1)
index = commaIndex
end += delta + 2
}
}
}
Expand Down
53 changes: 50 additions & 3 deletions Tests/RulesTests.swift
Expand Up @@ -1735,7 +1735,8 @@ class RulesTests: XCTestCase {
let input = "enum Foo {\ncase Bar,\nBaz\n}"
let output = "enum Foo {\n case Bar,\n Baz\n}"
let options = FormatOptions(xcodeIndentation: true)
testFormatting(for: input, output, rule: FormatRules.indent, options: options, exclude: ["multilineEnumCases"])
testFormatting(for: input, output, rule: FormatRules.indent, options: options,
exclude: ["multilineEnumCases"])
}

func testEnumCaseWrappedIfWithXcodeStyle() {
Expand Down Expand Up @@ -4687,6 +4688,50 @@ class RulesTests: XCTestCase {
testFormatting(for: input, output, rule: FormatRules.multilineEnumCases)
}

func testEnumCaseSplitOverMultipleLines() {
let input = """
enum Foo {
case bar(
x: String,
y: Int
), baz
}
"""
let output = """
enum Foo {
case bar(
x: String,
y: Int
)
case baz
}
"""
testFormatting(for: input, output, rule: FormatRules.multilineEnumCases)
}

func testEnumCasesAlreadyWrappedOntoMultipleLines() {
let input = """
enum Foo {
case bar,
baz,
quux
}
"""
let output = """
enum Foo {
case bar
case baz
case quux
}
"""
testFormatting(for: input, output, rule: FormatRules.multilineEnumCases)
}

func testNoWrapEnumStatementAllOnOneLine() {
let input = "enum Foo { bar, baz }"
testFormatting(for: input, rule: FormatRules.multilineEnumCases)
}

// MARK: - void

func testEmptyParensReturnValueConvertedToVoid() {
Expand Down Expand Up @@ -5957,13 +6002,15 @@ class RulesTests: XCTestCase {
func testRemoveCommaDelimitedCaseRawStringCases() {
let input = "enum Foo: String { case bar = \"bar\", baz = \"baz\" }"
let output = "enum Foo: String { case bar, baz }"
testFormatting(for: input, output, rule: FormatRules.redundantRawValues)
testFormatting(for: input, output, rule: FormatRules.redundantRawValues,
exclude: ["multilineEnumCases"])
}

func testRemoveBacktickCaseRawStringCases() {
let input = "enum Foo: String { case `as` = \"as\", `let` = \"let\" }"
let output = "enum Foo: String { case `as`, `let` }"
testFormatting(for: input, output, rule: FormatRules.redundantRawValues)
testFormatting(for: input, output, rule: FormatRules.redundantRawValues,
exclude: ["multilineEnumCases"])
}

func testNoRemoveRawStringIfNameDoesntMatch() {
Expand Down
3 changes: 3 additions & 0 deletions Tests/XCTestManifests.swift
Expand Up @@ -662,6 +662,8 @@ extension RulesTests {
("testEnumCaseIndentingCommasWithXcodeStyle", testEnumCaseIndentingCommasWithXcodeStyle),
("testEnumCaseLessThanEnumCase", testEnumCaseLessThanEnumCase),
("testEnumCaseNotEqualYodaCondition", testEnumCaseNotEqualYodaCondition),
("testEnumCasesAlreadyWrappedOntoMultipleLines", testEnumCasesAlreadyWrappedOntoMultipleLines),
("testEnumCaseSplitOverMultipleLines", testEnumCaseSplitOverMultipleLines),
("testEnumCaseWrappedIfWithXcodeStyle", testEnumCaseWrappedIfWithXcodeStyle),
("testEnumIfCaseEndifIndenting", testEnumIfCaseEndifIndenting),
("testExponentialGrouping", testExponentialGrouping),
Expand Down Expand Up @@ -1273,6 +1275,7 @@ extension RulesTests {
("testNoWrapBeforeNestedFirstArgumentInStringInterpolation2", testNoWrapBeforeNestedFirstArgumentInStringInterpolation2),
("testNoWrapColorLiteral", testNoWrapColorLiteral),
("testNoWrapDictionaryWithSingleElement", testNoWrapDictionaryWithSingleElement),
("testNoWrapEnumStatementAllOnOneLine", testNoWrapEnumStatementAllOnOneLine),
("testNoWrapFunctionArrow", testNoWrapFunctionArrow),
("testNoWrapGenericsIfClosingBracketWithinMaxWidth", testNoWrapGenericsIfClosingBracketWithinMaxWidth),
("testNoWrapImageLiteral", testNoWrapImageLiteral),
Expand Down

0 comments on commit 5155557

Please sign in to comment.