When I run my RSpec tests from the command line, the output is colorful, but from within Emacs, it's all just plain white text. Something must be done!
The first and most-obvious problem: spec (the testrunner) needs the -c flag before it produces colorful output. Easy fix! Update my test-running function to throw a -c in there, and presto! Beautiful output:
Compilation started at Sun Feb 15 16:35:33
spec spec/thingy.rb -c
[32m.[0m[31mF[0m[32m.[0m[32m.[0m[32m.[0m
Great. spec emitted a bunch of ANSI color escape sequences (yay!), and Emacs failed to interpret them (boo!).
Googling revealed that compilation-mode is derived from comint-mode, so I should just set up comint-mode to have color output. It's well-documented and easy to do:
(setq ansi-color-for-comint-mode t)
(add-hook 'comint-output-filter-functions 'ansi-color-process-output)
This let me run a shell from within Emacs and have
ls --color
show color in it. Unfortunately, this did absolutely nothing for my test output, which remained full of raw escape sequences.
The problem is in compile.el. It calls
comint-exec
, which sets the process's output filter to
comint-output-filter
, which in turn exposes a variety of useful hooks, including the aforementioned
comint-output-filter-functions
. Unfortunately, after calling
comint-exec
,
compile
sets the output filter to
compilation-filter
, which only exposes one hook, and that one gets called *after* the string's been inserted, with no arguments. It's not very useful.
Fortunately, Emacs's advice system makes it easy to modify the arguments that
compilation-filter
gets, so it's easy to turn those escape sequences into colors.
(defadvice compilation-filter (before ansify-compilation-output activate)
(ad-set-arg 1 (ansi-color-apply (ad-get-arg 1))))
Now I run my tests, and I get... no escape sequences or colors? Huh?
It turns out that you can't insert text with color properties (or something) into a buffer with font-lock-mode on. Since I have that on everywhere, I just need to turn off font-lock-mode in the compilation buffer. Fortunately, a process filter's first argument is the process.
(defadvice compilation-filter (before ansify-compilation-output activate)
(with-current-buffer (process-buffer (ad-get-arg 0))
(font-lock-mode -1)
(ad-set-arg 1 (ansi-color-apply (ad-get-arg 1)))))
Now I've got colorful test output in Emacs.
(Why not add something to
compilation-mode-hook
? It's because
compilation-mode
unconditionally turns on font-lock-mode after running
compilation-mode-hook
.)