Add/update a lot of documentation
This commit is contained in:
206
CUSTOMIZATION.md
Normal file
206
CUSTOMIZATION.md
Normal file
@@ -0,0 +1,206 @@
|
||||
There are two main areas of per-project customization: how `would-format`
|
||||
determines a given file's type, and how a file is checked or reformatted
|
||||
after its type has been determined.
|
||||
|
||||
# Conventions
|
||||
|
||||
`$YOUR_PROJECT_ROOT` is the root where your project is checked out.
|
||||
|
||||
# File type sniffing
|
||||
|
||||
To change a file's mapping, create a script at
|
||||
`$YOUR_PROJECT_ROOT/.would-reformat/custom-sniffer`. It should take one
|
||||
argument, the fully qualified path of the file whose type is to be sniffed.
|
||||
It should emit the type of file it thinks its argument is.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```shell-script
|
||||
#!/usr/bin/env bash
|
||||
|
||||
file="$1"
|
||||
|
||||
if [[ $file == *.pl ]] ; then
|
||||
# the default is that .pl corresponds to perl, but not here!
|
||||
echo -n "prolog"
|
||||
fi
|
||||
|
||||
if [[ $file == *.ts ]] ; then
|
||||
# qt translations, who knew
|
||||
echo -n "qt-translation"
|
||||
fi
|
||||
|
||||
# We're fine with the defaults for other types of files so we don't
|
||||
# print anything else.
|
||||
|
||||
exit 0
|
||||
```
|
||||
|
||||
(This file, possibly with updates, is also available
|
||||
[here](./examples/custom-sniffer).)
|
||||
|
||||
Now, if you run this script against a file that ends in `.pl` or `.ts`,
|
||||
`would-reformat` will not treat the file as perl or typescript as usual, but
|
||||
instead as prolog or a qt-translation file. But if you run this script
|
||||
against a file that ends in `.py` then it'll continue to be treated as python
|
||||
as usual.
|
||||
|
||||
You can perform arbitrarily sophisticated checks here. They're not limited to
|
||||
file names or extensions. You can take paths into account. You can can even
|
||||
take files' contents into account. But do keep in mind that this program
|
||||
will be run often. If it's slow you'll be frustrated by it.
|
||||
|
||||
Don't forget that this program can be written in something other than shell,
|
||||
in case that's easier for you or if performance is a serious concern. It
|
||||
doesn't actually need to be a "script".
|
||||
|
||||
Finally, keep in mind that if `would-reformat`'s defaults work for you, there
|
||||
is no need to have this file at all.
|
||||
|
||||
## Acceptable output
|
||||
|
||||
<!-- FIXME: I can't remember the syntax to include and escape ., _, and -.
|
||||
But those would be OK too, although starting with . or - is usually
|
||||
more trouble than it's worth. -->
|
||||
In general, you would do well to limit it to `/[0-9a-z]+/`. It must not
|
||||
include the `/` character. `would-reformat` doesn't care if you use
|
||||
uppercase, but some case-preserving filesystems make things difficult.
|
||||
|
||||
It must not output `custom-sniffer`. If there is a hitherto unknown
|
||||
programming language named "custom sniffer" you'll have to output something else.
|
||||
|
||||
## Return values
|
||||
|
||||
`would-reformat` expects `custom-sniffer` to return one of the following
|
||||
values:
|
||||
|
||||
- 0: success
|
||||
- 254: file can't be read due to permissions, etc ("etc" is as of
|
||||
2023-Q3 broad in scope; it could include trying and failing to read a file
|
||||
on a NFS mount)
|
||||
- 255: some sort of internal error
|
||||
|
||||
# Custom reformatter wrappers
|
||||
|
||||
Your custom wrappers live in `$YOUR_PROJECT_ROOT/.would-reformat`. Its name
|
||||
should be the file type as identified by the sniffer.
|
||||
|
||||
It takes one command line argument, the fully qualified path of the file to be
|
||||
checked or reformatted. It also receives input via three environment
|
||||
variables:
|
||||
|
||||
- `WOULD_REFORMAT` can be set to either `would_reformat` or `do_reformat`. If
|
||||
the former, it should run in non-destructive mode. If the latter, it should
|
||||
perform changes on file whose path was passed as the main argument.
|
||||
- `PROJECT_ROOT` has the value of `$YOUR_PROJECT_ROOT`.
|
||||
- `WF_ROOT` holds the path where `would-format` is checked out.
|
||||
|
||||
Often, these scripts won't need to check `$PROJECT_ROOT` or `$WF_ROOT`.
|
||||
`$WOULD_REFORMAT` is indepensable.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```shell-script
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
## This usually isn't necessary, but if you need to use wrflog this
|
||||
## is how you get it:
|
||||
# source "$WF_ROOT/_reformat-common.bash"
|
||||
|
||||
|
||||
if [[ "$WOULD_REFORMAT" = "would_reformat" ]] ; then
|
||||
set +e
|
||||
out=$(php $DIR/.././vendor/bin/pint --test "$1")
|
||||
retval="$?"
|
||||
set -e
|
||||
|
||||
# unfortunately, pint doesn't distinguish between files with
|
||||
# syntax errors and files that are merely misformatted
|
||||
|
||||
echo "$out"
|
||||
exit "$retval"
|
||||
fi
|
||||
|
||||
if [[ "$WOULD_REFORMAT" = "do_reformat" ]] ; then
|
||||
set +e
|
||||
out=$(php $DIR/.././vendor/bin/pint "$1")
|
||||
retval="$?"
|
||||
set -e
|
||||
|
||||
echo "$out"
|
||||
exit "$retval"
|
||||
fi
|
||||
|
||||
exit 255
|
||||
```
|
||||
|
||||
(This file, possibly with updates, is also available
|
||||
[here](./examples/php).)
|
||||
|
||||
As with `custom-sniffer`, a reformatter doesn't have to be written as a shell
|
||||
script. It just needs to be properly named and executable.
|
||||
|
||||
## Acceptable output
|
||||
|
||||
As output, this script should emit whatever the programs it calls emit.
|
||||
|
||||
## Return values
|
||||
|
||||
### In `would_format` mode
|
||||
|
||||
`would-format.sh` interprets return values to mean the following:
|
||||
|
||||
- 0: file wouldn't be reformatted
|
||||
- 1: file would be reformatted
|
||||
- 2: file has at least one syntax error
|
||||
- 252: Unexpected return value from the tool; that is, the value of `$?` is
|
||||
unexpected and thus unhandled
|
||||
- 253: Unexpected output from the tool; that is, the output emitted by the
|
||||
tool is unexpected and thus unhandled
|
||||
- 254: file can't be read due to permissions, etc ("etc" is as of
|
||||
2023-Q3 broad in scope; it could include trying and failing to read a file
|
||||
on an NFS mount)
|
||||
- 255: error internal to the script in question
|
||||
|
||||
(FIXME: Unsurprisingly, `gofmt` is the only tool I've tested so far that gets
|
||||
this right. That a file should be reformatted isn't an exceptional condition,
|
||||
so there's no good reason to signal failure here.
|
||||
|
||||
Even less unsurprisingly, Laravel pint gets it worse than all the others I
|
||||
checked; it doesn't distinguish misformatted files from files with actual
|
||||
syntax errors.
|
||||
|
||||
Anyway, `gofmt` is the obviously the model to follow. So we should
|
||||
probably drop `1`.)
|
||||
|
||||
|
||||
### in `do_format` mode
|
||||
|
||||
`do-reformat` expects a wrapper to return one of the following
|
||||
values:
|
||||
|
||||
- 0: file was successfully reformatted
|
||||
- 1: file was not successfully reformatted, presumably due to a syntax error
|
||||
- 254: file can't be rewritten due to permissions, etc ("etc" is as of
|
||||
2023-Q3 broad in scope; it could include trying and failing to read or write
|
||||
a file on an NFS mount)
|
||||
- 255: error internal to the script in question
|
||||
|
||||
# What goes into version control and what does not?
|
||||
|
||||
FIXME: Write this section
|
||||
|
||||
# What files can I modify?
|
||||
|
||||
You should not modify any of the files in `.would-reformat/bin` or the files
|
||||
that they link to. Everything else in `.would-reformat` is fair game.
|
||||
|
||||
Of course, `would-reformat` is FOSS. Within the limitations set by its
|
||||
license, you can do what you like with it. But if you want to make deeper
|
||||
changes, you're probably better off forking and going from there.
|
||||
|
||||
Reference in New Issue
Block a user