Skip to content

Commit 5a0ac33

Browse files
authored
Merge pull request #804 from TTOzzi/allowWhitespaceOnlyLines
Add a configuration to preserve whitespace on lines containing only whitespace
2 parents 2830399 + 8c68ec3 commit 5a0ac33

File tree

8 files changed

+339
-4
lines changed

8 files changed

+339
-4
lines changed

Documentation/Configuration.md

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ top-level keys and values:
9494

9595
* `multiElementCollectionTrailingCommas` _(boolean)_: Determines whether multi-element collection literals should have trailing commas.
9696
Defaults to `true`.
97+
98+
* `indentBlankLines` _(boolean)_: Determines whether blank lines should be modified
99+
to match the current indentation. When this setting is true, blank lines will be modified
100+
to match the indentation level, adding indentation whether or not there is existing whitespace.
101+
When false (the default), all whitespace in blank lines will be completely removed.
97102

98103
> TODO: Add support for enabling/disabling specific syntax transformations in
99104
> the pipeline.

Sources/SwiftFormat/API/Configuration+Default.swift

+1
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@ extension Configuration {
4141
self.noAssignmentInExpressions = NoAssignmentInExpressionsConfiguration()
4242
self.multiElementCollectionTrailingCommas = true
4343
self.reflowMultilineStringLiterals = .never
44+
self.indentBlankLines = false
4445
}
4546
}

Sources/SwiftFormat/API/Configuration.swift

+14
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public struct Configuration: Codable, Equatable {
4646
case noAssignmentInExpressions
4747
case multiElementCollectionTrailingCommas
4848
case reflowMultilineStringLiterals
49+
case indentBlankLines
4950
}
5051

5152
/// A dictionary containing the default enabled/disabled states of rules, keyed by the rules'
@@ -260,6 +261,13 @@ public struct Configuration: Codable, Equatable {
260261

261262
public var reflowMultilineStringLiterals: MultilineStringReflowBehavior
262263

264+
/// Determines whether to add indentation whitespace to blank lines or remove it entirely.
265+
///
266+
/// If true, blank lines will be modified to match the current indentation level:
267+
/// if they contain whitespace, the existing whitespace will be adjusted, and if they are empty, spaces will be added to match the indentation.
268+
/// If false (the default), the whitespace in blank lines will be removed entirely.
269+
public var indentBlankLines: Bool
270+
263271
/// Creates a new `Configuration` by loading it from a configuration file.
264272
public init(contentsOf url: URL) throws {
265273
let data = try Data(contentsOf: url)
@@ -368,6 +376,12 @@ public struct Configuration: Codable, Equatable {
368376
self.reflowMultilineStringLiterals =
369377
try container.decodeIfPresent(MultilineStringReflowBehavior.self, forKey: .reflowMultilineStringLiterals)
370378
?? defaults.reflowMultilineStringLiterals
379+
self.indentBlankLines =
380+
try container.decodeIfPresent(
381+
Bool.self,
382+
forKey: .indentBlankLines
383+
)
384+
?? defaults.indentBlankLines
371385

372386
// If the `rules` key is not present at all, default it to the built-in set
373387
// so that the behavior is the same as if the configuration had been

Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ public class PrettyPrinter {
441441
outputBuffer.enqueueSpaces(size)
442442
outputBuffer.write("\\")
443443
}
444-
outputBuffer.writeNewlines(newline)
444+
outputBuffer.writeNewlines(newline, shouldIndentBlankLines: configuration.indentBlankLines)
445445
lastBreak = true
446446
} else {
447447
if outputBuffer.isAtStartOfLine {
@@ -458,6 +458,10 @@ public class PrettyPrinter {
458458

459459
// Print out the number of spaces according to the size, and adjust spaceRemaining.
460460
case .space(let size, _):
461+
if configuration.indentBlankLines, outputBuffer.isAtStartOfLine {
462+
// An empty string write is needed to add line-leading indentation that matches the current indentation on a line that contains only whitespaces.
463+
outputBuffer.write("")
464+
}
461465
outputBuffer.enqueueSpaces(size)
462466

463467
// Print any indentation required, followed by the text content of the syntax token.

Sources/SwiftFormat/PrettyPrint/PrettyPrintBuffer.swift

+12-3
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,11 @@ struct PrettyPrintBuffer {
7070
/// subtract the previously written newlines during the second call so that we end up with the
7171
/// correct number overall.
7272
///
73-
/// - Parameter newlines: The number and type of newlines to write.
74-
mutating func writeNewlines(_ newlines: NewlineBehavior) {
73+
/// - Parameters:
74+
/// - newlines: The number and type of newlines to write.
75+
/// - shouldIndentBlankLines: A Boolean value indicating whether to insert spaces
76+
/// for blank lines based on the current indentation level.
77+
mutating func writeNewlines(_ newlines: NewlineBehavior, shouldIndentBlankLines: Bool) {
7578
let numberToPrint: Int
7679
switch newlines {
7780
case .elective:
@@ -86,7 +89,13 @@ struct PrettyPrintBuffer {
8689
}
8790

8891
guard numberToPrint > 0 else { return }
89-
writeRaw(String(repeating: "\n", count: numberToPrint))
92+
for number in 0..<numberToPrint {
93+
if shouldIndentBlankLines, number >= 1 {
94+
writeRaw(currentIndentation.indentation())
95+
}
96+
writeRaw("\n")
97+
}
98+
9099
lineNumber += numberToPrint
91100
isAtStartOfLine = true
92101
consecutiveNewlineCount += numberToPrint

Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift

+7
Original file line numberDiff line numberDiff line change
@@ -3521,6 +3521,12 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
35213521
leadingIndent = nil
35223522

35233523
case .newlines(let count), .carriageReturns(let count), .carriageReturnLineFeeds(let count):
3524+
if config.indentBlankLines,
3525+
let leadingIndent, leadingIndent.count > 0
3526+
{
3527+
requiresNextNewline = true
3528+
}
3529+
35243530
leadingIndent = .spaces(0)
35253531
guard !isStartOfFile else { break }
35263532

@@ -3557,6 +3563,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
35573563
case .spaces(let n):
35583564
guard leadingIndent == .spaces(0) else { break }
35593565
leadingIndent = .spaces(n)
3566+
35603567
case .tabs(let n):
35613568
guard leadingIndent == .spaces(0) else { break }
35623569
leadingIndent = .tabs(n)

Sources/_SwiftFormatTestSupport/Configuration+Testing.swift

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extension Configuration {
4141
config.spacesAroundRangeFormationOperators = false
4242
config.noAssignmentInExpressions = NoAssignmentInExpressionsConfiguration()
4343
config.multiElementCollectionTrailingCommas = true
44+
config.indentBlankLines = false
4445
return config
4546
}
4647
}

0 commit comments

Comments
 (0)