From ce717a9d9c159bfcd6aded78b5089daf2f35237a Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Sat, 6 Nov 2021 15:36:52 +0000 Subject: [PATCH] Fix indenting of wrapped member after #endif --- Sources/Rules.swift | 4 ++-- Sources/Tokenizer.swift | 3 ++- Tests/RulesTests+Indentation.swift | 15 ++++++++++++++ Tests/TokenizerTests.swift | 33 ++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Sources/Rules.swift b/Sources/Rules.swift index f98fa19a7..48290687e 100644 --- a/Sources/Rules.swift +++ b/Sources/Rules.swift @@ -1605,7 +1605,7 @@ public struct _FormatRules { var lineStart = formatter.startOfLine(at: lastNonSpaceOrLinebreakIndex, excludingIndent: true) let startToken = formatter.token(at: lineStart) if let startToken = startToken, [ - .startOfScope("#if"), .keyword("#else"), .keyword("#elseif") + .startOfScope("#if"), .keyword("#else"), .keyword("#elseif"), .endOfScope("#endif") ].contains(startToken) { if let index = formatter.index(of: .nonSpaceOrLinebreak, before: lineStart) { lastNonSpaceOrLinebreakIndex = index @@ -1613,7 +1613,7 @@ public struct _FormatRules { } } if formatter.token(at: lineStart) == .operator(".", .infix), - [.keyword("#else"), .keyword("#elseif")].contains(startToken) + [.keyword("#else"), .keyword("#elseif"), .endOfScope("#endif")].contains(startToken) { indent = formatter.indentForLine(at: lineStart) } else if formatter.tokens[lineStart ..< lastNonSpaceOrLinebreakIndex].allSatisfy({ diff --git a/Sources/Tokenizer.swift b/Sources/Tokenizer.swift index 78f4b2eb9..682e19143 100644 --- a/Sources/Tokenizer.swift +++ b/Sources/Tokenizer.swift @@ -1427,7 +1427,8 @@ public func tokenize(_ source: String) -> [Token] { case ":", "=", "->": type = .infix case ".": - type = prevNonSpaceToken.isLvalue || prevNonSpaceToken.isAttribute ? .infix : .prefix + type = prevNonSpaceToken.isLvalue || prevNonSpaceToken.isAttribute || + prevNonSpaceToken == .endOfScope("#endif") ? .infix : .prefix case "?": if prevToken.isSpaceOrCommentOrLinebreak { // ? is a ternary operator, treat it as the start of a scope diff --git a/Tests/RulesTests+Indentation.swift b/Tests/RulesTests+Indentation.swift index 694915537..d04ee435c 100644 --- a/Tests/RulesTests+Indentation.swift +++ b/Tests/RulesTests+Indentation.swift @@ -2291,6 +2291,21 @@ class IndentTests: RulesTests { testFormatting(for: input, output, rule: FormatRules.indent) } + func testIndentIfDefPostfixMemberSyntax2() { + let input = """ + class Bar { + func foo() { + Text("Hello") + #if os(iOS) + .font(.largeTitle) + #endif + .color(.red) + } + } + """ + testFormatting(for: input, rule: FormatRules.indent) + } + // indent #if/#else/#elseif/#endif (mode: noindent) func testIfEndifNoIndenting() { diff --git a/Tests/TokenizerTests.swift b/Tests/TokenizerTests.swift index ab9dfe09f..c2f299f81 100644 --- a/Tests/TokenizerTests.swift +++ b/Tests/TokenizerTests.swift @@ -3685,6 +3685,39 @@ class TokenizerTests: XCTestCase { XCTAssertEqual(tokenize(input), output) } + func testIfdefPrefixDot() { + let input = """ + foo + #if bar + .bar + #else + .baz + #endif + .quux + """ + let output: [Token] = [ + .identifier("foo"), + .linebreak("\n", 1), + .startOfScope("#if"), + .space(" "), + .identifier("bar"), + .linebreak("\n", 2), + .operator(".", .infix), + .identifier("bar"), + .linebreak("\n", 3), + .keyword("#else"), + .linebreak("\n", 4), + .operator(".", .infix), + .identifier("baz"), + .linebreak("\n", 5), + .endOfScope("#endif"), + .linebreak("\n", 6), + .operator(".", .infix), + .identifier("quux"), + ] + XCTAssertEqual(tokenize(input), output) + } + // MARK: linebreaks func testLF() {