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.1 # 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.1.tar.gz (19.6 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.1-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: lastlint-0.5.1.tar.gz
  • Upload date:
  • Size: 19.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lastlint-0.5.1.tar.gz
Algorithm Hash digest
SHA256 b82de73478e386e869ab4780d0fc509fc9232f7a61ef5129d258303c6f2f5e13
MD5 aed7ec2f2c1a7e6d54fe526fc8e5fb76
BLAKE2b-256 d48942ef5812fc3c2303e49ca129679029a76eb4f65bf7231ae9e934410dff3c

See more details on using hashes here.

Provenance

The following attestation bundles were made for lastlint-0.5.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: lastlint-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 16.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lastlint-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5a306b747a0f727a18afff0bcd47e35c9b21ee1e2a112b2f8dcb6843d5877f32
MD5 284c80a4194e6133f074a9bb13f4a3b2
BLAKE2b-256 72294656ebecc3e519dc46c3049c7e59bb9f6d511ef1d596df31a5c3cef25699

See more details on using hashes here.

Provenance

The following attestation bundles were made for lastlint-0.5.1-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

This release

0.5.1 This release

2 files

0.5.0

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