diff --git a/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift b/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift index 391d6e26..e8f55bdb 100644 --- a/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift +++ b/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift @@ -1307,7 +1307,15 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor { before(tokenToOpenWith.nextToken, tokens: .break(breakKindClose, newlines: .soft), .close) } - if let condition = node.condition { + if isNestedInPostfixIfConfig(node: Syntax(node)) { + before( + node.firstToken, + tokens: [ + .printerControl(kind: .enableBreaking), + .break(.reset), + ] + ) + } else if let condition = node.condition { before(condition.firstToken, tokens: .printerControl(kind: .disableBreaking)) after( condition.lastToken, @@ -3459,7 +3467,11 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor { if let calledMemberAccessExpr = calledExpression.as(MemberAccessExprSyntax.self) { if calledMemberAccessExpr.base != nil { - before(calledMemberAccessExpr.dot, tokens: [.break(.contextual, size: 0)]) + if isNestedInPostfixIfConfig(node: Syntax(calledMemberAccessExpr)) { + before(calledMemberAccessExpr.dot, tokens: [.break(.same, size: 0)]) + } else { + before(calledMemberAccessExpr.dot, tokens: [.break(.contextual, size: 0)]) + } } before(calledMemberAccessExpr.dot, tokens: beforeTokens) after(expr.lastToken, tokens: afterTokens) @@ -3484,6 +3496,20 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor { } } +private func isNestedInPostfixIfConfig(node: Syntax) -> Bool { + var this: Syntax? = node + + while this?.parent != nil { + if this?.parent?.is(PostfixIfConfigExprSyntax.self) == true { + return true + } + + this = this?.parent + } + + return false +} + extension Syntax { /// Creates a pretty-printable token stream for the provided Syntax node. func makeTokenStream(configuration: Configuration, operatorContext: OperatorContext) -> [Token] { diff --git a/Tests/SwiftFormatPrettyPrintTests/IfConfigTests.swift b/Tests/SwiftFormatPrettyPrintTests/IfConfigTests.swift index 71fab97b..9547816f 100644 --- a/Tests/SwiftFormatPrettyPrintTests/IfConfigTests.swift +++ b/Tests/SwiftFormatPrettyPrintTests/IfConfigTests.swift @@ -230,4 +230,164 @@ final class IfConfigTests: PrettyPrintTestCase { assertPrettyPrintEqual(input: input, expected: expected, linelength: 40) } + + func testPostfixPoundIfAfterParentheses() { + let input = + """ + VStack { + Text("something") + #if os(iOS) + .iOSSpecificModifier() + #endif + .commonModifier() + } + """ + + let expected = + """ + VStack { + Text("something") + #if os(iOS) + .iOSSpecificModifier() + #endif + .commonModifier() + } + + """ + + assertPrettyPrintEqual(input: input, expected: expected, linelength: 45) + } + + func testPostfixPoundIfAfterParenthesesMultipleMembers() { + let input = + """ + VStack { + Text("something") + #if os(iOS) + .iOSSpecificModifier() + .anotherModifier() + .anotherAnotherModifier() + #endif + .commonModifier() + .anotherCommonModifier() + } + """ + + let expected = + """ + VStack { + Text("something") + #if os(iOS) + .iOSSpecificModifier() + .anotherModifier() + .anotherAnotherModifier() + #endif + .commonModifier() + .anotherCommonModifier() + } + + """ + + assertPrettyPrintEqual(input: input, expected: expected, linelength: 45) + } + + func testPostfixPoundIfNested() { + let input = + """ + VStack { + Text("something") + #if os(iOS) || os(watchOS) + #if os(iOS) + .iOSModifier() + #else + .watchOSModifier() + #endif + .iOSAndWatchOSModifier() + #endif + } + """ + + let expected = + """ + VStack { + Text("something") + #if os(iOS) || os(watchOS) + #if os(iOS) + .iOSModifier() + #else + .watchOSModifier() + #endif + .iOSAndWatchOSModifier() + #endif + } + + """ + + assertPrettyPrintEqual(input: input, expected: expected, linelength: 45) + } + + + func testPostfixPoundIfAfterVariables() { + let input = + """ + VStack { + textView + #if os(iOS) + .iOSSpecificModifier() + #endif + .commonModifier() + } + """ + + let expected = + """ + VStack { + textView + #if os(iOS) + .iOSSpecificModifier() + #endif + .commonModifier() + } + + """ + + assertPrettyPrintEqual(input: input, expected: expected, linelength: 45) + } + + func testPostfixPoundIfAfterClosingBrace() { + let input = + """ + HStack { + Toggle(isOn: binding) { + Text("Some text") + } + #if !os(tvOS) + .toggleStyle(SwitchToggleStyle(tint: Color.blue)) + #endif + .accessibilityValue( + binding.wrappedValue == true ? "On" : "Off" + ) + } + """ + + let expected = + """ + HStack { + Toggle(isOn: binding) { + Text("Some text") + } + #if !os(tvOS) + .toggleStyle( + SwitchToggleStyle(tint: Color.blue)) + #endif + .accessibilityValue( + binding.wrappedValue == true + ? "On" : "Off" + ) + } + + """ + + assertPrettyPrintEqual(input: input, expected: expected, linelength: 45) + } }