patches: fix O(position) lag — O(1) fast path in accessibilityIndexForCharpos:

accessibilityIndexForCharpos: walked composed character sequences
from run.ax_start up to the target charpos offset.  For a run
covering an entire ASCII buffer, chars_in = pt - BUF_BEGV, making
each call O(cursor_position).

This method is called from ensureTextCache on EVERY redisplay frame
(as part of the cache validity check), making each frame O(position)
even when the buffer is completely unchanged.  At line 34,000 of a
large file this is ~1,000,000 iterations per frame.

Fix: when ax_length == length for a run (all single-unit characters),
the ax_index is simply ax_start + chars_in.  O(1) instead of O(N).

This is the symmetric counterpart to the charposForAccessibilityIndex:
fast path added in the previous commit.  Both conversion directions
now run in O(1) for pure-ASCII buffers.
This commit is contained in:
2026-03-01 09:14:52 +01:00
parent fb68dd50ea
commit 0c13f5d6a3
7 changed files with 94 additions and 51 deletions

View File

@@ -1,4 +1,4 @@
From 1b45f1f5ae3fe88836c8bfe60233e9a078a50641 Mon Sep 17 00:00:00 2001 From a0c39d23ba91ee2e6a80f58ac263513326d3653c Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100 Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 2/8] ns: implement buffer accessibility element (core Subject: [PATCH 2/8] ns: implement buffer accessibility element (core
@@ -18,14 +18,14 @@ setAccessibilityFocused.
Tested on macOS 14 with VoiceOver. Verified: buffer reading, Tested on macOS 14 with VoiceOver. Verified: buffer reading,
line-by-line navigation, word/character announcements. line-by-line navigation, word/character announcements.
--- ---
src/nsterm.m | 1112 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/nsterm.m | 1128 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1112 insertions(+) 1 file changed, 1128 insertions(+)
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index e516946..4d54940 100644 index e516946..999ca0d 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -7614,6 +7614,1118 @@ - (id)accessibilityTopLevelUIElement @@ -7614,6 +7614,1134 @@ - (id)accessibilityTopLevelUIElement
@end @end
@@ -474,10 +474,26 @@ index e516946..4d54940 100644
+ lo = mid + 1; + lo = mid + 1;
+ else + else
+ { + {
+<<<<<<< Updated upstream
+ /* Found: charpos is inside this run. Compute UTF-16 delta + /* Found: charpos is inside this run. Compute UTF-16 delta
+ directly from cachedText — no Lisp calls needed. */ + directly from cachedText — no Lisp calls needed. */
+=======
+ /* Found: charpos is inside this run. Compute UTF-16 delta.
+ Fast path for pure-ASCII runs (ax_length == length): every
+ Emacs charpos maps to exactly one UTF-16 code unit, so the
+ conversion is O(1). This matters because ensureTextCache
+ calls this method on every redisplay frame to validate the
+ cache --- a O(cursor_position) loop here means O(position)
+ cost per frame even when the buffer is unchanged.
+ Multi-byte runs fall through to the sequence walk, bounded
+ by run length (visible window), not total buffer size. */
+>>>>>>> Stashed changes
+ NSUInteger chars_in = (NSUInteger)(charpos - r->charpos); + NSUInteger chars_in = (NSUInteger)(charpos - r->charpos);
+ if (chars_in == 0 || !cachedText) + if (chars_in == 0)
+ return r->ax_start;
+ if (r->ax_length == (NSUInteger) r->length)
+ return r->ax_start + chars_in;
+ if (!cachedText)
+ return r->ax_start; + return r->ax_start;
+ NSUInteger run_end_ax = r->ax_start + r->ax_length; + NSUInteger run_end_ax = r->ax_start + r->ax_length;
+ NSUInteger scan = r->ax_start; + NSUInteger scan = r->ax_start;

View File

@@ -1,4 +1,4 @@
From 545547dca37282a5a9bc858e0ccac724aa87b3d8 Mon Sep 17 00:00:00 2001 From 683ddf23e2a4d4c981d2947d475f2c02a41ce66b Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100 Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 3/8] ns: add buffer notification dispatch and mode-line Subject: [PATCH 3/8] ns: add buffer notification dispatch and mode-line
@@ -24,10 +24,10 @@ region selection feedback, completion popups, mode-line reading.
1 file changed, 545 insertions(+) 1 file changed, 545 insertions(+)
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 4d54940..a73b7f5 100644 index 999ca0d..239666d 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -8726,6 +8726,551 @@ - (NSRect)accessibilityFrame @@ -8742,6 +8742,551 @@ - (NSRect)accessibilityFrame
@end @end

View File

@@ -1,4 +1,4 @@
From a1c42c0fefc4cc942884c0fe44520717742e4dba Mon Sep 17 00:00:00 2001 From 78b8d79ec5505165d6864cc65c7b3703a57e441c Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100 Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 4/8] ns: add interactive span elements for Tab navigation Subject: [PATCH 4/8] ns: add interactive span elements for Tab navigation
@@ -17,10 +17,10 @@ Tested on macOS 14. Verified: Tab-cycling through org-mode links,
1 file changed, 286 insertions(+) 1 file changed, 286 insertions(+)
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index a73b7f5..98ff027 100644 index 239666d..94a4602 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -9271,6 +9271,292 @@ - (NSRect)accessibilityFrame @@ -9287,6 +9287,292 @@ - (NSRect)accessibilityFrame
@end @end

View File

@@ -1,4 +1,4 @@
From ae1c7d6451f5a6be397f50c314e03b43b4e47b5c Mon Sep 17 00:00:00 2001 From 7aab25d3ba9b41d3d81693b04d8d74812cad9139 Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100 Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 5/8] ns: integrate accessibility with EmacsView and redisplay Subject: [PATCH 5/8] ns: integrate accessibility with EmacsView and redisplay
@@ -51,7 +51,7 @@ index 80661a9..2b1f9e6 100644
** Re-introduced dictation, lost in Emacs v30 (macOS). ** Re-introduced dictation, lost in Emacs v30 (macOS).
We lost macOS dictation in v30 when migrating to NSTextInputClient. We lost macOS dictation in v30 when migrating to NSTextInputClient.
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 98ff027..0a70f3e 100644 index 94a4602..51813b5 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -1258,7 +1258,7 @@ If a completion candidate is selected (overlay or child frame), @@ -1258,7 +1258,7 @@ If a completion candidate is selected (overlay or child frame),
@@ -157,7 +157,7 @@ index 98ff027..0a70f3e 100644
static BOOL static BOOL
ns_ax_find_completion_overlay_range (struct buffer *b, ptrdiff_t point, ns_ax_find_completion_overlay_range (struct buffer *b, ptrdiff_t point,
ptrdiff_t *out_start, ptrdiff_t *out_start,
@@ -8727,7 +8777,6 @@ - (NSRect)accessibilityFrame @@ -8743,7 +8793,6 @@ - (NSRect)accessibilityFrame
@end @end
@@ -165,7 +165,7 @@ index 98ff027..0a70f3e 100644
/* =================================================================== /* ===================================================================
EmacsAccessibilityBuffer (Notifications) — AX event dispatch EmacsAccessibilityBuffer (Notifications) — AX event dispatch
@@ -9272,7 +9321,6 @@ - (NSRect)accessibilityFrame @@ -9288,7 +9337,6 @@ - (NSRect)accessibilityFrame
@end @end
@@ -173,7 +173,7 @@ index 98ff027..0a70f3e 100644
/* =================================================================== /* ===================================================================
EmacsAccessibilityInteractiveSpan — helpers and implementation EmacsAccessibilityInteractiveSpan — helpers and implementation
=================================================================== */ =================================================================== */
@@ -9602,6 +9650,7 @@ - (void)dealloc @@ -9618,6 +9666,7 @@ - (void)dealloc
[layer release]; [layer release];
#endif #endif
@@ -181,7 +181,7 @@ index 98ff027..0a70f3e 100644
[[self menu] release]; [[self menu] release];
[super dealloc]; [super dealloc];
} }
@@ -10950,6 +10999,32 @@ - (void)windowDidBecomeKey /* for direct calls */ @@ -10966,6 +11015,32 @@ - (void)windowDidBecomeKey /* for direct calls */
XSETFRAME (event.frame_or_window, emacsframe); XSETFRAME (event.frame_or_window, emacsframe);
kbd_buffer_store_event (&event); kbd_buffer_store_event (&event);
ns_send_appdefined (-1); // Kick main loop ns_send_appdefined (-1); // Kick main loop
@@ -214,7 +214,7 @@ index 98ff027..0a70f3e 100644
} }
@@ -12187,6 +12262,332 @@ - (int) fullscreenState @@ -12203,6 +12278,332 @@ - (int) fullscreenState
return fs_state; return fs_state;
} }
@@ -547,7 +547,7 @@ index 98ff027..0a70f3e 100644
@end /* EmacsView */ @end /* EmacsView */
@@ -14187,12 +14588,17 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with @@ -14203,12 +14604,17 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with
ns_use_srgb_colorspace = YES; ns_use_srgb_colorspace = YES;
DEFVAR_BOOL ("ns-accessibility-enabled", ns_accessibility_enabled, DEFVAR_BOOL ("ns-accessibility-enabled", ns_accessibility_enabled,

View File

@@ -1,4 +1,4 @@
From 4341052ad931a98b8453368753b596e7743132b8 Mon Sep 17 00:00:00 2001 From 0accd96937592f4e9bc95356287367f0c56e0f5b Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 12:58:11 +0100 Date: Sat, 28 Feb 2026 12:58:11 +0100
Subject: [PATCH 6/8] doc: add VoiceOver accessibility section to macOS Subject: [PATCH 6/8] doc: add VoiceOver accessibility section to macOS

View File

@@ -1,4 +1,4 @@
From 8dd1a4cd6d3f58a3c6f9454ba1690a442c2048fe Mon Sep 17 00:00:00 2001 From a8172542efe800cf6d29759007c9f826630da881 Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 14:46:25 +0100 Date: Sat, 28 Feb 2026 14:46:25 +0100
Subject: [PATCH 7/8] ns: announce overlay completion candidates for VoiceOver Subject: [PATCH 7/8] ns: announce overlay completion candidates for VoiceOver
@@ -45,8 +45,8 @@ Key implementation details:
Independent overlay branch, BUF_CHARS_MODIFF gating, candidate Independent overlay branch, BUF_CHARS_MODIFF gating, candidate
--- ---
src/nsterm.h | 1 + src/nsterm.h | 1 +
src/nsterm.m | 332 ++++++++++++++++++++++++++++++++++++++++++++------- src/nsterm.m | 352 ++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 290 insertions(+), 43 deletions(-) 2 files changed, 306 insertions(+), 47 deletions(-)
diff --git a/src/nsterm.h b/src/nsterm.h diff --git a/src/nsterm.h b/src/nsterm.h
index 6e830de..2102fb9 100644 index 6e830de..2102fb9 100644
@@ -61,7 +61,7 @@ index 6e830de..2102fb9 100644
@property (nonatomic, assign) BOOL cachedMarkActive; @property (nonatomic, assign) BOOL cachedMarkActive;
@property (nonatomic, copy) NSString *cachedCompletionAnnouncement; @property (nonatomic, copy) NSString *cachedCompletionAnnouncement;
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 0a70f3e..c74eaf1 100644 index 51813b5..7ce683d 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -7254,11 +7254,154 @@ Accessibility virtual elements (macOS / Cocoa only) @@ -7254,11 +7254,154 @@ Accessibility virtual elements (macOS / Cocoa only)
@@ -307,16 +307,43 @@ index 0a70f3e..c74eaf1 100644
NSUInteger lo = 0, hi = visibleRunCount; NSUInteger lo = 0, hi = visibleRunCount;
while (lo < hi) while (lo < hi)
{ {
@@ -8110,7 +8245,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos @@ -8109,10 +8244,6 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
lo = mid + 1;
else else
{ {
/* Found: charpos is inside this run. Compute UTF-16 delta -<<<<<<< Updated upstream
- /* Found: charpos is inside this run. Compute UTF-16 delta
- directly from cachedText — no Lisp calls needed. */ - directly from cachedText — no Lisp calls needed. */
-=======
/* Found: charpos is inside this run. Compute UTF-16 delta.
Fast path for pure-ASCII runs (ax_length == length): every
Emacs charpos maps to exactly one UTF-16 code unit, so the
@@ -8122,7 +8253,23 @@ conversion is O(1). This matters because ensureTextCache
cost per frame even when the buffer is unchanged.
Multi-byte runs fall through to the sequence walk, bounded
by run length (visible window), not total buffer size. */
->>>>>>> Stashed changes
+ NSUInteger chars_in = (NSUInteger)(charpos - r->charpos);
+ if (chars_in == 0)
+ return r->ax_start;
+ if (r->ax_length == (NSUInteger) r->length)
+ return r->ax_start + chars_in;
+ if (!cachedText)
+ return r->ax_start;
+ NSUInteger run_end_ax = r->ax_start + r->ax_length;
+ NSUInteger scan = r->ax_start;
+ for (NSUInteger c = 0; c < chars_in && scan < run_end_ax; c++)
+ {
+ NSRange seq = [cachedText
+ rangeOfComposedCharacterSequenceAtIndex:scan];
+ scan = NSMaxRange (seq);
+ }=======
+ directly from cachedText --- no Lisp calls needed. */ + directly from cachedText --- no Lisp calls needed. */
+>>>>>>> 8dd1a4c (ns: announce overlay completion candidates for VoiceOver)
NSUInteger chars_in = (NSUInteger)(charpos - r->charpos); NSUInteger chars_in = (NSUInteger)(charpos - r->charpos);
if (chars_in == 0 || !cachedText) if (chars_in == 0)
return r->ax_start; return r->ax_start;
@@ -8135,10 +8270,10 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos @@ -8151,10 +8298,10 @@ by run length (visible window), not total buffer size. */
/* Convert accessibility string index to buffer charpos. /* Convert accessibility string index to buffer charpos.
Safe to call from any thread: uses only cachedText (NSString) and Safe to call from any thread: uses only cachedText (NSString) and
@@ -329,7 +356,7 @@ index 0a70f3e..c74eaf1 100644
@synchronized (self) @synchronized (self)
{ {
if (visibleRunCount == 0) if (visibleRunCount == 0)
@@ -8180,7 +8315,7 @@ the slow path (composed character sequence walk), which is @@ -8196,7 +8343,7 @@ the slow path (composed character sequence walk), which is
return cp; return cp;
} }
} }
@@ -338,7 +365,7 @@ index 0a70f3e..c74eaf1 100644
if (lo > 0) if (lo > 0)
{ {
ns_ax_visible_run *last = &visibleRuns[visibleRunCount - 1]; ns_ax_visible_run *last = &visibleRuns[visibleRunCount - 1];
@@ -8202,7 +8337,7 @@ the slow path (composed character sequence walk), which is @@ -8218,7 +8365,7 @@ the slow path (composed character sequence walk), which is
deadlocking the AX server thread. This is prevented by: deadlocking the AX server thread. This is prevented by:
1. validWindow checks WINDOW_LIVE_P and BUFFERP before every 1. validWindow checks WINDOW_LIVE_P and BUFFERP before every
@@ -347,7 +374,7 @@ index 0a70f3e..c74eaf1 100644
2. All dispatch_sync blocks run on the main thread where no 2. All dispatch_sync blocks run on the main thread where no
concurrent Lisp code can modify state between checks. concurrent Lisp code can modify state between checks.
3. block_input prevents timer events and process output from 3. block_input prevents timer events and process output from
@@ -8556,6 +8691,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber @@ -8572,6 +8719,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber
return [self lineForAXIndex:point_idx]; return [self lineForAXIndex:point_idx];
} }
@@ -398,7 +425,7 @@ index 0a70f3e..c74eaf1 100644
- (NSRange)accessibilityRangeForLine:(NSInteger)line - (NSRange)accessibilityRangeForLine:(NSInteger)line
{ {
if (![NSThread isMainThread]) if (![NSThread isMainThread])
@@ -8778,7 +8957,7 @@ - (NSRect)accessibilityFrame @@ -8794,7 +8985,7 @@ - (NSRect)accessibilityFrame
/* =================================================================== /* ===================================================================
@@ -407,7 +434,7 @@ index 0a70f3e..c74eaf1 100644
These methods notify VoiceOver of text and selection changes. These methods notify VoiceOver of text and selection changes.
Called from the redisplay cycle (postAccessibilityUpdates). Called from the redisplay cycle (postAccessibilityUpdates).
@@ -8793,7 +8972,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point @@ -8809,7 +9000,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point
if (point > self.cachedPoint if (point > self.cachedPoint
&& point - self.cachedPoint == 1) && point - self.cachedPoint == 1)
{ {
@@ -416,7 +443,7 @@ index 0a70f3e..c74eaf1 100644
[self invalidateTextCache]; [self invalidateTextCache];
[self ensureTextCache]; [self ensureTextCache];
if (cachedText) if (cachedText)
@@ -8812,7 +8991,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point @@ -8828,7 +9019,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point
/* Update cachedPoint here so the selection-move branch does NOT /* Update cachedPoint here so the selection-move branch does NOT
fire for point changes caused by edits. WebKit and Chromium fire for point changes caused by edits. WebKit and Chromium
never send both ValueChanged and SelectedTextChanged for the never send both ValueChanged and SelectedTextChanged for the
@@ -425,7 +452,7 @@ index 0a70f3e..c74eaf1 100644
self.cachedPoint = point; self.cachedPoint = point;
NSDictionary *change = @{ NSDictionary *change = @{
@@ -9145,16 +9324,83 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f @@ -9161,16 +9352,83 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f
BOOL markActive = !NILP (BVAR (b, mark_active)); BOOL markActive = !NILP (BVAR (b, mark_active));
/* --- Text changed (edit) --- */ /* --- Text changed (edit) --- */
@@ -513,7 +540,7 @@ index 0a70f3e..c74eaf1 100644
{ {
ptrdiff_t oldPoint = self.cachedPoint; ptrdiff_t oldPoint = self.cachedPoint;
BOOL oldMarkActive = self.cachedMarkActive; BOOL oldMarkActive = self.cachedMarkActive;
@@ -9322,7 +9568,7 @@ - (NSRect)accessibilityFrame @@ -9338,7 +9596,7 @@ - (NSRect)accessibilityFrame
/* =================================================================== /* ===================================================================
@@ -522,7 +549,7 @@ index 0a70f3e..c74eaf1 100644
=================================================================== */ =================================================================== */
/* Scan visible range of window W for interactive spans. /* Scan visible range of window W for interactive spans.
@@ -9530,7 +9776,7 @@ - (void) setAccessibilityFocused: (BOOL) focused @@ -9546,7 +9804,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
dispatch_async (dispatch_get_main_queue (), ^{ dispatch_async (dispatch_get_main_queue (), ^{
/* lwin is a Lisp_Object captured by value. This is GC-safe /* lwin is a Lisp_Object captured by value. This is GC-safe
because Lisp_Objects are tagged integers/pointers that because Lisp_Objects are tagged integers/pointers that
@@ -531,7 +558,7 @@ index 0a70f3e..c74eaf1 100644
Emacs. The WINDOW_LIVE_P check below guards against the Emacs. The WINDOW_LIVE_P check below guards against the
window being deleted between capture and execution. */ window being deleted between capture and execution. */
if (!WINDOWP (lwin) || NILP (Fwindow_live_p (lwin))) if (!WINDOWP (lwin) || NILP (Fwindow_live_p (lwin)))
@@ -9556,7 +9802,7 @@ - (void) setAccessibilityFocused: (BOOL) focused @@ -9572,7 +9830,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
@end @end
@@ -540,7 +567,7 @@ index 0a70f3e..c74eaf1 100644
Methods are kept here (same .m file) so they access the ivars Methods are kept here (same .m file) so they access the ivars
declared in the @interface ivar block. */ declared in the @interface ivar block. */
@implementation EmacsAccessibilityBuffer (InteractiveSpans) @implementation EmacsAccessibilityBuffer (InteractiveSpans)
@@ -12278,7 +12524,7 @@ - (int) fullscreenState @@ -12294,7 +12552,7 @@ - (int) fullscreenState
if (WINDOW_LEAF_P (w)) if (WINDOW_LEAF_P (w))
{ {
@@ -549,7 +576,7 @@ index 0a70f3e..c74eaf1 100644
EmacsAccessibilityBuffer *elem EmacsAccessibilityBuffer *elem
= [existing objectForKey:[NSValue valueWithPointer:w]]; = [existing objectForKey:[NSValue valueWithPointer:w]];
if (!elem) if (!elem)
@@ -12312,7 +12558,7 @@ - (int) fullscreenState @@ -12328,7 +12586,7 @@ - (int) fullscreenState
} }
else else
{ {
@@ -558,7 +585,7 @@ index 0a70f3e..c74eaf1 100644
Lisp_Object child = w->contents; Lisp_Object child = w->contents;
while (!NILP (child)) while (!NILP (child))
{ {
@@ -12424,7 +12670,7 @@ - (void)postAccessibilityUpdates @@ -12440,7 +12698,7 @@ - (void)postAccessibilityUpdates
accessibilityUpdating = YES; accessibilityUpdating = YES;
/* Detect window tree change (split, delete, new buffer). Compare /* Detect window tree change (split, delete, new buffer). Compare
@@ -567,7 +594,7 @@ index 0a70f3e..c74eaf1 100644
Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe); Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe);
if (!EQ (curRoot, lastRootWindow)) if (!EQ (curRoot, lastRootWindow))
{ {
@@ -12433,12 +12679,12 @@ - (void)postAccessibilityUpdates @@ -12449,12 +12707,12 @@ - (void)postAccessibilityUpdates
} }
/* If tree is stale, rebuild FIRST so we don't iterate freed /* If tree is stale, rebuild FIRST so we don't iterate freed

View File

@@ -1,4 +1,4 @@
From 35a32f4802822ee77350a6d652aa45cca38e304c Mon Sep 17 00:00:00 2001 From fed3a06865d403db5d25074e7473c4d7c360f917 Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Sat, 28 Feb 2026 16:01:29 +0100 Date: Sat, 28 Feb 2026 16:01:29 +0100
Subject: [PATCH 8/8] ns: announce child frame completion candidates for Subject: [PATCH 8/8] ns: announce child frame completion candidates for
@@ -109,7 +109,7 @@ index 2102fb9..dd98d56 100644
@end @end
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index c74eaf1..d2f88a5 100644 index 7ce683d..8a1316a 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -7398,6 +7398,112 @@ visual line index for Zoom (skip whitespace-only lines @@ -7398,6 +7398,112 @@ visual line index for Zoom (skip whitespace-only lines
@@ -268,7 +268,7 @@ index c74eaf1..d2f88a5 100644
cachedTextStart = start; cachedTextStart = start;
if (visibleRuns) if (visibleRuns)
@@ -9143,6 +9258,7 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b @@ -9171,6 +9286,7 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b
ptrdiff_t currentOverlayStart = 0; ptrdiff_t currentOverlayStart = 0;
ptrdiff_t currentOverlayEnd = 0; ptrdiff_t currentOverlayEnd = 0;
@@ -276,7 +276,7 @@ index c74eaf1..d2f88a5 100644
specpdl_ref count2 = SPECPDL_INDEX (); specpdl_ref count2 = SPECPDL_INDEX ();
record_unwind_current_buffer (); record_unwind_current_buffer ();
if (b != current_buffer) if (b != current_buffer)
@@ -9301,6 +9417,7 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b @@ -9329,6 +9445,7 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b
self.cachedCompletionOverlayEnd = 0; self.cachedCompletionOverlayEnd = 0;
self.cachedCompletionPoint = 0; self.cachedCompletionPoint = 0;
} }
@@ -284,7 +284,7 @@ index c74eaf1..d2f88a5 100644
} }
/* ---- Notification dispatch (main entry point) ---- */ /* ---- Notification dispatch (main entry point) ---- */
@@ -9897,6 +10014,10 @@ - (void)dealloc @@ -9925,6 +10042,10 @@ - (void)dealloc
#endif #endif
[accessibilityElements release]; [accessibilityElements release];
@@ -295,7 +295,7 @@ index c74eaf1..d2f88a5 100644
[[self menu] release]; [[self menu] release];
[super dealloc]; [super dealloc];
} }
@@ -11346,6 +11467,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f @@ -11374,6 +11495,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f
windowClosing = NO; windowClosing = NO;
processingCompose = NO; processingCompose = NO;
@@ -305,7 +305,7 @@ index c74eaf1..d2f88a5 100644
scrollbarsNeedingUpdate = 0; scrollbarsNeedingUpdate = 0;
fs_state = FULLSCREEN_NONE; fs_state = FULLSCREEN_NONE;
fs_before_fs = next_maximized = -1; fs_before_fs = next_maximized = -1;
@@ -12654,6 +12778,80 @@ - (id)accessibilityFocusedUIElement @@ -12682,6 +12806,80 @@ - (id)accessibilityFocusedUIElement
The existing elements carry cached state (modiff, point) from the The existing elements carry cached state (modiff, point) from the
previous redisplay cycle. Rebuilding first would create fresh previous redisplay cycle. Rebuilding first would create fresh
elements with current values, making change detection impossible. */ elements with current values, making change detection impossible. */
@@ -386,7 +386,7 @@ index c74eaf1..d2f88a5 100644
- (void)postAccessibilityUpdates - (void)postAccessibilityUpdates
{ {
NSTRACE ("[EmacsView postAccessibilityUpdates]"); NSTRACE ("[EmacsView postAccessibilityUpdates]");
@@ -12664,11 +12862,59 @@ - (void)postAccessibilityUpdates @@ -12692,11 +12890,59 @@ - (void)postAccessibilityUpdates
/* Re-entrance guard: VoiceOver callbacks during notification posting /* Re-entrance guard: VoiceOver callbacks during notification posting
can trigger redisplay, which calls ns_update_end, which calls us can trigger redisplay, which calls ns_update_end, which calls us