Skip to content

Commit

Permalink
Merge pull request #41 from dylansturg/condition_statement_indentation
Browse files Browse the repository at this point in the history
Indent continuation lines in conditions for if & guard statements.
  • Loading branch information
allevato committed Aug 14, 2019
2 parents 1db79c0 + 317aa14 commit d483917
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 2 deletions.
23 changes: 21 additions & 2 deletions Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift
Expand Up @@ -394,6 +394,16 @@ private final class TokenStreamCreator: SyntaxVisitor {
func visit(_ node: IfStmtSyntax) -> SyntaxVisitorContinueKind {
after(node.ifKeyword, tokens: .space)

// Add break groups around any conditions after the first so that those conditions have at least
// 1 non-continuation based indent from an indentation stack. Without that indent, all
// continuation lines in the condition are indented by the same amount as the condition's first
// line because continuation breaks don't stack. There are no breaks around the first condition
// because if-statements look better without a break between the "if" and the first condition.
for condition in node.conditions.dropFirst() {
before(condition.firstToken, tokens: .break(.open, size: 0))
after(condition.lastToken, tokens: .break(.close(mustBreak: false), size: 0))
}

arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)

let elsePrecedingBreak = config.lineBreakBeforeControlFlowKeywords ? Token.newline : Token.space
Expand All @@ -408,7 +418,16 @@ private final class TokenStreamCreator: SyntaxVisitor {
}

func visit(_ node: GuardStmtSyntax) -> SyntaxVisitorContinueKind {
after(node.guardKeyword, tokens: .break)
after(node.guardKeyword, tokens: .space)

// Add break groups around all conditions, similar to the break groups used around if-statement
// conditions. For guard-statements, breaking after the "guard" is visually acceptable hence the
// first condition is included.
for condition in node.conditions {
before(condition.firstToken, tokens: .break(.open, size: 0))
after(condition.lastToken, tokens: .break(.close(mustBreak: false), size: 0))
}

before(node.elseKeyword, tokens: .break(.reset), .open)
after(node.elseKeyword, tokens: .space)
before(node.body.leftBrace, tokens: .close)
Expand Down Expand Up @@ -1063,7 +1082,7 @@ private final class TokenStreamCreator: SyntaxVisitor {
func visit(_ node: ConditionElementSyntax) -> SyntaxVisitorContinueKind {
before(node.firstToken, tokens: .open)
if let comma = node.trailingComma {
after(comma, tokens: .close, .break)
after(comma, tokens: .close, .break(.same))
} else {
after(node.lastToken, tokens: .close)
}
Expand Down
47 changes: 47 additions & 0 deletions Tests/SwiftFormatPrettyPrintTests/GuardStmtTests.swift
Expand Up @@ -107,4 +107,51 @@ public class GuardStmtTests: PrettyPrintTestCase {

assertPrettyPrintEqual(input: input, expected: expected, linelength: 60)
}

public func testContinuationLineBreaking() {
let input =
"""
guard let someObject = object as? Int,
let anotherCastedObject = object as? SomeOtherSlightlyLongerType else {
return nil
}
guard let someObject = object as? SomeLongLineBreakingType,
let anotherCastedObject = object as? SomeOtherSlightlyLongerType else {
return nil
}
guard let someCastedObject = someFunc(foo, bar, baz, quxxe, far, fab, faz),
let anotherCastedObject = object as? SomeOtherSlightlyLongerType else {
return nil
}
"""

let expected =
"""
guard let someObject = object as? Int,
let anotherCastedObject = object
as? SomeOtherSlightlyLongerType
else {
return nil
}
guard
let someObject = object
as? SomeLongLineBreakingType,
let anotherCastedObject = object
as? SomeOtherSlightlyLongerType
else {
return nil
}
guard
let someCastedObject = someFunc(
foo, bar, baz, quxxe, far, fab, faz),
let anotherCastedObject = object
as? SomeOtherSlightlyLongerType
else {
return nil
}
"""

assertPrettyPrintEqual(input: input, expected: expected, linelength: 40)
}
}
47 changes: 47 additions & 0 deletions Tests/SwiftFormatPrettyPrintTests/IfStmtTests.swift
Expand Up @@ -216,6 +216,53 @@ public class IfStmtTests: PrettyPrintTestCase {
assertPrettyPrintEqual(input: input, expected: expected, linelength: 44)
}

public func testContinuationLineBreakIndentation() {
let input =
"""
if let someObject = object as? Int,
let anotherCastedObject = object as? SomeOtherSlightlyLongerType,
let thirdObject = object as? Int {
return nil
}
if let someObject = object as? SomeLongLineBreakingType,
let anotherCastedObject = object as? SomeOtherSlightlyLongerType {
return nil
}
if let someCastedObject = someFunc(foo, bar, baz, quxxe, far, fab, faz),
let anotherCastedObject = object as? SomeOtherSlightlyLongerType {
return nil
}
"""

let expected =
"""
if let someObject = object as? Int,
let anotherCastedObject = object
as? SomeOtherSlightlyLongerType,
let thirdObject = object as? Int
{
return nil
}
if let someObject = object
as? SomeLongLineBreakingType,
let anotherCastedObject = object
as? SomeOtherSlightlyLongerType
{
return nil
}
if let someCastedObject = someFunc(
foo, bar, baz, quxxe, far, fab, faz),
let anotherCastedObject = object
as? SomeOtherSlightlyLongerType
{
return nil
}
"""

assertPrettyPrintEqual(input: input, expected: expected, linelength: 50)
}

public func testHangingOpenBreakIsTreatedLikeContinuation() {
let input =
"""
Expand Down
13 changes: 13 additions & 0 deletions Tests/SwiftFormatPrettyPrintTests/XCTestManifests.swift
Expand Up @@ -249,6 +249,7 @@ extension GuardStmtTests {
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__GuardStmtTests = [
("testContinuationLineBreaking", testContinuationLineBreaking),
("testGuardStatement", testGuardStatement),
("testGuardWithFuncCall", testGuardWithFuncCall),
("testOpenBraceIsGluedToElseKeyword", testOpenBraceIsGluedToElseKeyword),
Expand All @@ -270,6 +271,7 @@ extension IfStmtTests {
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__IfStmtTests = [
("testContinuationLineBreakIndentation", testContinuationLineBreakIndentation),
("testHangingOpenBreakIsTreatedLikeContinuation", testHangingOpenBreakIsTreatedLikeContinuation),
("testIfElseStatement_breakBeforeElse", testIfElseStatement_breakBeforeElse),
("testIfElseStatement_noBreakBeforeElse", testIfElseStatement_noBreakBeforeElse),
Expand Down Expand Up @@ -377,6 +379,16 @@ extension RepeatStmtTests {
]
}

extension SemiColonTypeTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__SemiColonTypeTests = [
("testNoSemicolon", testNoSemicolon),
("testSemicolon", testSemicolon),
]
}

extension SomeTypeTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
Expand Down Expand Up @@ -567,6 +579,7 @@ public func __allTests() -> [XCTestCaseEntry] {
testCase(OperatorDeclTests.__allTests__OperatorDeclTests),
testCase(ProtocolDeclTests.__allTests__ProtocolDeclTests),
testCase(RepeatStmtTests.__allTests__RepeatStmtTests),
testCase(SemiColonTypeTests.__allTests__SemiColonTypeTests),
testCase(SomeTypeTests.__allTests__SomeTypeTests),
testCase(StringTests.__allTests__StringTests),
testCase(StructDeclTests.__allTests__StructDeclTests),
Expand Down

0 comments on commit d483917

Please sign in to comment.