Skip to content

Commit 2f91be0

Browse files
authored
Add an option to allow spaces around range formation operators. (#459)
Fixes #457
1 parent e42008c commit 2f91be0

File tree

4 files changed

+53
-5
lines changed

4 files changed

+53
-5
lines changed

Documentation/Configuration.md

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ top-level keys and values:
7979
true, a line break is forced before the "." of the component and after the component's
8080
closing delimiter (i.e. right paren, right bracket, right brace, etc.).
8181

82+
* `spacesAroundRangeFormationOperators` _(boolean)_: Determines whether whitespace should be forced
83+
before and after the range formation operators `...` and `..<`.
84+
8285
> TODO: Add support for enabling/disabling specific syntax transformations in
8386
> the pipeline.
8487

Sources/SwiftFormatConfiguration/Configuration.swift

+10
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public struct Configuration: Codable, Equatable {
3535
case fileScopedDeclarationPrivacy
3636
case indentSwitchCaseLabels
3737
case rules
38+
case spacesAroundRangeFormationOperators
3839
}
3940

4041
/// The version of this configuration.
@@ -142,6 +143,10 @@ public struct Configuration: Codable, Equatable {
142143
///```
143144
public var indentSwitchCaseLabels = false
144145

146+
/// Determines whether whitespace should be forced before and after the range formation operators
147+
/// `...` and `..<`.
148+
public var spacesAroundRangeFormationOperators = false
149+
145150
/// Constructs a Configuration with all default values.
146151
public init() {
147152
self.version = highestSupportedConfigurationVersion
@@ -194,6 +199,9 @@ public struct Configuration: Codable, Equatable {
194199
self.lineBreakAroundMultilineExpressionChainComponents =
195200
try container.decodeIfPresent(
196201
Bool.self, forKey: .lineBreakAroundMultilineExpressionChainComponents) ?? false
202+
self.spacesAroundRangeFormationOperators =
203+
try container.decodeIfPresent(
204+
Bool.self, forKey: .spacesAroundRangeFormationOperators) ?? false
197205
self.fileScopedDeclarationPrivacy =
198206
try container.decodeIfPresent(
199207
FileScopedDeclarationPrivacyConfiguration.self, forKey: .fileScopedDeclarationPrivacy)
@@ -226,6 +234,8 @@ public struct Configuration: Codable, Equatable {
226234
try container.encode(
227235
lineBreakAroundMultilineExpressionChainComponents,
228236
forKey: .lineBreakAroundMultilineExpressionChainComponents)
237+
try container.encode(
238+
spacesAroundRangeFormationOperators, forKey: .spacesAroundRangeFormationOperators)
229239
try container.encode(fileScopedDeclarationPrivacy, forKey: .fileScopedDeclarationPrivacy)
230240
try container.encode(indentSwitchCaseLabels, forKey: .indentSwitchCaseLabels)
231241
try container.encode(rules, forKey: .rules)

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -3296,7 +3296,8 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
32963296
return nil
32973297
}
32983298

3299-
/// Returns a value indicating whether whitespace should be required around the given operator.
3299+
/// Returns a value indicating whether whitespace should be required around the given operator,
3300+
/// for the given configuration.
33003301
///
33013302
/// If spaces are not required (for example, range operators), then the formatter will also forbid
33023303
/// breaks around the operator. This is to prevent situations where a break could occur before an
@@ -3308,8 +3309,9 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
33083309
// to ignore that and apply our own rules.
33093310
if let binaryOperator = operatorExpr.as(BinaryOperatorExprSyntax.self) {
33103311
let token = binaryOperator.operatorToken
3311-
if let binOp = operatorTable.infixOperator(named: token.text),
3312-
let precedenceGroup = binOp.precedenceGroup, precedenceGroup == "RangeFormationPrecedence"
3312+
if !config.spacesAroundRangeFormationOperators,
3313+
let binOp = operatorTable.infixOperator(named: token.text),
3314+
let precedenceGroup = binOp.precedenceGroup, precedenceGroup == "RangeFormationPrecedence"
33133315
{
33143316
// We want to omit whitespace around range formation operators if possible. We can't do this
33153317
// if the token is either preceded by a postfix operator, followed by a prefix operator, or

Tests/SwiftFormatPrettyPrintTests/BinaryOperatorExprTests.swift

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import SwiftFormatConfiguration
2+
13
final class BinaryOperatorExprTests: PrettyPrintTestCase {
24
func testNonRangeFormationOperatorsAreSurroundedByBreaks() {
35
let input =
@@ -26,7 +28,7 @@ final class BinaryOperatorExprTests: PrettyPrintTestCase {
2628
assertPrettyPrintEqual(input: input, expected: expected10, linelength: 10)
2729
}
2830

29-
func testRangeFormationOperatorsAreCompactedWhenPossible() {
31+
func testRangeFormationOperatorCompaction_noSpacesAroundRangeFormation() {
3032
let input =
3133
"""
3234
x = 1...100
@@ -48,7 +50,38 @@ final class BinaryOperatorExprTests: PrettyPrintTestCase {
4850
4951
"""
5052

51-
assertPrettyPrintEqual(input: input, expected: expected, linelength: 80)
53+
var configuration = Configuration()
54+
configuration.spacesAroundRangeFormationOperators = false
55+
assertPrettyPrintEqual(
56+
input: input, expected: expected, linelength: 80, configuration: configuration)
57+
}
58+
59+
func testRangeFormationOperatorCompaction_spacesAroundRangeFormation() {
60+
let input =
61+
"""
62+
x = 1...100
63+
x = 1..<100
64+
x = (1++)...(-100)
65+
x = 1 ... 100
66+
x = 1 ..< 100
67+
x = (1++) ... (-100)
68+
"""
69+
70+
let expected =
71+
"""
72+
x = 1 ... 100
73+
x = 1 ..< 100
74+
x = (1++) ... (-100)
75+
x = 1 ... 100
76+
x = 1 ..< 100
77+
x = (1++) ... (-100)
78+
79+
"""
80+
81+
var configuration = Configuration()
82+
configuration.spacesAroundRangeFormationOperators = true
83+
assertPrettyPrintEqual(
84+
input: input, expected: expected, linelength: 80, configuration: configuration)
5285
}
5386

5487
func testRangeFormationOperatorsAreNotCompactedWhenFollowingAPostfixOperator() {

0 commit comments

Comments
 (0)