Metadata-Version: 2.4
Name: clat-tidy
Version: 0.4.0
Summary: Colin's LaTeX Tidy — somewhere between a clang and a splat
Author: Colin Caprani
License-Expression: MIT
Project-URL: Homepage, https://ccaprani.github.io/clat/
Project-URL: Documentation, https://ccaprani.github.io/clat/
Project-URL: Repository, https://github.com/ccaprani/clat
Project-URL: Issues, https://github.com/ccaprani/clat/issues
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Text Processing :: Markup :: LaTeX
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rich
Requires-Dist: tomli>=1.0; python_version < "3.11"
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.25; extra == "docs"
Dynamic: license-file

<p align="center">
  <img src="https://raw.githubusercontent.com/ccaprani/clat/main/docs/assets/clat-logo.png" width="120" alt="clat logo">
</p>

# clat

[![PyPI](https://img.shields.io/pypi/v/clat-tidy?color=3949ab)](https://pypi.org/project/clat-tidy/)
[![Python versions](https://img.shields.io/pypi/pyversions/clat-tidy)](https://pypi.org/project/clat-tidy/)
[![Docs](https://github.com/ccaprani/clat/actions/workflows/docs.yml/badge.svg)](https://ccaprani.github.io/clat/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/ccaprani/clat/blob/main/LICENSE)

Colin's LaTeX Tidy -- somewhere between a clang and a splat.

📖 **Documentation:** <https://ccaprani.github.io/clat/>

A configurable LaTeX source formatter with opinions.
Every rule has a weight; you set a threshold.
What happens depends on the combination:

- **clang** -- weight >= threshold *and* fixable: auto-fixed
- **clunk** -- weight >= threshold *and* not fixable: needs your attention
- **splat** -- weight < threshold: advisory, take it or leave it

## 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.

## 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

```bash
# 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
```

## 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       |    5    |   yes   | Replace `\(...\)` with `$...$` and `\[...\]` with `$$...$$`|
|  9 | tilde_before_refs     |    7    |   yes   | Ensure `~` before `\ref`, `\cite` etc.                     |
| 10 | number_unit_spacing   |    6    |   yes   | Normalise number-unit spacing (`100\,kN`)                  |
| 11 | old_font_commands     |    5    |   yes   | Replace `{\bf text}` with `\textbf{text}` etc.             |
| 12 | ellipsis              |    4    |   yes   | Replace `...` with `\dots`                                 |
| 13 | ordinal_suffixes      |    8    |   yes   | Convert superscript ordinals to plain text (`1st`, `2nd`)  |
| 14 | long_file             |    3    |   no    | Warn if file exceeds 2000 lines                            |
| 15 | hardcoded_refs        |    6    |   no    | Detect `Figure 3` instead of `\cref{...}`                  |
| 16 | manual_sizing         |    3    |   no    | Detect `\big`, `\Big` etc.                                 |
| 17 | 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

```bash
clat set --init
```

This generates `.clat.toml` with all rules and their default weights:

```toml
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 17 rules listed
```

Edit the file directly, or use the CLI:

### Set threshold

```bash
clat set --threshold 8
```

### Set a rule weight

```bash
# By rule number (see clat list)
clat set 12 9     # set rule 12 (ellipsis) to weight 9
clat set 14 2     # demote hardcoded refs to a splat
```

### Reset to defaults

```bash
clat set --reset
```

### One-shot overrides

Override threshold for a single run without modifying the config:

```bash
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 list                    List all rules with weights and categories
clat list --config path      Use a specific config file

clat set <rule#> <weight>    Set a rule weight in .clat.toml
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:

```bash
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). 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)
weight <  threshold               =>  splat (advisory)
```

Fixable rules below threshold are still applied (the text is still fixed),
but reported as splats rather than clangs.

## Development

```bash
pip install -e .
python -m pytest tests/ -v
```

## License

MIT
