mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
Add --blank-line-after-switch-case always option to blankLineAfterSwitchCase rule (#2150)
This commit is contained in:
committed by
Cal Stephens
parent
142386035d
commit
0e6282849c
@@ -277,12 +277,18 @@ Insert blank line after import statements.
|
||||
|
||||
## blankLineAfterSwitchCase
|
||||
|
||||
Insert a blank line after multiline switch cases (excluding the last case,
|
||||
Insert a blank line after switch cases (excluding the last case,
|
||||
which is followed by a closing brace).
|
||||
|
||||
Option | Description
|
||||
--- | ---
|
||||
`--blank-line-after-switch-case` | Insert line After switch cases: "always" or "multiline-only" (default)
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
`--blank-line-after-switch-case multiline-only` (default)
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
@@ -304,6 +310,58 @@ which is followed by a closing brace).
|
||||
}
|
||||
```
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
case .engageWarpDrive:
|
||||
warpDrive.activate()
|
||||
|
||||
case let .scanPlanet(planet):
|
||||
scanner.scanForArticialLife()
|
||||
|
||||
case .handleIncomingEnergyBlast:
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
```
|
||||
`--blank-line-after-switch-case always`
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
case .engageWarpDrive:
|
||||
navigationComputer.destination = targetedDestination
|
||||
await warpDrive.spinUp()
|
||||
warpDrive.activate()
|
||||
+
|
||||
case let .scanPlanet(planet):
|
||||
scanner.target = planet
|
||||
scanner.scanAtmosphere()
|
||||
scanner.scanBiosphere()
|
||||
scanner.scanForArticialLife()
|
||||
+
|
||||
case .handleIncomingEnergyBlast:
|
||||
await energyShields.prepare()
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
case .engageWarpDrive:
|
||||
warpDrive.activate()
|
||||
+
|
||||
case let .scanPlanet(planet):
|
||||
scanner.scanForArticialLife()
|
||||
+
|
||||
case .handleIncomingEnergyBlast:
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<br/>
|
||||
|
||||
|
||||
@@ -1347,6 +1347,12 @@ struct _Descriptors {
|
||||
trueValues: ["true"],
|
||||
falseValues: ["false"]
|
||||
)
|
||||
let blankLineAfterSwitchCase = OptionDescriptor(
|
||||
argumentName: "blank-line-after-switch-case",
|
||||
displayName: "Blank Line After Switch Cases",
|
||||
help: "Insert line After switch cases: \"always\" or \"multiline-only\" (default)",
|
||||
keyPath: \.blankLineAfterSwitchCase
|
||||
)
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
|
||||
+10
-1
@@ -647,6 +647,13 @@ public enum EquatableMacro: Equatable, RawRepresentable, CustomStringConvertible
|
||||
}
|
||||
}
|
||||
|
||||
public enum BlankLineAfterSwitchCase: String, CaseIterable {
|
||||
/// Add blank lines after multiline switch cases only
|
||||
case multilineOnly = "multiline-only"
|
||||
/// Always add blank lines after switch cases
|
||||
case always
|
||||
}
|
||||
|
||||
public enum URLMacro: Equatable, RawRepresentable, CustomStringConvertible {
|
||||
/// No URL macro
|
||||
case none
|
||||
@@ -795,6 +802,7 @@ public struct FormatOptions: CustomStringConvertible {
|
||||
public var urlMacro: URLMacro
|
||||
public var preferFileMacro: Bool
|
||||
public var lineBetweenConsecutiveGuards: Bool
|
||||
public var blankLineAfterSwitchCase: BlankLineAfterSwitchCase
|
||||
|
||||
/// Deprecated
|
||||
public var indentComments: Bool
|
||||
@@ -928,6 +936,7 @@ public struct FormatOptions: CustomStringConvertible {
|
||||
urlMacro: URLMacro = .none,
|
||||
preferFileMacro: Bool = true,
|
||||
lineBetweenConsecutiveGuards: Bool = false,
|
||||
blankLineAfterSwitchCase: BlankLineAfterSwitchCase = .multilineOnly,
|
||||
// Doesn't really belong here, but hard to put elsewhere
|
||||
fragment: Bool = false,
|
||||
ignoreConflictMarkers: Bool = false,
|
||||
@@ -1050,7 +1059,7 @@ public struct FormatOptions: CustomStringConvertible {
|
||||
self.urlMacro = urlMacro
|
||||
self.preferFileMacro = preferFileMacro
|
||||
self.lineBetweenConsecutiveGuards = lineBetweenConsecutiveGuards
|
||||
// Doesn't really belong here, but hard to put elsewhere
|
||||
self.blankLineAfterSwitchCase = blankLineAfterSwitchCase
|
||||
self.indentComments = indentComments
|
||||
self.fragment = fragment
|
||||
self.ignoreConflictMarkers = ignoreConflictMarkers
|
||||
|
||||
@@ -11,19 +11,22 @@ import Foundation
|
||||
public extension FormatRule {
|
||||
static let blankLineAfterSwitchCase = FormatRule(
|
||||
help: """
|
||||
Insert a blank line after multiline switch cases (excluding the last case,
|
||||
Insert a blank line after switch cases (excluding the last case,
|
||||
which is followed by a closing brace).
|
||||
""",
|
||||
disabledByDefault: true,
|
||||
orderAfter: [.redundantBreak]
|
||||
orderAfter: [.redundantBreak],
|
||||
options: ["blank-line-after-switch-case"]
|
||||
) { formatter in
|
||||
formatter.forEach(.keyword("switch")) { switchIndex, _ in
|
||||
guard let switchCases = formatter.switchStatementBranchesWithSpacingInfo(at: switchIndex) else { return }
|
||||
|
||||
let shouldAlwaysInsertBlankLineAfterSwitchCase = formatter.options.blankLineAfterSwitchCase == .always
|
||||
for switchCase in switchCases.reversed() {
|
||||
// Any switch statement that spans multiple lines should be followed by a blank line
|
||||
// Any switch statement should be followed by a blank line, depending on the
|
||||
// `blankLineAfterSwitchCase` option.
|
||||
// (excluding the last case, which is followed by a closing brace).
|
||||
if switchCase.spansMultipleLines,
|
||||
if shouldAlwaysInsertBlankLineAfterSwitchCase || switchCase.spansMultipleLines,
|
||||
!switchCase.isLastCase,
|
||||
!switchCase.isFollowedByBlankLine
|
||||
{
|
||||
@@ -41,6 +44,8 @@ public extension FormatRule {
|
||||
}
|
||||
} examples: {
|
||||
#"""
|
||||
`--blank-line-after-switch-case multiline-only` (default)
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
@@ -61,6 +66,58 @@ public extension FormatRule {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
case .engageWarpDrive:
|
||||
warpDrive.activate()
|
||||
|
||||
case let .scanPlanet(planet):
|
||||
scanner.scanForArticialLife()
|
||||
|
||||
case .handleIncomingEnergyBlast:
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
```
|
||||
`--blank-line-after-switch-case always`
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
case .engageWarpDrive:
|
||||
navigationComputer.destination = targetedDestination
|
||||
await warpDrive.spinUp()
|
||||
warpDrive.activate()
|
||||
+
|
||||
case let .scanPlanet(planet):
|
||||
scanner.target = planet
|
||||
scanner.scanAtmosphere()
|
||||
scanner.scanBiosphere()
|
||||
scanner.scanForArticialLife()
|
||||
+
|
||||
case .handleIncomingEnergyBlast:
|
||||
await energyShields.prepare()
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```diff
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
case .engageWarpDrive:
|
||||
warpDrive.activate()
|
||||
+
|
||||
case let .scanPlanet(planet):
|
||||
scanner.scanForArticialLife()
|
||||
+
|
||||
case .handleIncomingEnergyBlast:
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
```
|
||||
"""#
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,39 @@ class BlankLineAfterSwitchCaseTests: XCTestCase {
|
||||
testFormatting(for: input, output, rule: .blankLineAfterSwitchCase)
|
||||
}
|
||||
|
||||
func testAddsBlankLineAfterSingleSwitchCasesWhenBlankLineAroundSingleLineCases() {
|
||||
let input = """
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
// The warp drive can be engaged by pressing a button on the control panel
|
||||
case .engageWarpDrive:
|
||||
warpDrive.activate()
|
||||
// Triggered automatically whenever we detect an energy blast was fired in our direction
|
||||
case .handleIncomingEnergyBlast:
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
let output = """
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
switch action {
|
||||
// The warp drive can be engaged by pressing a button on the control panel
|
||||
case .engageWarpDrive:
|
||||
warpDrive.activate()
|
||||
|
||||
// Triggered automatically whenever we detect an energy blast was fired in our direction
|
||||
case .handleIncomingEnergyBlast:
|
||||
energyShields.engage()
|
||||
}
|
||||
}
|
||||
"""
|
||||
testFormatting(for: input,
|
||||
output,
|
||||
rule: .blankLineAfterSwitchCase,
|
||||
options: FormatOptions(blankLineAfterSwitchCase: .always))
|
||||
}
|
||||
|
||||
func testRemovesBlankLineAfterLastSwitchCase() {
|
||||
let input = """
|
||||
func handle(_ action: SpaceshipAction) {
|
||||
|
||||
Reference in New Issue
Block a user