Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LSP & Environment Awareness

The formatter stays hermetic—its output is a pure function of the input plus shipped data (see 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).