Compilation mode is a major mode that allow us to run a command and see its output result in a special buffer, this resulting buffer show the errors and allow us to navigate through them, you can check the documentation for more details.
It's a "simple mode" but it can be used for many things like compile and run a program, run tests, and so on.
Usage
Interactive
compile
is an interactive function so we can call it with M-x compile
and enter the command we want to execute.
In the following example we're compiling this blog using hugo binary:
From code
compile
is a emacs-lisp function so we call it from our code, we just need to take care about the default-directory
when we call it, for example if we call it from lib/hello.ex
buffer, default-directory
will be lib
and in some cases we want to use our project root, or a different directory, to run our command.
To fix this we need to setup default-directory
before we call compile
, for example let's build a custom function to run hlint
in our entire project and then show its results in a compilation
buffer:
(defun my/run-hlint ()
"Run hlint over the current project."
(interactive)
(let ((default-directory (projectile-project-root)))
(compile "hlint .")))
In this case we're setting up default-directory
with our project root (using projectile to get the root) and then when we call compile
it will take default-directory
correctly.
Some tweaks
These modifications to default behaviour of compilation-mode
should be made after the mode was loaded so we need to use with-eval-after-load otherwise these changes won't be applied correctly.
Evil-mode
The compilation
buffer has some preset key bindings that conflict with evil-mode
, for example when we press g
in a compilation buffer this will re-run the command, but this key binding is also used by evil-mode
, to fix this we can disable the default key binding with:
(with-eval-after-load 'compile
(define-key compilation-mode-map (kbd "g") nil)
(define-key compilation-mode-map (kbd "r") 'recompile)
(define-key compilation-mode-map (kbd "h") nil))
In this case h
key binding is also disabled (also used by evil) and r
is remapped to recompile
for easy access now that we disabled g
default key binding.
Follow compilation output
By default compilation-mode
doesn't follow the output of the command so if our command result has a large output we'll need to scroll manually, to fix this we can change compilation-scroll-output
to t
(with-eval-after-load 'compile
;; set cursor to follow compilation output
(setq compilation-scroll-output t))
Enable ANSI colors
Some tools show results with colors for easy reading but compilation-mode
won't show them by default, you can make them look better with:
(require 'ansi-color)
(defun colorize-compilation-buffer ()
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max))))
(add-hook 'compilation-filter-hook 'colorize-compilation-buffer)
This was taken from this Stack Overflow answer
Re run compilation from another buffer
When we're making changes in our code we want to re-run our compilation process right after we save the changes but to do this we have to move to the compilation buffer to be able to re-run the compilation, a better approach to do this could be just call recompile
by using a key binding, I use evil-leader
to make this:
(evil-leader/set-key "R" 'recompile)
But it can be attached to any key binding, for example:
(global-set-key (kbd "C-c C-r") 'recompile)
Bonus: run parrot mode animation when a compilation is successful
I configured parrot-mode to animate the little parrot every time the compilation process is a success, to make this we need a small function that check if it was a success and then we need to attach it to 'compilation-finish-functions
, this is a variable defined in compilation-mode
.
(defun my/parrot-animate-when-compile-success (buffer result)
(if (string-match "^finished" result)
(parrot-start-animation)))
(use-package parrot
:ensure t
:config
(parrot-mode)
(add-to-list 'compilation-finish-functions 'my/parrot-animate-when-compile-success))
Conclusion
As we can see compilation-mode
is a simple but powerful mode that allow us to build our own tools, we can create an automatic build system in case there is not something already existing for the technology we're using or if we just want to run some tasks in an easier way.