54

Have anyone added support for ansi-color in compilation-mode Emacs? If so what property/attribute does the color-writing program have to check for in order to make sure its active terminal supports ANSI-escape coloring.

Nordlöw
  • 11,838
  • 10
  • 52
  • 99
  • 5
    possible duplicate of [Cucumber's ANSI colors messing up emacs compilation buffer](http://stackoverflow.com/questions/3072648/cucumbers-ansi-colors-messing-up-emacs-compilation-buffer) – legoscia Dec 10 '13 at 10:14
  • I will always initially see "ANSI Coloring-In Competition Mode". – phils Jun 09 '20 at 14:20

6 Answers6

73

There's already a function for applying color to comint buffers. You simply need to enable it on compilation buffers:

(require 'ansi-color)
(defun colorize-compilation-buffer ()
  (toggle-read-only)
  (ansi-color-apply-on-region compilation-filter-start (point))
  (toggle-read-only))
(add-hook 'compilation-filter-hook 'colorize-compilation-buffer)

Color writing programs should check the TERM environment variable and the terminfo database to check if the terminal supports color. In practice, a lot of programs ignore this and rely on a user setting. Emacs will set the compilation terminal type to dumb by default but this can be overriden by setting the compilation-environment variable.

Update: Note that in Emacs 24.5 the two calls to (toggle-read-only) in the code above are not needed.

Nordlöw
  • 11,838
  • 10
  • 52
  • 99
ataylor
  • 64,891
  • 24
  • 161
  • 189
  • 1
    It doesn't seem to work completely. I tested with `grep --color` and sometimes larger regions get colorized that shouldn't be. It seems like Emacs doesn't always detect disabling ANSI control sequences :( – Nordlöw Nov 16 '12 at 11:22
  • 2
    @Nordlöw, I've fixed this issue, and updated the post. The function was trying to colorize the whole buffer, although it should filter only the chunk that is spilled from a process. Although the new version is much more robust and fast, it can still be confused, since it is not guaranteed, that a process will not cut his output in the middle of escape sequence. – ivg Oct 30 '15 at 13:06
  • 4
    Using Emacs 24.5, it seems the (toggle-read-only) calls are unnecessary. – Abderrahim Kitouni Dec 17 '16 at 20:05
  • In emacs 27.2 the call `(ansi-color-apply-on-region compilation-filter-start (point))` inevitably seems to result in a "Marker does not point anywhere" error. – cpcallen Dec 01 '21 at 14:40
35

My optimized solution which don't pollute M-x grep (only for M-x compile):

(ignore-errors
  (require 'ansi-color)
  (defun my-colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  (add-hook 'compilation-filter-hook 'my-colorize-compilation-buffer))
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 1
    Thank you! When I was using something more like the accepted answer above, my rgrep buffers were showing in a solid red font. Your version is working much better for me. Using emacs 24.3.50.1. – sockmonk Jan 07 '14 at 14:14
  • 2
    Thanks, this seems like a better solution. Using `compilation-filter-start` should be much more efficient than re-coloring everything between `(point-min)` and `(point-max)` each time. – mgalgs Dec 20 '14 at 03:06
  • 2
    To make this work I needed to set the compilation-environment variable to TERM=xterm-256color. – Steve Broberg Aug 07 '17 at 16:32
13

As of emacs 28.1, this is now a built in !

(require 'ansi-color)
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)

Or with use-package

(use-package ansi-color
    :hook (compilation-filter . ansi-color-compilation-filter)) 
Charles G
  • 427
  • 3
  • 11
  • Thanks for providing both the imperative and the declarative way of configuring this! – logc Jul 27 '23 at 08:24
8

Riffing on @stribb's solution, which riffs on @gavenkoa's solution, this is how to set it up with the awesome use-package:

(use-package ansi-color
  :config
  (defun my-colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  :hook (compilation-filter . my-colorize-compilation-buffer))
Adam Spiers
  • 17,397
  • 5
  • 46
  • 65
7

Riffing on @gavenkoa's solution:

(when (require 'ansi-color nil t)
  (defun my-colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  (add-hook 'compilation-filter-hook 'my-colorize-compilation-buffer))

This will not block errors but will still not raise an error if ansi-color is unavailable. Personally, I find the wildcard catch semantics of ignore-error distasteful.

stribb
  • 81
  • 1
  • 2
3

As of 2020, the most modern way appears to be the xterm-color Emacs package.

See my answer on the duplicate question for details.

vog
  • 23,517
  • 11
  • 59
  • 75
  • Marked solution worked for me before 2019, but it wrecked on my setup today: `ansi-color-names-vector` is just ignored. I'm grateful alternative solution exists. – simno Nov 27 '20 at 15:33