Guide 44 of 47
Tooling
CLI, LSP, DAP debugger, formatter and VS Code extension.
On this page
Zolo comes with a comprehensive set of development tools.
CLI (zolo)¶
The zolo command is the primary interface for working with Zolo code.
Running Code¶
zolo run hello.zolo # compile and execute
zolo hello.zolo # shorthand for 'run'Compiling¶
zolo compile hello.zolo # show generated Lua codeThis is useful for debugging — you can see exactly what Lua code your Zolo program produces.
Cleaning build artifacts¶
zolo clean # remove target/ from the current project
zolo clean --dry-run # show file count and size without deleting
zolo clean path/to/project # clean a different projectzolo clean removes only project-local generated artifacts under target/.
Published web output under dist/ remains untouched. Immutable npm/JSR package
contents live in Zolo's shared package cache and are linked into the project,
so a clean rebuild stays fast and can remain offline; this is the same split
between cargo clean and Cargo's shared registry cache.
Removing target/ also removes the sealed editor-resolution descriptors the
IDE uses to type inline client TypeScript ([client.dependencies] packages
and verniz:* modules). The editor never installs or resolves packages on its
own, so hovers degrade to any until the next zolo install, zolo dev, or
zolo build regenerates the descriptors — zolo clean prints a note when
that applies.
Type Checking¶
zolo check hello.zolo # parse and type check without executingTesting¶
zolo test tests.zolo # run named and titled tests
zolo test tests.zolo --filter fib # only tests matching "fib"
zolo test tests.zolo --list # list test namesTest output shows pass/fail for each test function:
[PASS] test_addition
[PASS] test_fibonacci
[FAIL] test_broken - assertion failed: expected 5, got 4
Results: 2 passed, 1 failed, 3 totalTests with readable titles¶
A test can describe its behavior directly:
test "addition preserves zero" {
assert_eq(2 + 0, 2)
}Run it with zolo test tests.zolo. Existing @test functions remain
available, and titled tests use the same hooks, suites and test attributes.
A title is static text: quoted, raw or triple text with a nonempty decoded
single-line value. Interpolation, bytes and control characters are rejected.
The declaration may span lines and comments; it has no source-level
function name or parameters.
Human filters match the displayed title or a legacy test name. Duplicate
titles remain distinct tests. Use --list --events-json to obtain their
exact selectors, and repeat --exact SELECTOR to select particular tests.
An unknown selector is an error. Changing a title does not turn it into
an execution identity.
--events-json reports actual started and terminal events separately from
ordinary program output. Test output goes to stderr in that mode; printing
a JSON-looking line cannot fabricate a passing test. Titled snapshots use
the physical test file and structural occurrence, while existing named
snapshots retain their paths.
The test runner uses the VM. Exact selection and structured events in watch mode currently report an explicit unsupported request.
The editor lists tests by their readable titles and runs the exact selected test, including when titles repeat. Generated tests navigate to their physical source when that location is available. Debug Test launches the selected test with breakpoints; use Run Tests for its recorded pass/fail result.
Checked // expected: comments¶
A program can state its own output in comments, and zolo test --expected
holds it to them:
print(2 * 3) // expected: 6
for x in [1, 2] {
print(x)
}
// expected:
// 1
// 2
print(math.pi) // expected: 3.14...// expected: textstates one line, after a statement or on its own line.- A bare
// expected:opens a block: each// textcomment right below it states one more line. ...inside a stated line matches any text.
The stated lines, in source order, must appear in the output in that order.
Output that no comment states is allowed; --strict refuses it.
zolo test --expected examples/ # check every file with comments
zolo test --expected --promote drift.zolo # rewrite the contradicted comments
zolo test --expected --backend all f.zolo # vm, native and llvm alike
zolo test --expected --json examples/ # machine-readable resultsA failure names the line and what was printed there:
FAIL stale.zolo
line 1: expected 5
printed 6--promote rewrites a comment when the output says unambiguously which lines
replace it (as many lines as it stated, or a whole block regrown to what the
loop now prints); anything else is reported for a hand edit. It never deletes
a stated line: output that stops short may be a crash as easily as a change,
so fewer printed lines than stated are always left to you. A
// parity-timeout-ms: N directive raises the 30 s run limit. The repository
runs this over examples/ under a ratchet: cargo xtask expected.
Formatting¶
zolo fmt hello.zolo # format file in place
zolo fmt --check hello.zolo # check formatting without modifyingREPL¶
zolo repl # start interactive sessionVersion and Help¶
zolo version # or zolo -v
zolo help # or zolo -hLanguage Server Protocol (LSP)¶
The Zolo LSP server (zolo-lsp) provides IDE features. It's implemented in Rust using tower-lsp and communicates over stdin/stdout.
Supported Features¶
| Feature | Description |
|---|---|
| Diagnostics | Parse errors with source locations |
| Hover | Function signatures, struct/enum/trait info |
| Autocomplete | Keywords, types, document symbols, snippets |
| Go to Definition | Functions, structs, enums, traits, variables |
| Document Symbols | Hierarchical outline of the file |
| Semantic Tokens | Rich syntax highlighting (functions, methods, types, parameters, fields, decorators) |
| Signature Help | Parameter info while typing function calls |
| Inlay Hints | Parameter names in calls, inferred types for let bindings |
| Reversible sugar | Hovering +=, ^k, {x=}, in [...], ??, ?. or |> says what it stands for; an Expand refactor rewrites +=, ^k, {x=} and in [...] into their long form, and the idiom hints' quick fixes contract the long form back |
Semantic Token Types¶
The LSP provides semantic tokens for:
- function — function names (with
declarationmodifier) - method — method names
- parameter — function parameters
- variable — local variables
- property — struct fields
- type — type names (structs, enums)
- interface — trait names
- enumMember — enum variants
- decorator —
@annotations - keyword — language keywords
- string — string literals
- number — numeric literals
- comment — comments
Inlay Hints¶
Two types of inlay hints:
Parameter name hints — shown before arguments in function calls:
add(/*a:*/ 1, /*b:*/ 2)Type hints — shown after
letbindings with inferred types:let x /*: int*/ = 42
Debug Adapter Protocol (DAP)¶
The zolo-dap crate implements the Debug Adapter Protocol for debugging Zolo programs in VS Code.
Supported Features¶
| Feature | Description |
|---|---|
| Launch | Start debugging a .zolo file |
| Breakpoints | Set line breakpoints |
| Step Over | Execute next line |
| Step Into | Step into function calls |
| Step Out | Step out of current function |
| Continue | Run until next breakpoint |
| Stack Trace | View call stack with source locations |
| Source Maps | Maps Lua output lines back to Zolo source |
How It Works¶
- The DAP compiles Zolo to Lua using
compile_to_lua_with_source_map() - Source map entries track
(lua_line, zolo_line)mappings - Breakpoints are translated from Zolo lines to Lua lines
- The debug session manages stepping, stack frames, and variable scopes
VS Code Launch Configuration¶
Add to .vscode/launch.json:
{
"type": "zolo",
"request": "launch",
"name": "Debug Zolo",
"program": "${file}"
}Formatter (zolo fmt)¶
The Zolo formatter is AST-based — it parses the source, then reprints it with consistent style.
Features¶
- 4-space indentation
- Consistent brace placement
- Comment preservation
- Expression formatting
- Declaration alignment
Usage¶
zolo fmt myfile.zolo # format in place
zolo fmt --check myfile.zolo # check without modifying (exit code 1 if changes needed)External JavaScript and TypeScript in Verniz¶
Projects that opt in with [client.lint] engine = "oxlint" and
[client.format] engine = "oxfmt" gain an embedded, Node-free client quality
path:
zolo lint --client # safely discover authored JS/TS
zolo lint --client --fix src/client # apply safe fixes only
zolo lint --client --format json app.ts # editor/CI protocol
zolo lint --client --format sarif # code-scanning protocol
zolo fmt --client src/client # format after parsing every input
zolo fmt --client --check # CI check, no writes
zolo fmt --client --diff app.ts # review the changeDiscovery is confined to the current Zolo project and skips dist, public,
target/.zolo, package sources, temporary products, node_modules and
symlinks. Oxlint warnings/errors carry authored byte offsets and line/column;
--deny-warnings or deny_warnings = true controls the exit gate. Oxfmt
preserves comments and the file's line-ending style. Neither command changes
the TypeScript checker/emitter used by builds, and lint rules never become a
bundle requirement.
VS Code Extension¶
The Zolo VS Code extension provides a complete development environment.
Features¶
| Category | Features |
|---|---|
| Syntax | TextMate grammar for full syntax highlighting |
| Language Config | Comments, brackets, indentation, folding |
| Snippets | 28+ snippets for common constructs |
| LSP | Full LSP client with auto-discovery of zolo-lsp binary |
| Semantic Highlighting | Rich token coloring via LSP semantic tokens |
| Signature Help | Parameter info in function calls |
| Inlay Hints | Type and parameter name hints |
| Explorer | Sidebar tree view showing document symbols |
| AST Viewer | Webview panel showing the AST |
| Debugger | DAP integration for debugging |
| Commands | Run, restart LSP, show AST, show output |
| Run | Run current file with Ctrl+Shift+R |
Commands¶
| Command | Keybinding | Description |
|---|---|---|
Zolo: Run Current File |
Ctrl+Shift+R |
Compile and execute the active file |
Zolo: Restart Language Server |
— | Restart the LSP server |
Zolo: Show AST |
— | Open AST viewer panel |
Zolo: Show Output Channel |
— | Show LSP output logs |
Configuration¶
| Setting | Default | Description |
|---|---|---|
zolo.lsp.enabled |
true |
Enable/disable the LSP client |
zolo.lsp.serverPath |
auto | Path to the zolo-lsp binary |
zolo.trace.server |
off |
LSP trace level (off, messages, verbose) |
Status Bar¶
Shows the LSP connection status:
- Connected / Disconnected / Error
- Click to open the output channel with LSP logs
Zolo Explorer¶
A sidebar panel (activity bar) showing the document outline:
- Functions, structs, enums, traits, variables
- Click any symbol to navigate to its location
- Auto-refreshes on file changes
AST Viewer¶
A webview panel showing the parsed AST as an interactive tree:
- Updates live as you edit
- Shows all AST nodes with their types and spans
Debugging¶
Press F5 to start debugging with the Zolo debug adapter:
- Set breakpoints by clicking the gutter
- Step through code line by line
- View the call stack
- Continue/pause execution
Context Menus¶
Right-click a .zolo file in the explorer → "Run with Zolo"
Unwrap in tests¶
The editor's unsafe-unwrap warning is disabled inside functions marked @test,
including their nested blocks and closures. In a test, an unexpected Err or
None should fail immediately, so .unwrap() and .unwrap_or_panic() express
that expectation directly. The rule still applies to ordinary functions,
helpers and top-level code in the same file or @suite; other test diagnostics
remain enabled. The exemption follows the decorator, not a file naming convention.
DOCS / FEEDBACK
Did this page leave a question?
Tell us where the explanation lost you. Documentation is part of the language experience.