Update blankLinesAroundMark to insert blank line before MARK at start of scope when allowed by blankLinesAtStartOfScope config (#2405)

Co-authored-by: calda <1811727+calda@users.noreply.github.com>
This commit is contained in:
Copilot
2026-02-22 09:52:31 -08:00
committed by Cal Stephens
parent 4980eda912
commit 39bdad4ac3
3 changed files with 90 additions and 7 deletions
+12 -2
View File
@@ -13,7 +13,7 @@ public extension FormatRule {
static let blankLinesAroundMark = FormatRule(
help: "Insert blank line before and after `MARK:` comments.",
options: ["line-after-marks"],
sharedOptions: ["linebreaks"]
sharedOptions: ["linebreaks", "type-blank-lines"]
) { formatter in
formatter.forEachToken { i, token in
guard case let .commentBody(comment) = token, comment.hasPrefix("MARK:"),
@@ -29,8 +29,18 @@ public extension FormatRule {
if formatter.options.insertBlankLines,
let lastIndex = formatter.index(of: .linebreak, before: startIndex),
let lastToken = formatter.last(.nonSpaceOrComment, before: lastIndex),
!lastToken.isLinebreak, lastToken != .startOfScope("{")
!lastToken.isLinebreak
{
if lastToken == .startOfScope("{"),
formatter.options.enabledRules.contains(FormatRule.blankLinesAtStartOfScope.name)
{
// If blankLinesAtStartOfScope is enabled, only insert a blank line if it
// would not be removed by that rule (i.e. in a type body with insert or preserve option)
guard let braceIndex = formatter.index(of: .nonSpaceOrComment, before: lastIndex),
formatter.isStartOfTypeBody(at: braceIndex),
formatter.options.typeBlankLines != .remove
else { return }
}
formatter.insertLinebreak(at: lastIndex)
}
}
+77 -4
View File
@@ -63,7 +63,7 @@ final class BlankLinesAroundMarkTests: XCTestCase {
testFormatting(for: input, output, rule: .blankLinesAroundMark)
}
func testNoInsertBlankLineBeforeMarkAtStartOfScope() {
func testInsertBlankLineBeforeMarkAtStartOfScope() {
let input = """
do {
// MARK: foo
@@ -71,10 +71,21 @@ final class BlankLinesAroundMarkTests: XCTestCase {
let foo = "foo"
}
"""
testFormatting(for: input, rule: .blankLinesAroundMark)
let output = """
do {
// MARK: foo
let foo = "foo"
}
"""
// When only blankLinesAroundMark runs (without blankLinesAtStartOfScope), a blank line is
// inserted before the MARK. The second output (input) represents what happens when all rules
// run together, where blankLinesAtStartOfScope removes the blank line at the start of scope.
testFormatting(for: input, [output, input], rules: [.blankLinesAroundMark])
}
func testNoInsertBlankLineBeforeMarkAtStartOfScopeWithTrailingComment() {
func testInsertBlankLineBeforeMarkAtStartOfScopeWithTrailingComment() {
let input = """
struct Foo { // some comment here
// MARK: bar
@@ -82,7 +93,69 @@ final class BlankLinesAroundMarkTests: XCTestCase {
let string: String
}
"""
testFormatting(for: input, rule: .blankLinesAroundMark)
let output = """
struct Foo { // some comment here
// MARK: bar
let string: String
}
"""
// When only blankLinesAroundMark runs (without blankLinesAtStartOfScope), a blank line is
// inserted before the MARK. The second output (input) represents what happens when all rules
// run together, where blankLinesAtStartOfScope removes the blank line at the start of scope.
testFormatting(for: input, [output, input], rules: [.blankLinesAroundMark])
}
func testNoInsertBlankLineBeforeMarkAtStartOfScopeWhenBlankLinesAtStartOfScopeEnabled() {
let input = """
do {
// MARK: foo
let foo = "foo"
}
"""
testFormatting(for: input, rules: [.blankLinesAroundMark, .blankLinesAtStartOfScope])
}
func testNoInsertBlankLineBeforeMarkAtStartOfTypeBodyWithRemoveOption() {
let input = """
struct Foo {
// MARK: bar
let string: String
}
"""
testFormatting(for: input, rules: [.blankLinesAroundMark, .blankLinesAtStartOfScope])
}
func testInsertBlankLineBeforeMarkAtStartOfTypeBodyWithInsertOption() {
let input = """
struct Foo {
// MARK: bar
let string: String
}
"""
let output = """
struct Foo {
// MARK: bar
let string: String
}
"""
let outputAllRules = """
struct Foo {
// MARK: bar
let string: String
}
"""
let options = FormatOptions(typeBlankLines: .insert)
testFormatting(for: input, [output, outputAllRules], rules: [.blankLinesAroundMark, .blankLinesAtStartOfScope], options: options)
}
func testNoInsertBlankLineAfterMarkAtEndOfScope() {
+1 -1
View File
@@ -2227,7 +2227,7 @@ final class OrganizeDeclarationsTests: XCTestCase {
"""
testFormatting(for: input, output, rule: .organizeDeclarations,
exclude: [.blankLinesAtStartOfScope])
exclude: [.blankLinesAtStartOfScope, .blankLinesAroundMark])
}
func testOrganizeClassDeclarationsIntoCategoriesWithNoBlankLineAfterMark() {