aboutsummaryrefslogtreecommitdiff
path: root/MANUAL.md
blob: 27a555ecc829a77b08bf54d3dedf5077268a3234 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
# 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)

---

<a id="overview"></a>
## 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.

---

<a id="creating-a-task"></a>
## 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 |

---

<a id="common-options"></a>
## Common options

Several options appear in more than one template. They are documented once
here and referenced from each template section.

<a id="working-directory"></a>
### 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.

<a id="optimize"></a>
### 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 …
```

<a id="target"></a>
### Target

| Field | Default |
|---|---|
| Target | *(host)* |

A Zig target triple such as `aarch64-macos`, `x86_64-linux-gnu`, or
`wasm32-wasi`. Passed as `-Dtarget=<value>`. 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.

<a id="user-options"></a>
### 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.

<a id="build-arguments"></a>
### 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…] <Build Arguments> [step] …
```

<a id="program-arguments"></a>
### Program Arguments

Arguments passed to the compiled program after `--`:

```
zig build … run -- <Program Arguments>
```

For the **Zig Debug** template these are forwarded to the debugger's launch
request instead.

---

<a id="task-templates"></a>
## Task templates

<a id="zig-package"></a>
### 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.

---

<a id="zig-debug"></a>
### 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=<mode> [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/<name>` 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 |

---

<a id="zig-test"></a>
### 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 |

---

<a id="zig-watch"></a>
### 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 <N>` 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 |

---

<a id="automatic-tasks"></a>
## Automatic tasks

Automatic tasks appear in the task list without any configuration. They cannot
be edited and are not saved in project settings.

<a id="current-zig-file"></a>
### Current Zig File

Always present. Targets whichever `.zig` file is currently focused in the
editor.

| Action | Command |
|---|---|
| Run | `zig run <active-file>` (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.

---

<a id="discovered-build-steps"></a>
### 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 <step>` 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: <step>` tasks disappear; the
[Current Zig File](#current-zig-file) task and all configured templates are
unaffected.

---

<a id="recipes"></a>
## Recipes

<a id="recipe-run-executable"></a>
### 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.

<a id="recipe-custom-step"></a>
### 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`.

<a id="recipe-cross-compile"></a>
### 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
```

<a id="recipe-d-flags"></a>
### 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` |

<a id="recipe-tests"></a>
### 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)

<a id="recipe-ziglings"></a>
### Ziglings-style projects

Ziglings selects exercises with `-Dn=<number>` 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.

<a id="recipe-debug"></a>
### 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/<name>`. If your binary name doesn't
match the package name, set the path manually.

---

<a id="clean-action"></a>
## 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.

---

<a id="inline-issues"></a>
## Inline issue reporting

Compiler and test errors are shown as inline annotations in the editor using
the pattern:

```
<file>:<line>:<column>: error: <message>
<file>:<line>:<column>: warning: <message>
```

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.

---

<a id="settings"></a>
## 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. |