treefmt/docs/configure.md
Brian McGee ce14ee828f
feat: simplify pipeline model
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>
2024-05-26 16:52:04 +01:00

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 to command.
  • 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 being 0.

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