For each path we determine the list of formatters that are interested in formatting it. From there, we sort the list of formatters first by priority (lower value, higher priority) and then by name (lexicographically). With this information we create a batch key which is based on the unique sequence of formatters. When enough paths with the same sequence is ready we apply them in order to each formatter. By default, with no special configuration, this model guarantees that a given path will only be processed by one formatter at a time. If a user wishes to influence the order in which formatters are applied they can use the priority field. Signed-off-by: Brian McGee <brian@bmcgee.ie>
4.8 KiB
outline |
---|
deep |
Configure Treefmt
The treefmt.toml
configuration file consists of a mixture of global options and formatter sections:
excludes = ["*.md", "*.dat"]
[formatter.elm]
command = "elm-format"
options = ["--yes"]
includes = ["*.elm"]
[formatter.go]
command = "gofmt"
options = ["-w"]
includes = ["*.go"]
[formatter.python]
command = "black"
includes = ["*.py"]
# use the priority field to control the order of execution
# run shellcheck first
[formatter.shellcheck]
command = "shellcheck"
includes = ["*.sh"]
priority = 0 # default is 0, but we set it here for clarity
# shfmt second
[formatter.shfmt]
command = "shfmt"
options = ["-s", "-w"]
includes = ["*.sh"]
priority = 1
Global Options
excludes
- an optional list of glob patters used to exclude certain files from all formatters.
Formatter Options
command
- the command to invoke when applying the formatter.options
- an optional list of args to be passed tocommand
.includes
- a list of glob patterns used to determine whether the formatter should be applied against a given path.excludes
- an optional list of glob patterns used to exclude certain files from this formatter.priority
- influences the order of execution. Greater precedence is given to lower numbers, with the default being0
.
Same file, multiple formatters?
For each file, treefmt
determines a list of formatters based on the configured includes
/ excludes
rules. This list is
then sorted, first by priority (lower the value, higher the precedence) and secondly by formatter name (lexicographically).
The resultant sequence of formatters is used to create a batch key, and similarly matched files get added to that batch until it is full, at which point the files are passed to each formatter in turn.
This means that treefmt
guarantees only one formatter will be operating on a given file at any point in time.
Another consequence is that formatting is deterministic for a given file and a given treefmt
configuration.
By setting the priority fields appropriately, you can control the order in which those formatters are applied for any files they both happen to match on.
Supported Formatters
Here is a list of all the formatters we tested. Feel free to send a PR to add other ones!
prettier
An opinionated code formatter that supports many languages.
command = "prettier"
options = ["--write"]
includes = [
"*.css",
"*.html",
"*.js",
"*.json",
"*.jsx",
"*.md",
"*.mdx",
"*.scss",
"*.ts",
"*.yaml",
]
Black
A python formatter.
command = "black"
includes = ["*.py"]
clang-format
A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf/C# code.
command = "clang-format"
options = [ "-i" ]
includes = [ "*.c", "*.cpp", "*.cc", "*.h", "*.hpp" ]
Note: This example focuses on C/C++ but can be modified to use with other languages.
Elm
command = "elm-format"
options = ["--yes"]
includes = ["*.elm"]
Go
command = "gofmt"
options = ["-w"]
includes = ["*.go"]
Ormolu
Haskell formatter. Make sure to use ormolu 0.1.4.0+ as older versions don't adhere to the spec.
command = "ormolu"
options = [
"--ghc-opt", "-XBangPatterns",
"--ghc-opt", "-XPatternSynonyms",
"--ghc-opt", "-XTypeApplications",
"--mode", "inplace",
"--check-idempotence",
]
includes = ["*.hs"]
stylish-haskell
Another Haskell formatter.
command = "stylish-haskell"
options = [ "--inplace" ]
includes = [ "*.hs" ]
nixpkgs-fmt
Nix code formatter.
command = "nixpkgs-fmt"
includes = ["*.nix"]
rustfmt
command = "rustfmt"
options = ["--edition", "2018"]
includes = ["*.rs"]
rufo
Rufo is an opinionated ruby formatter. By default it exits with status 3 on
file change so we have to pass the -x
option.
command = "rufo"
options = ["-x"]
includes = ["*.rb"]
cargo fmt
cargo fmt
is not supported as it doesn't follow the spec. It doesn't allow
to pass arbitrary files to be formatted, which treefmt relies on. Use rustfmt
instead (which is what cargo fmt
uses under the hood).
shfmt
A shell code formatter.
command = "shfmt"
options = [
"-i",
"2", # indent 2
"-s", # simplify the code
"-w", # write back to the file
]
includes = ["*.sh"]
terraform
terraform fmt only supports formatting one file at the time. See https://github.com/hashicorp/terraform/pull/28191