Skip to content

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 code

This 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 project

zolo 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 executing

Testing

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 names

Test 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 total

Tests 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: text states one line, after a statement or on its own line.
  • A bare // expected: opens a block: each // text comment 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 results

A 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 modifying

REPL

zolo repl     # start interactive session

Version and Help

zolo version   # or zolo -v
zolo help      # or zolo -h

Language 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 declaration modifier)
  • 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:

  1. Parameter name hints — shown before arguments in function calls:

    add(/*a:*/ 1, /*b:*/ 2)
  2. Type hints — shown after let bindings 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

  1. The DAP compiles Zolo to Lua using compile_to_lua_with_source_map()
  2. Source map entries track (lua_line, zolo_line) mappings
  3. Breakpoints are translated from Zolo lines to Lua lines
  4. 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 change

Discovery 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.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

enespt-br