Subject: bug#71419: 30.0.50; Completion does not always highlight the "common part" corresponding to suffix

From: Dmitry Gutov <[email-masked]>
Date: Thu, 13 Jun 2024 02:57:43 +0300

On 10/06/2024 00:06, Stefan Monnier wrote:
>> diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
>> index f62cb2566b2..144cda8cfdc 100644
>> --- a/lisp/minibuffer.el
>> +++ b/lisp/minibuffer.el
>> @@ -3816,7 +3816,7 @@ completion-basic-all-completions
>>                               'point
>>                               (substring afterpoint 0 (cdr bounds)))))
>>            (all (completion-pcm--all-completions prefix pattern table pred)))
>> -    (completion-hilit-commonality all point (car bounds))))
>> +    (completion-pcm--hilit-commonality pattern all)))
>>
>>   ;;; Partial-completion-mode style completion.
> 
> Thanks for tracking it down.  It matches my expectation.

Thanks, now fixed on master.

>> But it would have been nice to be able to use it in the "progressive
>>   improvement" kind of fashion: when the suffix and the other parts are
>>   highlighted correctly, we do the right thing; if the style missed the
>>   suffix highlighting, we do the other thing - and put the responsibility on
>> the third party.
> 
> 🙂

It could work like in the attached. I agree that it's somewhat brittle, 
though.

If you're not in favor of installing this patch, what would be your 
preferred strategy for fixing bug#70968? We could try resurrecting the 
relevant part of Daniel's patch for completion-all-completions, but it 
means a fair amount of breakage. Or another dynamic variable similar to 
completion-lazy-hilit-fn...

FWIW my interest here is how to better implement the same step in 
company-mode, but the default UI is a good common ground.

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 144cda8cfdc..d8952094196 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2551,6 +2551,25 @@ completions--after-change
       (with-selected-window window
         (completions--deselect)))))
 
+(defun completions--count-common-spans (str)
+  (let ((pos 0)
+        prev-pos
+        value
+        (sum 0))
+    (while pos
+      (when prev-pos
+        (cl-incf sum (- pos prev-pos)))
+      (if (and (setq value (get-text-property pos 'face str))
+               (if (listp value)
+                   (memq 'completions-common-part value)
+                 (eq 'completions-common-part value)))
+          (setq prev-pos pos)
+        (setq prev-pos nil))
+      (setq pos (next-single-property-change pos 'face str))
+      (when (and (not pos) prev-pos)
+        (cl-incf sum (- (length str) prev-pos))))
+    sum))
+
 (defun minibuffer-completion-help (&optional start end)
   "Display a list of possible completions of the current minibuffer contents."
   (interactive)
@@ -2706,6 +2725,10 @@ minibuffer-completion-help
                                  ;; but that clashed with another existing marker.
                                  (cl-decf (nth 1 base-position)
                                           (- end start (length choice)))
+                                 ;; Completion style that doesn't match suffix.
+                                 (unless (> (completions--count-common-spans choice)
+                                            (- (point) start))
+                                   (setq end (point)))
                                  ;; FIXME: Use `md' to do quoting&terminator here.
                                  (completion--replace start (min end (point-max)) choice)
                                  (let* ((minibuffer-completion-table ctable)