patches: 0007 fix hl-line-mode blocking SelectedTextChanged
hl-line-mode (and similar) bumps BUF_MODIFF via text property changes on every cursor movement. The else-if structure caused the modiff branch to fire (skipping ValueChanged correctly) but also blocked the cursor-move branch (SelectedTextChanged). Fix: use textDidChange flag to decouple the two branches. ValueChanged and SelectedTextChanged remain mutually exclusive for real edits, but SelectedTextChanged now fires when only text properties changed.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
From 8157451dedda9b43de47f82d1deb85c9d2853a35 Mon Sep 17 00:00:00 2001
|
From 7d5fe56a0e86aee931787eda2e4988a6b4815291 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] ns: announce overlay completion candidates for VoiceOver
|
Subject: [PATCH 1/2] ns: announce overlay completion candidates for VoiceOver
|
||||||
|
|
||||||
Completion frameworks such as Vertico, Ivy, and Icomplete render
|
Completion frameworks such as Vertico, Ivy, and Icomplete render
|
||||||
candidates via overlay before-string/after-string properties rather
|
candidates via overlay before-string/after-string properties rather
|
||||||
@@ -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 | 319 +++++++++++++++++++++++++++++++++++++++++++++------
|
src/nsterm.m | 335 +++++++++++++++++++++++++++++++++++++++++++++------
|
||||||
2 files changed, 286 insertions(+), 36 deletions(-)
|
2 files changed, 300 insertions(+), 38 deletions(-)
|
||||||
|
|
||||||
diff --git a/src/nsterm.h b/src/nsterm.h
|
diff --git a/src/nsterm.h b/src/nsterm.h
|
||||||
index 51c30ca..5c15639 100644
|
index 51c30ca..5c15639 100644
|
||||||
@@ -77,7 +77,7 @@ index 51c30ca..5c15639 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 1780194..d13c5c7 100644
|
index 1780194..6efeb1d 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 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
|
||||||
@@ -403,26 +403,34 @@ index 1780194..d13c5c7 100644
|
|||||||
self.cachedPoint = point;
|
self.cachedPoint = point;
|
||||||
|
|
||||||
NSDictionary *change = @{
|
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));
|
BOOL markActive = !NILP (BVAR (b, mark_active));
|
||||||
|
|
||||||
/* --- Text changed (edit) --- */
|
/* --- Text changed (edit) --- */
|
||||||
+ ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b);
|
+ ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b);
|
||||||
|
+ BOOL textDidChange = NO;
|
||||||
if (modiff != self.cachedModiff)
|
if (modiff != self.cachedModiff)
|
||||||
{
|
{
|
||||||
self.cachedModiff = modiff;
|
self.cachedModiff = modiff;
|
||||||
- [self postTextChangedNotification:point];
|
- [self postTextChangedNotification:point];
|
||||||
+ /* Only post ValueChanged when actual characters changed.
|
+ /* 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
|
+ vertico--prompt-selection) bump BUF_MODIFF but not
|
||||||
+ BUF_CHARS_MODIFF. Posting ValueChanged for property-only
|
+ BUF_CHARS_MODIFF. Posting ValueChanged for property-only
|
||||||
+ changes causes VoiceOver to say "new line" when the diff
|
+ 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)
|
+ if (chars_modiff != self.cachedCharsModiff)
|
||||||
+ {
|
+ {
|
||||||
+ self.cachedCharsModiff = chars_modiff;
|
+ self.cachedCharsModiff = chars_modiff;
|
||||||
+ self.emacsView->overlayZoomActive = NO;
|
+ self.emacsView->overlayZoomActive = NO;
|
||||||
+ [self postTextChangedNotification:point];
|
+ [self postTextChangedNotification:point];
|
||||||
|
+ textDidChange = YES;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
@@ -514,11 +522,19 @@ index 1780194..d13c5c7 100644
|
|||||||
|
|
||||||
/* --- Cursor moved or selection changed ---
|
/* --- 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
|
||||||
+ Use 'else if' --- edits and selection moves are mutually exclusive
|
- 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)
|
+ 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.
|
/* 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
|
- (BOOL) isAccessibilityFocused
|
||||||
{
|
{
|
||||||
/* Read the cached point stored by EmacsAccessibilityBuffer on the main
|
/* Read the cached point stored by EmacsAccessibilityBuffer on the main
|
||||||
@@ -536,7 +552,7 @@ index 1780194..d13c5c7 100644
|
|||||||
EmacsAccessibilityBuffer *pb = self.parentBuffer;
|
EmacsAccessibilityBuffer *pb = self.parentBuffer;
|
||||||
if (!pb)
|
if (!pb)
|
||||||
return NO;
|
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 (), ^{
|
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
|
||||||
@@ -545,7 +561,7 @@ index 1780194..d13c5c7 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)))
|
||||||
@@ -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
|
@end
|
||||||
|
|
||||||
@@ -554,7 +570,7 @@ index 1780194..d13c5c7 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)
|
||||||
@@ -10520,13 +10767,13 @@ ns_in_echo_area (void)
|
@@ -10520,13 +10779,13 @@ ns_in_echo_area (void)
|
||||||
if (old_title == 0)
|
if (old_title == 0)
|
||||||
{
|
{
|
||||||
char *t = strdup ([[[self window] title] UTF8String]);
|
char *t = strdup ([[[self window] title] UTF8String]);
|
||||||
@@ -570,7 +586,7 @@ index 1780194..d13c5c7 100644
|
|||||||
[window setTitle: [NSString stringWithUTF8String: size_title]];
|
[window setTitle: [NSString stringWithUTF8String: size_title]];
|
||||||
[window display];
|
[window display];
|
||||||
xfree (size_title);
|
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))
|
if (WINDOW_LEAF_P (w))
|
||||||
{
|
{
|
||||||
@@ -579,7 +595,7 @@ index 1780194..d13c5c7 100644
|
|||||||
EmacsAccessibilityBuffer *elem
|
EmacsAccessibilityBuffer *elem
|
||||||
= [existing objectForKey:[NSValue valueWithPointer:w]];
|
= [existing objectForKey:[NSValue valueWithPointer:w]];
|
||||||
if (!elem)
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -588,7 +604,7 @@ index 1780194..d13c5c7 100644
|
|||||||
Lisp_Object child = w->contents;
|
Lisp_Object child = w->contents;
|
||||||
while (!NILP (child))
|
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;
|
accessibilityUpdating = YES;
|
||||||
|
|
||||||
/* Detect window tree change (split, delete, new buffer). Compare
|
/* Detect window tree change (split, delete, new buffer). Compare
|
||||||
@@ -597,7 +613,7 @@ index 1780194..d13c5c7 100644
|
|||||||
Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe);
|
Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe);
|
||||||
if (!EQ (curRoot, lastRootWindow))
|
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
|
/* If tree is stale, rebuild FIRST so we don't iterate freed
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
From 1a5ab75243e83665e6c1df9191bb5471d5233e5c Mon Sep 17 00:00:00 2001
|
From 0d018f15c088668df039e4776972969da1a719d5 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 2/2] ns: announce child frame completion candidates for
|
Subject: [PATCH 2/2] ns: announce child frame completion candidates for
|
||||||
@@ -67,7 +67,7 @@ index 5c15639..8b34300 100644
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||||
index d13c5c7..2e7d776 100644
|
index 6efeb1d..0255239 100644
|
||||||
--- a/src/nsterm.m
|
--- a/src/nsterm.m
|
||||||
+++ b/src/nsterm.m
|
+++ b/src/nsterm.m
|
||||||
@@ -7066,6 +7066,110 @@ ns_ax_selected_overlay_text (struct buffer *b,
|
@@ -7066,6 +7066,110 @@ ns_ax_selected_overlay_text (struct buffer *b,
|
||||||
@@ -181,7 +181,7 @@ index d13c5c7..2e7d776 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
|
||||||
@@ -12299,6 +12403,105 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
@@ -12311,6 +12415,105 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||||
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 +287,7 @@ index d13c5c7..2e7d776 100644
|
|||||||
- (void)postAccessibilityUpdates
|
- (void)postAccessibilityUpdates
|
||||||
{
|
{
|
||||||
NSTRACE ("[EmacsView postAccessibilityUpdates]");
|
NSTRACE ("[EmacsView postAccessibilityUpdates]");
|
||||||
@@ -12309,11 +12512,59 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
@@ -12321,11 +12524,59 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||||
|
|
||||||
/* 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
|
||||||
|
|||||||
Reference in New Issue
Block a user