Skip to content

Commit b855621

Browse files
committed
Add option to add a newline between 2 adjacent attributes
Add an option that inserts hard line breaks between adjacent attributes. Closes #773
1 parent b268009 commit b855621

File tree

4 files changed

+44
-2
lines changed

4 files changed

+44
-2
lines changed

Sources/SwiftFormat/API/Configuration+Default.swift

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extension Configuration {
3030
self.lineBreakBeforeControlFlowKeywords = false
3131
self.lineBreakBeforeEachArgument = false
3232
self.lineBreakBeforeEachGenericRequirement = false
33+
self.lineBreakBetweenAttributes = false
3334
self.prioritizeKeepingFunctionOutputTogether = false
3435
self.indentConditionalCompilationBlocks = true
3536
self.lineBreakAroundMultilineExpressionChainComponents = false

Sources/SwiftFormat/API/Configuration.swift

+8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public struct Configuration: Codable, Equatable {
3434
case lineBreakBeforeControlFlowKeywords
3535
case lineBreakBeforeEachArgument
3636
case lineBreakBeforeEachGenericRequirement
37+
case lineBreakBetweenAttributes
3738
case prioritizeKeepingFunctionOutputTogether
3839
case indentConditionalCompilationBlocks
3940
case lineBreakAroundMultilineExpressionChainComponents
@@ -111,6 +112,9 @@ public struct Configuration: Codable, Equatable {
111112
/// horizontally first, with line breaks only being fired when the line length would be exceeded.
112113
public var lineBreakBeforeEachGenericRequirement: Bool
113114

115+
/// If true, a line break will be added between adjacent attributes.
116+
public var lineBreakBetweenAttributes: Bool
117+
114118
/// Determines if function-like declaration outputs should be prioritized to be together with the
115119
/// function signature right (closing) parenthesis.
116120
///
@@ -243,6 +247,9 @@ public struct Configuration: Codable, Equatable {
243247
self.lineBreakBeforeEachGenericRequirement =
244248
try container.decodeIfPresent(Bool.self, forKey: .lineBreakBeforeEachGenericRequirement)
245249
?? defaults.lineBreakBeforeEachGenericRequirement
250+
self.lineBreakBetweenAttributes =
251+
try container.decodeIfPresent(Bool.self, forKey: .lineBreakBetweenAttributes)
252+
?? defaults.lineBreakBetweenAttributes
246253
self.prioritizeKeepingFunctionOutputTogether =
247254
try container.decodeIfPresent(Bool.self, forKey: .prioritizeKeepingFunctionOutputTogether)
248255
?? defaults.prioritizeKeepingFunctionOutputTogether
@@ -296,6 +303,7 @@ public struct Configuration: Codable, Equatable {
296303
try container.encode(lineBreakBeforeEachGenericRequirement, forKey: .lineBreakBeforeEachGenericRequirement)
297304
try container.encode(prioritizeKeepingFunctionOutputTogether, forKey: .prioritizeKeepingFunctionOutputTogether)
298305
try container.encode(indentConditionalCompilationBlocks, forKey: .indentConditionalCompilationBlocks)
306+
try container.encode(lineBreakBetweenAttributes, forKey: .lineBreakBetweenAttributes)
299307
try container.encode(
300308
lineBreakAroundMultilineExpressionChainComponents,
301309
forKey: .lineBreakAroundMultilineExpressionChainComponents)

Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -2893,11 +2893,12 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
28932893
suppressFinalBreak: Bool = false
28942894
) {
28952895
if let attributes = attributes {
2896+
let behavior: NewlineBehavior = config.lineBreakBetweenAttributes ? .hard : .elective
28962897
before(attributes.firstToken(viewMode: .sourceAccurate), tokens: .open)
2897-
insertTokens(.break(.same), betweenElementsOf: attributes)
2898+
insertTokens(.break(.same, newlines: behavior), betweenElementsOf: attributes)
28982899
var afterAttributeTokens = [Token.close]
28992900
if !suppressFinalBreak {
2900-
afterAttributeTokens.append(.break(.same))
2901+
afterAttributeTokens.append(.break(.same, newlines: behavior))
29012902
}
29022903
after(attributes.lastToken(viewMode: .sourceAccurate), tokens: afterAttributeTokens)
29032904
}

Tests/SwiftFormatTests/PrettyPrint/AttributeTests.swift

+32
Original file line numberDiff line numberDiff line change
@@ -468,4 +468,36 @@ final class AttributeTests: PrettyPrintTestCase {
468468

469469
assertPrettyPrintEqual(input: input, expected: expected, linelength: 100)
470470
}
471+
472+
func testLineBreakBetweenAttributes() {
473+
let input =
474+
"""
475+
@available(iOS 16.0, *) @available(macOS 14.0, *)
476+
@available(tvOS 16.0, *) @frozen
477+
struct X {
478+
@available(iOS 17.0, *) @available(macOS 15.0, *)
479+
@MainActor @discardableResult
480+
func f() -> Int { 0 }
481+
}
482+
"""
483+
484+
let expected =
485+
"""
486+
@available(iOS 16.0, *)
487+
@available(macOS 14.0, *)
488+
@available(tvOS 16.0, *)
489+
@frozen
490+
struct X {
491+
@available(iOS 17.0, *)
492+
@available(macOS 15.0, *)
493+
@MainActor
494+
@discardableResult
495+
func f() -> Int { 0 }
496+
}
497+
498+
"""
499+
var configuration = Configuration.forTesting
500+
configuration.lineBreakBetweenAttributes = true
501+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 80, configuration: configuration)
502+
}
471503
}

0 commit comments

Comments
 (0)