From 0ab0c2eeb6b367cabe215c854a464472810dd701 Mon Sep 17 00:00:00 2001 From: Yura Lazarev Date: Sun, 14 Jun 2026 23:20:30 +0200 Subject: [PATCH] chore: add treefmt formatting (nix fmt) and format the tree Wire treefmt via treefmt-nix: nixfmt, dhall format, purs-tidy (.tidyrc.json) and LuaFormatter for the FFI (.lua-format, kept over StyLua because it preserves the parentheses pslua's parser needs). `nix fmt` formats; the dev shell installs a content-based pre-commit hook and CI runs `nix fmt && git diff --exit-code` (content-based, since the in-place formatters bump mtime and would trip treefmt --fail-on-change). Lua lines budget 130 cols, matching the raised `luacheck --max-line-length`. The bulk of the diff is the first format pass. --- .github/workflows/ci.yml | 5 ++++- .gitignore | 2 ++ .lua-format | 10 ++++++++++ .tidyrc.json | 10 ++++++++++ AGENTS.md | 16 ++++++++++++--- flake.lock | 23 ++++++++++++++++++++- flake.nix | 43 ++++++++++++++++++++++++++++++++++++---- spago.dhall | 2 +- src/Data/Int.purs | 5 +++-- src/Data/Int/Bits.purs | 9 ++++++--- test/Test/Data/Int.purs | 33 ++++++++++++++++-------------- treefmt.nix | 43 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 171 insertions(+), 30 deletions(-) create mode 100644 .lua-format create mode 100644 .tidyrc.json create mode 100644 treefmt.nix diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d624d2e..4dc2d20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,4 +24,7 @@ jobs: run: if [ -f scripts/test ]; then nix develop -c bash ./scripts/test; fi - name: Luacheck - run: nix develop -c luacheck --quiet --std lua51 --no-unused-args src/ + run: nix develop -c luacheck --quiet --std lua51 --no-unused-args --max-line-length 130 src/ + + - name: Format check + run: nix fmt && git diff --exit-code diff --git a/.gitignore b/.gitignore index db67e9a..e070528 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /.* !/.gitignore !/.github/ +!/.tidyrc.json +!/.lua-format /output/ diff --git a/.lua-format b/.lua-format new file mode 100644 index 0000000..2945014 --- /dev/null +++ b/.lua-format @@ -0,0 +1,10 @@ +# LuaFormatter config for the hand-written FFI under src/. +# 2-space indent. Keep simple functions on one line; column_limit sits a few +# columns under luacheck's 130 limit because lua-format under-counts the leading +# indent and trailing comma, so this keeps every emitted line within 130. +indent_width: 2 +use_tab: false +column_limit: 126 +continuation_indent_width: 2 +keep_simple_function_one_line: true +keep_simple_control_block_one_line: true diff --git a/.tidyrc.json b/.tidyrc.json new file mode 100644 index 0000000..8636af8 --- /dev/null +++ b/.tidyrc.json @@ -0,0 +1,10 @@ +{ + "importSort": "source", + "importWrap": "source", + "indent": 2, + "operatorsFile": null, + "ribbon": 1, + "typeArrowPlacement": "first", + "unicode": "source", + "width": 80 +} diff --git a/AGENTS.md b/AGENTS.md index dde531a..a312901 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,11 +4,21 @@ A PureScript→Lua FFI fork in the [`purescript-lua`](https://github.com/purescr ## Commands -All commands run inside the nix dev shell: - - Build: `nix develop -c ./scripts/build` - Test (only if the fork has `scripts/test`): `nix develop -c bash ./scripts/test` -- Lint: `nix develop -c luacheck --quiet --std lua51 --no-unused-args src/` +- Lint: `nix develop -c luacheck --quiet --std lua51 --no-unused-args --max-line-length 130 src/` +- Format: `nix fmt` (check: `nix fmt && git diff --exit-code`) + +## Formatting + +`nix fmt` runs treefmt (`treefmt.nix`): nixfmt for Nix, `dhall format`, purs-tidy +for `*.purs` (config in `.tidyrc.json`), and LuaFormatter for the `*.lua` FFI +(config in `.lua-format`). LuaFormatter is used over StyLua because it keeps the +parentheses pslua's foreign-file parser requires. The Lua line budget is 130 +columns, matching the `luacheck --max-line-length` above. The check is +content-based (`nix fmt && git diff --exit-code`) rather than `treefmt --ci`, +since the in-place formatters bump mtime even when content is unchanged, which +trips treefmt's `--fail-on-change`. CI and the pre-commit hook use it. ## Lua 5.1 target diff --git a/flake.lock b/flake.lock index 6b6c417..c47b792 100644 --- a/flake.lock +++ b/flake.lock @@ -740,7 +740,8 @@ "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", "pslua": "pslua", - "purescript-overlay": "purescript-overlay" + "purescript-overlay": "purescript-overlay", + "treefmt-nix": "treefmt-nix" } }, "stackage": { @@ -803,6 +804,26 @@ "repo": "default", "type": "github" } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1780220602, + "narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "db947814a175b7ca6ded66e21383d938df01c227", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 5198865..4d86c4b 100644 --- a/flake.nix +++ b/flake.nix @@ -9,16 +9,33 @@ inputs.nixpkgs.follows = "nixpkgs"; }; pslua.url = "github:purescript-lua/purescript-lua"; + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs, flake-utils, purescript-overlay, pslua }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + purescript-overlay, + pslua, + treefmt-nix, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = import nixpkgs { inherit system; overlays = [ purescript-overlay.overlays.default ]; }; - in { + treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; + in + { + formatter = treefmtEval.config.build.wrapper; + checks.formatting = treefmtEval.config.build.check self; devShell = pkgs.mkShell { buildInputs = with pkgs; [ dhall @@ -31,8 +48,26 @@ spago-bin.spago-0_21_0 treefmt ]; + # Install a content-based pre-commit hook. It compares the working + # tree diff before and after `nix fmt`, so it only objects to changes + # the formatter itself introduces (not the developer's existing + # unstaged work) and is not fooled by formatters that only bump mtime. + # Rewritten each shell entry to stay in sync with this flake. + shellHook = '' + hook=.git/hooks/pre-commit + if [ -d .git ]; then + printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'before=$(git diff)' \ + 'nix fmt >/dev/null 2>&1 || exit 0' \ + '[ "$before" = "$(git diff)" ] || { echo "nix fmt changed files; re-stage them, then commit." >&2; exit 1; }' \ + > "$hook" + chmod +x "$hook" + fi + ''; }; - }); + } + ); # --- Flake Local Nix Configuration ---------------------------- nixConfig = { diff --git a/spago.dhall b/spago.dhall index 68998c7..b6c7b6d 100644 --- a/spago.dhall +++ b/spago.dhall @@ -1,5 +1,5 @@ { name = "purescript-lua-integers" -, dependencies = [ "maybe" , "numbers" , "prelude" ] +, dependencies = [ "maybe", "numbers", "prelude" ] , packages = ./packages.dhall , sources = [ "src/**/*.purs" ] } diff --git a/src/Data/Int.purs b/src/Data/Int.purs index c637fc8..4b21d21 100644 --- a/src/Data/Int.purs +++ b/src/Data/Int.purs @@ -196,8 +196,9 @@ base36 = Radix 36 -- | Create a `Radix` from a number between 2 and 36. radix :: Int -> Maybe Radix -radix n | n >= 2 && n <= 36 = Just (Radix n) - | otherwise = Nothing +radix n + | n >= 2 && n <= 36 = Just (Radix n) + | otherwise = Nothing -- | Like `fromString`, but the integer can be specified in a different base. -- | diff --git a/src/Data/Int/Bits.purs b/src/Data/Int/Bits.purs index d1b4715..98bc5bc 100644 --- a/src/Data/Int/Bits.purs +++ b/src/Data/Int/Bits.purs @@ -1,8 +1,11 @@ -- | This module defines bitwise operations for the `Int` type. module Data.Int.Bits - ( and, (.&.) - , or, (.|.) - , xor, (.^.) + ( and + , (.&.) + , or + , (.|.) + , xor + , (.^.) , shl , shr , zshr diff --git a/test/Test/Data/Int.purs b/test/Test/Data/Int.purs index 1eabc6b..9343eab 100644 --- a/test/Test/Data/Int.purs +++ b/test/Test/Data/Int.purs @@ -40,23 +40,24 @@ testInt = do assert $ floor 0.7 == 0 log "round, ceil, and floor should clamp values outside the Int range" - let testClamping f = do - let low = toNumber bottom - 1.5 - assert $ f low == bottom + let + testClamping f = do + let low = toNumber bottom - 1.5 + assert $ f low == bottom - let high = toNumber top + 1.5 - assert $ f high == top + let high = toNumber top + 1.5 + assert $ f high == top testClamping round testClamping ceil testClamping floor - log "round, ceil, and floor should return 0 for NaN and Infinities" - let testNonNumber f = do - assert $ f nan == 0 - assert $ f infinity == 0 - assert $ f (-infinity) == 0 + let + testNonNumber f = do + assert $ f nan == 0 + assert $ f infinity == 0 + assert $ f (-infinity) == 0 testNonNumber round testNonNumber ceil @@ -135,9 +136,10 @@ testInt = do log "parity is a ring homomorphism" do - let go x y = do - assert $ parity x + parity y == parity (x + y) - assert $ parity x * parity y == parity (x * y) + let + go x y = do + assert $ parity x + parity y == parity (x + y) + assert $ parity x * parity y == parity (x * y) go 0 0 go 0 1 @@ -155,8 +157,9 @@ testInt = do let q = quot a b r = rem a b - in do - assert $ q * b + r == a + in + do + assert $ q * b + r == a -- Check when dividend goes into divisor exactly go 8 2 go (-8) 2 diff --git a/treefmt.nix b/treefmt.nix new file mode 100644 index 0000000..0f57573 --- /dev/null +++ b/treefmt.nix @@ -0,0 +1,43 @@ +{ pkgs, ... }: +{ + projectRootFile = "flake.nix"; + + # Nix — RFC 166 formatter. + programs.nixfmt.enable = true; + + # Dhall — spago.dhall / packages.dhall layout. + programs.dhall.enable = true; + + # PureScript — purs-tidy is not a first-class treefmt program, so wire it via + # the generic mechanism. It picks up `.tidyrc.json` from the project root. + settings.formatter.purs-tidy = { + command = "${pkgs.purs-tidy}/bin/purs-tidy"; + options = [ "format-in-place" ]; + includes = [ "*.purs" ]; + }; + + # Lua FFI — LuaFormatter keeps the parentheses pslua's foreign-file parser + # requires (unlike StyLua, which strips them). Config in `.lua-format`. + settings.formatter.lua-format = { + command = "${pkgs.luaformatter}/bin/lua-format"; + options = [ + "-i" + "-c" + ".lua-format" + ]; + includes = [ "*.lua" ]; + }; + + # Never format generated output or vendored trees. + settings.global.excludes = [ + "dist/*" + "output/*" + ".spago/*" + "node_modules/*" + "*.lock" + "flake.lock" + "spago.lock" + ".tidyrc.json" + ".lua-format" + ]; +}