Skip to content

Commit be668bc

Browse files
committed
Fix Text Disappearing
1 parent 337b05f commit be668bc

File tree

3 files changed

+136
-11
lines changed

3 files changed

+136
-11
lines changed

Sources/CodeEditTextView/TextLineStorage/TextLineStorage.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ public final class TextLineStorage<Data: Identifiable> {
5858

5959
public init() { }
6060

61+
init(root: Node<Data>, count: Int, length: Int, height: CGFloat) {
62+
self.root = root
63+
self.count = count
64+
self.length = length
65+
self.height = height
66+
}
67+
6168
// MARK: - Public Methods
6269

6370
/// Inserts a new line for the given range.
@@ -408,9 +415,9 @@ private extension TextLineStorage {
408415
} else {
409416
transplant(nodeY, with: nodeY.right)
410417

411-
nodeY.right?.leftSubtreeCount = nodeY.leftSubtreeCount
412-
nodeY.right?.leftSubtreeHeight = nodeY.leftSubtreeHeight
413-
nodeY.right?.leftSubtreeOffset = nodeY.leftSubtreeOffset
418+
nodeY.right?.leftSubtreeCount += nodeY.leftSubtreeCount
419+
nodeY.right?.leftSubtreeHeight += nodeY.leftSubtreeHeight
420+
nodeY.right?.leftSubtreeOffset += nodeY.leftSubtreeOffset
414421

415422
nodeY.right = nodeZ.right
416423
nodeY.right?.parent = nodeY

Sources/CodeEditTextView/TextView/TextView+ReplaceCharacters.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ extension TextView {
4747
}
4848

4949
textStorage.endEditing()
50+
51+
// Cause a layout pass now that we've finished editing, if there were any edits.
52+
if !ranges.isEmpty {
53+
layout()
54+
}
55+
5056
if !skipUpdateSelection {
5157
selectionManager.notifyAfterEdit()
5258
}

Tests/CodeEditTextViewTests/TextLayoutLineStorageTests.swift

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ fileprivate extension CGFloat {
77
}
88
}
99

10+
extension UUID: @retroactive Identifiable {
11+
public var id: UUID { self }
12+
}
13+
1014
final class TextLayoutLineStorageTests: XCTestCase {
15+
1116
/// Creates a balanced height=3 tree useful for testing and debugging.
1217
/// - Returns: A new tree.
1318
fileprivate func createBalancedTree() -> TextLineStorage<TextLine> {
@@ -20,16 +25,16 @@ final class TextLayoutLineStorageTests: XCTestCase {
2025
return tree
2126
}
2227

28+
struct ChildData {
29+
let length: Int
30+
let count: Int
31+
let height: CGFloat
32+
}
33+
2334
/// Recursively checks that the given tree has the correct metadata everywhere.
2435
/// - Parameter tree: The tree to check.
25-
fileprivate func assertTreeMetadataCorrect(_ tree: TextLineStorage<TextLine>) throws {
26-
struct ChildData {
27-
let length: Int
28-
let count: Int
29-
let height: CGFloat
30-
}
31-
32-
func checkChildren(_ node: TextLineStorage<TextLine>.Node<TextLine>?) -> ChildData {
36+
fileprivate func assertTreeMetadataCorrect<T: Identifiable>(_ tree: TextLineStorage<T>) throws {
37+
func checkChildren(_ node: TextLineStorage<T>.Node<T>?) -> ChildData {
3338
guard let node else { return ChildData(length: 0, count: 0, height: 0.0) }
3439
let leftSubtreeData = checkChildren(node.left)
3540
let rightSubtreeData = checkChildren(node.right)
@@ -272,4 +277,111 @@ final class TextLayoutLineStorageTests: XCTestCase {
272277
}
273278
}
274279
}
280+
281+
func test_transplantWithExistingLeftNodes() throws { // swiftlint:disable:this function_body_length
282+
typealias Storage = TextLineStorage<UUID>
283+
typealias Node = TextLineStorage<UUID>.Node
284+
// Test that when transplanting a node with no left nodes, with a node with left nodes, that
285+
// the resulting tree has valid 'left_' metadata
286+
// 1
287+
// / \
288+
// 7 2
289+
// /
290+
// 3 ← this will be moved, this test ensures 4 retains it's left subtree count
291+
// \
292+
// 4
293+
// | |
294+
// 5 6
295+
296+
let node5 = Node(
297+
length: 5,
298+
data: UUID(),
299+
leftSubtreeOffset: 0,
300+
leftSubtreeHeight: 0,
301+
leftSubtreeCount: 0,
302+
height: 1,
303+
left: nil,
304+
right: nil,
305+
parent: nil,
306+
color: .black
307+
)
308+
309+
let node6 = Node(
310+
length: 6,
311+
data: UUID(),
312+
leftSubtreeOffset: 0,
313+
leftSubtreeHeight: 0,
314+
leftSubtreeCount: 0,
315+
height: 1,
316+
left: nil,
317+
right: nil,
318+
parent: nil,
319+
color: .black
320+
)
321+
322+
let node4 = Node(
323+
length: 4,
324+
data: UUID(),
325+
leftSubtreeOffset: 5,
326+
leftSubtreeHeight: 1,
327+
leftSubtreeCount: 1, // node5 is on the left
328+
height: 1,
329+
left: node5,
330+
right: node6,
331+
parent: nil,
332+
color: .black
333+
)
334+
node5.parent = node4
335+
node6.parent = node4
336+
337+
let node3 = Node(
338+
length: 3,
339+
data: UUID(),
340+
leftSubtreeOffset: 0,
341+
leftSubtreeHeight: 0,
342+
leftSubtreeCount: 0,
343+
height: 1,
344+
left: nil,
345+
right: node4,
346+
parent: nil,
347+
color: .black
348+
)
349+
node4.parent = node3
350+
351+
let node2 = Node(
352+
length: 2,
353+
data: UUID(),
354+
leftSubtreeOffset: 18,
355+
leftSubtreeHeight: 4,
356+
leftSubtreeCount: 4, // node3 is on the left
357+
height: 1,
358+
left: node3,
359+
right: nil,
360+
parent: nil,
361+
color: .black
362+
)
363+
node3.parent = node2
364+
365+
let node7 = Node(length: 7, data: UUID(), height: 1)
366+
367+
let node1 = Node(
368+
length: 1,
369+
data: UUID(),
370+
leftSubtreeOffset: 7,
371+
leftSubtreeHeight: 1,
372+
leftSubtreeCount: 1,
373+
height: 1,
374+
left: node7,
375+
right: node2,
376+
parent: nil,
377+
color: .black
378+
)
379+
node2.parent = node1
380+
381+
let storage = Storage(root: node1, count: 7, length: 28, height: 7)
382+
383+
storage.delete(lineAt: 7) // Delete the root
384+
385+
try assertTreeMetadataCorrect(storage)
386+
}
275387
}

0 commit comments

Comments
 (0)