treefmt/README.md

193 lines
5.8 KiB
Markdown
Raw Normal View History

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>
[![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)
**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
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
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
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
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>...]
```
* `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
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
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`.
* `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
composed with the `options` attribute during invocation. The first argument
is the name of the executable to run.
* `options`: A list of extra arguments to add to the command. This is typically
project-specific arguments.
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.
## 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
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 >
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
# 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\`.
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-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
`XDG_DATA_DIRS`.
Example:
2021-02-15 23:22:03 +03:00
In the `treefmt.toml` file of the project:
```toml
[formatters.ormolu]
options = [
"--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
contains:
```toml
command = ["ormolu", "--mode", "inplace"]
files = ["*.hs"]
options = []
```
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
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"]
options = [
"--ghc-opt", "-XBangPatterns",
"--check-idempotence"
]
```
Note how the empty ormolu `options` got overwritten by the project `options`.
## 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.
If you want to discuss, we have a public Matrix channel:
[#treefmt:numtide.com](https://matrix.to/#/#treefmt:numtide.com)
## License
MIT - (c) 2020 NumTide Ltd.