patches: fix 3 blockers — duplicate functions, idx typo, doc cap

BLOCKER fixes:
1. Remove duplicate ns_ax_face_is_selected, ns_ax_selected_overlay_text,
   ns_ax_selected_child_frame_text definitions from patch 0002
   (now defined only in 0007/0008 where they belong)
2. Fix idx → point_idx in accessibilityInsertionPointLineNumber (0002)
3. Remove stale 100K cap reference from documentation (0006)

Architecture fix:
- ns_ax_selected_child_frame_text moved from 0007 to 0008
  (where it logically belongs)

Verified: all 8 patches apply cleanly on fresh emacs HEAD.
This commit is contained in:
2026-02-28 22:00:10 +01:00
parent 30089e9413
commit bbe683e752
8 changed files with 84 additions and 342 deletions

View File

@@ -1,4 +1,4 @@
From d176c3c9d97574f0cd493d6491eda0a82ad28387 Mon Sep 17 00:00:00 2001 From 2730f8ddf26bfe5f5fb7553793fc537f45d46476 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 1/8] ns: add accessibility base classes and text extraction Subject: [PATCH 1/8] ns: add accessibility base classes and text extraction
@@ -193,7 +193,7 @@ diff --git a/src/nsterm.m b/src/nsterm.m
index 74e4ad5..2ac1d9d 100644 index 74e4ad5..2ac1d9d 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -46,6 +46,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) @@ -46,6 +46,7 @@ Updated by Christian Limpach (chris@nice.ch)
#include "blockinput.h" #include "blockinput.h"
#include "sysselect.h" #include "sysselect.h"
#include "nsterm.h" #include "nsterm.h"
@@ -201,7 +201,7 @@ index 74e4ad5..2ac1d9d 100644
#include "systime.h" #include "systime.h"
#include "character.h" #include "character.h"
#include "xwidget.h" #include "xwidget.h"
@@ -6856,6 +6857,430 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action) @@ -6856,6 +6857,430 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
} }
#endif #endif
@@ -632,7 +632,7 @@ index 74e4ad5..2ac1d9d 100644
/* ========================================================================== /* ==========================================================================
EmacsView implementation EmacsView implementation
@@ -11312,6 +11737,28 @@ syms_of_nsterm (void) @@ -11312,6 +11737,28 @@ Convert an X font name (XLFD) to an NS font name.
DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic"); DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic");
DEFSYM (Qns_handle_drag_motion, "ns-handle-drag-motion"); DEFSYM (Qns_handle_drag_motion, "ns-handle-drag-motion");
@@ -661,7 +661,7 @@ index 74e4ad5..2ac1d9d 100644
Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier)); Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier)); Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier)); Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier));
@@ -11460,6 +11907,15 @@ Note that this does not apply to images. @@ -11460,6 +11907,15 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with
This variable is ignored on Mac OS X < 10.7 and GNUstep. */); This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
ns_use_srgb_colorspace = YES; ns_use_srgb_colorspace = YES;

View File

