alloy fmt
UpdatedAnneal formats .aly and .alx files in place. The layout comes from the tokens and the [fmt] options, not from how the author laid the code out: the spacing between tokens, which bracket groups break, the quotes of a string, the parentheses of a call. Statements keep their lines, at most one blank line stays between them, and a long string or a long comment keeps its text. The program is the same afterwards; the token stream changes only where an option asks for a rewrite. A file the parser cannot read is skipped and keeps its text, and the run names it: the layout would move a statement into the block the recovery chose, not the one the author wrote.
alloy fmt the sources of the project alloy fmt src/ui.aly dir/ the paths given alloy fmt --check write nothing; fail when a file would change
A bracket group, the arguments of a call, a table, or an array, stays on one line when it fits in column_width, and breaks one element per line when it does not, or when a trailing comma in the source asks for it. An import { } list breaks on a trailing comma even when written on one line, and on every list with more than one name under expand_imports. A callback argument indents its body once: foo(function() opens one level, not two.
[fmt] recommended = true, which alloy init writes, applies the layout below. recommended = false makes the formatter preserving instead: no line is reflowed, quotes and numbers keep the form the author wrote, the parentheses of a call stay as they are, a blank line at a block's edge stays, no local becomes a const, and the indent of each file comes from that file. The [fmt] keys the project sets then apply over that, so recommended = false with quote_style = "force-double" rewrites the quotes and nothing else.
The options, with their defaults:
[fmt] recommended = true # false preserves what the file does column_width = 100 line_endings = "input" # unix, windows; input keeps the file's own indent_type = "spaces" # tabs indent_width = 2 quote_style = "force-single" # auto-prefer-double, auto-prefer-single, force-double, preserve leading_zero = "add" # `.5` becomes `0.5`; strip, preserve call_parentheses = "always" # no-single-string, no-single-table, none, input space_after_function_names = "never" # definitions, calls, always collapse_simple_statement = "never" # function-only, conditional-only, always block_newline_gaps = "never" # preserve keeps a blank line at a block's edge magic_trailing_comma = true # a trailing comma keeps a group expanded trailing_comma = true # an expanded group ends its last element with a comma space_inside_braces = true # { a } space_inside_parens = false # f(a) space_inside_brackets = false # t[k] space_inside_array = true # [ 1, 2 ]; Alloy's own align_struct_fields = false # the `:` of a struct's fields line up; Alloy's own expand_imports = false # an import list with more than one name breaks one per line; Alloy's own prefer_const = true # a local that nothing assigns again becomes a const; Alloy's own exclude = [] # paths to leave alone; `*` matches any run fix_naming = true # rename a name that breaks its `[lint.naming]` style [fmt.call_chains] style = "preserve" # method: break before each call past the first; full: before every call min_calls = 3 [fmt.sort_requires] enabled = false # sort the `import` lines at the top of the file grouping = "flat" # by-kind: aliases, then absolute, then relative paths [fmt.alx] attribute_quotes = "double" # single, preserve bracket_same_line = false # the `>` of a broken tag on the last attribute's line attribute_per_line = true # a broken tag puts every attribute on its own line; false packs them self_closing_space = true # <Frame /> text_wrap = "fill" # preserve keeps the author's line breaks in text blank_lines = true # a blank line between children stays
The names follow larvae and stylua where the option is theirs, so a config ports over. In an .alx file the code formats the same way and the markup prints from its tree: a tag that fits stays on one line, a tag that does not breaks its attributes and then its children, and text flows with the holes in it.
fix_naming renames a name that breaks its [lint.naming] style, the rename alloy flux --fix writes, while the naming_convention lint is on for the file. The lint warns by default, so a project gets the renames unless [lint.rules] naming = "allow" or [fmt] fix_naming = false. A name that another file reads keeps its name, and so does every name in a .d.aly, an .alx, and a .config.aly; in an .alx, alloy flux --fix renames, since it reads the lowered file. alloy doc naming-conventions explains the rules.
