diff options
| author | user <user@clank> | 2026-08-17 14:35:59 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-17 14:35:59 +0200 |
| commit | b1fe06633d68ec611d0b1269f4c95db82ac456f5 (patch) | |
| tree | 4059660e61805eaec6db011e3229a48cb0c26d7a /docs | |
| parent | sl0ppty: let git blame walk past the reformat (diff) | |
| download | slosh-b1fe06633d68ec611d0b1269f4c95db82ac456f5.tar.gz slosh-b1fe06633d68ec611d0b1269f4c95db82ac456f5.tar.xz slosh-b1fe06633d68ec611d0b1269f4c95db82ac456f5.zip | |
sl0ppty: ruff formats the Python, and sorts its imports
The other half of the pre-commit hook. C goes through clang-format, Python through
ruff: `ruff check --select I --fix` to sort the imports, then `ruff format` to lay
them out. `make fmt` does both, `make fmt-check` reports, `make hooks` installs it.
ruff rather than black because it is one static binary instead of a Python
dependency chain, and fast enough that a hook is free. Its formatter is
black-compatible, so this is the ecosystem's formatting rather than a dialect --
measured at 9,935 changed lines against black's 9,953, which is the same answer.
**Left entirely at the defaults**, which is the opposite of what `.clang-format`
does. That file argues with LLVM in five places because the C here was
hand-formatted into a house style worth keeping. The Python was not, and a
formatter of this kind is only worth having when there is nothing left to argue
about: every knob turned is an argument somebody has to have again later. 88
columns, double quotes, ruff's own line breaking.
**Import sorting is on, and C include sorting stays off.** Not an inconsistency: a
C include order can be load-bearing -- `_GNU_SOURCE` ahead of the system headers,
and a grouping somebody wrote by hand -- while Python import order is not. Where it
genuinely is, a statement between imports ends the block ruff will sort, and the
test files lean on exactly that:
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from harness import Session, check, report
`from harness import` cannot be hoisted above the line that makes it importable,
because the `sys.path.insert` between them is a barrier. Verified before touching
anything, since getting it wrong would have broken every test in the suite at once.
Two details in the hook worth naming. `--select I` is passed on the command line as
well as set in `ruff.toml`, so a stray `select` in somebody's own config cannot
turn a formatting hook into a linter that refuses a commit over an unused variable.
And the two tools are named together when either is missing, so setting up a
machine installs both at once instead of finding the second one on the next commit.
`set -e` and `[ -n "$c_files" ] && clang-format ...` do not mix: when the list is
empty the AND-list returns non-zero and the shell exits, so a Python-only commit
would have aborted with no message at all. They are `if` blocks. Found by testing
the case rather than by reading it.
Verified in a scratch clone, seven paths: Python alone, C alone, both in one
commit, imports sorted with the `sys.path` barrier intact, a `contrib/` script that
is Python with no extension on it, a partly staged Python file refused with `HEAD`
unchanged, and a commit with no code in it drawing no comment.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/design.md | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/docs/design.md b/docs/design.md index d24641f..012d4c2 100644 --- a/docs/design.md +++ b/docs/design.md @@ -51,9 +51,10 @@ selection, images and key encoding; everything above is ours. ## How it is formatted -`clang-format`, with the config in `.clang-format`. `make fmt` applies it, +`clang-format` for the C (`.clang-format`) and `ruff` for the Python +(`ruff.toml`) -- imports sorted, then laid out. `make fmt` applies both, `make fmt-check` only reports, and `make hooks` installs a pre-commit hook that -formats the C you staged so what lands in git is already formatted. +formats what you staged, so what lands in git is already formatted. The base is LLVM, because that is what this code was written in by hand — two spaces, 80 columns, `char *p`, braces attached. The settings that differ from it @@ -66,5 +67,19 @@ Comments are not reflowed. They are prose here, wrapped by hand, and sometimes t line breaks carry meaning — a paragraph, a list, a diagram of a pane. A comment that runs long is a thing for a person to fix. +The Python is the opposite: left entirely at ruff's defaults. The C here was +hand-formatted into a house style worth arguing for; the Python was not, and a +formatter of that kind is only worth having when there is nothing left to argue +about. Every knob turned would be an argument to have again later. It cost a 60% +reformat of the test suite, once. + +**Python imports are sorted and C includes are not**, which is not an +inconsistency. A C include order can be load-bearing -- `_GNU_SOURCE` ahead of the +system headers, and a grouping somebody wrote by hand -- while Python import order +is not. Where it genuinely is, a statement between the imports ends the block ruff +will sort, and the tests lean on exactly that: `sys.path.insert(...)` sits between +the standard library and `from harness import ...`, so the harness import cannot be +hoisted above the line that makes it importable. + The vendored terminal core is never formatted: it is pinned by commit (D12), and reformatting it would turn every re-vendor into a merge. |
