patches: fix echo area — read echo_area_buffer[0] directly

This commit is contained in:
2026-03-01 20:51:02 +01:00
parent 6d2d702aa7
commit 46930281db

View File

@@ -1,4 +1,4 @@
From d3915c6f58a0db4f8c0e3d681e207dbcda0e18f1 Mon Sep 17 00:00:00 2001 From 1e2f86a698a9157a43356816a4a221fe3b70beee 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
@@ -20,8 +20,8 @@ element when a child frame completion closes.
doc/emacs/macos.texi | 6 - doc/emacs/macos.texi | 6 -
etc/NEWS | 4 +- etc/NEWS | 4 +-
src/nsterm.h | 9 ++ src/nsterm.h | 9 ++
src/nsterm.m | 341 +++++++++++++++++++++++++++++++++++++++++-- src/nsterm.m | 353 +++++++++++++++++++++++++++++++++++++++++--
4 files changed, 337 insertions(+), 23 deletions(-) 4 files changed, 349 insertions(+), 23 deletions(-)
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 6514dfc..f47929e 100644 index 6514dfc..f47929e 100644
@@ -97,7 +97,7 @@ index 21a93bc..bbce9fe 100644
@end @end
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 8d44b5f..a6d2bf1 100644 index 8d44b5f..2f4e25f 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -7415,6 +7415,112 @@ visual line index for Zoom (skip whitespace-only lines @@ -7415,6 +7415,112 @@ visual line index for Zoom (skip whitespace-only lines
@@ -301,48 +301,60 @@ index 8d44b5f..a6d2bf1 100644
specpdl_ref count2 = SPECPDL_INDEX (); specpdl_ref count2 = SPECPDL_INDEX ();
record_unwind_current_buffer (); record_unwind_current_buffer ();
if (b != current_buffer) if (b != current_buffer)
@@ -9352,6 +9481,49 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f @@ -9352,6 +9481,61 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f
if (!b) if (!b)
return; return;
+ /* --- Echo area announcements --- + /* --- Echo area announcements ---
+ When the minibuffer is not active for user input (minibuf_level == 0) + When the minibuffer is not active for user input (minibuf_level == 0)
+ and its character content changes, announce the new message to + and an echo area message arrives, announce it to VoiceOver. This
+ VoiceOver. This surfaces error messages, completion notices, and + surfaces messages such as "Git finished", "Wrote file", and error
+ process status updates (e.g. "Wrote file", "Git finished"). + strings that appear in the echo area during background operations.
+ +
+ Priority High interrupts ongoing speech, which matches the urgency + IMPORTANT: Emacs displays echo area messages by calling
+ of a status change. While minibuf_level > 0 the user is composing + with_echo_area_buffer(), which sets current_buffer via
+ a command; we fall through to normal cursor and completion tracking + set_buffer_internal_1() but does NOT call Fset_window_buffer().
+ in that case. */ + As a result, w->contents (and thus the variable `b' above) still
+ points to the inactive minibuffer buffer " *Minibuf-0*", NOT to
+ the echo area buffer. We must read echo_area_buffer[0] directly.
+
+ Priority High is appropriate: echo area status messages are
+ time-sensitive and may arrive while VoiceOver is reading other
+ text. While minibuf_level > 0 the user is composing a command;
+ fall through to normal cursor/completion tracking in that case. */
+ if (MINI_WINDOW_P (w) && minibuf_level == 0) + if (MINI_WINDOW_P (w) && minibuf_level == 0)
+ { + {
+ ptrdiff_t echo_chars = BUF_CHARS_MODIFF (b); + Lisp_Object ea = echo_area_buffer[0];
+ if (echo_chars != self.cachedCharsModiff + if (BUFFERP (ea))
+ && BUF_ZV (b) > BUF_BEGV (b))
+ { + {
+ self.cachedCharsModiff = echo_chars; + struct buffer *eb = XBUFFER (ea);
+ struct buffer *prev = current_buffer; + ptrdiff_t echo_chars = BUF_CHARS_MODIFF (eb);
+ set_buffer_internal (b); + if (echo_chars != self.cachedCharsModiff
+ Lisp_Object ls = Fbuffer_string (); + && BUF_ZV (eb) > BUF_BEGV (eb))
+ set_buffer_internal (prev);
+ /* Use stringWithLispString: — it converts Emacs's internal
+ multibyte encoding to NSString correctly, unlike a raw
+ UTF-8 cast via SSDATA which fails for non-ASCII text. */
+ NSString *raw = [NSString stringWithLispString: ls];
+ NSString *msg = [raw stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if ([msg length] > 0)
+ { + {
+ NSDictionary *info = @{ + self.cachedCharsModiff = echo_chars;
+ NSAccessibilityAnnouncementKey: msg, + struct buffer *prev = current_buffer;
+ NSAccessibilityPriorityKey: + set_buffer_internal (eb);
+ @(NSAccessibilityPriorityHigh) + Lisp_Object ls = Fbuffer_string ();
+ }; + set_buffer_internal (prev);
+ ns_ax_post_notification_with_info ( + /* stringWithLispString: converts Emacs's internal multibyte
+ NSApp, + encoding to NSString correctly; SSDATA alone would produce
+ NSAccessibilityAnnouncementRequestedNotification, + invalid UTF-8 for non-ASCII characters. */
+ info); + NSString *raw = [NSString stringWithLispString: ls];
+ NSString *msg = [raw stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if ([msg length] > 0)
+ {
+ NSDictionary *info = @{
+ NSAccessibilityAnnouncementKey: msg,
+ NSAccessibilityPriorityKey:
+ @(NSAccessibilityPriorityHigh)
+ };
+ ns_ax_post_notification_with_info (
+ NSApp,
+ NSAccessibilityAnnouncementRequestedNotification,
+ info);
+ }
+ } + }
+ } + }
+ return; + return;
@@ -351,7 +363,7 @@ index 8d44b5f..a6d2bf1 100644
ptrdiff_t modiff = BUF_MODIFF (b); ptrdiff_t modiff = BUF_MODIFF (b);
ptrdiff_t point = BUF_PT (b); ptrdiff_t point = BUF_PT (b);
BOOL markActive = !NILP (BVAR (b, mark_active)); BOOL markActive = !NILP (BVAR (b, mark_active));
@@ -9488,6 +9660,16 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property @@ -9488,6 +9672,16 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property
granularity = ns_ax_text_selection_granularity_line; granularity = ns_ax_text_selection_granularity_line;
} }
@@ -368,7 +380,7 @@ index 8d44b5f..a6d2bf1 100644
/* Post notifications for focused and non-focused elements. */ /* Post notifications for focused and non-focused elements. */
if ([self isAccessibilityFocused]) if ([self isAccessibilityFocused])
[self postFocusedCursorNotification:point [self postFocusedCursorNotification:point
@@ -9931,6 +10113,10 @@ - (void)dealloc @@ -9931,6 +10125,10 @@ - (void)dealloc
#endif #endif
[accessibilityElements release]; [accessibilityElements release];
@@ -379,7 +391,7 @@ index 8d44b5f..a6d2bf1 100644
[[self menu] release]; [[self menu] release];
[super dealloc]; [super dealloc];
} }
@@ -11380,6 +11566,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f @@ -11380,6 +11578,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f
windowClosing = NO; windowClosing = NO;
processingCompose = NO; processingCompose = NO;
@@ -389,7 +401,7 @@ index 8d44b5f..a6d2bf1 100644
scrollbarsNeedingUpdate = 0; scrollbarsNeedingUpdate = 0;
fs_state = FULLSCREEN_NONE; fs_state = FULLSCREEN_NONE;
fs_before_fs = next_maximized = -1; fs_before_fs = next_maximized = -1;
@@ -12688,6 +12877,80 @@ - (id)accessibilityFocusedUIElement @@ -12688,6 +12889,80 @@ - (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. */
@@ -470,7 +482,7 @@ index 8d44b5f..a6d2bf1 100644
- (void)postAccessibilityUpdates - (void)postAccessibilityUpdates
{ {
NSTRACE ("[EmacsView postAccessibilityUpdates]"); NSTRACE ("[EmacsView postAccessibilityUpdates]");
@@ -12698,11 +12961,59 @@ - (void)postAccessibilityUpdates @@ -12698,11 +12973,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