Skip to content

Commit 3d4b36c

Browse files
consider queued newlines when wrapping elements in MarkupFormatter (swiftlang#116)
rdar://106915293
1 parent 07da205 commit 3d4b36c

File tree

2 files changed

+89
-6
lines changed

2 files changed

+89
-6
lines changed

Sources/Markdown/Walker/Walkers/MarkupFormatter.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,19 @@ public struct MarkupFormatter: MarkupWalker {
345345
/// The length of the last line.
346346
var lastLineLength = 0
347347

348-
/// The current line number.
348+
/// The line number of the most recently printed content.
349+
///
350+
/// This is updated in `addressPendingNewlines(for:)` when line breaks are printed.
349351
var lineNumber = 0
352+
353+
/// The "effective" line number, taking into account any queued newlines which have not
354+
/// been printed.
355+
///
356+
/// This property allows line number comparisons between different formatter states to
357+
/// accommodate queued soft line breaks as well as printed content.
358+
var effectiveLineNumber: Int {
359+
lineNumber + queuedNewlines
360+
}
350361
}
351362

352363
/// The state of the formatter.
@@ -769,7 +780,7 @@ public struct MarkupFormatter: MarkupWalker {
769780
// If printing with automatic wrapping still put us over the line,
770781
// prefer to print it on the next line to give as much opportunity
771782
// to keep the contents on one line.
772-
if inlineCode.indexInParent > 0 && (isOverPreferredLineLimit || state.lineNumber > savedState.lineNumber) {
783+
if inlineCode.indexInParent > 0 && (isOverPreferredLineLimit || state.effectiveLineNumber > savedState.effectiveLineNumber) {
773784
restoreState(to: savedState)
774785
queueNewline()
775786
softWrapPrint("`\(inlineCode.code)`", for: inlineCode)
@@ -800,7 +811,7 @@ public struct MarkupFormatter: MarkupWalker {
800811
// Image elements' source URLs can't be split. If wrapping the alt text
801812
// of an image still put us over the line, prefer to print it on the
802813
// next line to give as much opportunity to keep the alt text contents on one line.
803-
if image.indexInParent > 0 && (isOverPreferredLineLimit || state.lineNumber > savedState.lineNumber) {
814+
if image.indexInParent > 0 && (isOverPreferredLineLimit || state.effectiveLineNumber > savedState.effectiveLineNumber) {
804815
restoreState(to: savedState)
805816
queueNewline()
806817
printImage()
@@ -837,7 +848,7 @@ public struct MarkupFormatter: MarkupWalker {
837848
// Link elements' destination URLs can't be split. If wrapping the link text
838849
// of a link still put us over the line, prefer to print it on the
839850
// next line to give as much opportunity to keep the link text contents on one line.
840-
if link.indexInParent > 0 && (isOverPreferredLineLimit || state.lineNumber > savedState.lineNumber) {
851+
if link.indexInParent > 0 && (isOverPreferredLineLimit || state.effectiveLineNumber > savedState.effectiveLineNumber) {
841852
restoreState(to: savedState)
842853
queueNewline()
843854
printRegularLink()
@@ -1133,7 +1144,7 @@ public struct MarkupFormatter: MarkupWalker {
11331144
public mutating func visitInlineAttributes(_ attributes: InlineAttributes) {
11341145
let savedState = state
11351146
func printInlineAttributes() {
1136-
print("[", for: attributes)
1147+
print("^[", for: attributes)
11371148
descendInto(attributes)
11381149
print("](", for: attributes)
11391150
print(attributes.attributes, for: attributes)
@@ -1147,7 +1158,7 @@ public struct MarkupFormatter: MarkupWalker {
11471158
// gets into the realm of JSON formatting which might be out of scope of
11481159
// this formatter. Therefore if exceeded, prefer to print it on the next
11491160
// line to give as much opportunity to keep the attributes on one line.
1150-
if attributes.indexInParent > 0 && (isOverPreferredLineLimit || state.lineNumber > savedState.lineNumber) {
1161+
if attributes.indexInParent > 0 && (isOverPreferredLineLimit || state.effectiveLineNumber > savedState.effectiveLineNumber) {
11511162
restoreState(to: savedState)
11521163
queueNewline()
11531164
printInlineAttributes()

Tests/MarkdownTests/Visitors/MarkupFormatterTests.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,78 @@ class MarkupFormatterSimpleRoundTripTests: XCTestCase {
690690
checkCharacterEquivalence(for: source)
691691
}
692692

693+
func testRoundTripHardBreakWithInlineCode() {
694+
let source = """
695+
This is some text.\(" ")
696+
`This is some code.`
697+
"""
698+
checkRoundTrip(for: source)
699+
checkCharacterEquivalence(for: source)
700+
}
701+
702+
func testRoundTripSoftBreakWithInlineCode() {
703+
let source = """
704+
This is some text.
705+
`This is some code.`
706+
"""
707+
checkRoundTrip(for: source)
708+
checkCharacterEquivalence(for: source)
709+
}
710+
711+
func testRoundTripHardBreakWithImage() {
712+
let source = """
713+
This is some text.\(" ")
714+
![This is an image.](image.png "")
715+
"""
716+
checkRoundTrip(for: source)
717+
checkCharacterEquivalence(for: source)
718+
}
719+
720+
func testRoundTripSoftBreakWithImage() {
721+
let source = """
722+
This is some text.
723+
![This is an image.](image.png "")
724+
"""
725+
checkRoundTrip(for: source)
726+
checkCharacterEquivalence(for: source)
727+
}
728+
729+
func testRoundTripHardBreakWithLink() {
730+
let source = """
731+
This is some text.\(" ")
732+
[This is a link.](https://swift.org)
733+
"""
734+
checkRoundTrip(for: source)
735+
checkCharacterEquivalence(for: source)
736+
}
737+
738+
func testRoundTripSoftBreakWithLink() {
739+
let source = """
740+
This is some text.
741+
[This is a link.](https://swift.org)
742+
"""
743+
checkRoundTrip(for: source)
744+
checkCharacterEquivalence(for: source)
745+
}
746+
747+
func testRoundTripHardBreakWithInlineAttribute() {
748+
let source = """
749+
This is some text.\(" ")
750+
^[This is some attributed text.](rainbow: 'extreme')
751+
"""
752+
checkRoundTrip(for: source)
753+
checkCharacterEquivalence(for: source)
754+
}
755+
756+
func testRoundTripSoftBreakWithInlineAttribute() {
757+
let source = """
758+
This is some text.
759+
^[This is some attributed text.](rainbow: 'extreme')
760+
"""
761+
checkRoundTrip(for: source)
762+
checkCharacterEquivalence(for: source)
763+
}
764+
693765
/// Why not?
694766
func testRoundTripReadMe() throws {
695767
let readMeURL = URL(fileURLWithPath: #file)

0 commit comments

Comments
 (0)