Skip to main content

lastlint: LaTeX strict linter

A linter for Evan Chen's LaTeX style guide.

Usage

Pre-commit hook

Add to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/cjquines/lastlint
    rev: v0.5.0 # x-release-please-version
    hooks:
      - id: lastlint-fix

To only report errors rather than auto-fixing them, use the lastlint hook id.

Standalone

Install from PyPI. Using uv (recommended):

uv tool install lastlint
lastlint path/to/file.tex another.tex

To run without installing: uvx lastlint path/to/file.tex. With pip: pip install lastlint.

Multiple files are accepted, and glob patterns are expanded.

Pass --fix to auto-fix supported rules in place.

Pass --ignore E001,E013 to skip both reporting and fixing.

On a terminal, output is grouped per file and colorized; when piped or redirected it uses a plain file:line:col: EXXX: message format parseable by editors. Force either mode with --color always or --color never (also honors NO_COLOR and FORCE_COLOR).

Editor

An optional language server exposes lastlint to compatible text editors. Install it with the lsp extra:

uv tool install 'lastlint[lsp]'
# or: pip install 'lastlint[lsp]'

The server lastlint-lsp, over stdio, publishes diagnostics and implements formatting, so format-on-save will auto-fix LaTeX files. Pass ignored rules through initializationOptions, e.g. {"ignore": ["E001", "E013"]}.

The setups below assume lastlint-lsp is globally installed. To skip a global install, replace the command with uvx --from 'lastlint[lsp]' lastlint-lsp.

Neovim

0.11+, native vim.lsp:

vim.lsp.config('lastlint', {
  cmd = { 'lastlint-lsp' },
  filetypes = { 'tex', 'plaintex' },
  root_markers = { '.git' },
})
vim.lsp.enable('lastlint')
Sublime Text

The LSP package, in LSP.sublime-settings:

{
  "clients": {
    "lastlint": {
      "enabled": true,
      "command": ["lastlint-lsp"],
      "selector": "text.tex.latex"
    }
  }
}
Emacs

Eglot (built in since 29) — then run M-x eglot in a TeX buffer:

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               '((latex-mode LaTeX-mode) . ("lastlint-lsp"))))

Suppression

Add an inline comment to skip rules on a single line:

This text has "intentional" quotes.  % lastlint: disable=E002

Rules

Fixable rules are marked with 🔧.

ID Rule from style guide
E001 Line length must be ≤ 120
E002 🔧 No literal "
E003 🔧 Operators (\sin etc.) must be commands
E004 🔧 No \ldots, \cdots, or ...
E005 🔧 No grammatical punctuation inside inline math
E006 🔧 No extraneous space before punctuation
E007 Spacing around = must be symmetric
E009 🔧 No bad math operators (| etc.)
E010 🔧 No $$ ... $$
E011 No adjacent \[ ... \] blocks
E012 \begin{align*} / \end{align*} must have own line
E013 🔧 Env contents must be indented
E014 🔧 No trailing whitespace
E015 No \\\\ paragraph break
E017 🔧 No : for function signatures

Rules not implemented:

  • Rule 8 (balanced delimiters): hard to lint reliably.
  • Rule 16 (variables in prose): requires natural-language understanding.

E001

E001 skips two kinds of unfixable long lines: those containing a URL (http:// or https://), and fully-commented lines (only whitespace before the %). Lines with a long trailing comment after real content are still flagged.

I recommend SemBr for automatically adding line breaks.

E004

E004 picks the right \dots variant from context (\dotsc after a comma, \dotsb after an operator) and leaves a \cdots unresolved when neither side determines spacing.

E013

E013 checks every env except a small denylist: document, center, quote, and the verbatim envs (asy, verbatim, lstlisting, …). See NO_INDENT_ENVS in lastlint.py to adjust.

The --fix pads under-indented lines inside indent envs to 2 * depth spaces (already-correctly-indented or deeper lines are left alone).

Development

pip install -e .[dev]
pytest

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lastlint-0.5.0.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lastlint-0.5.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file lastlint-0.5.0.tar.gz.

File metadata

  • Download URL: lastlint-0.5.0.tar.gz
  • Upload date:
  • Size: 18.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lastlint-0.5.0.tar.gz
Algorithm Hash digest
SHA256 2ea02857203afc5baedf0ee0498817fb5172ef45ad8cbc3c103bee6865a6024d
MD5 a600d46e282ac2d1c2a1214537940bfb
BLAKE2b-256 221dd7ed8754976dd3ac23a300c80d9499b3f1f87ab37b9fed5f44bf16046135

See more details on using hashes here.

Provenance

The following attestation bundles were made for lastlint-0.5.0.tar.gz:

Publisher: release-please.yml on cjquines/lastlint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lastlint-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: lastlint-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 16.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lastlint-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ea055205e8f93f343dcc808270be7260d54a2731023d0c1ebdd6cd4c7a8350d0
MD5 560c0e8bfe7f745e10918fb383b8ae66
BLAKE2b-256 c87f6d40b532408a446577bb16054494ee3c2a934f7a7cebbc9e63ac137fbfda

See more details on using hashes here.

Provenance

The following attestation bundles were made for lastlint-0.5.0-py3-none-any.whl:

Publisher: release-please.yml on cjquines/lastlint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.5.1

2 files

This release

0.5.0 This release

2 files

0.4.1

2 files

0.4.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page