@@ -1,4 +1,4 @@
From 6f2e1b097c2ed1d2f45e99cf85792a1b28556202 Mon Sep 17 00:00:00 2001 From c823e3e2338c9f45d49735829577e373d9dfc27a 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,271 +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 | 1346 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/nsterm.m | 1096 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1346 insertions(+) 1 file changed, 1096 insertions(+)
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 2ac1d9d..fc5906a 100644 index 2ac1d9d..1bcc84d 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -6867,6 +6867,256 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action) @@ -7278,6 +7278,1102 @@ - (id)accessibilityTopLevelUIElement
/* ---- Helper: extract buffer text for accessibility ---- */
+/* Return true if FACE is or contains a face symbol whose name
+ includes "current" or "selected", indicating a highlighted
+ completion candidate. Works for vertico-current,
+ icomplete-selected-match, ivy-current-match, etc. */
+static bool
+ns_ax_face_is_selected (Lisp_Object face)
+{
+ if (SYMBOLP (face) && !NILP (face))
+ {
+ const char *name = SSDATA (SYMBOL_NAME (face));
+ /* Substring match is intentionally broad --- it catches
+ vertico-current, icomplete-selected-match, ivy-current-match,
+ company-tooltip-selection, and similar. False positives are
+ harmless since this runs only on overlay strings during
+ completion. */
+ if (strstr (name, "current") || strstr (name, "selected")
+ || strstr (name, "selection"))
+ return true;
+ }
+ if (CONSP (face))
+ {
+ for (Lisp_Object tail = face; CONSP (tail); tail = XCDR (tail))
+ if (ns_ax_face_is_selected (XCAR (tail)))
+ return true;
+ }
+ return false;
+}
+
+/* Extract the currently selected candidate text from overlay display
+ strings. Completion frameworks render candidates as overlay
+ before-string/after-string and highlight the current candidate
+ with a face whose name contains "current" or "selected"
+ (e.g. vertico-current, icomplete-selected-match, ivy-current-match).
+
+ Scan all overlays in the buffer region [BEG, END), find the line
+ whose face matches the selection heuristic, and return it (already
+ trimmed of surrounding whitespace).
+
+ Also set *OUT_LINE_INDEX to the 0-based visual line index of the
+ selected candidate (for Zoom positioning), counting only non-trivial
+ lines. Set to -1 if not found.
+
+ Returns nil if no selected candidate is found. */
+static NSString *
+ns_ax_selected_overlay_text (struct buffer *b,
+ ptrdiff_t beg, ptrdiff_t end,
+ int *out_line_index)
+{
+ *out_line_index = -1;
+
+ Lisp_Object ov_list = Foverlays_in (make_fixnum (beg),
+ make_fixnum (end));
+
+ for (Lisp_Object tail = ov_list; CONSP (tail); tail = XCDR (tail))
+ {
+ Lisp_Object ov = XCAR (tail);
+ Lisp_Object strings[2];
+ strings[0] = Foverlay_get (ov, intern_c_string ("before-string"));
+ strings[1] = Foverlay_get (ov, intern_c_string ("after-string"));
+
+ for (int s = 0; s < 2; s++)
+ {
+ if (!STRINGP (strings[s]))
+ continue;
+
+ Lisp_Object str = strings[s];
+ ptrdiff_t slen = SCHARS (str);
+ if (slen == 0)
+ continue;
+
+ /* Scan for newline positions using SDATA for efficiency.
+ The data pointer is used only in this loop, before any
+ Lisp calls (Fget_text_property etc.) that could trigger
+ GC and relocate string data. */
+ const unsigned char *data = SDATA (str);
+ ptrdiff_t byte_len = SBYTES (str);
+ /* 512 lines is sufficient for any completion UI;
+ vertico-count defaults to 10. */
+ ptrdiff_t line_starts[512];
+ ptrdiff_t line_ends[512];
+ int nlines = 0;
+ ptrdiff_t char_pos = 0, byte_pos = 0, lstart = 0;
+
+ while (byte_pos < byte_len && nlines < 512)
+ {
+ if (data[byte_pos] == '\n')
+ {
+ if (char_pos > lstart)
+ {
+ line_starts[nlines] = lstart;
+ line_ends[nlines] = char_pos;
+ nlines++;
+ }
+ lstart = char_pos + 1;
+ }
+ if (STRING_MULTIBYTE (str))
+ byte_pos += BYTES_BY_CHAR_HEAD (data[byte_pos]);
+ else
+ byte_pos++;
+ char_pos++;
+ }
+ if (char_pos > lstart && nlines < 512)
+ {
+ line_starts[nlines] = lstart;
+ line_ends[nlines] = char_pos;
+ nlines++;
+ }
+
+ /* Find the line whose face indicates selection. Track
+ visual line index for Zoom (skip whitespace-only lines
+ like Vertico's leading cursor-space). */
+ int candidate_idx = 0;
+ for (int li = 0; li < nlines; li++)
+ {
+ Lisp_Object face
+ = Fget_text_property (make_fixnum (line_starts[li]),
+ Qface, str);
+ if (ns_ax_face_is_selected (face))
+ {
+ Lisp_Object line
+ = Fsubstring_no_properties (
+ str,
+ make_fixnum (line_starts[li]),
+ make_fixnum (line_ends[li]));
+ NSString *text = [NSString stringWithLispString:line];
+ text = [text stringByTrimmingCharactersInSet:
+ [NSCharacterSet
+ whitespaceAndNewlineCharacterSet]];
+ if ([text length] > 0)
+ {
+ *out_line_index = candidate_idx;
+ return text;
+ }
+ }
+
+ /* Count non-trivial lines as candidates for Zoom. */
+ if (line_ends[li] - line_starts[li] > 1)
+ candidate_idx++;
+ }
+ }
+ }
+
+ return nil;
+}
+
+
+/* Scan buffer text of a child frame for the selected completion
+ candidate. Used for frameworks that render candidates in a
+ child frame (e.g. Corfu, Company-box) rather than as overlay
+ strings. Check the effective face (text properties + overlays)
+ at the start of each line via Fget_char_property.
+
+ Returns the candidate text (trimmed) or nil. Sets
+ *OUT_LINE_INDEX to the 0-based line index for Zoom. */
+static NSString *
+ns_ax_selected_child_frame_text (struct buffer *b, Lisp_Object buf_obj,
+ int *out_line_index)
+{
+ *out_line_index = -1;
+ ptrdiff_t beg = BUF_BEGV (b);
+ ptrdiff_t end = BUF_ZV (b);
+
+ if (beg >= end)
+ return nil;
+
+ /* Temporarily switch to the child frame buffer.
+ Fbuffer_substring_no_properties operates on current_buffer,
+ which may be a different buffer (e.g., the parent frame's). */
+ specpdl_ref count = SPECPDL_INDEX ();
+ record_unwind_current_buffer ();
+ set_buffer_internal_1 (b);
+
+ /* Get buffer text as a Lisp string for efficient scanning.
+ The buffer is a small completion popup (typically < 20 lines). */
+ Lisp_Object str
+ = Fbuffer_substring_no_properties (make_fixnum (beg),
+ make_fixnum (end));
+ if (!STRINGP (str) || SCHARS (str) == 0)
+ {
+ unbind_to (count, Qnil);
+ return nil;
+ }
+
+ /* Scan newlines (same pattern as ns_ax_selected_overlay_text).
+ The data pointer is used only in this loop, before Lisp calls. */
+ const unsigned char *data = SDATA (str);
+ ptrdiff_t byte_len = SBYTES (str);
+ ptrdiff_t line_starts[128];
+ ptrdiff_t line_ends[128];
+ int nlines = 0;
+ ptrdiff_t char_pos = 0, byte_pos = 0, lstart = 0;
+
+ while (byte_pos < byte_len && nlines < 128)
+ {
+ if (data[byte_pos] == '\n')
+ {
+ if (char_pos > lstart)
+ {
+ line_starts[nlines] = lstart;
+ line_ends[nlines] = char_pos;
+ nlines++;
+ }
+ lstart = char_pos + 1;
+ }
+ if (STRING_MULTIBYTE (str))
+ byte_pos += BYTES_BY_CHAR_HEAD (data[byte_pos]);
+ else
+ byte_pos++;
+ char_pos++;
+ }
+ if (char_pos > lstart && nlines < 128)
+ {
+ line_starts[nlines] = lstart;
+ line_ends[nlines] = char_pos;
+ nlines++;
+ }
+
+ /* Find the line with a selected face. Use Fget_char_property on
+ the BUFFER (not the string) so overlay faces are included.
+ Offset string positions by beg to get buffer positions. */
+ for (int li = 0; li < nlines; li++)
+ {
+ ptrdiff_t buf_pos = beg + line_starts[li];
+ Lisp_Object face
+ = Fget_char_property (make_fixnum (buf_pos), Qface, buf_obj);
+
+ if (ns_ax_face_is_selected (face))
+ {
+ Lisp_Object line
+ = Fsubstring_no_properties (str,
+ make_fixnum (line_starts[li]),
+ make_fixnum (line_ends[li]));
+ NSString *text = [NSString stringWithLispString:line];
+ text = [text stringByTrimmingCharactersInSet:
+ [NSCharacterSet
+ whitespaceAndNewlineCharacterSet]];
+ if ([text length] > 0)
+ {
+ *out_line_index = li;
+ unbind_to (count, Qnil);
+ return text;
+ }
+ }
+ }
+
+ unbind_to (count, Qnil);
+ return nil;
+}
+
+
/* Build accessibility text for window W, skipping invisible text.
Populates *OUT_START with the buffer start charpos.
Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS
@@ -7278,6 +7528,1102 @@ ns_ax_post_notification_with_info (id element,
@end @end
@@ -1160,7 +903,7 @@ index 2ac1d9d..fc5906a 100644
+ if (point_idx > [cachedText length]) + if (point_idx > [cachedText length])
+ point_idx = [cachedText length]; + point_idx = [cachedText length];
+ +
+ return [self lineForAXIndex:idx]; + return [self lineForAXIndex:point_idx];
+} +}
+ +
+- (NSRange)accessibilityRangeForLine:(NSInteger)line +- (NSRange)accessibilityRangeForLine:(NSInteger)line

View File

@@ -1,4 +1,4 @@
From 97baf7b5f8b0ccc85342e7d552b69b337c98f772 Mon Sep 17 00:00:00 2001 From 14323e5cddf4a7767361a76a755f51f021ca16d8 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 fc5906a..f1a1b42 100644 index 1bcc84d..dfb84ca 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -8624,6 +8624,551 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8374,6 +8374,551 @@ - (NSRect)accessibilityFrame
@end @end

View File

@@ -1,4 +1,4 @@
From 1bd12dd5d464d0c3f9774630014e434b8fb0e19e Mon Sep 17 00:00:00 2001 From 4ddd874dcf700fc830796ce16d949ba7d2fa4d78 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 f1a1b42..91d0241 100644 index dfb84ca..c852929 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -9169,6 +9169,292 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8919,6 +8919,292 @@ - (NSRect)accessibilityFrame
@end @end

View File

@@ -1,4 +1,4 @@
From 3bbe8ba29725a4708595befa6b73e5873a2aab43 Mon Sep 17 00:00:00 2001 From e8472811cf1d730e10b01d2e10d6a158f0cf441a 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
@@ -29,10 +29,10 @@ Known limitations documented in patch 6 Texinfo node.
2 files changed, 408 insertions(+), 3 deletions(-) 2 files changed, 408 insertions(+), 3 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS diff --git a/etc/NEWS b/etc/NEWS
index 7367e3c..608650e 100644 index 04bf92a..bd94b66 100644
--- a/etc/NEWS --- a/etc/NEWS
+++ b/etc/NEWS +++ b/etc/NEWS
@@ -4374,6 +4374,19 @@ allowing Emacs users access to speech recognition utilities. @@ -4382,6 +4382,19 @@ allowing Emacs users access to speech recognition utilities.
Note: Accepting this permission allows the use of system APIs, which may Note: Accepting this permission allows the use of system APIs, which may
send user data to Apple's speech recognition servers. send user data to Apple's speech recognition servers.
@@ -53,10 +53,10 @@ index 7367e3c..608650e 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 91d0241..125e52c 100644 index c852929..b3bef4b 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -1105,6 +1105,11 @@ ns_update_end (struct frame *f) @@ -1105,6 +1105,11 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
unblock_input (); unblock_input ();
ns_updating_frame = NULL; ns_updating_frame = NULL;
@@ -68,7 +68,7 @@ index 91d0241..125e52c 100644
} }
static void static void
@@ -3233,6 +3238,43 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, @@ -3233,6 +3238,43 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
/* Prevent the cursor from being drawn outside the text area. */ /* Prevent the cursor from being drawn outside the text area. */
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
@@ -112,7 +112,7 @@ index 91d0241..125e52c 100644
ns_focus (f, NULL, 0); ns_focus (f, NULL, 0);
NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
@@ -7531,7 +7573,6 @@ ns_ax_post_notification_with_info (id element, @@ -7281,7 +7323,6 @@ - (id)accessibilityTopLevelUIElement
@@ -120,7 +120,7 @@ index 91d0241..125e52c 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,
@@ -8625,7 +8666,6 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8375,7 +8416,6 @@ - (NSRect)accessibilityFrame
@end @end
@@ -128,7 +128,7 @@ index 91d0241..125e52c 100644
/* =================================================================== /* ===================================================================
EmacsAccessibilityBuffer (Notifications) — AX event dispatch EmacsAccessibilityBuffer (Notifications) — AX event dispatch
@@ -9170,7 +9210,6 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8920,7 +8960,6 @@ - (NSRect)accessibilityFrame
@end @end
@@ -136,7 +136,7 @@ index 91d0241..125e52c 100644
/* =================================================================== /* ===================================================================
EmacsAccessibilityInteractiveSpan — helpers and implementation EmacsAccessibilityInteractiveSpan — helpers and implementation
=================================================================== */ =================================================================== */
@@ -9500,6 +9539,7 @@ ns_ax_scan_interactive_spans (struct window *w, @@ -9250,6 +9289,7 @@ - (void)dealloc
[layer release]; [layer release];
#endif #endif
@@ -144,7 +144,7 @@ index 91d0241..125e52c 100644
[[self menu] release]; [[self menu] release];
[super dealloc]; [super dealloc];
} }
@@ -10848,6 +10888,32 @@ ns_in_echo_area (void) @@ -10598,6 +10638,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
@@ -177,7 +177,7 @@ index 91d0241..125e52c 100644
} }
@@ -12085,6 +12151,332 @@ ns_in_echo_area (void) @@ -11835,6 +11901,332 @@ - (int) fullscreenState
return fs_state; return fs_state;
} }

