12

When running the compile command and jumping to the 'next error', emacs identifies the line of the current error by placing a little black triangle, pointing right, in the left-hand fringe of the *compilation* buffer. This is nice, but my old eyes would like a bolder indicator. The fundamental goal here is to be able to quickly visually identify which line emacs is identifying as the current compiler error. Some solutions which come to mind:

  1. a different face for the current error (bigger for example).
  2. a different background color for the current error (something like hl-line-mode).
  3. a bigger triangle.

but I'm open to other ideas too.

Can someone help me out?

Spacemoose
  • 877
  • 1
  • 7
  • 18

3 Answers3

3

I wanted to achieve the same thing as it was often painful to find the current error message in the compilation buffer. This solution is based on Drew's suggestion to use a next-error-hook to highlight the error message. Currently it only highlights the first line in the error message, but I find this is good enough.

(defcustom next-error-message-highlight-p nil
  "If non-nil, highlight the current error message in the ‘next-error’ buffer"
  :type 'boolean
  :group 'next-error
  :version "??")

(defface next-error-message
  '((t (:inherit highlight)))
  "Face used to highlight the current error message in the ‘next-error’ buffer"
  :group 'next-error
  :version "??")

(defvar next-error-message-highlight-overlay
  nil
  "Overlay highlighting the current error message in the ‘next-error’ buffer")

