16 Compilation Mode

AI generated

Compilation mode runs a shell command, captures the output, and parses error messages so you can jump directly to the source location. It works for compilers, linters, test runners, and anything else that outputs file/line references.

16.1 Configuration

The compile package is configured in lisp/init-prog.el:

(use-package compile
  :ensure nil
  :custom
  (compilation-scroll-output 'first-error)
  (compilation-ask-about-save nil)
  (compilation-always-kill t))

16.2 Running a compilation

M-x compile prompts for a shell command and runs it. M-x recompile (or g in the compilation buffer) re-runs the last command.

For per-language compile commands, compile-multi is configured in lisp/init-project.el with presets for Go, Python, Haskell, Nix, and Rust:

(compile-multi-config
 '((go-ts-mode   . (("go test"         . "go test ./...")
                    ("go test current" . "go test .")
                    ("go test -race"   . "go test -race ./...")
                    ("go build"        . "go build ./...")
                    ("go run"          . "go run .")
                    ("go vet"          . "go vet ./...")
                    ("golangci-lint"   . "golangci-lint run")))
   (go-mod-ts-mode . (("go mod tidy"     . "go mod tidy")
                      ("go mod download" . "go mod download")))
   (python-mode  . (("pytest"         . "pytest")
                    ("pytest file"    . "pytest %file-name%")))
   (haskell-mode . (("stack test"     . "stack test")
                    ("cabal test"     . "cabal test")))
   (nix-ts-mode  . (("nix flake check" . "nix flake check")
                    ("nix fmt"        . "nix fmt")))
   (rust-ts-mode . (("cargo test"     . "cargo test")
                    ("cargo clippy"   . "cargo clippy --all-targets")
                    ("cargo build"    . "cargo build")))))

Run M-x compile-multi to pick from these. The consult-compile-multi integration provides a narrowing UI.

16.4 Editing grep results

The wgrep package (configured in lisp/init-prog.el) enables editing grep result buffers in place. The workflow is:

  1. consult-ripgrep — search across the project
  2. C-c C-o (embark-export) — export results to a grep buffer
  3. C-x C-q — enter wgrep edit mode
  4. Edit the results as you would any buffer
  5. C-c C-c — apply changes to all matched files

Starting with Emacs 31, a built-in grep-edit-mode will also be available.

16.5 How error parsing works

Compilation mode uses compilation-error-regexp-alist and compilation-error-regexp-alist-alist to parse error output. Emacs ships with dozens of entries for GCC, Java, Ruby, Python, Perl, and many more — no configuration needed for common tools.

Each entry has the shape:

(SYMBOL REGEXP FILE LINE COLUMN TYPE HYPERLINK HIGHLIGHT...)

Where TYPE controls severity: 2 = error, 1 = warning, 0 = info. The TYPE field can also be a cons cell for conditional severity based on match groups.

16.5.1 Adding a custom error regexp

If you use a tool whose output format is not recognized, you can teach compilation mode about it:

(with-eval-after-load 'compile
  (push '(my-linter
          "^\\[\\(?:ERROR\\|\\(WARN\\)\\)\\] \\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)"
          2 3 4 (1))
        compilation-error-regexp-alist-alist)
  (push 'my-linter compilation-error-regexp-alist))

16.6 Useful variables

Beyond what this config sets, a few more compilation variables are worth knowing:

;; Skip warnings and info when navigating with next-error.
;; 2 = only errors, 1 = errors + warnings, 0 = everything (default).
(setopt compilation-skip-threshold 2)

;; Some languages (e.g. OCaml) use 0-indexed columns.
(setq compilation-first-column 0)

;; Auto-close the compilation window on success.
(add-hook 'compilation-finish-functions
          (lambda (buf status)
            (when (string-match-p "finished" status)
              (run-at-time 1 nil #'delete-windows-on buf))))

16.7 The compilation mode family

Compilation mode is not just for compilers — it is the infrastructure for any structured output with source locations:

Any tool that outputs file/line references can plug into this system. Whether you are navigating compiler errors, grep results, test failures, or linter output, the workflow is the same: M-g n to jump to the next problem.