Skip to Content
DocumentationFormatting

Formatting

nio format rewrites Nio source in one canonical style. It has no options. Every project uses the same style. As a result, a diff shows only changes to the program.

nio format . # rewrite every .nio file under here nio format src/main.nio # or just these files nio format -l . # name the files that are not formatted, # change nothing, and exit 1 if any

A directory means every .nio file under it, except in .git and node_modules. -l is for a continuous-integration check. It writes nothing, prints the paths that would change, and exits 1 when the list is not empty.

If a file has a syntax error, nio format reports it and does not change the file.

What it decides, and what it leaves alone

The formatter sets the indent (four spaces for each level), the spaces around each token, the number of blank lines between two statements, and the column of a trailing comment. Where the file has one or more blank lines between two statements, the formatter writes one.

It does not change where a construct breaks over lines. The formatter keeps the line breaks of the file:

// Both of these are formatted. Neither becomes the other. if (ready) { start(); } if (ready) { start(); }

The same rule applies to an argument list, a literal, an operator chain and an else chain. If the file has it on one line, it stays on one line. If the file breaks it over lines, it stays broken at the same places, with a new indent. There is no line-length limit.

A construct that is broken over lines gets two more changes. When the closing bracket of a literal is on its own line, it stays there, and the formatter adds a comma after the last element. Then, when an element is added, only one line changes:

byte[] const HEADER = [ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, ];

An operator that starts a line goes at the start of that line, under the operand that it continues:

return Error("pins is empty, so no peer can match it; leave it null to " + "verify without pinning", ErrorCode.MISCONFIGURED);

Comments stay in their positions. A comment above a declaration stays above it, and a comment after code stays on that line. When neighbouring lines have trailing comments, the formatter aligns them in one column, set by the longest line:

type Unit { String path; // resolved file path String dir; // directory imports inside this file resolve against String qual; // unique symbol prefix ("" for the entry module) }

What it will not change

The formatter changes only whitespace. It does not change any token.

The formatter writes grouping parentheses where the file has them. It does not calculate them from operator precedence. As a result, (a && b) || c keeps its parentheses, although they are not necessary. A string keeps its delimiter. A backtick string that holds a program does not change to a " string with \n escapes. A number keeps its spelling, for example 0x1f. A union stays a union.

The formatter adds only punctuation that the grammar lets a file omit: the ; after a statement that ends with a brace, the ; after the last field of a body, and the , after the last element of a list that is broken over lines. The standard style always writes these.

Formatting twice

Formatting a file that is already formatted changes nothing.

Last updated on