From c05b46b0583305ad1a2dfcc26172dfbc7c51ec47 Mon Sep 17 00:00:00 2001 From: Daneel Date: Sat, 28 Feb 2026 17:42:00 +0100 Subject: [PATCH] patches: 0007 textDidChange fix (hl-line-mode), remove config workaround --- config.el | 5 -- ...lay-completion-candidates-for-VoiceO.patch | 54 ++++++++++++------- ...d-frame-completion-candidates-for-Vo.patch | 2 +- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/config.el b/config.el index 872d05b..c3cd29f 100644 --- a/config.el +++ b/config.el @@ -905,11 +905,6 @@ Skip for beamer exports — beamer uses adjustbox on plain tabular." "RET" #'dired-find-alternate-file "^" #'dired-up-directory)) -;; Disable hl-line-mode — its text property changes bump BUF_MODIFF -;; on every cursor movement, which blocks VoiceOver's -;; SelectedTextChanged notification in read-only buffers (dired, etc.) -(global-hl-line-mode -1) -(remove-hook 'dired-mode-hook #'hl-line-mode) ;; Dirvish — modern dired replacement (use-package! dirvish diff --git a/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch b/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch index d698d82..119cfaa 100644 --- a/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch +++ b/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch @@ -1,4 +1,4 @@ -From 8157451dedda9b43de47f82d1deb85c9d2853a35 Mon Sep 17 00:00:00 2001 +From bb69ef51db4c87dfe88861927264121f95fc627f Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 14:46:25 +0100 Subject: [PATCH 1/2] 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. --- src/nsterm.h | 3 + - src/nsterm.m | 319 +++++++++++++++++++++++++++++++++++++++++++++------ - 2 files changed, 286 insertions(+), 36 deletions(-) + src/nsterm.m | 335 +++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 300 insertions(+), 38 deletions(-) diff --git a/src/nsterm.h b/src/nsterm.h index 51c30ca..5c15639 100644 @@ -77,7 +77,7 @@ index 51c30ca..5c15639 100644 BOOL font_panel_active; NSFont *font_panel_result; diff --git a/src/nsterm.m b/src/nsterm.m -index 1780194..d13c5c7 100644 +index 1780194..6efeb1d 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3258,7 +3258,12 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, @@ -403,26 +403,34 @@ index 1780194..d13c5c7 100644 self.cachedPoint = point; NSDictionary *change = @{ -@@ -8789,14 +8938,112 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, +@@ -8789,16 +8938,126 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, BOOL markActive = !NILP (BVAR (b, mark_active)); /* --- Text changed (edit) --- */ + ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b); ++ BOOL textDidChange = NO; if (modiff != self.cachedModiff) { self.cachedModiff = modiff; - [self postTextChangedNotification:point]; + /* Only post ValueChanged when actual characters changed. -+ Text property changes (e.g. face updates from ++ Text property changes (e.g. face updates from hl-line-mode, + vertico--prompt-selection) bump BUF_MODIFF but not + BUF_CHARS_MODIFF. Posting ValueChanged for property-only + changes causes VoiceOver to say "new line" when the diff -+ is non-empty due to overlay content changes. */ ++ is non-empty due to overlay content changes. ++ ++ Use textDidChange to avoid blocking the cursor-move branch ++ below: property-only changes must not prevent ++ SelectedTextChanged from firing when point also moved ++ (e.g. hl-line-mode updates face properties on every cursor ++ movement in dired and other read-only buffers). */ + if (chars_modiff != self.cachedCharsModiff) + { + self.cachedCharsModiff = chars_modiff; + self.emacsView->overlayZoomActive = NO; + [self postTextChangedNotification:point]; ++ textDidChange = YES; + } + } + @@ -514,11 +522,19 @@ index 1780194..d13c5c7 100644 /* --- Cursor moved or selection changed --- - Use 'else if' — edits and selection moves are mutually exclusive -+ Use 'else if' --- edits and selection moves are mutually exclusive - per the WebKit/Chromium pattern. */ - else if (point != self.cachedPoint || markActive != self.cachedMarkActive) +- per the WebKit/Chromium pattern. */ +- else if (point != self.cachedPoint || markActive != self.cachedMarkActive) ++ Skip when ValueChanged was already posted (edits and selection ++ moves are mutually exclusive per the WebKit/Chromium pattern). ++ But DO fire when only text properties changed (BUF_MODIFF bumped ++ without BUF_CHARS_MODIFF) --- hl-line-mode and similar packages ++ update face properties on every cursor movement. */ ++ if (!textDidChange ++ && (point != self.cachedPoint || markActive != self.cachedMarkActive)) { -@@ -8966,7 +9213,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, + ptrdiff_t oldPoint = self.cachedPoint; + BOOL oldMarkActive = self.cachedMarkActive; +@@ -8966,7 +9225,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, /* =================================================================== @@ -527,7 +543,7 @@ index 1780194..d13c5c7 100644 =================================================================== */ /* Scan visible range of window W for interactive spans. -@@ -9157,7 +9404,7 @@ ns_ax_scan_interactive_spans (struct window *w, +@@ -9157,7 +9416,7 @@ ns_ax_scan_interactive_spans (struct window *w, - (BOOL) isAccessibilityFocused { /* Read the cached point stored by EmacsAccessibilityBuffer on the main @@ -536,7 +552,7 @@ index 1780194..d13c5c7 100644 EmacsAccessibilityBuffer *pb = self.parentBuffer; if (!pb) return NO; -@@ -9174,7 +9421,7 @@ ns_ax_scan_interactive_spans (struct window *w, +@@ -9174,7 +9433,7 @@ ns_ax_scan_interactive_spans (struct window *w, dispatch_async (dispatch_get_main_queue (), ^{ /* lwin is a Lisp_Object captured by value. This is GC-safe because Lisp_Objects are tagged integers/pointers that @@ -545,7 +561,7 @@ index 1780194..d13c5c7 100644 Emacs. The WINDOW_LIVE_P check below guards against the window being deleted between capture and execution. */ if (!WINDOWP (lwin) || NILP (Fwindow_live_p (lwin))) -@@ -9200,7 +9447,7 @@ ns_ax_scan_interactive_spans (struct window *w, +@@ -9200,7 +9459,7 @@ ns_ax_scan_interactive_spans (struct window *w, @end @@ -554,7 +570,7 @@ index 1780194..d13c5c7 100644 Methods are kept here (same .m file) so they access the ivars declared in the @interface ivar block. */ @implementation EmacsAccessibilityBuffer (InteractiveSpans) -@@ -10520,13 +10767,13 @@ ns_in_echo_area (void) +@@ -10520,13 +10779,13 @@ ns_in_echo_area (void) if (old_title == 0) { char *t = strdup ([[[self window] title] UTF8String]); @@ -570,7 +586,7 @@ index 1780194..d13c5c7 100644 [window setTitle: [NSString stringWithUTF8String: size_title]]; [window display]; xfree (size_title); -@@ -11922,7 +12169,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, +@@ -11922,7 +12181,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, if (WINDOW_LEAF_P (w)) { @@ -579,7 +595,7 @@ index 1780194..d13c5c7 100644 EmacsAccessibilityBuffer *elem = [existing objectForKey:[NSValue valueWithPointer:w]]; if (!elem) -@@ -11956,7 +12203,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, +@@ -11956,7 +12215,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, } else { @@ -588,7 +604,7 @@ index 1780194..d13c5c7 100644 Lisp_Object child = w->contents; while (!NILP (child)) { -@@ -12068,7 +12315,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, +@@ -12068,7 +12327,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, accessibilityUpdating = YES; /* Detect window tree change (split, delete, new buffer). Compare @@ -597,7 +613,7 @@ index 1780194..d13c5c7 100644 Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe); if (!EQ (curRoot, lastRootWindow)) { -@@ -12077,12 +12324,12 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, +@@ -12077,12 +12336,12 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view, } /* If tree is stale, rebuild FIRST so we don't iterate freed diff --git a/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch b/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch index 4acfab5..29d16dc 100644 --- a/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch +++ b/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch @@ -1,4 +1,4 @@ -From 0d018f15c088668df039e4776972969da1a719d5 Mon Sep 17 00:00:00 2001 +From bdb5aefe515662fb294b719ad32fabc4008a5cb8 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 16:01:29 +0100 Subject: [PATCH 2/2] ns: announce child frame completion candidates for