Skip to content

Commit

Permalink
Add option to not indent conditional compilation blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandro-isaza committed Aug 19, 2019
1 parent d483917 commit 5264e9d
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Documentation/Configuration.md
Expand Up @@ -59,6 +59,10 @@ top-level keys and values:
If false (the default), arguments will be laid out horizontally first, with
line breaks only being fired when the line length would be exceeded.

* `indentConditionalCompilationBlocks` _(boolean)_: Determines if
conditional compilation blocks are indented. If this setting is `false` the body
of `#if`, `#elseif`, and `#else` is not indented. Defaults to `true`.

> TODO: Add support for enabling/disabling specific syntax transformations in
> the pipeline.
Expand Down
7 changes: 7 additions & 0 deletions Sources/SwiftFormatConfiguration/Configuration.swift
Expand Up @@ -29,6 +29,7 @@ public class Configuration: Codable {
case blankLineBetweenMembers
case lineBreakBeforeControlFlowKeywords
case lineBreakBeforeEachArgument
case indentConditionalCompilationBlocks
case rules
}

Expand Down Expand Up @@ -87,6 +88,9 @@ public class Configuration: Codable {
/// each argument, forcing the entire argument list to be laid out vertically.
public var lineBreakBeforeEachArgument = false

/// Determines the indentation behavior for `#if`, `#elseif`, and `#else`.
public var indentConditionalCompilationBlocks = true

/// Constructs a Configuration with all default values.
public init() {
self.version = highestSupportedConfigurationVersion
Expand Down Expand Up @@ -129,6 +133,8 @@ public class Configuration: Codable {
?? true
self.lineBreakBeforeEachArgument
= try container.decodeIfPresent(Bool.self, forKey: .lineBreakBeforeEachArgument) ?? true
self.indentConditionalCompilationBlocks
= try container.decodeIfPresent(Bool.self, forKey: .indentConditionalCompilationBlocks) ?? true
self.rules = try container.decodeIfPresent([String: Bool].self, forKey: .rules) ?? [:]
}

Expand All @@ -145,6 +151,7 @@ public class Configuration: Codable {
try container.encode(
lineBreakBeforeControlFlowKeywords, forKey: .lineBreakBeforeControlFlowKeywords)
try container.encode(lineBreakBeforeEachArgument, forKey: .lineBreakBeforeEachArgument)
try container.encode(indentConditionalCompilationBlocks, forKey: .indentConditionalCompilationBlocks)
try container.encode(rules, forKey: .rules)
}
}
Expand Down
16 changes: 13 additions & 3 deletions Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift
Expand Up @@ -843,16 +843,26 @@ private final class TokenStreamCreator: SyntaxVisitor {
preconditionFailure()
}

let breakKindOpen: BreakKind
let breakKindClose: BreakKind
if config.indentConditionalCompilationBlocks {
breakKindOpen = .open
breakKindClose = .close
} else {
breakKindOpen = .same
breakKindClose = .same
}

let tokenToOpenWith = node.condition?.lastToken ?? node.poundKeyword
after(tokenToOpenWith, tokens: .break(.open), .open)
after(tokenToOpenWith, tokens: .break(breakKindOpen), .open)

// Unlike other code blocks, where we may want a single statement to be laid out on the same
// line as a parent construct, the content of an `#if` block must always be on its own line;
// the newline token inserted at the end enforces this.
if let lastElemTok = node.elements.lastToken {
after(lastElemTok, tokens: .break(.close), .newline, .close)
after(lastElemTok, tokens: .break(breakKindClose), .newline, .close)
} else {
before(tokenToOpenWith.nextToken, tokens: .break(.close), .newline, .close)
before(tokenToOpenWith.nextToken, tokens: .break(breakKindClose), .newline, .close)
}
return .visitChildren
}
Expand Down
61 changes: 61 additions & 0 deletions Tests/SwiftFormatPrettyPrintTests/IfConfigTests.swift
@@ -1,3 +1,5 @@
import SwiftFormatConfiguration

public class IfConfigTests: PrettyPrintTestCase {
public func testBasicIfConfig() {
let input =
Expand Down Expand Up @@ -56,6 +58,65 @@ public class IfConfigTests: PrettyPrintTestCase {
assertPrettyPrintEqual(input: input, expected: expected, linelength: 45)
}

public func testIfConfigNoIndentation() {
let input =
"""
#if someCondition
let a = 123
let b = "abc"
#endif
#if someCondition
let a = 123
let b = "abc"
#else
let c = 456
let d = "def"
#endif
#if swift(>=4.0)
print("Stuff")
#endif
#if swift(>=4.0)
print("Stuff")
#elseif compiler(>=3.0)
print("More Stuff")
print("Another Line")
#endif
"""

let expected =
"""
#if someCondition
let a = 123
let b = "abc"
#endif
#if someCondition
let a = 123
let b = "abc"
#else
let c = 456
let d = "def"
#endif
#if swift(>=4.0)
print("Stuff")
#endif
#if swift(>=4.0)
print("Stuff")
#elseif compiler(>=3.0)
print("More Stuff")
print("Another Line")
#endif
"""

let config = Configuration()
config.indentConditionalCompilationBlocks = false
assertPrettyPrintEqual(input: input, expected: expected, linelength: 45, configuration: config)
}

public func testPoundIfAroundMembers() {
let input =
"""
Expand Down

0 comments on commit 5264e9d

Please sign in to comment.