Documentation

whitehall format

One canonical style. No config, no options to argue about.

Usage

whitehall format [target] [options]

target defaults to . and can also be a single .wh file:

whitehall format
whitehall format src/lib/components/Header.wh

Options

FlagWhat it does
--checkExit 1 if any file needs formatting. Writes nothing. For CI
--diffShow what would change, without writing it
# GitHub Actions
- name: Check formatting
  run: whitehall format --check
fmt is an alias for format, cargo's own shorthand.

What it will not touch

Whitespace is the formatter's job. Everything else is yours, and it keeps it:

  • Comments, wherever they are — attached to the declaration after them
  • Declaration order — a data class written above the store that uses it stays above it
  • Annotations as written — @store(persist) comes back as @store(persist)

It also refuses to write a file it cannot read back: the output is parsed again before being written, and a mismatch is an error naming the file, with nothing written — never a formatted file that no longer builds.

Indentation and line width

2 spaces, always. 100 characters, wrapped past that:

<Column>
  <Text>Indented with 2 spaces</Text>
  <Row>
    <Text>Nested: 4 spaces</Text>
  </Row>
</Column>
<TextField
  bind:value={email}
  label="Email Address"
  helperText="We'll never share your email"
/>

Components

Single-line when props fit, one prop per line when they do not, and children always on their own line:

<Button onClick={handleClick}>Click</Button>

<Button
  color="primary"
  fillMaxWidth
  onClick={handleSave}
>
  Save Changes
</Button>

<Spacer h={16} />

Prop order

Props are reordered by category:

  1. Binding (bind:value, bind:checked)
  2. Transitions (in:, out:, transition:, animate:)
  3. Core (label, value, src, icon, title, name, id, placeholder)
  4. Styling (color, fontSize, fontWeight)
  5. Spacing (p, gap, w, h)
  6. Layout (fillMaxWidth, alignment and arrangement props)
  7. Event handlers (any on* prop)
  8. Everything else, alphabetically
// Before
<TextField onClick={handler} p={8} label="Name" bind:value={text} />

// After
<TextField bind:value={text} label="Name" p={8} onClick={handler} />

Control flow

@if (isLoading) {
  <CircularProgressIndicator />
} else {
  <LazyColumn>
    @for (item in items) {
      <Text>{item}</Text>
    }
  </LazyColumn>
}

Kotlin code

Standard Kotlin formatting applies to imports, functions, and data classes — one that fits stays on one line, one that does not wraps with a trailing comma:

import $lib.models.Post
import $lib.models.User
import $lib.stores.UserStore

data class User(val id: String, val name: String)

data class DetailedUser(
  val id: String,
  val name: String,
  val email: String,
  val avatarUrl: String?,
)

Double quotes for strings, triple quotes preserved for multi-line ones:

val message = "Welcome"

val json = """{
    "name": "Alice"
}"""

Ignored files

.gitignore is respected automatically. build/, node_modules/ and generated .kt files are always skipped.

Editor integration

The VS Code extension spawns whitehall lsp, which formats the buffer in-process on save through textDocument/formatting — the same formatter this command runs, over LSP instead of a file write. A file that does not parse is left as it is.

SettingDefaultMeaning
whitehall.path"whitehall"Path to the binary the extension runs lsp on

Format on save is VS Code's own setting, on by default for .wh files. To turn it off:

// settings.json
{
  "[whitehall]": {
    "editor.formatOnSave": false
  }
}

Pre-commit hook

repos:
  - repo: local
    hooks:
      - id: whitehall-format
        name: Whitehall Format
        entry: whitehall format --check
        language: system
        files: \.wh$

Philosophy

No configuration file, no rule to turn off. One style removes the debate rather than settling it in the project's favor.

Format on save, and never review whitespace in a diff again.

Troubleshooting

A file that keeps coming back the way it was is not unformatted — the formatter follows strict rules, and output that looks wrong is usually the canonical style winning over a habit. --check writes nothing; plain whitehall format applies changes.

See Also