Skip to content

Formatter

Zeus ships with a built-in code formatter. zeus fmt rewrites a source file into a single, canonical style — so you never have to think about indentation, spacing, or where the braces go.

It’s inspired by Prettier: it parses your code, throws away the original whitespace, and re-prints it, fitting each construct to an 80-column width.

Usage

Format a file in place:

Terminal window
zeus fmt app.zs

That’s it. The file is rewritten with the canonical style. If the file is already formatted, nothing is written.

What it does

Consistent Indentation

4-space indentation, everywhere, automatically.

Canonical Spacing

Spaces around operators, after commas and keywords, normalized.

Smart Line Breaking

Long argument lists wrap one-per-line; short ones stay inline.

Comments Preserved

Line and block comments are kept in place.

Example

Given this messy input:

// Point in 2D space
class Point{
public x:i32; // x coordinate
public y:i32; // y coordinate
constructor(x:i32,y:i32){this.x=x;this.y=y;}
}
function main():i32{
let p:Point=new Point(3,4); // make a point
// verify
if(p.x==3){return 0;}
return 1;
}

Running zeus fmt produces:

// Point in 2D space
class Point {
public x: i32 // x coordinate
public y: i32 // y coordinate
constructor(x: i32, y: i32) {
this.x = x
this.y = y
}
}
function main(): i32 {
let p: Point = new Point(3, 4) // make a point
// verify
if (p.x == 3) {
return 0
}
return 1
}

Width-based line breaking

When a call is short, it stays on one line. When it would exceed the print width, the formatter breaks it — one argument per line, with a trailing comma:

function main(): i32 {
let result: i32 = computeSomething(
argumentNumberOne,
argumentNumberTwo,
argumentNumberThree,
argumentFour,
)
return result
}

Comments

Both comment styles are preserved:

// a line comment
let x: i32 = 1 // a trailing comment
/* a block comment */
let y: i32 = 2

JSDoc-style block comments are re-indented with their * lines aligned (other multi-line block comments — tables, ASCII art — are kept exactly as written):

/*
* Computes the answer.
*/
function answer(): i32 {
return 42
}

Blank lines you write between statements are preserved (collapsed to at most one).

Style

The formatter ships with sensible defaults and a small set of flags to override them:

SettingDefaultFlag
Indentation4 spaces--indent-width
Tabsoff--use-tabs
Print width80 columns--print-width
Semicolonsoff--semicolons
Control-flowAlways braced

By default statement terminators are omitted — Zeus’s automatic semicolon insertion makes them redundant. Opt back in with --semicolons=true:

Terminal window
# semicolon-free (default)
zeus fmt app.zs
# keep semicolons, tabs, and a wider ruler
zeus fmt app.zs --semicolons=true --use-tabs --print-width=100

Semicolons

Zeus inserts a semicolon at a line break after any token that can end a statement — a value (identifier, number, ), ], …) or a type keyword (i32, void, …). So the formatter drops the ; from statements, class fields, and interface members, and only keeps it where automatic insertion can’t help: a bare return, break, or continue, which end in a keyword.

Editor integration

The same formatter is built into the language server, so Format Document and format-on-save work in any LSP client. The VS Code extension turns on format-on-save for .zs files by default — no extra setup. The zeus fmt command is there for scripts, pre-commit hooks, and CI.

Current limitations

  • Comments in unusual positions (for example, in the middle of an expression) are never dropped, but may move to an adjacent line.
  • Long binary expressions and ternaries are not yet broken across lines.
  • new allocations of function-type arrays (new ((x: i32) => i32)[]) are left as-is.

See Also