Subject: bug#14017: Highlight prefix line numbers in occur

From: Juri Linkov <[email-masked]>
Date: Fri, 22 Mar 2013 00:38:17 +0200

Currently the `prefix-face' arg of `occur-engine' is unused.
Its caller `occur-1' just sends nil to `occur-engine'.
This is the reason why a bug in its usage in `occur-engine'
remained undiscovered for a long time.  The bug is that this code:

                            (when prefix-face
                              `(font-lock-face prefix-face))

should be fixed to:

                            (when prefix-face
                              `(font-lock-face ,prefix-face))

To take it into use I propose to add a new face option
`list-matching-lines-prefix-face' to accompany the existing
`list-matching-lines-buffer-name-face' and `list-matching-lines-face'.

Its default value could be `shadow' - the same face as is used to
highlight line numbers in `linum-mode' (their output will look similar).

=== modified file 'lisp/replace.el'
--- lisp/replace.el	2013-03-10 08:44:07 +0000
+++ lisp/replace.el	2013-03-21 22:36:56 +0000
@@ -1125,6 +1125,14 @@ (defcustom list-matching-lines-buffer-name-face
   :type 'face
   :group 'matching)
 
+(defcustom list-matching-lines-prefix-face 'shadow
+  "Face used by \\[list-matching-lines] to show the prefix column.
+If the face doesn't differ from the default face,
+don't highlight the prefix with line numbers specially."
+  :type 'face
+  :group 'matching
+  :version "24.4")
+
 (defcustom occur-excluded-properties
   '(read-only invisible intangible field mouse-face help-echo local-map keymap
     yank-handler follow-link)
@@ -1334,7 +1342,9 @@ (defun occur-1 (regexp nlines bufs &opti
 		      (isearch-no-upper-case-p regexp t)
 		    case-fold-search)
 		  list-matching-lines-buffer-name-face
-		  nil list-matching-lines-face
+		  (if (face-differs-from-default-p list-matching-lines-prefix-face)
+		      list-matching-lines-prefix-face)
+		  list-matching-lines-face
 		  (not (eq occur-excluded-properties t))))))
 	  (let* ((bufcount (length active-bufs))
 		 (diff (- (length bufs) bufcount)))
@@ -1423,7 +1433,7 @@ (defun occur-engine (regexp buffers out-
 			    (apply #'propertize (format "%7d:" lines)
 				   (append
 				    (when prefix-face
-				      `(font-lock-face prefix-face))
+				      `(font-lock-face ,prefix-face))
 				    `(occur-prefix t mouse-face (highlight)
 				      ;; Allow insertion of text at
 				      ;; the end of the prefix (for
@@ -1447,7 +1457,9 @@ (defun occur-engine (regexp buffers out-
 			     ;; of multi-line matches.
 			     (replace-regexp-in-string
 			      "\n"
-			      "\n       :"
+			      (if prefix-face
+				  (propertize "\n       :" 'font-lock-face prefix-face)
+				"\n       :")
 			      match-str)
 			     ;; Add marker at eol, but no mouse props.
 			     (propertize "\n" 'occur-target marker)))
@@ -1458,7 +1470,8 @@ (defun occur-engine (regexp buffers out-
 			      ;; The complex multi-line display style.
 			      (setq ret (occur-context-lines
 					 out-line nlines keep-props begpt endpt
-					 lines prev-lines prev-after-lines))
+					 lines prev-lines prev-after-lines
+					 prefix-face))
 			      ;; Set first elem of the returned list to `data',
 			      ;; and the second elem to `prev-after-lines'.
 			      (setq prev-after-lines (nth 1 ret))
@@ -1482,7 +1495,7 @@ (defun occur-engine (regexp buffers out-
 		(when prev-after-lines
 		  (with-current-buffer out-buf
 		    (insert (apply #'concat (occur-engine-add-prefix
-					     prev-after-lines)))))))
+					     prev-after-lines prefix-face)))))))
 	    (when (not (zerop matches)) ;; is the count zero?
 	      (setq globalcount (+ globalcount matches))
 	      (with-current-buffer out-buf
@@ -1537,10 +1550,13 @@ (defun occur-engine-line (beg end &optio
 	str)
     (buffer-substring-no-properties beg end)))
 
-(defun occur-engine-add-prefix (lines)
+(defun occur-engine-add-prefix (lines &optional prefix-face)
   (mapcar
    #'(lambda (line)
-       (concat "       :" line "\n"))
+       (concat (if prefix-face
+		   (propertize "       :" 'font-lock-face prefix-face)
+		 "       :")
+	       line "\n"))
    lines))
 
 (defun occur-accumulate-lines (count &optional keep-props pt)
@@ -1569,7 +1585,8 @@ (defun occur-accumulate-lines (count &op
 ;; Generate a list of lines, add prefixes to all but OUT-LINE,
 ;; then concatenate them all together.
 (defun occur-context-lines (out-line nlines keep-props begpt endpt
-				     lines prev-lines prev-after-lines)
+				     lines prev-lines prev-after-lines
+				     &optional prefix-face)
   ;; Find after- and before-context lines of the current match.
   (let ((before-lines
 	 (nreverse (cdr (occur-accumulate-lines
@@ -1609,10 +1626,13 @@ (defun occur-context-lines (out-line nli
      ;; Return a list where the first element is the output line.
      (apply #'concat
 	    (append
-	     (and prev-after-lines
-		  (occur-engine-add-prefix prev-after-lines))
-	     (and separator (list separator))
-	     (occur-engine-add-prefix before-lines)
+	     (if prev-after-lines
+		 (occur-engine-add-prefix prev-after-lines prefix-face))
+	     (if separator
+		 (list (if prefix-face
+			   (propertize separator 'font-lock-face prefix-face)
+			 separator)))
+	     (occur-engine-add-prefix before-lines prefix-face)
 	     (list out-line)))
      ;; And the second element is the list of context after-lines.
      (if (> nlines 0) after-lines))))