From 31ad0383607c32498ab97fac7127f9e2674c810a Mon Sep 17 00:00:00 2001 From: Daneel Date: Sun, 1 Mar 2026 08:27:45 +0100 Subject: [PATCH] =?UTF-8?q?patches:=20fix=20O(position)=20lag=20=E2=80=94?= =?UTF-8?q?=20use=20lineForAXIndex:=20instead=20of=20lineRangeForRange:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit postAccessibilityNotificationsForFrame: was calling NSString lineRangeForRange: to detect line-crossing cursor moves. That method scans from the start of the string, making it O(cursor_offset). In large buffers with the cursor near the end, this executes on every redisplay cycle — causing progressive slowdown proportional to cursor position. patch 0002 already builds lineStartOffsets in ensureTextCache (O(N) once per text change) and exposes lineForAXIndex: (O(log L) binary search). Use it instead. Also remove the now-redundant tlen clamping that existed solely to prevent lineRangeForRange: from receiving an out-of-range index. lineForAXIndex: handles out-of-range inputs safely. --- ...tification-dispatch-and-mode-line-el.patch | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch b/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch index aede7b9..3f2b6d9 100644 --- a/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch +++ b/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch @@ -27,7 +27,7 @@ diff --git a/src/nsterm.m b/src/nsterm.m index 8f528bd..7e3d57a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m -@@ -8718,6 +8718,551 @@ - (NSRect)accessibilityFrame +@@ -8718,6 +8718,552 @@ - (NSRect)accessibilityFrame @end @@ -432,17 +432,18 @@ index 8f528bd..7e3d57a 100644 + [self ensureTextCache]; + if (cachedText && oldPoint > 0) + { -+ NSUInteger tlen = [cachedText length]; + NSUInteger oldIdx = [self accessibilityIndexForCharpos:oldPoint]; + NSUInteger newIdx = [self accessibilityIndexForCharpos:point]; -+ if (oldIdx > tlen) oldIdx = tlen; -+ if (newIdx > tlen) newIdx = tlen; + -+ NSRange oldLine = [cachedText lineRangeForRange: -+ NSMakeRange (oldIdx, 0)]; -+ NSRange newLine = [cachedText lineRangeForRange: -+ NSMakeRange (newIdx, 0)]; -+ if (oldLine.location != newLine.location) ++ /* Use precomputed lineStartOffsets for O(log L) line lookup. ++ NSString lineRangeForRange: is O(offset) — it scans from ++ the start of the string, causing progressive slowdown in ++ large buffers (O(cursor_position) per redisplay cycle). ++ lineForAXIndex: binary-searches lineStartOffsets, built ++ once per cache rebuild in ensureTextCache. */ ++ NSInteger oldLine = [self lineForAXIndex: oldIdx]; ++ NSInteger newLine = [self lineForAXIndex: newIdx]; ++ if (oldLine != newLine) + granularity = ns_ax_text_selection_granularity_line; + else + {