Code Formatting in Turmeric

Turmeric ships a built-in formatter that produces canonical, consistent style for .tur source files. It is a pure pretty-printer: it reads source text, walks the Form tree produced by the existing reader, and re-emits formatted output. It never touches the elaborator or code generator, so it works on any syntactically valid file regardless of type errors.

CLI usage

# Format a file and print to stdout
tur format myfile.tur

# Format stdin and print to stdout
tur format < myfile.tur

# Overwrite a file in-place
tur format myfile.tur > myfile.tur.tmp && mv myfile.tur.tmp myfile.tur

# Check whether a file is already formatted (exits 1 if not)
tur format --check myfile.tur

The --check flag is useful in CI:

# Fail the build if any .tur file is not canonically formatted
find stdlib -name '*.tur' | xargs -n1 tur format --check

Web REPL

The Try Turmeric web interface has a Format button in the editor toolbar (between Clear and Share). It calls turi_wasm_format() from the WASM module and replaces the editor contents with the formatted output.

Keyboard shortcut: Alt+Shift+F (or Option+Shift+F on macOS).

Formatting rules

Indentation

Two-space indentation by default. A form is emitted on one line if it fits within the configured line width (default 80 columns); otherwise it is broken into a block layout.

Special forms

These forms have well-known argument roles and use custom layouts:

Form Layout
defn (defn name params :ret\n body...)
defmacro same as defn
fn (fn params\n body...)
let (let [bindings...]\n body...) -- each binding pair on its own line
if (if test\n then\n else)
when / unless (when test\n body...)
do (do\n form...)
case (case expr\n pat result...) -- each arm on its own line
loop (loop [bindings]\n body...)
handle (handle expr\n arm...)
defclass (defclass Name [params]\n method...)
definstance (definstance Name Class Type\n impl...)
defeffect (defeffect Name [] :ret)

Regular function calls

Vectors, maps, sets

Comments

Type annotations

:keyword type annotations stay on the same line as the expression they annotate and are never line-wrapped independently.

Quote / quasiquote sugar

Sugar forms are preserved: 'x, `x, ,x, ,@x stay as-is rather than being expanded to their (quote ...) equivalents.

Inline C blocks

```c ... ``` blocks are emitted verbatim; the formatter does not reformat embedded C.

Example

Before formatting:

(defn add [x :int y :int] :int (+ x y))
(defn factorial [n :int] :int (if (<= n 1) 1 (* n (factorial (- n 1)))))

After tur format:

(defn add [x :int y :int] :int
  (+ x y))

(defn factorial [n :int] :int
  (if (<= n 1)
    1
    (* n (factorial (- n 1)))))

See also