Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Formatter Guide

What formatting guarantees

The formatter is idempotent — running it twice produces the same result as running it once (format(format(x)) == format(x)). It is strictly behavior-preserving: it never reorders statements, never changes which lines are continuations of a prior statement, and never alters program meaning. It only ever changes whitespace and, opt-in, keyword casing. If a script is structurally broken (see the Editor Guide’s diagnostic list), the formatter still does its best on the parts it understands rather than refusing outright — but a diagnosed/unmatched block’s own children are left with their original indentation rather than guessed at.

Every field below is documented in full in the Configuration Reference — this page focuses on what changes, with real examples.

Casing

The four independent casing fields — casing_control_words, casing_pair_keywords, casing_data_references, and casing_function_calls — only ever touch keyword names — never a value, and never a category they aren’t scoped to. This example makes several boundaries visible at once, with casing_control_words = "upper":

-run pgm=matrix
+RUN pgm=matrix
     mati=base.mat,mo=out.mat
-endrun
+ENDRUN

run/endrun (control words) are uppercased — but pgm (a pair-keyword name, casing_pair_keywords’s own scope, left unset here), matrix (a value, never touched), and mati/mo (data-reference tokens, casing_data_references’s own scope, also left unset here) all stay exactly as written. Each field only ever affects its own category — set the one(s) you want independently.

Function-call casing

casing_function_calls normalizes a recognized Cube Voyager built-in function name’s casing, but only where it’s immediately followed by ( with no intervening whitespace — the unambiguous call position, since Voyager has no user-definable functions:

-RouteName = replacestr(RouteName,'-','',0)
+RouteName = REPLACESTR(RouteName,'-','',0)

The recognized list (138 names) spans the general Control Language core (ABS, TRIM, REPLACESTR, ROUND, …), Highway/Matrix-program functions (ROWSUM, PATHTRACE, …), Public Transport skim functions (TIMEA, BRDINGS, GCOST, …), the CONVERGE-phase iteration-statistics family (GAPCHANGE, RGAPMIN, …), and CUBE Cluster utility functions — the same list the VS Code extension’s syntax highlighting uses (see the Editor Guide).

Two real names exist as more than one thing in Cube Voyager: FORMAT is also a FILEO pair-keyword, and LOG is also a control word. Each occurrence’s own position decides which field governs it — never both, never neither:

 [format]
 casing_pair_keywords = "upper"
 casing_function_calls = "lower"
-FILEO format=csv
+FILEO FORMAT=csv
-X = FORMAT(volume,8,2,',')
+X = format(volume,8,2,',')

format on the first line is a pair-keyword name (followed by =), governed by casing_pair_keywords alone. FORMAT on the second line is a function call (followed by (), governed by casing_function_calls alone.

Indentation

indent_top_level controls depth-0 statements; indent_width controls spacing per nesting level inside a block, relative to the block’s own opening-statement column. See Getting Started for a full before/after example.

Operator spacing

preserve (the default) leaves spacing exactly as written. fixed normalizes every operator to exactly one space on each side and removes interior padding inside brackets/parens:

-IF(ZONES==1)
-    ZONES=1
-    CNT=2
-    ITER=333
+IF(ZONES == 1)
+    ZONES = 1
+    CNT = 2
+    ITER = 333
 ENDIF

auto does everything fixed does, plus vertically aligns the = of consecutive Assignment statements at the same nesting depth to the longest left-hand side in the run:

-IF(ZONES==1)
-    ZONES=1
-    CNT=2
-    ITER=333
+IF(ZONES == 1)
+    ZONES = 1
+    CNT   = 2
+    ITER  = 333
 ENDIF

A run resets at a blank line, a comment-only line, a nesting-depth change, or a non-Assignment statement — so alignment never reaches across unrelated sections of a script.

Blank-line normalization

preserve (the default) leaves every run of consecutive blank lines exactly as written, however long. auto contracts a run down to the applicable cap (blank_lines_top_cap between top-level statements/blocks, default 2; blank_lines_nested_cap inside any block’s body, default 1) — only when a run exceeds the cap, never padding a shorter run up:

 RUN PGM=MATRIX
-
 
     MATI=a.mat
 
-
     MATO=b.mat
-
-
 
 ENDRUN

Line wrapping

preserve (the default) leaves every line exactly as written, however long. auto wraps an over-width Control statement’s keyword=value pair list across multiple physical lines once it exceeds line_wrap_width (default 120) — using Cube Voyager’s own existing line-continuation syntax, the same trailing comma that already makes the next physical line a continuation of the same statement. Only Control statements are eligible; an Assignment statement’s arithmetic/string expression is never touched by this feature.

line_wrap_style decides how pairs are distributed across the new continuation lines. fill (the default) packs as many pairs as fit per line:

-RUN PGM=MATRIX, ZONES=5, PRINT=1, COMBINE=T
+RUN PGM=MATRIX, ZONES=5, PRINT=1,
+    COMBINE=T

one_per_line places exactly one pair per continuation line instead, however much width is left over on any given line:

-RUN PGM=MATRIX, ZONES=5, PRINT=1, COMBINE=T
+RUN PGM=MATRIX,
+    ZONES=5,
+    PRINT=1,
+    COMBINE=T

(Both examples above use a narrowed line_wrap_width = 40 so the wrap is visible at doc-page width — the real default is 120.)

A statement that already contains a continuation character anywhere — i.e. you already hand-wrapped it — is left completely untouched, regardless of width:

RUN PGM=MATRIX,
    ZONES=5, PRINT=1, COMBINE=T

stays exactly as written under line_wrap = "auto", even though the combined statement is well over 40 characters. This is deliberate, not a missed case: it’s the safest boundary for an output-modifying transform (no fighting hand-formatted content) and it’s also what makes the feature idempotent by construction — once auto wraps a statement, the wrapped result itself contains a continuation character, so a second format pass sees “already continued” and leaves it alone. format(format(x)) == format(x) holds without needing to re-derive it from scratch.

; FMT: OFF / ; FMT: ON regions

Wrap a range in ; FMT: OFF / ; FMT: ON to exclude it from formatting entirely — useful for a block whose hand-tuned spacing carries meaning to a reviewer that automatic formatting would otherwise flatten:

-RUN PGM=MATRIX
+RUN PGM = MATRIX
 ; FMT: OFF
     ZONES=1
 ; FMT: ON
-    MATI=a.mat
+    MATI = a.mat
 ENDRUN

Everything between the markers (ZONES=1 above) is untouched, while the lines outside them still get operator_spacing = "fixed" applied. An unclosed ; FMT: OFF (no matching ; FMT: ON before end of file) protects through the rest of the file and is always surfaced — never silently unbounded with no indication — as a Hint diagnostic (source drut-fmt, see the Editor Guide), a CLI stderr notice, or an MCP format response field, depending on which surface you’re using.