-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0ca71b1
Showing
49 changed files
with
333,634 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
name: CI | ||
on: [push, pull_request] | ||
|
||
concurrency: # Cancel stale PR builds (but not push builds) | ||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
build: | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
target: | ||
- os: linux | ||
cpu: amd64 | ||
TEST_LANG: c | ||
include: | ||
- target: | ||
os: linux | ||
builder: ubuntu-20.04 | ||
shell: bash | ||
defaults: | ||
run: | ||
shell: ${{ matrix.shell }} | ||
|
||
name: '${{ matrix.target.os }}-${{ matrix.target.cpu }}-${{ matrix.target.TEST_LANG }}' | ||
runs-on: ${{ matrix.builder }} | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
|
||
- name: Fetch nimble | ||
run: | | ||
wget https://github.com/nim-lang/nimble/releases/download/latest/nimble-linux_x64.tar.gz | ||
tar xvf nimble-linux_x64.tar.gz | ||
echo "$PWD" >> $GITHUB_PATH | ||
- name: Build nimph | ||
run: | | ||
nimble setup -l | ||
nimble build | ||
- name: Check formatting | ||
run: | | ||
find -name "*.nim" ! -path "./tests/before/*" ! -path "./nimbledeps/*" -print0 | xargs -0 -n1 ./nimph | ||
git diff --exit-code | ||
find -name "*.nim" ! -path "./tests/before/*" ! -path "./nimbledeps/*" -print0 | xargs -0 -n1 ./nimph --check |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
nimbledeps | ||
/nimph |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
# Nimph | ||
|
||
Nimph is an opinionated source code formatter for the Nim language, aiming to | ||
take the drudgery of manual formatting out of your coding day. | ||
|
||
Following the great tradition of [`black`](https://github.com/psf/black/), | ||
[`prettier`](https://prettier.io/), [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) | ||
and other AST-based formatters, it discards existing styling to create a | ||
consistent and beautiful codebase. | ||
|
||
## Usage | ||
|
||
Install `nimph`, then run it on some files: | ||
|
||
```sh | ||
# Format the given files in-place | ||
nimph file0.nim file1.nim | ||
|
||
# Format the given files, writing the formatted code to /tmp | ||
nimph file0.nim file1.nim --outdir:/tmp | ||
|
||
# Use --check to verify that a file is formatted correctly - useful in CI | ||
nimph --check somefile.nim || echo "Not formatted!" | ||
|
||
# You can format stuff as part of a pipe using `-` as input: | ||
echo "echo 1" | nimph - | ||
``` | ||
|
||
For bonus points, replace `nimpretty` with a symlink to `nimph` - similar | ||
command line options are supported ;) | ||
|
||
## Installation | ||
|
||
`nimph` can be compiled or installed using `nimble` version `v0.14.2`+: | ||
|
||
```sh | ||
nimble -l setup | ||
nimble build | ||
``` | ||
|
||
## Priorities | ||
|
||
`nimph` aims to format code in such way that: | ||
|
||
* it remains semantically unchanged, aka correct (!) | ||
* the AST is checked for equivalence before writing the formatted code to | ||
disk - on mismatch, the code is left untouched | ||
* it remains simple, consistent and pleasant to read | ||
* _most_ code should look as good as or better than its hand-formatted | ||
counterpart | ||
* diffs are kept at a minimum | ||
* diff-inducing constructs such as vertical alignment are avoided, for more | ||
productive merges | ||
* it broadly follows the [Status Nim style guide](https://status-im.github.io/nim-style-guide/) | ||
and [NEP1](https://nim-lang.org/docs/nep1.html) | ||
* this is tool aimed at making collaboration easier, with others and your | ||
future self | ||
* where NEP1 contradicts itself, see above | ||
|
||
The formatting rules are loosely derived from other formatters that already have | ||
gone through the journey of debating what "pleasing to read" might mean while | ||
making adaptations for both features and quirks of the Nim parser. | ||
|
||
If in doubt, formatting that works well for descriptive identifiers and avoids | ||
putting too much information in a single like will be preferred. | ||
|
||
## FAQ | ||
|
||
### Why use a formatter? | ||
|
||
A formatter removes the tedium of manually adding structure to code to make it | ||
more readable - overlong lines, inconsistent indentation, lack of visual | ||
structure and other small distractions quickly nibble away at the mental budget | ||
available for writing code while a formatter solves this many many other things | ||
at the press of a button. | ||
|
||
When you work with others, debates and nitpicking over style go away and | ||
collaborative efforts can focus on substance instead. | ||
|
||
Finally, the code is likely to look better - manually formatting code takes a | ||
lot of effort which ultimately can be spent better elsewhere - as such, poorly | ||
formatted code ends up being more common than not. | ||
|
||
### But I've spent a significant part of my life realigning code and now it's lost! | ||
|
||
https://en.wikipedia.org/wiki/Sunk_cost | ||
|
||
### How do I introduce `nimph` in an existing codebase? | ||
|
||
Assuming `git` is used, format all code using `nimph`, put it in a single commit | ||
and add a CI rule to ensure that future commits are all formatted using the same | ||
`nimph` version. | ||
|
||
Formatting commits can be ignored for the purpose of `git blame` by adding a | ||
file named `.git-blame-ignore-revs` containing the formatted source code to the | ||
root of the project: | ||
|
||
```sh | ||
cd myproject | ||
|
||
# Format all source code with nimph | ||
find -name "*.nim" -exec nimph {} \; | ||
|
||
# Create a single commit with all changes | ||
git add -A && git commit -m "Formatted code with nimph" | ||
|
||
# Record the commit hash in the blame file | ||
echo "# Formatted code with nimph" >> .git-blame-ignore-revs | ||
echo $(git rev-parse HEAD) >> .git-blame-ignore-revs | ||
``` | ||
|
||
then configure git to use it: | ||
```sh | ||
git --global config blame.ignoreRevsFile .git-blame-ignore-revs | ||
``` | ||
|
||
The same strategy can be used when upgrading `nimph` to a new version that | ||
introduces formatting changes. | ||
|
||
### `nimph` complains about my code! | ||
|
||
One of several things could have happened: | ||
|
||
* The code was not valid enough - `nimph` can only parse valid Nim grammar and | ||
while it would be nice to handle partially formatted stuff gracefully, we're | ||
not there yet. | ||
* The parser has a bug and is unable to parse valid Nim code | ||
* Probably you can move some comments around to make it work! | ||
* the formatter has a bug and the resulting formatting is invalid | ||
* Probably you can move some comments around to make it work! | ||
* the AST equivalence checker complains | ||
* This often happens in complex expressions such as `do` and parenthesis used | ||
for indent purposes where the Nim grammar has ambiguities and parsing | ||
complexity - it can usually be worked around by simplifying complex | ||
expressions, introducing a template or similar | ||
* It could also be that the AST checker is too strict - the Nim parser will | ||
generate different AST:s depending on whitespace even if semantically there | ||
is no difference | ||
|
||
Regardless of what happened, `nimph` takes the conservative approach and retains | ||
the original formatting! | ||
|
||
If you have time, try to find the offending code snippet and submit an issue. | ||
|
||
### Why the cited formatters in particular? | ||
|
||
* `black` because of our syntactic similarity with Python and its | ||
[stability policy](https://black.readthedocs.io/en/stable/the_black_code_style/index.html#stability-policy) | ||
* `prettier` for its wisdom in how formatting [options](https://prettier.io/docs/en/option-philosophy) | ||
are approached and for the closeness to user experience of its developers | ||
* `clang-format` for being the formatter that made me stop worrying about | ||
formatting | ||
* its secret sauce was treating formatting as a balancing of priorities rather | ||
than a mechanical stringification using a [lowest-penalty](https://youtu.be/s7JmdCfI__c?t=640) | ||
algorithm | ||
|
||
### What is meant by consistency? | ||
|
||
* Similar constructs are formatted with similar rules | ||
* Does it look like a list? Format it with list-like rules regardless if | ||
its a parameter list, array of values or import list | ||
* Original styling is generally not preserved - instead, the formatting is based | ||
on the semantic structure of the program | ||
* Spacing emphasizes structure and control flow to help you read the code | ||
|
||
`nimph` makes your code consistent without introducing hobgoblins in your mind! | ||
|
||
### Why are there no options? | ||
|
||
The aim of `nimph` is to create a single consistent style that allows you to | ||
focus on programming while `nimph` takes care of the formatting, even across | ||
different codebases and authors. | ||
|
||
Consistency helps reading speed by removing unique and elaborate formatting | ||
distractions, allowing you, the experienced programmer, to derive structural | ||
information about the codebase at a glance. | ||
|
||
The style might feel unfamiliar in the beginning - this is fine and not a reason | ||
to panic - a few weeks from now, you'll forget you ever used another one. | ||
|
||
### Do you accept style suggestions and changes? | ||
|
||
Yes! The project is still in its early phase meaning that the style is not yet | ||
set in stone. | ||
|
||
To submit a proposal, include some existing code, how you'd like it to be | ||
formatted and an option-free algorithm detailing how to achieve it and how the | ||
outcome relates to the above styling priorities. | ||
|
||
When in doubt, look at what other opinionated formatters have done and link to | ||
it! | ||
|
||
Eventually, the plan is to adopt a [stability policy](https://black.readthedocs.io/en/stable/the_black_code_style/index.html#stability-policy) | ||
similar to `black`, meaning that style changes will still be accepted, but | ||
introduced only rarely so that you don't have to worry about massive PR-breaking | ||
formatting diffs all the time. | ||
|
||
### Why does the formatting code look an awful lot like the Nim compiler renderer? | ||
|
||
Because it is based on it, of course! As a starting point this is fine but the | ||
code would benefit greatly from being rewritten with a dedicated formatting | ||
AST. | ||
|
||
In particular, the comment handling is done in a hand-wavy manner with bits and | ||
pieces of the old code mixed with new heuristics resulting in quite the mess. | ||
|
||
### Should it be upstreamed? | ||
|
||
Maybe parts - feel free to make PR:s to the Nim repo from this codebase! That | ||
said, the aim of a compiler is to compile while a formatter formats - we are not | ||
the same. | ||
|
||
### What about `nimpretty`? | ||
|
||
`nimpretty` formats tokens, not the AST. Use whichever you like better, but keep | ||
a backup if you don't use `nimph` :) | ||
|
||
### Why 88 characters? | ||
|
||
This is an experiment. | ||
|
||
Astute and experienced programmers have noticed two things: longer variable | ||
names aren't that bad and monitors have gotten bigger since the 80 standard was | ||
set. | ||
|
||
Going beyond allows code that uses descriptive names to look better - how much | ||
extra is needed here is an open question but 10% seems like a good start for a | ||
language like Nim which defaults to 2-space significant indent and a naive | ||
module system that encourages globally unique identifiers with longer names. | ||
|
||
### What about comments? | ||
|
||
`nimph` currently touches comments as little as possible - specifically, they | ||
are not re-flowed or re-aligned and the aim is to make them sticky to where they | ||
were originally written. | ||
|
||
Improvements in this area are much welcome - the compiler AST was not really | ||
written with comment preservation in mind and `nimph`'s handling is not great. | ||
|
||
### What features will likely not be added? | ||
|
||
* formatting options - things that change the way the formatting is done for | ||
aesthetic reasons - exceptions here might include options that increase | ||
compatiblity (for example with older Nim versions) | ||
* semantic refactoring - reordings of imports etc - the focus is on style only | ||
|
||
### What's with the semicolons? | ||
|
||
Nim's grammar unfortunately allows the use of either `,` or `;` in some places | ||
with a subtly different AST being produced which _sometimes_ has a semantic | ||
impact - `nimph` takes a conservative approach here and uses `;` to avoid | ||
ambiguity. | ||
|
||
Future versions may try to identify where `,` can be used safely - very few | ||
programmers _really_ want `;` judging from the frequency with which it is used. | ||
|
||
Regardless, you can usually type either and `nimph` will clean it up. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# begin Nimble config (version 2) | ||
when withDir(thisDir(), system.fileExists("nimble.paths")): | ||
include "nimble.paths" | ||
# end Nimble config | ||
|
||
switch("p", "$projectDir/nimbledeps/pkgs2/nim-2.0.0-35b9d926d314ce8c3326902c138f5c2247cfd390/compiler") | ||
switch("p", "$projectDir/../nimbledeps/pkgs2/nim-2.0.0-35b9d926d314ce8c3326902c138f5c2247cfd390/compiler") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
===================================================== | ||
nimph code formatter | ||
|
||
Copyright (C) 2023 Jacek Sieka. All rights reserved. | ||
|
||
|
||
Based in large parts on code from the Nim compiler, which is: | ||
Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
|
||
[ MIT license: http://www.opensource.org/licenses/mit-license.php ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
--noNimblePath |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Package | ||
|
||
version = "0.1" | ||
author = "Jacek Sieka" | ||
description = "Nim code formatter" | ||
license = "MIT" | ||
srcDir = "src" | ||
bin = @["nimph"] | ||
|
||
# Dependencies | ||
|
||
# TODO https://github.com/nim-lang/nimble/issues/1166 | ||
# Using exact version here and adding path manually :facepalm: | ||
# run `nimble setup -l` to hopefully make it work | ||
requires "nim == 2.0.0", | ||
"compiler" | ||
|
||
proc build() = | ||
exec "nim c --debuginfo -o:nimph src/nimph" | ||
|
||
task self, "Format nimph itself": | ||
build() | ||
|
||
# Stage changes before doing self-formatting! | ||
exec "git diff --staged --no-ext-diff --quiet --exit-code" | ||
exec "git add -A" | ||
|
||
for file in listFiles("src"): | ||
if file.len > 4 and file[^4..^1] == ".nim": | ||
echo file | ||
exec "./nimph " & file & " --debug" | ||
|
||
task f, "Format": | ||
build() | ||
|
||
cd "tests/before" | ||
for file in listFiles("."): | ||
if file.len > 4 and file[^4..^1] == ".nim": | ||
echo file | ||
exec "../../nimph " & file & " --outDir:../after --debug" |
Oops, something went wrong.