From 5ffe5e04ddf27e46e6be71954b1398659e191ff5 Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Tue, 26 May 2026 13:50:21 +0200 Subject: [PATCH] doc: elaborate on what `associations` is good for MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I could not make sense of why there is three ways to match files. I had an AI look over the code and it came up with this explanation. Feel free to take smaller or larger pieces of this explanation if it’s too verbose to go in as a whole. --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/README.md b/README.md index 6f37df4..b2a4731 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,53 @@ General config: - `timeout` - Number of seconds to allow an executable format to occur before a timeout error occurs (default: `30`). - `cwd` - Recommend setting this to `${configDir}` to force it to use the cwd of the current config file. +Matching files to commands: + +A command can be matched to files in three ways: `exts`, `fileNames`, or +`associations`. They differ in what they match and — importantly — in whether +multiple commands can run on the same file. + +What each matches: + +- `exts` — by file extension, e.g. `["rs", "py"]`. +- `fileNames` — by full file name, useful for files without an extension, e.g. + `["Dockerfile", "BUILD"]`. +- `associations` — by glob pattern, e.g. `"**/*.{bazel,bzl}"`. Only **one** glob + per command is supported, though brace expansion within that glob is allowed. + +How many commands run per file: + +- With `exts` or `fileNames`, only the **first** matching command runs on a + given file. Subsequent commands that also match are skipped. +- With `associations`, **every** matching command runs, in the order they appear + in the `commands` array. + +So if you want to chain formatters on the same file, each chained command must use `associations` — and +you must also declare `associations` at the **plugin level** (the top-level +`"exec"` block), otherwise dprint won't route those files to this plugin at all: + +```jsonc +{ + "exec": { + "associations": ["**/*.{rs,swift,txt}"], + "commands": [ + { "command": "rustfmt", "associations": "**/*.rs" }, + { "command": "swift-format -", "associations": "**/*.swift" }, + { "command": "keep-sorted -", "associations": "**/*" }, + ], + }, +} +``` + +`associations` can do the work of `exts` and `fileNames`; the latter two exist +as a convenience for the common case where you don't need glob matching or +command chaining. + +Mixing styles across commands is allowed, but if you want chaining for a given +file type, use `associations` on every command that should participate — an +`exts`/`fileNames`-only command that matches first will short-circuit the loop +and prevent later commands from running on that file. + Command config: - `command` - Command to execute.