From 2e5505f044e403ccaef8c43bdc66480c71dcf05a Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 14:44:37 +0100 Subject: [PATCH] ns: fix overlay candidate detection (Fequal face comparison) The previous ns_ax_selected_overlay_text matched ANY non-nil face, but all Vertico lines have faces. Fix: collect line boundaries, compare each line's face against the first line's face via Fequal, return the line with a DIFFERENT face (the selected candidate). Also fix duplicate 'NSString *candidate' declaration. * src/nsterm.m (ns_ax_selected_overlay_text): Rewrite to compare faces line-by-line via Fequal instead of matching first non-nil face. --- src/nsterm.m | 94 +++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/src/nsterm.m b/src/nsterm.m index 43d30f9..35edd39 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -6916,12 +6916,12 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action) #define NS_AX_TEXT_CAP 100000 /* Extract the currently selected candidate text from overlay display - strings in window W. Completion frameworks (Vertico, Ivy, Icomplete) - highlight the current candidate by applying a face property to a - portion of the overlay's before-string or after-string. We find - that highlighted portion and return it as an NSString. + strings. Completion frameworks (Vertico, Ivy, Icomplete) highlight + the current candidate with a distinct face. We find the line whose + face DIFFERS from the first line's face (the "normal" candidate + face) — that is the selected candidate. - Returns nil if no highlighted overlay text is found. */ + Returns nil if no distinctly-faced line is found. */ static NSString * ns_ax_selected_overlay_text (struct buffer *b, ptrdiff_t beg, ptrdiff_t end) @@ -6942,57 +6942,60 @@ ns_ax_selected_overlay_text (struct buffer *b, continue; Lisp_Object str = strings[s]; - ptrdiff_t len = SCHARS (str); - ptrdiff_t pos = 0; + ptrdiff_t slen = SCHARS (str); + if (slen == 0) + continue; + + /* Collect line boundaries. */ + ptrdiff_t line_starts[512]; + ptrdiff_t line_ends[512]; + int nlines = 0; + ptrdiff_t lstart = 0; - while (pos < len) + for (ptrdiff_t i = 0; i <= slen && nlines < 512; i++) { - Lisp_Object face - = Fget_text_property (make_fixnum (pos), - Qface, str); - if (!NILP (face)) + bool is_nl = false; + if (i < slen) + { + Lisp_Object ch = Faref (str, make_fixnum (i)); + is_nl = (FIXNUMP (ch) && XFIXNUM (ch) == '\n'); + } + if (is_nl || i == slen) { - /* Found highlighted text. Extract the full line - containing this position. */ - ptrdiff_t line_start = pos; - while (line_start > 0) + if (i > lstart) { - /* Check character before line_start. */ - Lisp_Object ch - = Faref (str, make_fixnum (line_start - 1)); - if (FIXNUMP (ch) && XFIXNUM (ch) == '\n') - break; - line_start--; + line_starts[nlines] = lstart; + line_ends[nlines] = i; + nlines++; } + lstart = i + 1; + } + } - ptrdiff_t line_end = pos; - while (line_end < len) - { - Lisp_Object ch - = Faref (str, make_fixnum (line_end)); - if (FIXNUMP (ch) && XFIXNUM (ch) == '\n') - break; - line_end++; - } + if (nlines < 2) + continue; + /* Get the face of the first line (the "normal" face). */ + Lisp_Object normal_face + = Fget_text_property (make_fixnum (line_starts[0]), + Qface, str); + + /* Find the first line with a DIFFERENT face. */ + for (int li = 0; li < nlines; li++) + { + Lisp_Object line_face + = Fget_text_property (make_fixnum (line_starts[li]), + Qface, str); + if (NILP (Fequal (line_face, normal_face))) + { Lisp_Object line - = Fsubstring_no_properties (str, - make_fixnum (line_start), - make_fixnum (line_end)); + = Fsubstring_no_properties ( + str, + make_fixnum (line_starts[li]), + make_fixnum (line_ends[li])); if (SCHARS (line) > 0) return [NSString stringWithLispString:line]; } - - /* Skip to next face change. */ - Lisp_Object next - = Fnext_single_property_change (make_fixnum (pos), - Qface, str, - make_fixnum (len)); - ptrdiff_t npos - = FIXNUMP (next) ? XFIXNUM (next) : len; - if (npos <= pos) - break; - pos = npos; } } } @@ -8956,7 +8959,6 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem, properties. Completion frameworks highlight the current candidate with a text face (e.g. vertico-current, icomplete-selected-match). */ - NSString *candidate NSString *candidate = ns_ax_selected_overlay_text (b, BUF_BEGV (b), BUF_ZV (b)); if (candidate) -- 2.43.0