2021-02-10 11:51:58 +03:00
< h1 align = "center" >
< br >
2021-02-10 11:53:14 +03:00
< img src = "assets/logo.svg" alt = "logo" width = "200" >
2021-02-10 11:51:58 +03:00
< br >
2021-02-15 23:55:18 +03:00
treefmt - one CLI to format the code tree
2021-02-10 11:51:58 +03:00
< br >
< br >
< / h1 >
2021-01-18 18:03:58 +03:00
2021-02-17 21:17:02 +03:00
[![Support room on Matrix ](https://img.shields.io/matrix/treefmt:numtide.com.svg?label=%23treefmt%3Anumtide.com&logo=matrix&server_fqdn=matrix.numtide.com )](https://matrix.to/#/#treefmt:numtide.com)
2021-01-18 18:03:58 +03:00
**Status: experimental** -- not all the features described here are working
yet.
Every project has different languages and code formatters, with possibly
different configurations. When jumping between project it always takes a bit
of time to get accustomed to them and update our editor configuration.
This project tries to solve that by proposing a unified CLI interface: type
2021-02-15 23:22:03 +03:00
`treefmt` to format all of the files in a given project, using the project's
2021-01-18 18:03:58 +03:00
configuration.
## Design decisions
We assume that project code is checked into source control. Therefor, the
default should be to write formatter changes back in place. Options like
`--dry-run` are not needed, we rely on the source control to revert or check
for code changes.
2021-02-15 23:22:03 +03:00
`treefmt` is responsible for traversing the file-system and mapping files to
2021-01-18 18:03:58 +03:00
specific code formatters.
2021-02-15 23:22:03 +03:00
We want *all* of the project files to be formatted. `treefmt` should hint if
2021-01-18 18:03:58 +03:00
any files in the project are not covered.
2021-02-15 23:22:03 +03:00
Only *one* formatter per file. `treefmt` should enforces that only one tool is
2021-01-18 18:03:58 +03:00
executed per file. Guaranteeing two tools to product idempotent outputs is
quite difficult.
## Usage
```
2021-02-15 23:22:03 +03:00
treefmt [options] [< file > ...]
2021-01-18 18:03:58 +03:00
```
* `file` : path to files to format. If no files are passed, format all of the
files from the current folder and down.
### Options
* `--stdin` : If this option is passed, only a single `file` must be passed to
the command-line. Instead of reading the file, it will read the content from
stdin, and write the formatted result to stdout. The `file` is only used to
select the right formatter.
2021-02-15 23:22:03 +03:00
* `--init` : Creates a templated `treefmt.toml` in the current directory. In the
2021-01-18 18:03:58 +03:00
future we want to add some heuristic for detecting the languages available
in the project and make some suggestions for it.
* `--show-config` : Prints out the merged configuration for the current folder.
* `--help` : Shows this help.
## Configuration format
2021-02-15 23:22:03 +03:00
`treefmt` depends on the `treefmt.toml` to map file extensions to actual code
2021-01-18 18:03:58 +03:00
formatters. That file is searched for recursively from the current folder and
up.
TODO: describe the actual format here
### `[formatters.<name>]`
This section describes the integration between a single formatter and
2021-02-15 23:22:03 +03:00
`treefmt` .
2021-01-18 18:03:58 +03:00
* `files` : A list of glob patterns used to select files. Usually this would be
something like `[ "*.sh" ]` to select all the shell scripts. Sometimes,
full filenames can be passed. Eg: `[ "Makefile" ]` .
* `command` : A list of arguments to execute the formatter. This will be
2021-02-03 13:19:11 +03:00
composed with the `options` attribute during invocation. The first argument
2021-01-18 18:03:58 +03:00
is the name of the executable to run.
2021-02-03 13:19:11 +03:00
* `options` : A list of extra arguments to add to the command. This is typically
2021-01-18 18:03:58 +03:00
project-specific arguments.
2021-02-02 13:25:32 +03:00
NOTE: Formatters SHOULD adhere to the [formatter
spec](docs/formatter_spec.md). If they don't, the best is to create a wrapper
script that transforms the usage to match that spec.
2021-01-18 18:03:58 +03:00
## Use cases
### CLI usage
2021-02-15 23:22:03 +03:00
As a developer, I want to run `treefmt` in any folder and it would
2021-01-18 18:03:58 +03:00
automatically format all of the code, configured for the project. I don't want
to remember what tool to use, or their magic incantation.
### Editor integration
Editors often want to be able to format a file, before it gets written to disk.
Ideally, the editor would pipe the code in, pass the filename, and get the
2021-02-15 23:22:03 +03:00
formatted code out. Eg: `cat ./my_file.sh | treefmt --stdin my_file.sh >
2021-01-18 18:03:58 +03:00
formatted_file.sh`
### CI integration
We can assume that code lives in a source control.
For example a Git integration would look like this:
```sh
#!/usr/bin/env bash
set -euo pipefail
# Format all of the code
2021-02-15 23:22:03 +03:00
treefmt
2021-01-18 18:03:58 +03:00
# Check that there are no changes in the code
if [[ -n "$(git status --porcelain -unormal)" ]]; then
2021-02-15 23:22:03 +03:00
echo "Some code needs formatting! Please run \`treefmt\`.
2021-01-18 18:03:58 +03:00
git status -unormal
exit 1
fi
echo "OK"
```
## Interfaces
### Formatter integration
Formatters can ship with a config file, that describes and simplifies the
2021-02-15 23:22:03 +03:00
integration between the formatter and `treefmt` .
2021-01-18 18:03:58 +03:00
2021-02-15 23:22:03 +03:00
Whenever a new formatter is described in the project's `treefmt.toml` config
file, `treefmt` will look for that formatter config in
`$dir/share/treefmt.d/<formatter>.toml` where `$dir` is each folder in
2021-01-18 18:03:58 +03:00
`XDG_DATA_DIRS` .
Example:
2021-02-15 23:22:03 +03:00
In the `treefmt.toml` file of the project:
2021-01-18 18:03:58 +03:00
```toml
[formatters.ormolu]
2021-02-03 13:19:11 +03:00
options = [
2021-01-18 18:03:58 +03:00
"--ghc-opt", "-XBangPatterns",
"--ghc-opt", "-XPatternSynonyms",
]
```
2021-02-15 23:22:03 +03:00
Now assuming that ormolu ships with `$out/share/treefmt.d/ormolu.toml` that
2021-01-18 18:03:58 +03:00
contains:
```toml
command = ["ormolu", "--mode", "inplace"]
files = ["*.hs"]
2021-02-03 13:19:11 +03:00
options = []
2021-01-18 18:03:58 +03:00
```
2021-02-15 23:22:03 +03:00
The project will first load `treefmt.toml` , take note of the ormolu formatter,
then load the `ormolu.toml` file, and merge back the `treefmt.toml` config for
2021-01-18 18:03:58 +03:00
that section back on top. The end-result would be the same as if the user has
this in their config:
```toml
[formatters.ormolu]
command = ["ormolu", "--mode", "inplace"]
files = ["*.hs"]
2021-02-03 13:19:11 +03:00
options = [
2021-01-18 18:03:58 +03:00
"--ghc-opt", "-XBangPatterns",
"--check-idempotence"
]
```
2021-02-03 13:19:11 +03:00
Note how the empty ormolu `options` got overwritten by the project `options` .
2021-01-18 18:03:58 +03:00
## Related projects
* [EditorConfig ](https://editorconfig.org/ ): unifies file indentations
configuration on a per-project basis.
## Contributing
All contributions are welcome! We try to keep the project simple and focused
so not everything will be accepted. Please open an issue to discuss before
working on a big item.
2021-02-17 21:17:02 +03:00
If you want to discuss, we have a public Matrix channel:
[#treefmt:numtide.com ](https://matrix.to/#/#treefmt:numtide.com )
2021-01-18 18:03:58 +03:00
## License
MIT - (c) 2020 NumTide Ltd.