View File

@@ -1,4 +1,4 @@
From 5ddf6227b581bf292fc187a1ebcaf80d2cd4cf2a Mon Sep 17 00:00:00 2001 From 753c2e18a589d38d70df221fa7490d94bdaba937 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
@@ -12,7 +12,7 @@ Zoom cursor tracking, ns-accessibility-enabled, known limitations.
1 file changed, 75 insertions(+) 1 file changed, 75 insertions(+)
diff --git a/doc/emacs/macos.texi b/doc/emacs/macos.texi diff --git a/doc/emacs/macos.texi b/doc/emacs/macos.texi
index 6bd334f..c4dced5 100644 index 6bd334f..4825cf9 100644
--- a/doc/emacs/macos.texi --- a/doc/emacs/macos.texi
+++ b/doc/emacs/macos.texi +++ b/doc/emacs/macos.texi
@@ -36,6 +36,7 @@ Support}), but we hope to improve it in the future. @@ -36,6 +36,7 @@ Support}), but we hope to improve it in the future.
@@ -78,9 +78,9 @@ index 6bd334f..c4dced5 100644
+ +
+@itemize @bullet +@itemize @bullet
+@item +@item
+Accessibility text is capped at 100,000 UTF-16 units per window. +Very large buffers (tens of megabytes) may cause slow initial
+Buffers exceeding this limit are truncated for accessibility purposes; +accessibility text extraction. Once cached, subsequent queries
+VoiceOver will announce ``end of text'' at the cap boundary. +are fast.
+@item +@item
+Mode-line text extraction handles only character glyphs. Mode lines +Mode-line text extraction handles only character glyphs. Mode lines
+using icon fonts (e.g., @code{doom-modeline} with nerd-font icons) +using icon fonts (e.g., @code{doom-modeline} with nerd-font icons)

