Skip to content

Commit cbe4886

Browse files
authored
Fix handling of raw multiline string newline-suppressing continuations. (#1041)
1 parent c2b33f2 commit cbe4886

File tree

3 files changed

+58
-13
lines changed

3 files changed

+58
-13
lines changed

Sources/SwiftFormat/Core/Trivia+Convenience.swift

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,19 @@ extension Trivia {
8080
})
8181
}
8282

83-
/// Returns `true` if this trivia contains any backslashes (used for multiline string newline
84-
/// suppression).
85-
var containsBackslashes: Bool {
86-
return contains(
87-
where: {
88-
if case .backslashes = $0 { return true }
89-
return false
90-
})
83+
/// Returns the prefix of this trivia that corresponds to the backslash and pound signs used to
84+
/// represent a non-line-break continuation of a multiline string, or nil if the trivia does not
85+
/// represent such a continuation.
86+
var multilineStringContinuation: String? {
87+
var result = ""
88+
for piece in pieces {
89+
switch piece {
90+
case .backslashes, .pounds:
91+
piece.write(to: &result)
92+
default:
93+
break
94+
}
95+
}
96+
return result.isEmpty ? nil : result
9197
}
9298
}

Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,11 +2637,13 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
26372637
emitSegmentTextTokens(segmentText[...])
26382638
}
26392639

2640-
if node.trailingTrivia.containsBackslashes && !config.reflowMultilineStringLiterals.isAlways {
2641-
// Segments with trailing backslashes won't end with a literal newline; the backslash is
2642-
// considered trivia. To preserve the original text and wrapping, we need to manually render
2643-
// the backslash and a break into the token stream.
2644-
appendToken(.syntax("\\"))
2640+
if !config.reflowMultilineStringLiterals.isAlways,
2641+
let continuation = node.trailingTrivia.multilineStringContinuation
2642+
{
2643+
// Segments with trailing backslashes won't end with a literal newline; the backslash and any
2644+
// `#` delimiters for raw strings are considered trivia. To preserve the original text and
2645+
// wrapping, we need to manually render them break into the token stream.
2646+
appendToken(.syntax(continuation))
26452647
appendToken(.break(breakKind, newlines: .hard(count: 1)))
26462648
}
26472649
return .skipChildren

Tests/SwiftFormatTests/PrettyPrint/StringTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,4 +739,41 @@ final class StringTests: PrettyPrintTestCase {
739739

740740
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 20)
741741
}
742+
743+
func testMultilineStringWithContinuations() {
744+
let input =
745+
##"""
746+
let someString =
747+
"""
748+
lines \
749+
\nare \
750+
short.
751+
"""
752+
let someString =
753+
#"""
754+
lines \#
755+
\#nare \#
756+
short.
757+
"""#
758+
"""##
759+
760+
let expected =
761+
##"""
762+
let someString =
763+
"""
764+
lines \
765+
\nare \
766+
short.
767+
"""
768+
let someString =
769+
#"""
770+
lines \#
771+
\#nare \#
772+
short.
773+
"""#
774+
775+
"""##
776+
777+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 30)
778+
}
742779
}

0 commit comments

Comments
 (0)