# Zig for Nova — User Manual This manual covers the task system. For installation, language-server, and debugging prerequisites see [README.md](README.md). --- ## Table of Contents - [Overview](#overview) - [Creating a task](#creating-a-task) - [Common options](#common-options) - [Working Directory](#working-directory) - [Optimize](#optimize) - [Target](#target) - [User Options](#user-options) - [Build Arguments](#build-arguments) - [Program Arguments](#program-arguments) - [Task templates](#task-templates) - [Zig Package](#zig-package) - [Zig Debug](#zig-debug) - [Zig Test](#zig-test) - [Zig Watch](#zig-watch) - [Automatic tasks](#automatic-tasks) - [Current Zig File](#current-zig-file) - [Discovered build steps](#discovered-build-steps) - [Recipes](#recipes) - [Run a single executable](#recipe-run-executable) - [Run with a custom step name](#recipe-custom-step) - [Cross-compile to a different target](#recipe-cross-compile) - [Pass custom -D flags](#recipe-d-flags) - [Run specific tests](#recipe-tests) - [Ziglings-style projects](#recipe-ziglings) - [Debug a binary that isn't in zig-out/bin](#recipe-debug) - [Clean action](#clean-action) - [Inline issue reporting](#inline-issues) - [Settings reference](#settings) --- ## Overview The extension integrates with `zig build` at three levels: | Kind | How it appears | Configurable | Persistent | |---|---|---|---| | **Task template** | Added by you in Project Settings | Yes — full config UI | Yes — saved in `.nova/` | | **Current Zig File** | Always present automatically | No | No | | **Discovered step** | One per step in `zig build --list-steps` | No | No | Task templates are the right tool when you need to control optimize mode, target, test filters, or program arguments. Automatic tasks are zero-config quick-launchers. --- ## Creating a task 1. Open **Project Settings** (`⌘,` with a project open, or **Project → Project Settings…**). 2. Select the **Tasks** tab. 3. Click **+** and choose a template from the Zig section. 4. Fill in the options and close the panel — Nova saves the task automatically. Each task exposes up to three action slots that map to Nova's toolbar buttons: | Slot | Toolbar button | What it does | |---|---|---| | **Build** | ⌘B | Compiles without running | | **Run** | ▶ | Builds (if needed) and runs | | **Clean** | Broom icon | Removes build artifacts | --- ## Common options Several options appear in more than one template. They are documented once here and referenced from each template section. ### Working Directory | Field | Default | |---|---| | Working Directory | Workspace root | The directory from which `zig build` is invoked. Relative paths in other options are resolved against this directory. Leave blank to use the workspace root. Change this for monorepos or sub-package layouts where `build.zig` lives below the workspace root. ### Optimize | Value | Flag emitted | When to use | |---|---|---| | **Project Default** | *(nothing)* | Let `build.zig` decide (most projects default to `Debug`) | | **Debug** | `-Doptimize=Debug` | Development, debugging | | **ReleaseSafe** | `-Doptimize=ReleaseSafe` | Production with safety checks | | **ReleaseFast** | `-Doptimize=ReleaseFast` | Maximum performance | | **ReleaseSmall** | `-Doptimize=ReleaseSmall` | Smallest binary size | The flag is inserted immediately after `zig build`: ``` zig build -Doptimize=ReleaseFast … ``` ### Target | Field | Default | |---|---| | Target | *(host)* | A Zig target triple such as `aarch64-macos`, `x86_64-linux-gnu`, or `wasm32-wasi`. Passed as `-Dtarget=`. Leave blank to compile for the machine you are running on. ``` zig build -Dtarget=aarch64-macos … ``` See `zig targets` for the full list of supported triples. ### User Options A list of custom `-D` flags defined by the project's `build.zig`. Each entry can be either: - `key` — emits `-Dkey` (boolean `true`) - `key=value` — emits `-Dkey=value` Example entries and the flags they produce: | Entry | Flag | |---|---| | `verbose` | `-Dverbose` | | `n=42` | `-Dn=42` | | `healed-path=patches/healed` | `-Dhealed-path=patches/healed` | Entries that do not match the pattern `[A-Za-z_][A-Za-z0-9_-]*(=.*)?` are silently skipped with a warning in the Extension Console. ### Build Arguments Free-form arguments appended after the `-D` flags but before the step name. Use this for `zig build` flags that are not exposed as dedicated fields, such as `--summary all`, `--verbose`, or `-j4`. ``` zig build [-Doptimize=…] [-Dtarget=…] [-D…] [step] … ``` ### Program Arguments Arguments passed to the compiled program after `--`: ``` zig build … run -- ``` For the **Zig Debug** template these are forwarded to the debugger's launch request instead. --- ## Task templates ### Zig Package > **Build → Run → Clean** a Zig package from a single task configuration. **When to use:** everyday development — building, running, and cleaning a package whose output is an executable. #### Actions | Action | Command | |---|---| | Build | `zig build [flags…]` | | Run | `zig build [flags…] [step] [-- program-args]` | | Clean | removes `.zig-cache`, `zig-cache`, `zig-out` | The Build action compiles without running (equivalent to `zig build` with no run step). The Run action builds *and* runs in a single `zig build` invocation — Nova does not chain them; `zig build` handles both internally. #### Options | Option | Type | Default | Description | |---|---|---|---| | Working Directory | path | workspace root | See [Working Directory](#working-directory) | | Run Step | string | *(blank)* | Step name for the Run action. See below. | | Optimize | enum | Project Default | See [Optimize](#optimize) | | Target | string | host | See [Target](#target) | | User Options | string list | — | See [User Options](#user-options) | | Build Arguments | string list | — | See [Build Arguments](#build-arguments) | | Program Arguments | string list | — | See [Program Arguments](#program-arguments) | | Console | enum | Internal Console | Where to run the program | #### Run Step The step name appended to `zig build` for the Run action. Common values: | Value | Command produced | When | |---|---|---| | *(blank)* | `zig build` | Default install step — artifacts land in `zig-out/` | | `run` | `zig build run` | Project exposes a `run` step | | `serve` | `zig build serve` | Any custom step name | Leave blank if the project uses `-D` flags instead of a step name (Ziglings style — see [Recipes](#recipes)). #### Console | Value | Behaviour | |---|---| | **Internal Console** | Output appears in Nova's built-in console panel | | **External Terminal** | Opens macOS Terminal.app in a new window or tab | Use External Terminal for interactive programs that read from stdin. --- ### Zig Debug > **Build → Debug** a Zig executable under lldb-dap. **When to use:** stepping through code, setting breakpoints, inspecting variables. The Run action always triggers a Build first (`buildBeforeRunning`), so the debugger always launches the freshest binary. Requires `lldb-dap`, discovered automatically via `xcrun` or `PATH`. Install the Xcode Command Line Tools if it is missing: `xcode-select --install`. #### Actions | Action | Command | |---|---| | Build | `zig build -Doptimize= [flags…]` | | Run | launches lldb-dap (build runs first automatically) | | Clean | removes `.zig-cache`, `zig-cache`, `zig-out` | #### Options | Option | Type | Default | Description | |---|---|---|---| | Working Directory | path | workspace root | See [Working Directory](#working-directory) | | Program | path | *(auto-detected)* | Path to the executable to debug. See below. | | Optimize | enum | **Debug** | See [Optimize](#optimize) | | Target | string | host | See [Target](#target) | | User Options | string list | — | See [User Options](#user-options) | | Build Arguments | string list | — | See [Build Arguments](#build-arguments) | | Program Arguments | string list | — | Forwarded to the debugged process | | Console | enum | Internal Console | Where the debugged process runs | | Stop On Entry | boolean | off | Pause at the very first instruction | #### Program path auto-detection When the **Program** field is blank, the extension reads `build.zig.zon` and extracts the package `.name`. It then probes `zig-out/bin/` relative to the working directory. If the file exists it is used automatically; otherwise the task shows a warning asking you to fill in the field manually. This works for the common case of a single executable whose name matches the package name. For other layouts — multiple executables, custom install prefixes, library packages — set the path explicitly. #### Console (debug) | Value | Where the debugged process runs | |---|---| | **Internal Console** | Nova's built-in console (default) | | **Integrated Terminal** | Nova's integrated terminal | | **External Terminal** | macOS Terminal.app | --- ### Zig Test > **Build → Run → Clean** tests via `zig build test`. **When to use:** running the project's test suite, optionally filtered to a subset of tests. #### Actions | Action | Command | |---|---| | Build | `zig build test [flags…]` | | Run | `zig build test [flags…] [--summary=…] [--test-filter …] [-- runner-args]` | | Clean | removes `.zig-cache`, `zig-cache`, `zig-out` | Both Build and Run invoke `zig build test`. The distinction is that the Run action additionally applies the Test Filter and Summary fields. Test failures surface as inline issues in the editor via the same `file:line:col: error:` pattern used for compiler errors. #### Options | Option | Type | Default | Description | |---|---|---|---| | Working Directory | path | workspace root | See [Working Directory](#working-directory) | | Test Filter | string | — | Substring filter on test names. See below. | | Summary | enum | Default | Verbosity of `--summary`. See below. | | Optimize | enum | Project Default | See [Optimize](#optimize) | | Target | string | host | See [Target](#target) | | User Options | string list | — | See [User Options](#user-options) | | Build Arguments | string list | — | Appended after `zig build test` | | Program Arguments | string list | — | Passed after `--` to the test runner | #### Test Filter A substring of the test name. Only tests whose names contain this string are run. Maps directly to `zig build`'s `--test-filter` flag. ``` zig build test --test-filter "parser" ``` Leave blank to run all tests. #### Summary Controls how much output `zig build` prints about the test run. | Value | Flag | Output | |---|---|---| | **Default** | *(nothing)* | Zig's built-in default | | **All** | `--summary=all` | Every step result | | **Failures only** | `--summary=failures` | Only failed steps | | **None** | `--summary=none` | Silent on success | --- ### Zig Watch > **Build** with `zig build --watch`, rebuilding automatically on file changes. **When to use:** tight edit–compile loops where you want continuous feedback without manually re-triggering the Build action. > **⚠ Known limitation:** Nova's issue matchers fire only on the first build > cycle. Errors found in subsequent automatic rebuilds will not appear as > inline annotations in the editor. Re-run the task (stop and start again) to > refresh the issue overlay. #### Actions | Action | Command | |---|---| | Build | `zig build [step] --watch [--debounce N] [-fincremental] [flags…]` | | Clean | removes `.zig-cache`, `zig-cache`, `zig-out` | There is no Run action — `zig build --watch` manages the build loop itself. #### Options | Option | Type | Default | Description | |---|---|---|---| | Working Directory | path | workspace root | See [Working Directory](#working-directory) | | Step | string | *(blank)* | Step to watch. Leave blank for Zig's default install step. | | Debounce (ms) | number | *(Zig default)* | Milliseconds to wait after a change before rebuilding. | | Incremental | enum | Default | Force incremental compilation on or off. | | Optimize | enum | Project Default | See [Optimize](#optimize) | | Target | string | host | See [Target](#target) | | User Options | string list | — | See [User Options](#user-options) | | Build Arguments | string list | — | See [Build Arguments](#build-arguments) | #### Debounce Passed as `--debounce ` to `zig build`. Controls how long Zig waits after detecting a file change before starting a rebuild. Useful on projects with slow file-system events or many simultaneous saves. Leave blank to use Zig's built-in default. #### Incremental | Value | Flag | Effect | |---|---|---| | **Default** | *(nothing)* | Zig decides | | **On** | `-fincremental` | Force incremental compilation on | | **Off** | `-fno-incremental` | Force incremental compilation off | --- ## Automatic tasks Automatic tasks appear in the task list without any configuration. They cannot be edited and are not saved in project settings. ### Current Zig File Always present. Targets whichever `.zig` file is currently focused in the editor. | Action | Command | |---|---| | Run | `zig run ` (in the file's directory) | | Clean | removes `.zig-cache`, `zig-cache`, `zig-out` from the nearest ancestor directory that contains a `build.zig` | The Clean action walks up the directory tree from the active file until it finds a `build.zig`, then cleans that project root. If no `build.zig` is found above the file, it falls back to the workspace root. **Note:** there is no Build action — `zig run` compiles and runs in one step. --- ### Discovered build steps When the workspace contains a `build.zig`, the extension runs `zig build --list-steps` in the background and creates one task per step: ``` Zig Build: install Zig Build: run Zig Build: test Zig Build: bench … ``` Each task has a single **Run** action that invokes `zig build ` in the workspace root with no extra flags. #### How discovery works 1. On workspace open (or task-list refresh), the extension stats `build.zig` and `build.zig.zon` to capture their modification times. 2. It spawns `zig build --list-steps` asynchronously — the workspace is usable immediately; discovered tasks appear once the command finishes. 3. The result is cached. The cache is considered fresh if: - Both `build.zig` and `build.zig.zon` have the same mtimes as when last fetched, **and** - The cache is less than 5 minutes old. 4. When `build.zig` or `build.zig.zon` changes on disk, the cache is invalidated and `--list-steps` is re-run automatically. #### What steps appear `zig build --list-steps` executes `build.zig` with no `-D` options, so only the steps registered unconditionally by the build script are visible. Steps that are registered only under a `-D` branch (such as Ziglings' `zigling` and `random` steps) do not appear unless that branch is taken — and it won't be, because the discovery command passes no flags. Steps whose names are not valid identifiers (`[A-Za-z_][A-Za-z0-9_-]*`) are silently filtered out. #### Disabling discovery Some projects run expensive logic at the top of `build()` that you may not want triggered on every workspace open. Discovery can be turned off: - **Globally:** Nova Preferences → Extensions → Zig → Tasks → uncheck **Discover Build Steps**. - **Per workspace:** Project Settings → Zig → Tasks → uncheck **Discover Build Steps** (overrides the global setting for this project only). When disabled, the `Zig Build: ` tasks disappear; the [Current Zig File](#current-zig-file) task and all configured templates are unaffected. --- ## Recipes ### Run a single executable Create a **Zig Package** task. - **Run Step:** `run` (or the name your `build.zig` uses for the run step) - Leave everything else at defaults. The Run (▶) button compiles and launches the program in Nova's console. ### Run with a custom step name Same as above but change **Run Step** to whatever `b.step(…)` name your `build.zig` declares: ```zig const serve_step = b.step("serve", "Start the HTTP server"); ``` → set **Run Step** to `serve`. ### Cross-compile to a different target Create a **Zig Package** task and set: - **Target:** `aarch64-linux-musl` - **Optimize:** `ReleaseSmall` The command produced will be: ``` zig build -Doptimize=ReleaseSmall -Dtarget=aarch64-linux-musl run ``` ### Pass custom -D flags Your `build.zig` declares: ```zig const verbose = b.option(bool, "verbose", "Enable verbose output") orelse false; const port = b.option(u16, "port", "Listening port") orelse 8080; ``` Add two entries to **User Options**: | Entry | Flag produced | |---|---| | `verbose` | `-Dverbose` | | `port=9000` | `-Dport=9000` | ### Run specific tests Create a **Zig Test** task and set: - **Test Filter:** `parser` (runs any test whose name contains "parser") - **Summary:** Failures only (quieter output when most tests pass) ### Ziglings-style projects Ziglings selects exercises with `-Dn=` rather than a named step. For "run all exercises" use a **Zig Package** task with: - **Run Step:** *(blank)* — runs `zig build`, which hits the default `ziglings` step For a single exercise use: - **Run Step:** *(blank)* - **User Options:** `n=42` This produces `zig build -Dn=42`. Alternatively, if you have step discovery enabled, **Zig Build: ziglings** appears automatically and covers the "run all" case with one click. ### Debug a binary that isn't in zig-out/bin Create a **Zig Debug** task and set **Program** explicitly: - `zig-out/bin/my-tool` (relative to Working Directory) - or an absolute path When the field is left blank the extension checks `build.zig.zon` for the package name and probes `zig-out/bin/`. If your binary name doesn't match the package name, set the path manually. --- ## Clean action Every template task includes a Clean action. It: 1. Checks that the working directory is a real absolute path inside the current workspace. Clean refuses to run if the path resolves to `/`, `$HOME`, or anywhere outside the workspace root, and shows a warning instead. 2. If the project's `build.zig` exposes an `uninstall` step (already in the step discovery cache), runs `zig build uninstall` first. 3. Removes `.zig-cache`, `zig-cache`, and `zig-out` with `rm -rf`. The [Current Zig File](#current-zig-file) automatic task's Clean action applies the same logic but targets the nearest ancestor directory that contains a `build.zig`, rather than a configured working directory. --- ## Inline issue reporting Compiler and test errors are shown as inline annotations in the editor using the pattern: ``` ::: error: ::: warning: ``` This covers output from `zig build`, `zig build test`, `zig run`, `zig test`, and `zig fmt` (non-`--check` mode). `zig fmt --check` only prints filenames, not line numbers, so it does not produce inline annotations. For the **Zig Watch** template, annotations are populated from the first build cycle only. Subsequent automatic rebuilds do not update them — stop and restart the task to refresh. --- ## Settings reference Settings live in two places: - **Nova Preferences → Extensions → Zig** — global defaults for all projects. - **Project Settings → Zig** — workspace-specific overrides. These take precedence over the global settings for the open project. ### Tooling | Setting | Description | |---|---| | Zig Executable | Absolute path to `zig`. Leave blank to discover from `PATH`. | | ZLS Executable | Absolute path to `zls`. Leave blank to discover from `PATH`. | | LLDB DAP Executable | Absolute path to `lldb-dap`. Leave blank to discover via `xcrun` or `PATH`. | ### Language Server | Setting | Default | Description | |---|---|---| | Enable ZLS | on | Enable diagnostics, completion, hover, go-to-definition, and formatting via ZLS. | | Build On Save | off | Allow ZLS to run its build/check runner when you save a file. | | Debug Server Messages | off | Log ZLS protocol traffic to the Extension Console (for troubleshooting). | ### Debug Adapter | Setting | Default | Description | |---|---|---| | Enable Proxy Log | off | Write lldb-dap proxy traffic to a log file. For extension development only. | ### Tasks | Setting | Default | Description | |---|---|---| | Discover Build Steps | on | Run `zig build --list-steps` and surface each step as a task. Disable for projects where executing `build.zig` on activation is undesirable. |