Subject: Re: bug#13250: 24.3.50; Add a way to show pre-highlighted candidates in completions buffer

From: Dmitry Gutov <[email-masked]>
Date: Sat, 12 Jan 2013 07:45:55 +0400

On 29.12.2012 9:29, Stefan Monnier wrote:
>> It would have to be a different function and metadata property, no?
>
> Could be.
>
>> I don't think we can change annotation-function to return the candidate plus
>> annotation, for example.
>
> Currently it can only return a string (which is combined with the
> completion into a cons cell), but we could let it return the cons cell
> directly.  That wouldn't necessarily help with "annotations before" (and
> it wouldn't make sure that the annotations don't actually change
> the completions).

I decided not to do this for now, because it doesn't actually help in my 
case. Or maybe I just haven't encountered a bug that would be caused by 
the additional fontification (as long as I use 'face, not 'font-lock-face).

And the part below works the same, whether the base highlighting was 
added in the completion strings directly, or through the annotation 
function.

Speaking of "annotations before", I don't see how they can be used in 
the current interface. Showing the classes where the methods are defined 
would be good, but lining the candidates up vertically is important for 
visual scan-ability, and the "before strings" can be of different lengths.

>> So, AFAICT, the proper solution would be to walk the part of the string,
>> look at every piece in it that has a different value of 'face, then where
>> the value is a symbol, wrap it into a list, and then add the new face to the
>> end of the lists. And repeat for the "first difference".
>
> Yes.  Lars wanted to add a function that does just that, but you can use
> font-lock-prepend-text-property in the mean time.

Thanks, that was rather easy. I'm attaching a patch that fixes this 
bug's problem for me (letting the fontifications through), so maybe we 
should leave improvements to annotation function for later.
=== modified file 'lisp/ChangeLog'
--- lisp/ChangeLog	2013-01-11 23:24:52 +0000
+++ lisp/ChangeLog	2013-01-12 03:37:51 +0000
@@ -1,3 +1,16 @@
+2013-01-12  Dmitry Gutov  <gutov@vbx>
+
+	* minibuffer.el (completions-first-difference): State that the
+	face is "added" in the docstring.
+	(completions-common-part): Same.  And not inheric from default.
+	(completion-hilit-commonality): Prepend 'completions-common-part
+	and 'completion-first-difference faces to the 'face property,
+	instead of replacing the value.
+	(completion--insert-strings): Same with 'completions-annotations face.
+	(completion-hilit-commonality): Use 'face instead of
+	'font-lock-face, because it gets priority if the completion
+	strings already have 'face set.
+
 2013-01-11  Felix H. Dahlke  <[email-masked]>
 
 	* progmodes/js.el: Fix multiline declarations's indentation (bug#8576).

=== modified file 'lisp/minibuffer.el'
--- lisp/minibuffer.el	2013-01-02 16:13:04 +0000
+++ lisp/minibuffer.el	2013-01-12 03:29:23 +0000
@@ -1458,9 +1458,11 @@
                                    'mouse-face 'highlight)
               (put-text-property (point) (progn (insert (car str)) (point))
                                  'mouse-face 'highlight)
-              (add-text-properties (point) (progn (insert (cadr str)) (point))
-                                   '(mouse-face nil
-                                     face completions-annotations)))
+              (let ((beg (point))
+                    (end (progn (insert (cadr str)) (point))))
+                (put-text-property beg end 'mouse-face nil)
+                (font-lock-prepend-text-property beg end 'face
+                                                 'completions-annotations)))
 	    (cond
 	     ((eq completions-format 'vertical)
 	      ;; Vertical format
@@ -1487,12 +1489,11 @@
 
 (defface completions-first-difference
   '((t (:inherit bold)))
-  "Face put on the first uncommon character in completions in *Completions* buffer."
+  "Face added on the first uncommon character in completions in *Completions* buffer."
   :group 'completion)
 
-(defface completions-common-part
-  '((t (:inherit default)))
-  "Face put on the common prefix substring in completions in *Completions* buffer.
+(defface completions-common-part '((t nil))
+  "Face added on the common prefix substring in completions in *Completions* buffer.
 The idea of `completions-common-part' is that you can use it to
 make the common parts less visible than normal, so that the rest
 of the differing parts is, by contrast, slightly highlighted."
@@ -1513,17 +1514,18 @@
                      (car (setq elem (cons (copy-sequence (car elem))
                                            (cdr elem))))
                    (setq elem (copy-sequence elem)))))
-            (put-text-property 0
-			       ;; If completion-boundaries returns incorrect
-			       ;; values, all-completions may return strings
-			       ;; that don't contain the prefix.
-			       (min com-str-len (length str))
-                               'font-lock-face 'completions-common-part
-                               str)
+            (font-lock-prepend-text-property
+             0
+             ;; If completion-boundaries returns incorrect
+             ;; values, all-completions may return strings
+             ;; that don't contain the prefix.
+             (min com-str-len (length str))
+             'face 'completions-common-part str)
             (if (> (length str) com-str-len)
-                (put-text-property com-str-len (1+ com-str-len)
-                                   'font-lock-face 'completions-first-difference
-                                   str)))
+                (font-lock-prepend-text-property com-str-len (1+ com-str-len)
+                                                 'face
+                                                 'completions-first-difference
+                                                 str)))
           elem)
         completions)
        base-size))))