summaryrefslogtreecommitdiffstats
path: root/Makefile
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-17 14:21:40 +0200
committeruser <user@clank>2026-08-17 14:21:40 +0200
commit1f52c39ab0875162be013e6d78720a780df1d889 (patch)
tree29e9d72aa85a39d5aec52fafcecd80deb3bdf2a7 /Makefile
parentsl0ppty: a dead pane says what it ran (diff)
downloadslosh-1f52c39ab0875162be013e6d78720a780df1d889.tar.gz
slosh-1f52c39ab0875162be013e6d78720a780df1d889.tar.xz
slosh-1f52c39ab0875162be013e6d78720a780df1d889.zip
sl0ppty: clang-format, and a hook that runs it on what you staged
`make hooks` points `core.hooksPath` at `.githooks`, and from then on committing C formats it first, so what lands in git is already formatted. `make fmt` does the whole tree, `make fmt-check` only reports. The reformat itself is the next commit. **The config was chosen by measuring, not by taste.** LLVM is the base because it is what this code was already written in by hand -- two spaces, 80 columns, `char *p`, braces attached -- but LLVM alone rewrote 38% of the lines. Three disagreements account for most of that, and each is a real house idiom rather than an accident: - `if (!p) return false;` on one line, which is the guard idiom throughout. LLVM splits every one of them in two, two thirds of the churn on its own. `WithoutElse`, so an `if` that has an `else` still opens up: a one-line `if` hiding an `else` is the arrangement that hides a bug. - Comments are not reflowed. They are prose, wrapped by hand, and the breaks sometimes carry meaning -- a paragraph, a list, a diagram of a pane. A comment that runs long is a thing for a person to fix, not for a formatter to even out. - Include order is left alone. It is grouped by hand here and is not alphabetical within a group; sorting it would be churn at best and, at worst, a build that depends on an order nobody wrote down. Those three, plus one-line `case` labels and loops, bring the reformat from 38% to 17% -- and what is left is alignment and the hand-packed tables, which is the part a formatter is *for*. The vendored terminal core is excluded everywhere: `.githooks/pre-commit`, `make fmt` and `make fmt-check` all filter `^vendor/`. It is pinned by commit (D12) and reformatting it would turn every future re-vendor into a merge. **The hook refuses a partly staged file rather than widening the commit.** `clang-format -i` rewrites the working tree, so re-staging afterwards would commit work somebody deliberately left out with `git add -p`. It says which files and what to do instead. It also says when it formatted something, because a hook that edits your commit silently is a hook people learn to distrust, and it fails with the package name when `clang-format` is missing rather than letting unformatted C through the one check meant to stop it. `--no-verify` still escapes. Verified in a scratch clone, all four paths: a badly formatted file is committed formatted; a partly staged one is refused with `HEAD` unchanged and the index untouched; a commit with no C in it draws no comment; and `--no-verify` puts unformatted code in, which is what asking for it means.
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile24
1 files changed, 23 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 50e2fda..5e4544b 100644
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,8 @@ else
say = @:
endif
-.PHONY: all clean vendor run test retest test-live test-all smoke help coverage docs
+.PHONY: all clean vendor run test retest test-live test-all smoke help coverage \
+ docs fmt fmt-check hooks
.DEFAULT_GOAL := help
help: ## show this
@@ -243,6 +244,27 @@ coverage: $(COV_DIR)/sl0ppty $(COV_UNITS) ## how much of the code the tests run
done
@contrib/coverage
+# The C in this tree, minus the vendored library: that one is pinned by commit
+# (D12) and reformatting it would turn every re-vendor into a merge.
+CSRC := $(shell git ls-files '*.c' '*.h' 2>/dev/null | grep -v '^vendor/')
+
+fmt: ## format the C in place (.clang-format)
+ $(Q)clang-format -i $(CSRC)
+ $(say) " [FMT] $(words $(CSRC)) files"
+
+fmt-check: ## ...or just say which files are not formatted
+ @bad=$$(for f in $(CSRC); do \
+ clang-format "$$f" | cmp -s - "$$f" || echo "$$f"; \
+ done); \
+ if [ -n "$$bad" ]; then \
+ echo "not formatted:"; echo "$$bad" | sed 's/^/ /'; \
+ echo "run: make fmt"; exit 1; \
+ else echo "all $(words $(CSRC)) files formatted"; fi
+
+hooks: ## install the pre-commit hook (formats staged C)
+ $(Q)git config core.hooksPath .githooks
+ @echo "core.hooksPath -> .githooks (git commit --no-verify to skip)"
+
clean: ## remove our build output (not the vendor lib)
rm -rf build