Skip to content

Commit 653ae4b

Browse files
committed
Fix indentation of nested multi-line string literals
1 parent db662d8 commit 653ae4b

File tree

2 files changed

+79
-6
lines changed

2 files changed

+79
-6
lines changed

Sources/SwiftBasicFormat/BasicFormat.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,18 @@ open class BasicFormat: SyntaxRewriter {
498498
}
499499
}
500500

501-
let isEmptyLine = token.leadingTrivia.isEmpty && leadingTriviaIsFollowedByNewline
502-
if leadingTrivia.indentation(isOnNewline: isInitialToken || previousTokenWillEndWithNewline) == [] && !isEmptyLine {
501+
let isStringSegment: Bool
502+
if case .stringSegment = token.tokenKind {
503+
isStringSegment = true
504+
} else {
505+
isStringSegment = false
506+
}
507+
if leadingTrivia.indentation(isOnNewline: isInitialToken || previousTokenWillEndWithNewline) == [] && !isStringSegment {
503508
// If the token starts on a new line and does not have indentation, this
504-
// is the last non-indented token. Store its indentation level
509+
// is the last non-indented token. Store its indentation level.
510+
// But never consider string segments as anchor points since you can’t
511+
// indent individual lines of a multi-line string literals without breaking
512+
// their integrity.
505513
anchorPoints[token] = currentIndentationLevel
506514
}
507515

@@ -529,14 +537,17 @@ open class BasicFormat: SyntaxRewriter {
529537
var leadingTriviaIndentation = self.currentIndentationLevel
530538
var trailingTriviaIndentation = self.currentIndentationLevel
531539

532-
// If the trivia contain user-defined indentation, find their anchor point
540+
// If the trivia contains user-defined indentation, find their anchor point
533541
// and indent the token relative to that anchor point.
534-
if leadingTrivia.containsIndentation(isOnNewline: previousTokenWillEndWithNewline),
542+
// Always indent string segments relative to their anchor point because
543+
// their indentation has structural meaning and we just want to maintain
544+
// what the user wrote.
545+
if leadingTrivia.containsIndentation(isOnNewline: previousTokenWillEndWithNewline) || isStringSegment,
535546
let anchorPointIndentation = self.anchorPointIndentation(for: token)
536547
{
537548
leadingTriviaIndentation = anchorPointIndentation
538549
}
539-
if combinedTrailingTrivia.containsIndentation(isOnNewline: previousTokenWillEndWithNewline),
550+
if combinedTrailingTrivia.containsIndentation(isOnNewline: previousTokenWillEndWithNewline) || isStringSegment,
540551
let anchorPointIndentation = self.anchorPointIndentation(for: token)
541552
{
542553
trailingTriviaIndentation = anchorPointIndentation

Tests/SwiftBasicFormatTest/BasicFormatTests.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,68 @@ final class BasicFormatTest: XCTestCase {
285285
assertFormatted(source: source, expected: source)
286286
}
287287

288+
func testIndentNestedMultilineStringLiterals() throws {
289+
let stringLiteral: ExprSyntax = #"""
290+
"""
291+
292+
\("""
293+
First Line
294+
""")
295+
"""
296+
"""#
297+
298+
assertFormatted(tree: stringLiteral, expected: stringLiteral.description)
299+
300+
let tree = try FunctionDeclSyntax("func test()") {
301+
stringLiteral
302+
}
303+
304+
assertFormatted(
305+
tree: tree,
306+
expected: #"""
307+
func test() {
308+
"""
309+
310+
\("""
311+
First Line
312+
""")
313+
"""
314+
}
315+
"""#
316+
)
317+
}
318+
319+
func testFooIndentNestedMultilineStringLiterals() throws {
320+
let stringLiteral: ExprSyntax = #"""
321+
_ = """
322+
323+
\("""
324+
First Line
325+
""")
326+
"""
327+
"""#
328+
329+
assertFormatted(tree: stringLiteral, expected: stringLiteral.description)
330+
331+
let tree = try FunctionDeclSyntax("func test()") {
332+
stringLiteral
333+
}
334+
335+
assertFormatted(
336+
tree: tree,
337+
expected: #"""
338+
func test() {
339+
_ = """
340+
341+
\("""
342+
First Line
343+
""")
344+
"""
345+
}
346+
"""#
347+
)
348+
}
349+
288350
func testNestedUserDefinedIndentation() {
289351
assertFormatted(
290352
source: """

0 commit comments

Comments
 (0)