badness 0.0.1

An LSP, formatter, and linter for LaTeX
Documentation

Badness

Build and Test Lint Documentation License: MIT

Badness is a formatter, linter, and language server for LaTeX, built on a lossless concrete syntax tree.

It parses LaTeX once and serves three tools from that tree:

  • Formatter (badness format): deterministic, rule-based layout.
  • Linter (badness lint): diagnostics with source snippets.
  • Language server (badness lsp): both, live in your editor.

The architecture follows rust-analyzer: a generic, error-tolerant, hand-written parser produces a lossless tree, semantics are layered on top as a separate concern, and recomputation is incremental. badness never requires resolving macros or catcodes to succeed—anything it cannot statically recognize degrades to generic nodes rather than a crash. Two properties hold by construction and are enforced as tests: losslessness (the tree reconstructs the input byte-for-byte) and idempotence (formatting an already formatted file changes nothing).

Installation

Badness is written in Rust. Build from a checkout:

git clone https://github.com/jolars/badness
cd badness
cargo install --path .

Usage

# Format a file in place (or stdin → stdout with no path)
badness format paper.tex

# Verify formatting without writing — exits non-zero if anything would change
badness format --check paper.tex

# Lint, reporting parse diagnostics
badness lint paper.tex

# Run the language server over stdio
badness lsp

Formatter style is set through flags: --line-width (default 80), --indent-width (default 2), and --wrap (reflow by default; also preserve, with sentence/semantic planned). See the documentation for the full reference.

Documentation

Full documentation lives at https://jolars.github.io/badness/ (built with mdBook from docs/).

Contributing

Architecture, tenets, and conventions are documented in AGENTS.md, written for both human and AI contributors. In short: keep the syntactic layer free of semantic knowledge, every parser feature needs corpus and snapshot tests plus a losslessness assertion, and code stays rustfmt-clean with clippy warnings treated as errors.

License

MIT