Skip to content

Commit

Permalink
Add inference for noSpaceOperators option
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Jul 12, 2020
1 parent 1f5a2e8 commit 945ef15
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 32 deletions.
36 changes: 29 additions & 7 deletions Sources/Inference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,42 @@ private struct Inference {
options.allowInlineSemicolons = allow
}

let spaceAroundRangeOperators = OptionInferrer { formatter, options in
var spaced = 0, unspaced = 0
formatter.forEach(.rangeOperator) { i, _ in
guard let nextToken = formatter.next(.nonSpaceOrCommentOrLinebreak, after: i),
let noSpaceOperators = OptionInferrer { formatter, options in
var spaced = [String: Int](), unspaced = [String: Int]()
formatter.forEach(.operator) { i, token in
guard case let .operator(name, .infix) = token, name != ".",
let nextToken = formatter.next(.nonSpaceOrCommentOrLinebreak, after: i),
nextToken.string != ")", nextToken.string != "," else {
return
}
if formatter.token(at: i + 1)?.isSpaceOrLinebreak == true {
spaced += 1
spaced[name, default: 0] += 1
} else {
unspaced += 1
unspaced[name, default: 0] += 1
}
}
var noSpaceOperators = Set<String>()
let operators = Set(spaced.keys).union(unspaced.keys)
for name in operators where unspaced[name, default: 0] > spaced[name, default: 0] + 1 {
noSpaceOperators.insert(name)
}
// Related pairs
let relatedPairs = [
("...", "..<"), ("*", "/"), ("*=", "/="), ("+", "-"), ("+=", "-="),
("==", "!="), ("<", ">"), ("<=", ">="), ("<<", ">>"),
]
for pair in relatedPairs {
if noSpaceOperators.contains(pair.0),
!noSpaceOperators.contains(pair.1),
!operators.contains(pair.1) {
noSpaceOperators.insert(pair.1)
} else if noSpaceOperators.contains(pair.1),
!noSpaceOperators.contains(pair.0),
!operators.contains(pair.0) {
noSpaceOperators.insert(pair.0)
}
}
options.spaceAroundRangeOperators = (spaced >= unspaced)
options.noSpaceOperators = noSpaceOperators
}

let useVoid = OptionInferrer { formatter, options in
Expand Down
6 changes: 3 additions & 3 deletions Sources/Rules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,7 @@ public struct _FormatRules {
) { formatter in
formatter.forEach(.rangeOperator) { i, token in
guard case let .operator(name, .infix) = token else { return }
if !formatter.options.spaceAroundRangeOperators ||
formatter.options.noSpaceOperators.contains(name) {
if !formatter.options.spaceAroundRangeOperators {
if formatter.token(at: i + 1)?.isSpace == true,
formatter.token(at: i - 1)?.isSpace == true,
let nextToken = formatter.next(.nonSpace, after: i),
Expand All @@ -619,7 +618,8 @@ public struct _FormatRules {
formatter.removeToken(at: i + 1)
formatter.removeToken(at: i - 1)
}
} else {
} else if formatter.options.spaceAroundRangeOperators,
!formatter.options.noSpaceOperators.contains(name) {
if formatter.token(at: i + 1)?.isSpaceOrLinebreak == false {
formatter.insertToken(.space(" "), at: i + 1)
}
Expand Down
58 changes: 44 additions & 14 deletions Tests/InferenceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,20 +138,6 @@ class InferenceTests: XCTestCase {
XCTAssertFalse(options.allowInlineSemicolons)
}

// MARK: spaceAroundRangeOperators

func testInferSpaceAroundRangeOperators() {
let input = "let foo = 0 ..< bar\n;let baz = 1...quux"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertTrue(options.spaceAroundRangeOperators)
}

func testInferNoSpaceAroundRangeOperators() {
let input = "let foo = 0..<bar\n;let baz = 1...quux"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertFalse(options.spaceAroundRangeOperators)
}

// MARK: useVoid

func testInferUseVoid() {
Expand Down Expand Up @@ -631,4 +617,48 @@ class InferenceTests: XCTestCase {
let options = inferFormatOptions(from: tokenize(input))
XCTAssertFalse(options.indentCase)
}

// MARK: nospaceoperators

func testInferNoSpaceAroundTimesOperator() {
let input = "let foo = a*b + c / d + e*f"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, ["*"])
}

func testInferSpaceAroundTimesOperator() {
let input = "let foo = a*b + c * d + e*f"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, [])
}

func testInferNoSpaceAroundTimesAndDivideOperator() {
let input = "let foo = a*b + c*d"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, ["/", "*"])
}

func testInferSpaceAroundRangeOperators() {
let input = "let foo = a ... b"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, [])
}

func testInferSpaceAroundRangeOperators2() {
let input = "let foo = a ..< b"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, [])
}

func testInferSpaceAroundRangeOperators3() {
let input = "let foo = a...b; let bar = a...b; let baz = a ..< b"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, ["..."])
}

func testInferNoSpaceAroundRangeOperators3() {
let input = "let foo = a...b; let bar = a...b"
let options = inferFormatOptions(from: tokenize(input))
XCTAssertEqual(options.noSpaceOperators, ["...", "..<"])
}
}
20 changes: 13 additions & 7 deletions Tests/RulesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3987,15 +3987,14 @@ class RulesTests: XCTestCase {
testFormatting(for: input, output, rule: FormatRules.ranges)
}

// spaceAroundRangeOperators = true

func testNoSpaceAroundRangeOperatorsWithCustomOptions() {
let input = "foo ..< bar"
let output = "foo..<bar"
let options = FormatOptions(spaceAroundRangeOperators: false)
testFormatting(for: input, output, rule: FormatRules.ranges, options: options)
func testNoSpaceAroundRangeOperatorsWithExplicitNoSpace() {
let input = "foo..<bar"
let options = FormatOptions(noSpaceOperators: ["..<"])
testFormatting(for: input, rule: FormatRules.ranges, options: options)
}

// spaceAroundRangeOperators = true

func testNoSpaceAddedAroundVariadic() {
let input = "foo(bar: Int...)"
let options = FormatOptions(spaceAroundRangeOperators: true)
Expand Down Expand Up @@ -4041,6 +4040,13 @@ class RulesTests: XCTestCase {

// spaceAroundRangeOperators = false

func testNoSpaceAroundRangeOperatorsWithCustomOptions() {
let input = "foo ..< bar"
let output = "foo..<bar"
let options = FormatOptions(spaceAroundRangeOperators: false)
testFormatting(for: input, output, rule: FormatRules.ranges, options: options)
}

func testSpaceNotRemovedBeforeLeadingRangeOperatorWithSpaceAroundRangeOperatorsFalse() {
let input = "let range = ..<foo.endIndex"
let options = FormatOptions(spaceAroundRangeOperators: false)
Expand Down
8 changes: 7 additions & 1 deletion Tests/XCTestManifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ extension InferenceTests {
("testInferNoIndentCase", testInferNoIndentCase),
("testInferNoOctalGrouping", testInferNoOctalGrouping),
("testInferNoSpaceAfterOperatorFunc", testInferNoSpaceAfterOperatorFunc),
("testInferNoSpaceAroundRangeOperators", testInferNoSpaceAroundRangeOperators),
("testInferNoSpaceAroundRangeOperators3", testInferNoSpaceAroundRangeOperators3),
("testInferNoSpaceAroundTimesAndDivideOperator", testInferNoSpaceAroundTimesAndDivideOperator),
("testInferNoSpaceAroundTimesOperator", testInferNoSpaceAroundTimesOperator),
("testInferNoTrailingCommas", testInferNoTrailingCommas),
("testInferNoTruncateBlanklines", testInferNoTruncateBlanklines),
("testInferOctetHexGrouping", testInferOctetHexGrouping),
Expand All @@ -243,6 +245,9 @@ extension InferenceTests {
("testInferSelfInInitOnly", testInferSelfInInitOnly),
("testInferSpaceAfterOperatorFunc", testInferSpaceAfterOperatorFunc),
("testInferSpaceAroundRangeOperators", testInferSpaceAroundRangeOperators),
("testInferSpaceAroundRangeOperators2", testInferSpaceAroundRangeOperators2),
("testInferSpaceAroundRangeOperators3", testInferSpaceAroundRangeOperators3),
("testInferSpaceAroundTimesOperator", testInferSpaceAroundTimesOperator),
("testInferThousands", testInferThousands),
("testInferTrailingCommas", testInferTrailingCommas),
("testInferUnhoisted", testInferUnhoisted),
Expand Down Expand Up @@ -1176,6 +1181,7 @@ extension RulesTests {
("testNoSpaceAroundMultipleOptionalChaining", testNoSpaceAroundMultipleOptionalChaining),
("testNoSpaceAroundPrefixMinus", testNoSpaceAroundPrefixMinus),
("testNoSpaceAroundRangeOperatorsWithCustomOptions", testNoSpaceAroundRangeOperatorsWithCustomOptions),
("testNoSpaceAroundRangeOperatorsWithExplicitNoSpace", testNoSpaceAroundRangeOperatorsWithExplicitNoSpace),
("testNoSpaceBeforeColon", testNoSpaceBeforeColon),
("testNoSpaceBeforeComma", testNoSpaceBeforeComma),
("testNoSpaceBetweenArrayLiteralAndParen", testNoSpaceBetweenArrayLiteralAndParen),
Expand Down

0 comments on commit 945ef15

Please sign in to comment.