- Remove 'extern Lisp_Object last_command_event' - last_command_event
is a macro in globals.h (expands to globals.f_last_command_event),
so an extern declaration conflicts with the existing
'extern struct emacs_globals globals'
- Replace invalid C escape sequences '\C-n' and '\C-p' with
('n' & 0x1f) and ('p' & 0x1f) respectively
Root cause: ns_ax_buffer_text used BUF_BYTE_ADDRESS + raw pointer
read which crosses the buffer gap when visible runs span it. The gap
follows point, so completion cycling and dired navigation reliably
trigger corruption — VoiceOver reads wrong text.
Fix: Replace raw pointer extraction with Fbuffer_substring_no_properties
which handles the gap internally. Add ax_length field to visible run
struct for accurate UTF-16 length tracking (fixes supplementary
Unicode character offset drift).
Secondary: ax_offset accumulation now uses NSString length (UTF-16
units) instead of Emacs char count, preventing progressive drift in
index mapping for subsequent visible runs.
Major architectural change: ns_ax_buffer_text now skips text with
the 'invisible' property using TEXT_PROP_MEANS_INVISIBLE. Accessibility
text matches what the user sees on screen.
New ns_ax_visible_run struct tracks charpos↔ax-index mapping for each
visible text run. All 8 index conversion sites updated. Fixes wrong
line reading in dired, completions, and any buffer with invisible text.
Completions announcement now detects completions-highlight overlay
and reads the full highlighted candidate text instead of partial line.
2000-line patch, 54 references to new mapping infrastructure.
1. setAccessibilitySelectedTextRange: — enables bidirectional cursor
sync. Converts AX index to buffer charpos, moves point via
SET_PT_BOTH. VoiceOver can now place cursor in text interaction mode.
2. setAccessibilityFocused: — handles VO+Shift+Down interaction entry.
Ensures NS window focus, posts SelectedTextChanged so VoiceOver
reads current line.
3. Completions announcement — when point changes in a non-focused
buffer (e.g. *Completions* during Tab), posts
AnnouncementRequestedNotification with the current line text.
VoiceOver speaks the selected completion while minibuffer keeps focus.