Here's something that was idling in my code attic for quite a while and finally got pushed past the "is it useful yet" line this weekend: a source code formatter for Nim!
Apart from a working package manager, I can't really think of a tool that I've missed more than this on a daily basis from other languages, so without further ado: <https://github.com/arnetheduck/nph/>. **I intend to never ever format Nim code manually again - it is an utterly useless waste of time** `nph` takes the opinionated route of discarding existing formatting and normalizing all code to a single, beautiful style which loosely is based on already-existing formatters for other languages such as [`black`](https://github.com/psf/black) and [`prettier`](https://prettier.io/). The formatter parses the input using a somewhat customized parser based on the one that ships with the compiler, creates a somewhat customized AST that retains a bit more information about the original source code than a typical AST, then writes it back best it can. Before writing the changes to disk, the original compiler parser is called on both the unformatted and formatted code, comparing the two AST:s for semantic differences - if there is any difference, the original code is left untouched thus fulfilling the first rule of formatters: thou shalt not break working code. If everything goes well, the formatted code is written to disk and you can get on with your life :) To get an idea what the format looks like, here's a typical `proc` definition - everything fits on one line, nice!: proc covers(entry: AttestationEntry; bits: CommitteeValidatorsBits): bool = ... Run If we add more arguments, it starts getting long - `nph` will try with a version where the arguments sit on a line of their own: proc addAttestation( entry: var AttestationEntry; attestation: Attestation; signature: CookedSig ): bool = ... Run The return type was given its own line which makes it easy to pick out as the function definition grows - it stays aligned with `proc` however so you can find arguments, return type and actual implementation at a glance. Some procedures take even more space - specially when using descriptive names, libraries like [`Result`](https://github.com/arnetheduck/nim-results) or macros like`async` - such a signature provides a lot of useful information to both the compiler and the programmer and `nph` will break it down for you to make it easy to grok: proc validateBlsToExecutionChange*( pool: ValidatorChangePool; batchCrypto: ref BatchCrypto; signed_address_change: SignedBLSToExecutionChange; wallEpoch: Epoch ): Future[Result[void, ValidationError]] {.async.} = ... Run The above idea extends to most formatting: if something is simple, format it in a simple way - if not, use a bit of style to break down what's going on into more easily consumable pieces - here's a function call: let res = check_bls_to_execution_change( pool.dag.cfg.genesisFork, forkyState.data, signed_address_change, {skipBlsValidation} ) Run `nph` is formatted with itself and comes with a bunch of before/after examples used for testing, which certainly could be extended. Some of the tests cover cases where there's still room for improvement (of which there is plenty) - comments in particular are tricky and might get moved to slightly unexpected places if they weren't placed in a location recognised by the `nph` heuristics. Here's the Nim compiler, formatted with `nph`: <https://github.com/arnetheduck/Nim/commit/75bdacdd4a3f829c0f1fe149673c2afd6add55a2> The README has a section on frequently asked questions that nobody yet has asked as well as all information you could possibly want in terms of how to run it - have a look and let me know what you think! P.S. the name nph is a last-minute change after yardanico alerted me that `nimph`, the original name I had used, [was taken](https://github.com/disruptek/nimph) and by nothing less than a package manager! I knew I should have published it when I started - now, I'm taking naming suggestions.