(make-variable-buffer-local 'next-error-message-highlight-overlay)

(defun next-error-message-highlight (from-buffer)
  "Highlight the current error message in the ‘next-error’ FROM-BUFFER."
  (when next-error-message-highlight-p
    (with-current-buffer from-buffer
      (when next-error-message-highlight-overlay
        (delete-overlay next-error-message-highlight-overlay))
      (save-excursion
        (goto-char (point))
        (let ((ol (make-overlay (line-beginning-position) (line-end-position))))
          ;; do not override region highlighting
          (overlay-put ol 'priority -50)
          (overlay-put ol 'face 'next-error-message)
          (overlay-put ol 'window (get-buffer-window))
          (setf next-error-message-highlight-overlay ol))))))


(add-hook 'next-error-hook 'next-error-message-highlight)

Usage:

(setq next-error-message-highlight-p t)

Demo:

demo

erjoalgo
  • 853
  • 1
  • 5
  • 18
1

Doesn't next-error scroll the compilation-errors buffer, so that the current error shows as the first line of the window?

If not, doesn't it at least put the cursor on the current error line? If it does, and if the cursor is not visible enough for you, consider using hl-line-mode to highlight the current line. Or consider using library crosshairs to highlight the current line and current column.


Update after your comment

I thought you were invoking next-error in buffer *compilation*. If you do that then the line is scrolled to the top, as I described.

But if you are invoking next-error outside buffer *compilation* then you need to use next-error-hook to, in buffer *compilation*, highlight the current line or fringe or whatever, in whatever way you like.

Here is a quick-and-dirty example:

(defun foo ()
  "..."
  (with-current-buffer next-error-last-buffer
    (hl-line-mode 1)))

(add-hook 'next-error-hook 'foo)

(Of course, you really only need to turn on hl-line-mode once in that buffer. Doing it as shown above is overkill, but it doesn't hurt. You might think that you could just add foo to grep-mode-hook or compilation-mode-hook. But when those hooks are invoked there is no next-error-last-buffer.)

Note:

  1. There are two user options that control the ways to indicate the hit in the source buffer (not in the compilation buffer): next-error-highlight and next-error-highlight-no-select. They offer the same possibilities, but they are used by different commands. The possibilities include using a fringe arrow or highlighting the match for a certain time.

  2. But there is no such option controlling indication of the current hit in buffer *compilation*. So Emacs offers two options (where one would probably be enough) for the source buffer but no option for the compilation buffer.

You might consider filing an enhancement request, to get a similar option for the compilation (including grep) buffer: M-x report-emacs-bug. Using a hook with your own function to perform the highlighting is OK, but it shouldn't be necessary.


And if you just want to change the fringe indicator, you can do this (use whatever fringe bitmap you want, instead of filled-rectangle -- see (elisp) Fringe Bitmaps for a list of the predefined ones):

(defun bar ()
  (with-current-buffer next-error-last-buffer
    (unless (eq 'filled-rectangle (cdr (assq 'overlay-arrow fringe-indicator-alist)))
      (setq fringe-indicator-alist
            (cons '(overlay-arrow . filled-rectangle) fringe-indicator-alist)))))

(add-hook 'next-error-hook 'bar)

Update #2:

I just discovered that if you turn off showing the left fringe then you will see the behavior I described in the beginning: the window is scrolled to put the current error at the top. So that is another possibility. (It is the behavior I see in my setup, since I do not show fringe.)

There is a bug in this behavior, which I just reported (#20829). What counts (currently, until the bug is fixed) is whether the left fringe is showing in the selected window when you do C-x ` (next-error). It is (currently) not enough that the window showing the compilation buffer does not show the left fringe.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • The scrolling of the compilation buffer seems to work like the rest of emacs -- when 'point' (in the case of compilation buffer, the current error) moves past a certain point, the screen scrolls. for a big screen of data, this makes for a hard to find error. The behavior of hl-line-mode would be great, but it only highlights the current buffer (can I override this?) -- so the line of code where the error occurs is highlighted, but there error data is not. crosshairs seems to do the same thing bit with column and line, which I don't need. – Spacemoose Jun 13 '15 at 17:06
  • Still unclear, to me at least. For me, `next-error` puts the current error line at the top line of the window for buffer `*compilation*`. There is of course `global-hl-line-mode`, but your complaint/question was supposedly about the `*compilation*` buffer. The question is getting less clear, not more (IMHO). – Drew Jun 13 '15 at 19:46
  • When you compile in emacs with errors, execute next-error. In the source buffer your cursor will be at the source of the error, and there is small black triangle indicating the current compiler-error-message in the *compilation buffer*. The current error is ***not*** generally the topmost line of the buffer (I have just done the experiment in 24.5.1). I find it visually tasking to look for the black triangle. hl-line-mode only highlight the line of the ***active*** buffer, which is the source buffer. I don't want to jump to the compilation buffer just to find the line. – Spacemoose Jun 13 '15 at 20:55
  • I thought you were invoking next-error in buffer `*compilation*`. If not then you need to put a function on `next-error-hook` to do the highlighting (or whatever) *in buffer `*compilation*`*. I updated the answer with an example. – Drew Jun 13 '15 at 22:04
  • Your quick and dirty example answers OP's point 2, which is exactly what I was looking for. The compilation buffer scrolling so that the active line is on top (which only is valid if left fringes are of size 0) made me lose context (since the lines above the error are meaningful), so I had to set `compilation-context-lines`. As a result, the currently selected error was hard to find. Your solution saved me. – Gauthier Nov 17 '17 at 08:00
  • 1
    the problem with `hl-line-mode` is that it highlights the line at the current point, but not line at the current error marker. – erjoalgo Sep 10 '18 at 01:19
  • Does 'next-error` not move point in the `*compilation*` buffer to the location of the error marker? That should trigger hl-line-mode at that location, otherwise I think it's a bug in emacs. – rpluim Sep 13 '18 at 14:29
  • @rpluim Point and error marker are independent and may diverge, for example when user issues movement commands to change the current line in `next-error-last-buffer`. Also `hl-line-mode` works based on buffer-local pre and post-command hooks. This generally fails whenever `next-error` is invoked outside of `next-error-last-buffer`. – erjoalgo Sep 30 '18 at 14:55
1

Here is an example of how to modify the bitmap image that appears in the left-hand fringe of the *compilation* buffer (e.g., the *grep* results buffer):

(define-fringe-bitmap 'custom-right-arrow [128 192 96 48 24 48 96 192 128] 9 8 'center)

(put 'overlay-arrow-position 'overlay-arrow-bitmap 'custom-right-arrow)

Here is an example of how to set the colors of fringe bitmaps:

(defface right-triangle-face
  '((t (:background "red" :foreground "yellow")))
  "Face for `right-triangle-face`.")

(set-fringe-bitmap-face 'right-triangle 'right-triangle-face)

Here is an example of how to create your own fringe bitmap:

;; AUTHOR:  Nikolaj Schumacher -- https://github.com/nschum/fringe-helper.el
;;
(defun fringe-helper-convert (&rest strings)
"Convert STRINGS into a vector usable for `define-fringe-bitmap'.
Each string in STRINGS represents a line of the fringe bitmap.
Periods (.) are background-colored pixel; Xs are foreground-colored. The
fringe bitmap always is aligned to the right. If the fringe has half
width, only the left 4 pixels of an 8 pixel bitmap will be shown.
For example, the following code defines a diagonal line.
\(fringe-helper-convert
\"XX......\"
\"..XX....\"
\"....XX..\"
\"......XX\"\)"
  (unless (cdr strings)
  ;; only one string, probably with newlines
    (setq strings (split-string (car strings) "\n")))
  (apply 'vector
    (mapcar
      (lambda (str)
        (let ((num 0))
          (dolist (c (string-to-list str))
            (setq num (+ (* num 2) (if (eq c ?.) 0 1))))
          num))
      strings)))

(define-fringe-bitmap 'backslash (fringe-helper-convert
  "XX......"
  "XX......"
  " XX....."
  ".XX....."
  "..XX...."
  "..XX...."
  "...XX..."
  "...XX..."
  "....XX.."
  "....XX.."
  ".....XX."
  ".....XX.") nil nil 'center)
lawlist
  • 18,826
  • 5
  • 37
  • 118