inkfmt (pronounced "ink format") is a self-hosting code formatter for the Ink programming language. It's written in Ink itself, and designed to be run before commits to canonicalize syntax and whitespace, but still respects the code author's line breaks and comments. It's a work in progress, but gives the expected output for 95% of cases today.
All Ink code in this project is, of course, formatted with inkfmt. You can read an in-depth review of inkfmt's design and implementation in the inkfmt post on the Ink blog.
inkfmt makes these transformations:
- Remove unnecessary commas
- At ends of lines (Ink has automatic comma insertion at line endings)
a := 1, a := 1 b := 2, -> b := 2 c := a + b, c := a + b
- At end of expression and argument lists
result := f(1, 2, [3, 4, ], { key: val, }, ) -> result := f(1, 2, [3, 4], { key: val })
- Canonicalize whitespaces
- Sensibly auto-indent lines
func := n => even?(n) :: { true -> 'is' + ' even' false -> 'is odd' } -> func := n => even?(n) :: { true -> 'is' + ' even' false -> 'is odd }
- Ensure single spaces between specific tokens, when appropriate
func := (x,y)=> pow(x,2)+3.1415 -> func := (x, y) => pow(x, 2) + 3.1415
inkfmt intentionally avoids certain kinds of code transformations that might be disruptive to the intent of the code author.
- inkfmt doesn't change line breaks in code. Many other formatters like Prettier and rustfmt break lines according to some length heuristic, while others like gofmt do not. I personally prefer formatters not to mess with my line breaks. Line breaks often convey important information, grouping arguments or list entries together in semantically important ways. If a line gets too long, I can manually break it in a sensible place. It might also be an indicator that there might be a better way to describe what I'm doing in code.
- inkfmt doesn't add or remove idempotent parentheses. Some more strict and deterministic formatters like Prettier will add and remove parentheses around expressions to disambiguate expressions or add consistency, but like line breaks, I think programmers use parentheses to group things in meaningful ways or make the code more readable, and formatters should clean them up, not remove them.
At this point, the fmt
program reads Ink code in from stdin
and writes formatted code and/or errors out to stdout
. Eventually, the goal will be for the executable to read a tree of files and format all Ink programs within.
With Ink installed, we can simply run:
./fmt.ink < input.ink > output.ink
- Phil Wadler's Prettier Printer
- Prettier's JavaScript implementation of the above, GitHub
- Go's implementation of gofmt