Skip to content

Commit b38f46e

Browse files
Fix TextBuilder stack overflow with many runs (#65)
1 parent 2dc1682 commit b38f46e

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

Sources/Textual/Internal/TextFragment/TextBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ extension Text {
9797
}
9898

9999
self = textValues.reduce(Text(verbatim: "")) { partialResult, text in
100-
Text("\(partialResult)\(text)")
100+
partialResult + text
101101
}
102102
}
103103

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#if os(macOS)
2+
import SwiftUI
3+
import Testing
4+
5+
@testable import Textual
6+
7+
@MainActor
8+
struct TextBuilderTests {
9+
@Test func renderingManyAttributedRunsDoesNotOverflowStack() {
10+
let renderer = ImageRenderer(
11+
content: TextFragment(Self.attributedStringWithManyRuns(count: 2_500))
12+
.frame(width: 320)
13+
.fixedSize(horizontal: false, vertical: true)
14+
.coordinateSpace(.textContainer)
15+
)
16+
renderer.proposedSize = .init(width: 320, height: 4_000)
17+
18+
#expect(renderer.nsImage != nil)
19+
}
20+
21+
private static func attributedStringWithManyRuns(count: Int) -> AttributedString {
22+
(0..<count).reduce(into: AttributedString()) { result, index in
23+
var fragment = AttributedString(index.isMultiple(of: 40) ? "\n" : "x")
24+
fragment.font = index.isMultiple(of: 2) ? .body.bold() : .body
25+
result += fragment
26+
}
27+
}
28+
}
29+
#endif

0 commit comments

Comments
 (0)