Command line¶
rainbow-fmt format [-u] PATH... rewrite files in place
rainbow-fmt check [-u] PATH... report files that would change
rainbow-fmt diff [-u] PATH... print the changes as unified diffs
rainbow-fmt format - --stdin-filepath PATH read stdin, write stdout
rainbow-fmt options FILE show the options that apply to FILE
format, check and diff accept --set KEY=VALUE (repeatable), which
sets an option for every file, above configuration files
(configuration.md), --no-verify
(Verification), --no-cache (Cache) and
-j N / --jobs N (Parallel jobs).
Paths¶
- A file is formatted if its language is known (today: JSON and JSONC,
*.jsonand*.jsonc; CSS,*.css—css.md; Python,*.py—python.md; JavaScript,*.js,*.mjs,*.cjs,*.jsx—javascript.md; TypeScript,*.ts,*.mts,*.cts,*.tsx—typescript.md). - A directory is searched recursively for files of known languages.
Hidden directories (names starting with
.),node_modulesand the[files] excludepatterns of the nearest configuration are skipped; so are files of unknown languages, silently, and TypeScript declaration files (*.d.ts,*.d.mts,*.d.cts), which are formatted only when named. - A file named more than once (directly or through a directory) is formatted once.
-reads standard input and, forformat, writes the result to standard output.--stdin-filepathis required: its suffix selects the language and its directory the configuration.-cannot be combined with other paths.
Each file is formatted with its own nearest configuration
(configuration.md).
Output¶
| Command | Standard output |
|---|---|
format |
reformatted PATH for each file it rewrote |
check |
would reformat PATH for each file that would change |
diff |
a unified diff (--- PATH / +++ PATH (formatted)) per file |
Files that are already formatted are not written, and produce no output. Warnings and errors go to standard error.
Unknown file types¶
A file named explicitly whose language is unknown is skipped with a warning:
warning: notes.txt: unknown file type, skipped
Turn the warning off with --ignore-unknown (-u), or in the
configuration that applies to the file:
[files]
ignore_unknown = true
With -, input of an unknown type is copied to standard output unchanged.
Files that cannot be formatted¶
A file with a syntax error, an invalid inline directive
(configuration.md), that is not
valid UTF-8, that cannot be read, or that is nested too deeply (JSON: tens
of thousands of levels) is left unchanged and reported; the other files are
still formatted:
error: bad.json:1:5: syntax error, not formatted
error: app.py:2:1: unknown directive 'rainbow: of', not formatted
error: latin1.json: not valid UTF-8, not formatted
error: locked.json: Permission denied, not formatted
error: deep.json: nested too deeply, not formatted
The same goes for a bug: an unexpected exception while formatting a file is reported as an internal error for that file, and the run continues:
error: app.js: internal error (KeyError: 'x'), not formatted
Please report internal errors. Setting the environment variable
RAINBOW_FMT_TRACEBACK (to any value) prints the traceback after the
message.
The line and column of a syntax error are an estimate: the parser marks the region it could not read, and rainbow-fmt reports the stray text in it, or the point after the text that did parse.
Verification¶
Before a file is written, reported by check or diffed, the formatted
result is verified (rainbow_fmt.verify):
- it parses without syntax errors;
- its syntax tree equals the input's, apart from whitespace and comments: the same nodes in the same shape, and every token with the same text;
- it has the same comments, with the same text, in the same order (a comment may move past a comma);
- formatting it again changes nothing.
A file that fails is left unchanged and reported; the other files are still formatted, and the exit code is 1:
error: data.json:1:7: formatting would change the meaning, not formatted
error: data.json:1:5: formatting would change the comments, not formatted
error: data.json: formatting would produce invalid syntax, not formatted
error: data.json: formatting is not stable (a second pass changes the result), not formatted
The line and column point at the first difference in the input. A failure
means a bug in rainbow-fmt or in a [[rule]] override
(extending.md).
Verification roughly quadruples the time per file (0.35 s without and 1.5 s
with it for a 139 KiB JSON file). Skip it with --no-verify, or in the
configuration that applies to the file:
[files]
verify = false
Cache¶
A run records the files it found formatted (and format the files it
wrote); the next run skips them: they are neither formatted nor verified,
and count as unchanged. A file is skipped only if all of these match the
recorded run: its bytes, its options as resolved for it (so any change to a
configuration file, .editorconfig, override or --set that affects it
counts), its [[rule]] overrides, whether it is verified, and the versions
of rainbow-fmt and its grammars. Files with errors, files that would change
and standard input are not recorded.
The cache is a file in the user cache directory:
| Platform | Directory |
|---|---|
| Linux and others | $XDG_CACHE_HOME/rainbow-fmt (default ~/.cache/rainbow-fmt) |
| macOS | ~/Library/Caches/rainbow-fmt |
| Windows | %LOCALAPPDATA%\rainbow-fmt\Cache |
RAINBOW_FMT_CACHE_DIR overrides the directory (for CI caches). Deleting
the directory is always safe. A cache that cannot be read or written is
ignored, never an error. Turn the cache off with --no-cache or, for the
files a configuration applies to:
[files]
cache = false
Parallel jobs¶
From 8 files on, files are formatted by worker processes, one per CPU by
default. -j N / --jobs N sets the number (1: no workers), as does
[files] jobs in the configuration that applies to the working directory
(the command line wins). Output, its order, the messages, the files
written and the exit code are the same whatever the number of jobs.
Exit codes¶
| Code | Meaning |
|---|---|
| 0 | Every file is formatted (or was skipped) |
| 1 | check/diff: some file would change; any command: some file could not be formatted or failed verification |
| 2 | Usage or configuration error (missing path, invalid option or [[rule]]); no file was written |
Files are formatted in memory first and written only when no usage or configuration error occurred.
rainbow-fmt options¶
$ rainbow-fmt options --set core.indent_size=2 legacy/new.json
# legacy/new.json (json)
core.max_width = 100 # rainbow.toml:2:13
core.indent_style = "space" # default
core.indent_size = 2 # --set core.indent_size
core.tab_width = 4 # default
core.line_ending = "lf" # default
language.json.trailing_comma = "never" # default
language.json.object_wrap = "fit" # rainbow.toml:6:29 override[0]
language.json.align_values = false # default
rule.pair = "source()" # rainbow.toml:8:1 rule[0]
FILE need not exist; its suffix selects the language and its directory the
configuration. Each line gives the value and its origin: default, a
preset (rainbow:balanced), an .editorconfig position and section
(.editorconfig:4:15 [*.json]), a configuration position (with the
override[N] or rule[N] it belongs to), or --set. Errors exit 2 as for the other commands.
rainbow-fmt explain¶
The same information by source: which configuration sources apply to
FILE, in resolution order, and the values each one decides, followed by
the inline directives found in the file:
$ rainbow-fmt explain legacy/new.json
# legacy/new.json (json)
defaults
core.indent_style = "space"
…
preset rainbow:balanced
core.line_ending = "lf"
shared.trailing_comma = "never"
rainbow.toml
core.max_width = 100
rainbow.toml override[0]
language.json.object_wrap = "fit"
directives
3: // rainbow: off
9: // rainbow: on
A source that decides nothing for the file (every value it sets is
overridden, or it does not match) is not listed; rainbow-fmt options
shows where every single value comes from. Directives that are not valid
are listed with the error ((invalid: unknown directive 'rainbow: nope')).
rainbow-fmt infer¶
$ rainbow-fmt infer src tests
# Inferred by rainbow-fmt infer from 61 files (javascript: 11, python: 50).
[core]
indent_size = 2
[language.javascript]
semicolons = "always" # mixed: "always" in 9 files, "as_needed" in 2 files
infer reads the files under the given paths (hidden directories and
node_modules skipped; up to --limit N files per language, the largest
first, 50 by default), formats them under each candidate value of each
option, and picks, option by option, the value that changes the fewest
lines. The result is the rainbow.toml that reproduces the project's
style; --write saves it in the working directory (never over an
existing one). Values equal to the defaults are left out.
"preserve"is never inferred: it reproduces anything, so it says nothing about the style. Use it by hand for an option the project does not care about.- An option whose files disagree is mixed: it is set to the value that wins in most files, and the counts are in a comment. That is the list of things to decide.
- Line endings are counted, not formatted:
crlfwhen at least half the files use it. - Every candidate means formatting every sampled file, so a large
project takes a minute or two;
--limittrades accuracy for time.