View File

@@ -1,4 +1,4 @@
From 8f619411ec75efbd18e663bb3f2ed6f8c9af60d8 Mon Sep 17 00:00:00 2001 From 6bb9020421ce0e8459d2095385972b47c64fd184 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
@@ -52,8 +52,8 @@ Independent overlay branch, BUF_CHARS_MODIFF gating, candidate
announcement with overlay Zoom rect storage. announcement with overlay Zoom rect storage.
--- ---
src/nsterm.h | 3 + src/nsterm.h | 3 +
src/nsterm.m | 361 ++++++++++++++++++++++++++++++++++++++++++++++----- src/nsterm.m | 359 ++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 329 insertions(+), 35 deletions(-) 2 files changed, 327 insertions(+), 35 deletions(-)
diff --git a/src/nsterm.h b/src/nsterm.h diff --git a/src/nsterm.h b/src/nsterm.h
index 5298386..a007925 100644 index 5298386..a007925 100644
@@ -77,10 +77,10 @@ index 5298386..a007925 100644
BOOL font_panel_active; BOOL font_panel_active;
NSFont *font_panel_result; NSFont *font_panel_result;
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 125e52c..ebd52c6 100644 index b3bef4b..7025e6e 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -3258,7 +3258,12 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, @@ -3258,7 +3258,12 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
&& MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 && MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
if (UAZoomEnabled ()) if (UAZoomEnabled ())
{ {
@@ -94,9 +94,9 @@ index 125e52c..ebd52c6 100644
NSRect screenRect = [[view window] convertRectToScreen:windowRect]; NSRect screenRect = [[view window] convertRectToScreen:windowRect];
CGRect cgRect = NSRectToCGRect (screenRect); CGRect cgRect = NSRectToCGRect (screenRect);
@@ -7159,11 +7164,156 @@ ns_ax_selected_child_frame_text (struct buffer *b, Lisp_Object buf_obj, @@ -6909,11 +6914,154 @@ Accessibility virtual elements (macOS / Cocoa only)
}
/* ---- Helper: extract buffer text for accessibility ---- */
+/* Return true if FACE is or contains a face symbol whose name +/* Return true if FACE is or contains a face symbol whose name
+ includes "current" or "selected", indicating a highlighted + includes "current" or "selected", indicating a highlighted
@@ -242,8 +242,6 @@ index 125e52c..ebd52c6 100644
+ +
+ return nil; + return nil;
+} +}
+
+
/* Build accessibility text for window W, skipping invisible text. /* Build accessibility text for window W, skipping invisible text.
Populates *OUT_START with the buffer start charpos. Populates *OUT_START with the buffer start charpos.
Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS
@@ -252,7 +250,7 @@ index 125e52c..ebd52c6 100644
static NSString * static NSString *
ns_ax_buffer_text (struct window *w, ptrdiff_t *out_start, ns_ax_buffer_text (struct window *w, ptrdiff_t *out_start,
ns_ax_visible_run **out_runs, NSUInteger *out_nruns) ns_ax_visible_run **out_runs, NSUInteger *out_nruns)
@@ -7234,7 +7384,7 @@ ns_ax_buffer_text (struct window *w, ptrdiff_t *out_start, @@ -6984,7 +7132,7 @@ Accessibility virtual elements (macOS / Cocoa only)
/* Extract this visible run's text. Use /* Extract this visible run's text. Use
Fbuffer_substring_no_properties which correctly handles the Fbuffer_substring_no_properties which correctly handles the
@@ -261,7 +259,7 @@ index 125e52c..ebd52c6 100644
include garbage bytes when the run spans the gap position. */ include garbage bytes when the run spans the gap position. */
Lisp_Object lstr = Fbuffer_substring_no_properties ( Lisp_Object lstr = Fbuffer_substring_no_properties (
make_fixnum (pos), make_fixnum (run_end)); make_fixnum (pos), make_fixnum (run_end));
@@ -7315,7 +7465,7 @@ ns_ax_frame_for_range (struct window *w, EmacsView *view, @@ -7065,7 +7213,7 @@ Mode lines using icon fonts (e.g. doom-modeline with nerd-font)
return NSZeroRect; return NSZeroRect;
/* charpos_start and charpos_len are already in buffer charpos /* charpos_start and charpos_len are already in buffer charpos
@@ -270,7 +268,7 @@ index 125e52c..ebd52c6 100644
charposForAccessibilityIndex which handles invisible text. */ charposForAccessibilityIndex which handles invisible text. */
ptrdiff_t cp_start = charpos_start; ptrdiff_t cp_start = charpos_start;
ptrdiff_t cp_end = cp_start + charpos_len; ptrdiff_t cp_end = cp_start + charpos_len;
@@ -7794,6 +7944,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7544,6 +7692,7 @@ @implementation EmacsAccessibilityBuffer
@synthesize cachedOverlayModiff; @synthesize cachedOverlayModiff;
@synthesize cachedTextStart; @synthesize cachedTextStart;
@synthesize cachedModiff; @synthesize cachedModiff;
@@ -278,7 +276,7 @@ index 125e52c..ebd52c6 100644
@synthesize cachedPoint; @synthesize cachedPoint;
@synthesize cachedMarkActive; @synthesize cachedMarkActive;
@synthesize cachedCompletionAnnouncement; @synthesize cachedCompletionAnnouncement;
@@ -7891,7 +8042,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7641,7 +7790,7 @@ - (void)ensureTextCache
NSTRACE ("EmacsAccessibilityBuffer ensureTextCache"); NSTRACE ("EmacsAccessibilityBuffer ensureTextCache");
/* This method is only called from the main thread (AX getters /* This method is only called from the main thread (AX getters
dispatch_sync to main first). Reads of cachedText/cachedTextModiff dispatch_sync to main first). Reads of cachedText/cachedTextModiff
@@ -287,7 +285,7 @@ index 125e52c..ebd52c6 100644
write section at the end needs synchronization to protect write section at the end needs synchronization to protect
against concurrent reads from AX server thread. */ against concurrent reads from AX server thread. */
eassert ([NSThread isMainThread]); eassert ([NSThread isMainThread]);
@@ -7904,16 +8055,15 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7654,16 +7803,15 @@ - (void)ensureTextCache
return; return;
ptrdiff_t modiff = BUF_MODIFF (b); ptrdiff_t modiff = BUF_MODIFF (b);
@@ -310,7 +308,7 @@ index 125e52c..ebd52c6 100644
&& cachedTextStart == BUF_BEGV (b) && cachedTextStart == BUF_BEGV (b)
&& pt >= cachedTextStart && pt >= cachedTextStart
&& (textLen == 0 && (textLen == 0
@@ -7930,7 +8080,6 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7680,7 +7828,6 @@ - (void)ensureTextCache
[cachedText release]; [cachedText release];
cachedText = [text retain]; cachedText = [text retain];
cachedTextModiff = modiff; cachedTextModiff = modiff;
@@ -318,7 +316,7 @@ index 125e52c..ebd52c6 100644
cachedTextStart = start; cachedTextStart = start;
if (visibleRuns) if (visibleRuns)
@@ -7995,7 +8144,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7745,7 +7892,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
/* Binary search: runs are sorted by charpos (ascending). Find the /* Binary search: runs are sorted by charpos (ascending). Find the
run whose [charpos, charpos+length) range contains the target, run whose [charpos, charpos+length) range contains the target,
or the nearest run after an invisible gap. O(log n) instead of or the nearest run after an invisible gap. O(log n) instead of
@@ -327,7 +325,7 @@ index 125e52c..ebd52c6 100644
NSUInteger lo = 0, hi = visibleRunCount; NSUInteger lo = 0, hi = visibleRunCount;
while (lo < hi) while (lo < hi)
{ {
@@ -8008,7 +8157,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7758,7 +7905,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
else else
{ {
/* Found: charpos is inside this run. Compute UTF-16 delta /* Found: charpos is inside this run. Compute UTF-16 delta
@@ -336,7 +334,7 @@ index 125e52c..ebd52c6 100644
NSUInteger chars_in = (NSUInteger)(charpos - r->charpos); NSUInteger chars_in = (NSUInteger)(charpos - r->charpos);
if (chars_in == 0 || !cachedText) if (chars_in == 0 || !cachedText)
return r->ax_start; return r->ax_start;
@@ -8033,10 +8182,10 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7783,10 +7930,10 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
/* 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
@@ -349,7 +347,7 @@ index 125e52c..ebd52c6 100644
@synchronized (self) @synchronized (self)
{ {
if (visibleRunCount == 0) if (visibleRunCount == 0)
@@ -8070,7 +8219,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7820,7 +7967,7 @@ - (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
return cp; return cp;
} }
} }
@@ -358,7 +356,7 @@ index 125e52c..ebd52c6 100644
if (lo > 0) if (lo > 0)
{ {
ns_ax_visible_run *last = &visibleRuns[visibleRunCount - 1]; ns_ax_visible_run *last = &visibleRuns[visibleRunCount - 1];
@@ -8092,7 +8241,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -7842,7 +7989,7 @@ - (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
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
@@ -367,13 +365,10 @@ index 125e52c..ebd52c6 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
@@ -8443,7 +8592,51 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8196,6 +8343,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber
if (point_idx > [cachedText length]) return [self lineForAXIndex:point_idx];
point_idx = [cachedText length]; }
+ return [self lineForAXIndex:point_idx];
+}
+
+- (NSString *)accessibilityStringForRange:(NSRange)range +- (NSString *)accessibilityStringForRange:(NSRange)range
+{ +{
+ if (![NSThread isMainThread]) + if (![NSThread isMainThread])
@@ -414,12 +409,14 @@ index 125e52c..ebd52c6 100644
+ if (idx > [cachedText length]) + if (idx > [cachedText length])
+ idx = [cachedText length]; + idx = [cachedText length];
+ +
return [self lineForAXIndex:idx]; + return [self lineForAXIndex:idx];
+
+}
+ +
}
- (NSRange)accessibilityRangeForLine:(NSInteger)line - (NSRange)accessibilityRangeForLine:(NSInteger)line
@@ -8667,7 +8860,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, {
if (![NSThread isMainThread])
@@ -8417,7 +8608,7 @@ - (NSRect)accessibilityFrame
/* =================================================================== /* ===================================================================
@@ -428,7 +425,7 @@ index 125e52c..ebd52c6 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).
@@ -8682,7 +8875,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8432,7 +8623,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point
if (point > self.cachedPoint if (point > self.cachedPoint
&& point - self.cachedPoint == 1) && point - self.cachedPoint == 1)
{ {
@@ -437,7 +434,7 @@ index 125e52c..ebd52c6 100644
[self invalidateTextCache]; [self invalidateTextCache];
[self ensureTextCache]; [self ensureTextCache];
if (cachedText) if (cachedText)
@@ -8701,7 +8894,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8451,7 +8642,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
@@ -446,7 +443,7 @@ index 125e52c..ebd52c6 100644
self.cachedPoint = point; self.cachedPoint = point;
NSDictionary *change = @{ NSDictionary *change = @{
@@ -9034,14 +9227,112 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8784,14 +8975,112 @@ - (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) --- */
@@ -561,7 +558,7 @@ index 125e52c..ebd52c6 100644
per the WebKit/Chromium pattern. */ per the WebKit/Chromium pattern. */
else if (point != self.cachedPoint || markActive != self.cachedMarkActive) else if (point != self.cachedPoint || markActive != self.cachedMarkActive)
{ {
@@ -9211,7 +9502,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, @@ -8961,7 +9250,7 @@ - (NSRect)accessibilityFrame
/* =================================================================== /* ===================================================================
@@ -570,7 +567,7 @@ index 125e52c..ebd52c6 100644
=================================================================== */ =================================================================== */
/* Scan visible range of window W for interactive spans. /* Scan visible range of window W for interactive spans.
@@ -9402,7 +9693,7 @@ ns_ax_scan_interactive_spans (struct window *w, @@ -9152,7 +9441,7 @@ - (NSRect) accessibilityFrame
- (BOOL) isAccessibilityFocused - (BOOL) isAccessibilityFocused
{ {
/* Read the cached point stored by EmacsAccessibilityBuffer on the main /* Read the cached point stored by EmacsAccessibilityBuffer on the main
@@ -579,7 +576,7 @@ index 125e52c..ebd52c6 100644
EmacsAccessibilityBuffer *pb = self.parentBuffer; EmacsAccessibilityBuffer *pb = self.parentBuffer;
if (!pb) if (!pb)
return NO; return NO;
@@ -9419,7 +9710,7 @@ ns_ax_scan_interactive_spans (struct window *w, @@ -9169,7 +9458,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
@@ -588,7 +585,7 @@ index 125e52c..ebd52c6 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)))
@@ -9445,7 +9736,7 @@ ns_ax_scan_interactive_spans (struct window *w, @@ -9195,7 +9484,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
@end @end
@@ -597,7 +594,7 @@ index 125e52c..ebd52c6 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)
@@ -10765,13 +11056,13 @@ ns_in_echo_area (void) @@ -10515,13 +10804,13 @@ - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
if (old_title == 0) if (old_title == 0)
{ {
char *t = strdup ([[[self window] title] UTF8String]); char *t = strdup ([[[self window] title] UTF8String]);
@@ -613,7 +610,7 @@ index 125e52c..ebd52c6 100644
[window setTitle: [NSString stringWithUTF8String: size_title]]; [window setTitle: [NSString stringWithUTF8String: size_title]];
[window display]; [window display];
xfree (size_title); xfree (size_title);
@@ -12167,7 +12458,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, @@ -11917,7 +12206,7 @@ - (int) fullscreenState
if (WINDOW_LEAF_P (w)) if (WINDOW_LEAF_P (w))
{ {
@@ -622,7 +619,7 @@ index 125e52c..ebd52c6 100644
EmacsAccessibilityBuffer *elem EmacsAccessibilityBuffer *elem
= [existing objectForKey:[NSValue valueWithPointer:w]]; = [existing objectForKey:[NSValue valueWithPointer:w]];
if (!elem) if (!elem)
@@ -12201,7 +12492,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, @@ -11951,7 +12240,7 @@ - (int) fullscreenState
} }
else else
{ {
@@ -631,7 +628,7 @@ index 125e52c..ebd52c6 100644
Lisp_Object child = w->contents; Lisp_Object child = w->contents;
while (!NILP (child)) while (!NILP (child))
{ {
@@ -12313,7 +12604,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, @@ -12063,7 +12352,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
@@ -640,7 +637,7 @@ index 125e52c..ebd52c6 100644
Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe); Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe);
if (!EQ (curRoot, lastRootWindow)) if (!EQ (curRoot, lastRootWindow))
{ {
@@ -12322,12 +12613,12 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, @@ -12072,12 +12361,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 d68d1334147a7de273e39cf26c778389faa424ad Mon Sep 17 00:00:00 2001 From aed0e5447ad6bfb5dc15f7d47b1793e735afd995 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
@@ -43,8 +43,8 @@ childFrameCompletionActive flag.
refocus parent buffer element when child frame closes. refocus parent buffer element when child frame closes.
--- ---
src/nsterm.h | 2 + src/nsterm.h | 2 +
src/nsterm.m | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/nsterm.m | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 254 insertions(+), 1 deletion(-) 2 files changed, 256 insertions(+), 1 deletion(-)
diff --git a/src/nsterm.h b/src/nsterm.h diff --git a/src/nsterm.h b/src/nsterm.h
index a007925..1a8a84d 100644 index a007925..1a8a84d 100644
@@ -67,13 +67,15 @@ index a007925..1a8a84d 100644
@end @end
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index ebd52c6..a7025a9 100644 index 7025e6e..dba0e49 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -7310,6 +7310,110 @@ ns_ax_selected_overlay_text (struct buffer *b, @@ -7058,6 +7058,112 @@ visual line index for Zoom (skip whitespace-only lines
return nil;
} }
+
+
+/* Scan buffer text of a child frame for the selected completion +/* Scan buffer text of a child frame for the selected completion
+ candidate. Used for frameworks that render candidates in a + candidate. Used for frameworks that render candidates in a
+ child frame (e.g. Corfu, Company-box) rather than as overlay + child frame (e.g. Corfu, Company-box) rather than as overlay
@@ -181,7 +183,7 @@ index ebd52c6..a7025a9 100644
/* Build accessibility text for window W, skipping invisible text. /* Build accessibility text for window W, skipping invisible text.
Populates *OUT_START with the buffer start charpos. Populates *OUT_START with the buffer start charpos.
Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS
@@ -12588,6 +12692,105 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, @@ -12336,6 +12442,105 @@ - (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. */
@@ -287,7 +289,7 @@ index ebd52c6..a7025a9 100644
- (void)postAccessibilityUpdates - (void)postAccessibilityUpdates
{ {
NSTRACE ("[EmacsView postAccessibilityUpdates]"); NSTRACE ("[EmacsView postAccessibilityUpdates]");
@@ -12598,11 +12801,59 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, @@ -12346,11 +12551,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