From 7456734b56522db87498fd8d89def8b37ac597c7 Mon Sep 17 00:00:00 2001 From: Khan Winter <35942988+thecoolwinter@users.noreply.github.com> Date: Sun, 17 Nov 2024 14:15:09 -0600 Subject: [PATCH 1/2] Move All Delegate Calls Outside Layout Pass --- .../TextLayoutManager/TextLayoutManager.swift | 15 +++++++++------ .../TextView/TextView+Layout.swift | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift b/Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift index 788c76b6f..7e0e56067 100644 --- a/Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift +++ b/Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift @@ -266,6 +266,13 @@ public class TextLayoutManager: NSObject { // Update the visible lines with the new set. visibleLineIds = newVisibleLines + #if DEBUG + isInLayout = false + #endif + + // These are fine to update outside of `isInLayout` as our internal data structures are finalized at this point + // so laying out again won't break our line storage or visible line. + if maxFoundLineWidth > maxLineWidth { maxLineWidth = maxFoundLineWidth } @@ -274,15 +281,11 @@ public class TextLayoutManager: NSObject { delegate?.layoutManagerYAdjustment(yContentAdjustment) } - #if DEBUG - isInLayout = false - #endif - needsLayout = false - - // This needs to happen after ``needsLayout`` is toggled. Things can be triggered by frame changes. if originalHeight != lineStorage.height || layoutView?.frame.size.height != lineStorage.height { delegate?.layoutManagerHeightDidUpdate(newHeight: lineStorage.height) } + + needsLayout = false } /// Lays out a single text line. diff --git a/Sources/CodeEditTextView/TextView/TextView+Layout.swift b/Sources/CodeEditTextView/TextView/TextView+Layout.swift index a68d78be4..038dd349a 100644 --- a/Sources/CodeEditTextView/TextView/TextView+Layout.swift +++ b/Sources/CodeEditTextView/TextView/TextView+Layout.swift @@ -58,6 +58,8 @@ extension TextView { inputContext?.invalidateCharacterCoordinates() } + /// Updates the view's frame if needed depending on wrapping lines, a new maximum width, or changed available size. + /// - Returns: Whether or not the view was updated. @discardableResult public func updateFrameIfNeeded() -> Bool { var availableSize = scrollView?.contentSize ?? .zero From 6ed9afabb8a883f80383d9636664b82f9750a87f Mon Sep 17 00:00:00 2001 From: Khan Winter <35942988+thecoolwinter@users.noreply.github.com> Date: Sun, 17 Nov 2024 14:43:37 -0600 Subject: [PATCH 2/2] Fix Flaking Test --- Sources/CodeEditTextView/TextView/TextView+Delete.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/CodeEditTextView/TextView/TextView+Delete.swift b/Sources/CodeEditTextView/TextView/TextView+Delete.swift index 2691c37fd..fe4363dfa 100644 --- a/Sources/CodeEditTextView/TextView/TextView+Delete.swift +++ b/Sources/CodeEditTextView/TextView/TextView+Delete.swift @@ -60,6 +60,7 @@ extension TextView { guard extendedRange.location >= 0 else { continue } textSelection.range.formUnion(extendedRange) } + selectionManager.textSelections.sort(by: { $0.range.location < $1.range.location }) KillRing.shared.kill( strings: selectionManager.textSelections.map(\.range).compactMap({ textStorage.substring(from: $0) }) )