> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jylhis.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Compilation Mode

> How compilation mode is configured and how to use it for building, linting, and navigating errors

<Note>AI generated</Note>

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.

## Configuration

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

```elisp theme={}
(use-package compile
  :ensure nil
  :custom
  (compilation-scroll-output 'first-error)
  (compilation-ask-about-save nil)
  (compilation-always-kill t))
```

* `compilation-scroll-output` is set to `'first-error` — the compilation buffer scrolls to follow
  output and stops scrolling when the first error appears.
* `compilation-ask-about-save` is disabled — Emacs saves modified buffers before compiling without
  prompting.
* `compilation-always-kill` is enabled — starting a new compilation kills any running one without
  asking.

## 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:

```elisp theme={}
(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.

## Navigating errors

### In the compilation buffer

| Key       | Command                        | What it does                                   |
| --------- | ------------------------------ | ---------------------------------------------- |
| `g`       | `recompile`                    | Re-run the last compilation command            |
| `M-n`     | `compilation-next-error`       | Move to the next error message                 |
| `M-p`     | `compilation-previous-error`   | Move to the previous error message             |
| `RET`     | `compile-goto-error`           | Jump to the source location at point           |
| `C-c C-f` | `next-error-follow-minor-mode` | Auto-display source as you move through errors |

### From any buffer

The standard `M-g n` (`next-error`) and `M-g p` (`previous-error`) work from any buffer — Emacs
tracks the last buffer that produced errors and jumps you there. This works across `compile`, `grep`,
`occur`, and any other mode that produces error-like output. `M-g M-n` and `M-g M-p` do the same
thing but are easier to type since you can hold Meta throughout.

This config also binds `M-g e` to `consult-compile-error` (in `lisp/init-completion.el`), which
provides a searchable, narrowable list of all compilation errors via consult.

### Flymake integration

For in-buffer diagnostics, `M-n` and `M-p` are bound to `flymake-goto-next-error` and
`flymake-goto-prev-error` in `flymake-mode-map` (in `lisp/init-prog.el`). These navigate flymake
diagnostics inline without needing a compilation buffer.

## 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.

## 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.

### Adding a custom error regexp

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

```elisp theme={}
(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))
```

## Useful variables

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

```elisp theme={}
;; 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))))
```

## The compilation mode family

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

* **grep-mode** — `M-x grep`, `M-x rgrep`, `M-x lgrep` all produce compilation-derived buffers with
  the same navigation.
* **occur-mode** — `M-x occur` participates in the same `next-error` infrastructure.
* **flymake** — uses compilation-style error navigation under the hood.

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.
