patches: fix O(buffer) cache invalidation caused by font-lock

BUF_CHARS_MODIFF fix — the core performance regression:
ensureTextCache checked BUF_MODIFF which font-lock bumps on every
redisplay. Each cursor movement in a large file triggered full buffer
rebuild. Now uses BUF_CHARS_MODIFF (changes only on char insert/delete).
This commit is contained in:
2026-03-01 04:56:37 +01:00
parent bc71e58123
commit cd16d45584
10 changed files with 97 additions and 18 deletions

View File

@@ -1,7 +1,7 @@
From 8ef9b7f50f9ebb1c23e8e8bf2b5158e073b35e37 Mon Sep 17 00:00:00 2001
From b38d702cb19f2b7c36d88d7e397323ea1aca1c9b Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 22:39:35 +0100
Subject: [PATCH 1/9] ns: integrate with macOS Zoom for cursor tracking
Subject: [PATCH 01/10] ns: integrate with macOS Zoom for cursor tracking
Inform macOS Zoom of the text cursor position so the zoomed viewport
follows keyboard focus in Emacs.

View File

@@ -1,7 +1,7 @@
From 6e8cc407d6f407c2201a35438bab60b112a11c9e Mon Sep 17 00:00:00 2001
From e6800d12d350def06dd6475fcb807ceaf7f82e02 Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 2/9] ns: add accessibility base classes and text extraction
Subject: [PATCH 02/10] ns: add accessibility base classes and text extraction
Add the foundation for macOS VoiceOver accessibility in the NS
(Cocoa) port. No existing code paths are modified.

View File

@@ -1,7 +1,7 @@
From aa788f7df93a3307f52cf10d16fe4af10eaae03d Mon Sep 17 00:00:00 2001
From d3dd16835ff6b7456f987893ef610e3847a92fde Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 3/9] ns: implement buffer accessibility element (core
Subject: [PATCH 03/10] ns: implement buffer accessibility element (core
protocol)
Implement the NSAccessibility text protocol for Emacs buffer windows.

View File

@@ -1,7 +1,7 @@
From 3da80e1c56c7270d458dfacd45e78e111359f526 Mon Sep 17 00:00:00 2001
From 601df3982e20e60f041fa2658aa7ef1efb69939b Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 4/9] ns: add buffer notification dispatch and mode-line
Subject: [PATCH 04/10] ns: add buffer notification dispatch and mode-line
element
Add VoiceOver notification methods and mode-line readout.

View File

@@ -1,7 +1,7 @@
From 9e13d137b009d4c2ecd2b6f55afa672637e8d62c Mon Sep 17 00:00:00 2001
From 8c67a2b5a89ac302cbac91790fdfb6827b74285a Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 5/9] ns: add interactive span elements for Tab navigation
Subject: [PATCH 05/10] ns: add interactive span elements for Tab navigation
* src/nsterm.m (ns_ax_scan_interactive_spans): New function.
(EmacsAccessibilityInteractiveSpan): Implement AXButton/AXLink

View File

@@ -1,7 +1,8 @@
From 8d882bfbad959b55915da0a43897acf2aca3b2ed Mon Sep 17 00:00:00 2001
From 3237374282389cd61bcd99beed187ec75d1b06fc Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 6/9] ns: integrate accessibility with EmacsView and redisplay
Subject: [PATCH 06/10] ns: integrate accessibility with EmacsView and
redisplay
Wire the accessibility infrastructure into EmacsView and the

View File

@@ -1,7 +1,7 @@
From 6eddc6fb5933f561e7459198e403519d1c7eecd0 Mon Sep 17 00:00:00 2001
From e2b76f1850489e8188236bed10e4d7f28e5cde2b Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 7/9] doc: add VoiceOver accessibility section to macOS
Subject: [PATCH 07/10] doc: add VoiceOver accessibility section to macOS
appendix
* doc/emacs/macos.texi (VoiceOver Accessibility): New node. Document

View File

@@ -1,7 +1,8 @@
From 5cd1b5f46e670f031ce5fcca2d9312059d6efa87 Mon Sep 17 00:00:00 2001
From 3e868d0234c858fa20588e664354685ef8b08576 Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 14:46:25 +0100
Subject: [PATCH 8/9] ns: announce overlay completion candidates for VoiceOver
Subject: [PATCH 08/10] ns: announce overlay completion candidates for
VoiceOver
Completion frameworks such as Vertico, Ivy, and Icomplete render
candidates via overlay before-string/after-string properties rather

