Colin's LaTeX Tidy — somewhere between a clang and a splat
Project description
Colin's LaTeX Tidy — somewhere between a clang and a splat.
📖 Documentation
A configurable LaTeX source formatter with opinions.
Every rule has a weight; you set a threshold.
A weight of 0 disables a rule. What happens otherwise depends on the
combination:
- clang -- weight >= threshold and fixable: auto-fixed
- clunk -- weight >= threshold and not fixable: needs your attention
- splat -- 0 < weight < threshold: advisory, take it or leave it
- off -- weight <= 0: disabled
Why "clat"?
Prosaically, clat is Colin's LaTeX Tool. But the name also has a bit of
printer's noise in it.
In the "Aeolus" episode of Ulysses -- "How a great daily organ is turned out" -- Bloom moves through the newspaper office amid the machinery of print: clanking, rhythmic, three-four time; thump, thump, thump. My great-great-grandfather, a Dublin printer, is mentioned there too, though some editions mangle Caprani as Cuprani.
So clat is meant to sound a little like that composing-room racket: a small,
opinionated machine for turning untidy copy into clean type.
How clat compares
The usual LaTeX formatting tools — latexindent, tex-fmt, prettier-plugin-latex — are excellent at indentation and line wrapping. They normalise whitespace, align tables, and keep columns tidy.
clat operates at a different layer. It doesn't touch indentation. Instead, it applies content-aware style rules that those tools don't cover:
| What you need | Tool |
|---|---|
| Indentation, line wrapping, alignment | latexindent, tex-fmt |
| Style conventions and writing hygiene | clat |
For example, clat can:
- Merge stray
\labels onto their\sectionlines - Split prose to one sentence per line
- Replace
{\bf text}with\textbf{text} - Configure inline and display math delimiter preferences separately
- Ensure
~before\ref,\cite, and similar commands - Replace
...with\dots - Normalise number-unit spacing (
100\,kN) - Detect hardcoded references (
Figure 3instead of\cref{...}) - Add trailing punctuation to display equations
- Convert superscript ordinals (
1\textsuperscript{st}→1st) - And more
None of these are available in latexindent, tex-fmt, or prettier-plugin-latex. clat is complementary — you can (and should) run both. A typical pipeline:
tex-fmt main.tex # indentation, line wrapping
clat main.tex # style rules
The weight/threshold system (clang/clunk/splat/off) also gives you granular control over which rules auto-fix, which flag for manual review, which are just advisory noise, and which are disabled — something the existing tools don't offer.
Install
pip install clat-tidy
The command is clat. (The distribution is published as clat-tidy because
clat was already taken on PyPI; everything you type is still clat.)
For local development:
pip install -e .
Requires Python >= 3.8. On Python < 3.11, tomli is installed automatically.
Quick start
# Format files in place
clat main.tex appendix.tex
# Format a multi-file document by following LaTeX inputs/includes
clat -r main.tex
# Dry run (report without fixing)
clat --check main.tex
# Dry run a multi-file document
clat --check -r main.tex
# List all rules
clat list
# Override threshold for one run
clat --threshold 3 main.tex
# Limit formatting to a single pass instead of fixed-point sweeps
clat --max-iter 1 main.tex
Rules
Run clat list to see all rules with their numbers, weights, and current category.
| # | Rule | Default | Fixable | Description |
|---|---|---|---|---|
| 1 | labels_inline | 8 | yes | Merge \label onto the same line as \section |
| 2 | decorative_comments | 6 | yes | Strip decorative comment separators (%%=== etc.) |
| 3 | heading_spacing | 7 | yes | Two blank lines before headings, none after |
| 4 | equation_separators | 7 | yes | Insert % lines around display-math environments |
| 5 | equation_punctuation | 6 | yes | Add trailing comma or period to display equations |
| 6 | float_indentation | 5 | yes | Tab-indent content inside figure/table/list environments |
| 7 | one_sentence_per_line | 8 | yes | Split sentences onto individual lines |
| 8 | math_delimiters_inline | 5 | yes | Replace \(...\) with $...$ |
| 9 | math_delimiters_display | 0 | yes | Replace \[...\] with $$...$$ |
| 10 | math_delimiters_equation | 0 | yes | Replace \[...\] or $$...$$ with equation |
| 11 | tilde_before_refs | 7 | yes | Ensure ~ before \ref, \cite etc. |
| 12 | number_unit_spacing | 6 | yes | Normalise number-unit spacing (100\,kN) |
| 13 | old_font_commands | 5 | yes | Replace {\bf text} with \textbf{text} etc. |
| 14 | ellipsis | 4 | yes | Replace ... with \dots |
| 15 | ordinal_suffixes | 8 | yes | Convert superscript ordinals to plain text (1st, 2nd) |
| 16 | long_file | 3 | no | Warn if file exceeds 2000 lines |
| 17 | hardcoded_refs | 6 | no | Detect Figure 3 instead of \cref{...} |
| 18 | manual_sizing | 3 | no | Detect \big, \Big etc. |
| 19 | float_after_heading | 4 | no | Detect float placed directly after a heading |
Configuration
Config is read from .clat.toml in the project directory, falling back to
~/.config/clat/config.toml.
Create a config file
clat set --init
This generates .clat.toml with all rules and their default weights:
threshold = 5
[weights]
labels_inline = 8 # Merge \label onto the same line as \section (fixable)
decorative_comments = 6 # Strip decorative comment separators (fixable)
heading_spacing = 7 # Two blank lines before headings, none after (fixable)
# ... all 19 rules listed
Edit the file directly, or use the CLI:
Set threshold
clat set --threshold 8
Set a rule weight
# Prefer rule ids for scripts/configuration
clat set ellipsis 9 # set ellipsis to weight 9
clat set hardcoded_refs 2 # demote hardcoded refs to a splat
clat set math_delimiters_display 5 # enable display math delimiter conversion
clat set math_delimiters_equation 5 # convert display delimiters to equation
# List numbers are also accepted for interactive use
clat set 14 9
Reset to defaults
clat set --reset
One-shot overrides
Override threshold for a single run without modifying the config:
clat --threshold 3 main.tex
CLI reference
clat <files...> Format .tex files in place
clat -r <root.tex...> Recursively format LaTeX inputs/includes
clat --recursive <root.tex> Long form of -r
clat --check <files...> Dry run: report issues without fixing
clat --check -r <root.tex> Dry run a multi-file document
clat -o out.tex in.tex Write to a different file
clat --threshold N <files> Override threshold for this run
clat --max-iter N <files> Maximum fixable-rule sweeps (default 5)
clat list List all rules with weights and categories
clat list --config path Use a specific config file
clat set <rule-id|rule#> <weight>
Set a rule weight in .clat.toml (0 disables)
clat set --threshold N Set the threshold in .clat.toml
clat set --init Create .clat.toml with defaults
clat set --reset Restore .clat.toml to defaults
clat set --config path Target a specific config file
clat --version Show version
Multi-file documents
Use -r or --recursive when a root .tex file assembles a document from
other source files:
clat -r main.tex
Recursive mode follows \input, \include, \subfile, \import,
\subimport, \includefrom, and \subincludefrom commands. Paths are
resolved relative to the file containing the command, .tex is appended when
no extension is given, duplicate files are skipped, and missing .tex inputs
are reported through the normal formatter output.
How it works
Each rule is either fixable (clat can rewrite the source) or unfixable
(clat can only detect the issue). clat applies enabled fixable rules repeatedly
until a full sweep makes no text changes, up to --max-iter sweeps (default
5). Then detect-only rules run once on the final text. At runtime, each rule's
weight is compared to the threshold:
weight >= threshold + fixable => clang (auto-fixed)
weight >= threshold + NOT fixable => clunk (needs manual fix)
0 < weight < threshold => splat (advisory)
weight <= 0 => off (disabled)
Fixable rules below threshold are still applied (the text is still fixed),
but reported as splats rather than clangs. Set a rule's weight to 0 to
disable it entirely. Use --max-iter 1 for single-pass behaviour.
Development
pip install -e .
python -m pytest tests/ -v
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clat_tidy-0.5.0.tar.gz.
File metadata
- Download URL: clat_tidy-0.5.0.tar.gz
- Upload date:
- Size: 30.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3860fef2ea10b068717b5e70ceab056dd7373db2e1a38bd1ab0bc9cf785a362
|
|
| MD5 |
6f1b1c844f4bbf6fd3e5496c22b08073
|
|
| BLAKE2b-256 |
67268418e657becefd7cabb1ea3675c613b6ddb49f66d4d0b770f14e5de7a0eb
|
Provenance
The following attestation bundles were made for clat_tidy-0.5.0.tar.gz:
Publisher:
publish.yml on ccaprani/clat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clat_tidy-0.5.0.tar.gz -
Subject digest:
f3860fef2ea10b068717b5e70ceab056dd7373db2e1a38bd1ab0bc9cf785a362 - Sigstore transparency entry: 1741865729
- Sigstore integration time:
-
Permalink:
ccaprani/clat@4b2d280715231d08e1cbd0dde631892b15d38ff6 -
Branch / Tag:
refs/tags/v0.5 - Owner: https://github.com/ccaprani
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4b2d280715231d08e1cbd0dde631892b15d38ff6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file clat_tidy-0.5.0-py3-none-any.whl.
File metadata
- Download URL: clat_tidy-0.5.0-py3-none-any.whl
- Upload date:
- Size: 22.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3122e129a0649f8a7b86dd566754d9a18a1067befb8906c29e66c3eb02adad25
|
|
| MD5 |
34f6d3d16811bb1e14fbbc6638ff8e29
|
|
| BLAKE2b-256 |
579744dcbe2e4773ec35691d6687525c35d5a373c15cdfc9ab21afb0a8efbb90
|
Provenance
The following attestation bundles were made for clat_tidy-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on ccaprani/clat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clat_tidy-0.5.0-py3-none-any.whl -
Subject digest:
3122e129a0649f8a7b86dd566754d9a18a1067befb8906c29e66c3eb02adad25 - Sigstore transparency entry: 1741865825
- Sigstore integration time:
-
Permalink:
ccaprani/clat@4b2d280715231d08e1cbd0dde631892b15d38ff6 -
Branch / Tag:
refs/tags/v0.5 - Owner: https://github.com/ccaprani
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4b2d280715231d08e1cbd0dde631892b15d38ff6 -
Trigger Event:
release
-
Statement type: