badness 0.12.0

A language server, formatter, and linter for LaTeX
# LSP & Environment Awareness

The **formatter stays hermetic**—its output is a pure function of the input plus
shipped data (see [Non-goals](architecture.md#non-goals)). The **language
server** is allowed more latitude: it may look past the document's directory
into the installed TeX tree, because navigation is inherently about the local
environment. This page covers that sanctioned, LSP-only environment awareness,
and the LSP technology choice.

## Why `lsp-server`, not `tower-lsp`

The LSP is built on `lsp-server` + `lsp-types` (rust-analyzer's stack), **not**
`tower-lsp-server`. salsa cancellation is a synchronous unwind
(`salsa::Cancelled`) that composes with `lsp-server`'s sync main loop plus
threadpool, and fights tower-lsp's async `&self` model. `text/line_index.rs`
uses `lsp_types::Position`.

## Environment awareness

Two tiers of environment awareness, both reading static facts only (no macro
meaning, no typesetting):

### 1. Shipped static CTAN metadata

`data/package_metadata.json` (generated by `scripts/gen_package_names.py` from
the pinned tlpdb) is a stem → `{desc, ctan}` map, with the same read-only
posture as the name lists and CWL. It drives package hover and completion detail
(`semantic::signature::package_metadata`).

### 2. A read-only TEXMF file index

`project::texmf` indexes the installed `.sty`/`.cls`/`.dtx` files, discovered by
*delegating* root discovery to `kpsewhich -var-value` (reimplementing kpathsea's
`texmf.cnf` resolution is out of scope, and MiKTeX doesn't use it) and
enumerating via `ls-R`/walk. It is cached to the OS cache dir keyed by a distro
fingerprint—a lazy process-global (first config wins). It powers document links,
go-to-definition, and installed-set completion for system packages.

### 3. The compile's `.aux` artifacts

`project::aux` is a dedicated line-oriented scanner (never the LaTeX parser—aux
files are written under `\makeatletter`, so `\@input`/`\@writefile` would
mis-lex). It extracts `\newlabel` numbers and `\@writefile{toc}` entries,
following `\@input` per-chapter chains. Freshness is a per-file
`(mtime, len)`-keyed process cache—a recompile is picked up on the next request,
no watcher. Aux files are located per label namespace (sibling `.aux`, or
`[build] aux-dir` for out-of-tree builds; latexmkrc/Tectonic auto-detection is
deferred). This powers label hover (`Figure 3: A chart`) and document-symbol
number enrichment (`1.2 Intro`; toc titles are matched whitespace-normalized,
consumed in document order). Guarded by `format_never_reads_the_aux_file`
(`tests/format_packages.rs`).

## The distinction

A **runtime distro query feeding the formatter** stays a non-goal—it would break
the formatter's hermeticism. A **read-only index or metadata feeding LSP
navigation** is sanctioned.

The index is gated by the `texmf` editor settings
(`enabled`/`roots`/`useKpsewhich`, supplied as `initializationOptions` or via
`didChangeConfiguration`—machine config, so it lives in the editor, not
`badness.toml`; `project::texmf::TexmfConfig`) and is **never** wired into
`scope_signatures`/`DiskPackageSource` (guarded by
`formatter_scope_never_reaches_the_texmf_tree`).