View File

@@ -1,7 +1,7 @@
From 5db9f29f8a8fee97f01ae716f36f37c605dbd70d Mon Sep 17 00:00:00 2001
From 5aba3491f8f5268f2e6093003b79fe69e7932a4b Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 16:01:29 +0100
Subject: [PATCH 9/9] ns: announce child frame completion candidates for
Subject: [PATCH 09/10] ns: announce child frame completion candidates for
VoiceOver
Completion frameworks such as Corfu, Company-box, and similar

View File

@@ -0,0 +1,77 @@
From 4b739781a019fd1ad5b6ac1c9c12dc62e2c82ec3 Mon Sep 17 00:00:00 2001
From: Daneel <daneel@sukany.cz>
Date: Sun, 1 Mar 2026 04:56:16 +0100
Subject: [PATCH 10/10] perf: use BUF_CHARS_MODIFF for AX text cache validity
in ensureTextCache
The cache validity check in -[EmacsAccessibilityBuffer ensureTextCache]
used BUF_MODIFF, which is bumped by every text-property change ---
including face applications by font-lock on each redisplay cycle.
Since the AX text value contains only characters (no face or property
data), property-only changes do not affect it. Rebuilding the full
buffer text on each font-lock pass is O(buffer-size) per redisplay,
causing progressive slowdown proportional to how far the cursor is
from the beginning of the file.
Switch to BUF_CHARS_MODIFF, which is bumped only when characters are
actually inserted or deleted. This matches the semantic of 'did the
text change' and is the approach used by WebKit and NSTextView.
BUF_OVERLAY_MODIFF is intentionally not tracked here (unchanged):
overlay content is handled by separate announcements in
postAccessibilityNotificationsForFrame, and including it in this
check would prevent those announcements from firing.
---
src/nsterm.m | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/nsterm.m b/src/nsterm.m
index 12c451b..e3f9466 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -8148,16 +8148,25 @@ - (void)ensureTextCache
if (!b)
return;
- ptrdiff_t modiff = BUF_MODIFF (b);
- ptrdiff_t pt = BUF_PT (b);
- NSUInteger textLen = cachedText ? [cachedText length] : 0;
- /* Cache validity: track BUF_MODIFF and buffer narrowing.
+ /* Use BUF_CHARS_MODIFF, not BUF_MODIFF, for cache validity.
+ BUF_MODIFF is bumped by every text-property change, including
+ font-lock face applications on every redisplay. AX text contains
+ only characters, not face data, so property-only changes do not
+ affect the cached value. Rebuilding the full buffer text on
+ each font-lock pass is O(buffer-size) per redisplay --- this
+ causes progressive slowdown when scrolling through large files.
+ BUF_CHARS_MODIFF is bumped only on actual character insertions
+ and deletions, matching the semantic of "did the text change".
+ This is the pattern used by WebKit and NSTextView.
Do NOT track BUF_OVERLAY_MODIFF here --- overlay text is not
included in the cached AX text (it is handled separately via
- explicit announcements). Including overlay_modiff would
- silently update cachedOverlayModiff and prevent the
- notification dispatch from detecting overlay changes. */
- if (cachedText && cachedTextModiff == modiff
+ explicit announcements in postAccessibilityNotificationsForFrame).
+ Including overlay_modiff would silently update cachedOverlayModiff
+ and prevent the notification dispatch from detecting changes. */
+ ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b);
+ ptrdiff_t pt = BUF_PT (b);
+ NSUInteger textLen = cachedText ? [cachedText length] : 0;
+ if (cachedText && cachedTextModiff == chars_modiff
&& cachedTextStart == BUF_BEGV (b)
&& pt >= cachedTextStart
&& (textLen == 0
@@ -8173,7 +8182,7 @@ included in the cached AX text (it is handled separately via
{
[cachedText release];
cachedText = [text retain];
- cachedTextModiff = modiff;
+ cachedTextModiff = chars_modiff;
cachedTextStart = start;
if (visibleRuns)
--
2.43.0