patches: review fixes — specpdl protection, overlay_modiff tracking, binary search, enum cleanup

M1: accessibilityRangeForPosition uses specpdl unwind protection for
    block_input/unblock_input (consistent with all other methods).
M2: Track BUF_OVERLAY_MODIFF in ensureTextCache — overlay-only changes
    (timer-based completion highlight) now invalidate the text cache.
M3: Detect narrowing/widening by comparing cachedTextStart vs BUF_BEGV.
m1: Binary search (O(log n)) for visible runs in both
    accessibilityIndexForCharpos and charposForAccessibilityIndex.
m3: Add EmacsAXSpanTypeNone = -1 to enum instead of (EmacsAXSpanType)-1 cast.
m5: Add TODO comment in ns_ax_mode_line_text about non-CHAR_GLYPH limitation.
README: Remove resolved overlay_modiff limitation, document binary search
    and narrowing detection, update architecture section.
This commit is contained in:
2026-02-27 16:56:05 +01:00
parent 765725aaef
commit 65c799dc3f
2 changed files with 75 additions and 49 deletions

View File

@@ -77,7 +77,8 @@ ARCHITECTURE
text range, line/index/range conversions, frame-for-range,
range-for-position, and insertion-point-line-number.
- Maintains a text cache (cachedText / visibleRuns) keyed on
BUF_MODIFF. The cache is the single source of truth for all
BUF_MODIFF, BUF_OVERLAY_MODIFF, and BUF_BEGV (narrowing).
The cache is the single source of truth for all
index-to-charpos and charpos-to-index mappings.
- Detects buffer edits (modiff change), cursor movement (point
change), and mark changes, and posts the appropriate
@@ -282,14 +283,19 @@ TEXT CACHE AND VISIBLE RUNS
non-contiguous visible segments. The mapping array is stored in the
EmacsAccessibilityBuffer ivar `visibleRuns' (C array, xmalloc'd).
Index mapping (charpos <-> ax_index) does a linear scan of the run
array. Within a run, UTF-16 unit counting uses
Index mapping (charpos <-> ax_index) uses binary search over the
sorted run array — O(log n) per lookup. Within a run, UTF-16 unit
counting uses
rangeOfComposedCharacterSequenceAtIndex: to handle surrogate pairs
(emoji, rare CJK) correctly -- one Emacs character may occupy 2
UTF-16 units.
Cache invalidation is triggered whenever BUF_MODIFF changes
(ensureTextCache compares cachedTextModiff). The cache is also
Cache invalidation is triggered whenever BUF_MODIFF or
BUF_OVERLAY_MODIFF changes (ensureTextCache compares both
cachedTextModiff and cachedOverlayModiff). Additionally,
narrowing/widening is detected by comparing cachedTextStart
against BUF_BEGV — these operations change the visible region
without bumping either modiff counter. The cache is also
invalidated when the window tree is rebuilt. NS_AX_TEXT_CAP = 100,000
UTF-16 units (~200 KB) caps total exposure; buffers larger than
~50,000 lines are truncated for accessibility purposes. VoiceOver
@@ -499,13 +505,6 @@ KEY DESIGN DECISIONS
KNOWN LIMITATIONS
-----------------
- BUF_OVERLAY_MODIFF is not tracked. Overlay changes (e.g. moving
the completions-highlight overlay via Tab without changing buffer
text) do not bump BUF_MODIFF, so the text cache is not invalidated.
The notification logic detects point changes (cachedPoint) which
covers the common case, but overlay-only changes with a stationary
point would be missed. A future fix would compare overlay_modiff.
- Interactive span scan uses Fnext_single_property_change across
multiple properties to skip non-interactive regions in bulk, but
still visits every property-change boundary. For buffers with