diff --git a/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift b/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift index 3832d6874..e7d773427 100644 --- a/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift +++ b/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift @@ -1492,7 +1492,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor { override func visit(_ node: IfConfigDeclSyntax) -> SyntaxVisitorContinueKind { // there has to be a break after an #endif - after(node.poundEndif, tokens: .break(.same, size: 0)) + after(node.poundEndif, tokens: .break(.same, size: 0, newlines: .soft)) return .visitChildren } @@ -1951,17 +1951,28 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor { } override func visit(_ node: ImportDeclSyntax) -> SyntaxVisitorContinueKind { - // Import declarations should never be wrapped. - before( - node.firstToken(viewMode: .sourceAccurate), - tokens: .printerControl(kind: .disableBreaking(allowDiscretionary: false)) - ) + // Import declarations ignore wrapping when it is safe to do so (no #if constructs) + let isSafeToIgnoreBreaking = !node.attributes.contains(where: { element in + return element.is(IfConfigDeclSyntax.self) + }) + + if isSafeToIgnoreBreaking { + before( + node.firstToken(viewMode: .sourceAccurate), + tokens: .printerControl(kind: .disableBreaking(allowDiscretionary: false)) + ) + } arrangeAttributeList(node.attributes) after(node.importKeyword, tokens: .space) after(node.importKindSpecifier, tokens: .space) - after(node.lastToken(viewMode: .sourceAccurate), tokens: .printerControl(kind: .enableBreaking)) + if isSafeToIgnoreBreaking { + after( + node.lastToken(viewMode: .sourceAccurate), + tokens: .printerControl(kind: .enableBreaking) + ) + } return .visitChildren } diff --git a/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift b/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift index 1b725a94b..48fccc5e0 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift @@ -383,10 +383,10 @@ final class IfConfigTests: PrettyPrintTestCase { .toggleStyle( SwitchToggleStyle(tint: Color.blue)) #endif - .accessibilityValue( - binding.wrappedValue == true - ? "On" : "Off" - ) + .accessibilityValue( + binding.wrappedValue == true + ? "On" : "Off" + ) } """ @@ -482,7 +482,7 @@ final class IfConfigTests: PrettyPrintTestCase { #if os(iOS) .iOSSpecificModifier() #endif - .commonModifier() + .commonModifier() """ @@ -510,7 +510,7 @@ final class IfConfigTests: PrettyPrintTestCase { #if os(iOS) .iOSSpecificModifier() #endif - .commonModifier() + .commonModifier() """ @@ -557,4 +557,24 @@ final class IfConfigTests: PrettyPrintTestCase { configuration.indentConditionalCompilationBlocks = false assertPrettyPrintEqual(input: input, expected: input, linelength: 45, configuration: configuration) } + + func testIfConfigDeclPartOfImport() { + let input = + """ + #if os(Foo) + @_spiOnly + #elseif os(Bar) + @_spiOnly + #else + @_spiOnly + #endif + @_spi(Foo) import Foundation + + """ + var configuration = Configuration.forTesting + configuration.respectsExistingLineBreaks = false + configuration.indentConditionalCompilationBlocks = false + assertPrettyPrintEqual(input: input, expected: input, linelength: 80, configuration: configuration) + + } }