Complete guide to the MinZ VSCode extension (v0.5.0), LSP server, and DeZog source-level debugging.
cd minzc
make build # Build mz compiler
go build -o mzlsp ./cmd/mzlsp/ # Build LSP serverCopy both mz and mzlsp to your PATH (or ~/.local/bin/).
cd tools/vscode-minz
npm install
npm run compile
npx @vscode/vsce package # Creates .vsix fileInstall the .vsix in VSCode: Extensions → "..." → "Install from VSIX..."
In VSCode settings (settings.json):
{
"minz.compilerPath": "mz", // Path to MinZ compiler
"minz.lspPath": "", // Path to mzlsp (auto-detect if empty)
"minz.outputDirectory": "./build", // Compile output directory
"minz.enableOptimizations": true, // Enable -O by default
"minz.enableSMC": false, // Self-modifying code
"minz.enableTrueSMC": false // TRUE SMC (immediate anchors)
}The TextMate grammar covers the full MinZ language:
- Keywords:
fun/fn,let,const,global,struct,enum,import,if/else,while,for,match,gen/yield - Types:
u8,u16,u24,i8,i16,bool,void,Error, fixed-point types - Lambdas:
|x: u8, y: u8| => u8 { x + y }— pipe delimiters and parameters highlighted - String interpolation:
"Hello #{name}!"— interpolated expressions get MinZ scoping - Inline assembly:
asm { LD A, 42 }— Z80 mnemonics, registers, flags, hex literals - Iterator chains:
.iter(),.map(),.filter(),.forEach(),.take(),.skip(),.reduce(),.enumerate() - Attributes:
@[smc],@[extern(0x0005)],@[inline],@[tailrec] - Metafunctions:
@define(),@print(),@if/@elif/@else,@error(),@emit() - Metaprogramming blocks:
@lua[[[...]]],@minz[[[...]]] - Operators:
..(range),::(scope),->(return type),=>(lambda arrow)
The LSP server provides real-time IDE features:
| Feature | Description |
|---|---|
| Diagnostics | Red squiggles on parse/semantic errors, updated on every save |
| Hover | Hover over any symbol to see its type signature |
| Go to Definition | Ctrl+click (or F12) jumps to function/struct/enum/variable definitions |
| Completion | Keywords, types, metafunctions, symbols from analysis, iterator methods after . |
The server starts automatically when you open a .minz file. If mzlsp is not found, the extension falls back to compile-on-save diagnostics.
| Command | Shortcut | Description |
|---|---|---|
| Compile to Z80 Assembly | Cmd+Alt+B | Standard compile, opens .a80 side-by-side |
| Compile to MIR | Cmd+Alt+M | Dump MIR intermediate representation |
| Compile to ASM | Cmd+Alt+I | Compile to .a80, opens side-by-side |
| Compile All | Cmd+Alt+Shift+B | MIR + ASM in one shot |
| Compile Optimized | Cmd+Alt+O | Full optimizations + SMC flags |
| Show AST | Cmd+Alt+A | Dump AST in JSON format |
| Debug Build | Cmd+Alt+D | Compile with SLD source maps for DeZog |
| Start Debugging | F5 | Debug build + launch DeZog |
All commands are also available in the editor context menu (right-click) and the editor title bar.
Compiler errors appear in the Problems panel with click-to-navigate:
fibonacci.minz:12:5: error: undeclared variable 'x'
Click the error to jump directly to the source location.
- Install the DeZog extension in VSCode
- Build
mzwith--emit-sldsupport (included by default)
- Debug Build: The compiler emits
; @src:filename:lineannotations in the Z80 assembly output - SLD Generation: The
--emit-sldflag assembles the .a80 and generates a.sldfile mapping Z80 addresses to MinZ source lines - DeZog Integration: DeZog reads the
.sldfile to map breakpoints and step-through to MinZ source
One-click debugging:
- Open a
.minzfile - Set breakpoints (click in the gutter)
- Press F5 (or run "MinZ: Start Debugging")
- The extension builds with SLD, then launches DeZog
Manual debug build:
mz program.minz -o build/program.a80 --emit-sld
# Generates: build/program.a80, build/program.mir, build/program.sldManual DeZog launch (launch.json):
{
"type": "dezog",
"request": "launch",
"name": "Debug MinZ",
"sjasmplus": [{
"path": "${workspaceFolder}/build/program.sld"
}],
"topOfStack": "0xFFF0",
"load": "${workspaceFolder}/build/program.bin",
"startAddress": "0x8000"
}The SLD (Source Level Debug) file is a pipe-delimited text format:
|SLD.data.version|1
||<file>|<line>|<col>|<page>|<address>|F|<label> ← label entry
||<file>|<line>|<col>|<page>|<address>||<size> ← source mapping
Example from fibonacci.minz:
|SLD.data.version|1
|||0|0|0|32768|F|FIBONACCI_MAIN
|||0|0|0|32797|F|FIBONACCI_FIBONACCI_U8
||examples/fibonacci.minz|3|0|0|32802||1
||examples/fibonacci.minz|7|0|0|32847||1
||examples/fibonacci.minz|11|0|0|32874||3
||examples/fibonacci.minz|18|0|0|32995||3
tools/vscode-minz/
├── src/extension.ts # Commands, LSP client, DeZog config provider
├── syntaxes/
│ └── minz.tmLanguage.json # TextMate grammar (full language)
├── snippets/
│ └── minz-snippets.json # Code snippets
├── language-configuration.json
└── package.json # Commands, keybindings, settings, problem matcher
minzc/
├── cmd/mzlsp/main.go # Entry point (stdio JSON-RPC)
└── pkg/lsp/
├── protocol.go # LSP message types (subset of 3.17)
└── server.go # Handler: diagnostics, hover, goto-def, completion
The LSP server reuses the existing parser and semantic analyzer. On each document change:
- Write content to temp file →
parser.ParseFile()→ AST semantic.Analyze()→ IR module + errors- Build symbol table from AST declarations
- Publish diagnostics, serve hover/definition/completion from symbol table
The SLD pipeline:
- Semantic analysis sets
SourceLine/SourceFileon IR instructions viatrackSourcePos()+stampSourcePositions() - Z80 codegen emits
; @src:file:linecomments in assembly when source info is present - CLI (
--emit-sld): assembles the .a80, parses@srcannotations, writes.sld
LSP not starting?
- Check that
mzlspis in your PATH or setminz.lspPathin settings - Look at the MinZ output channel (View → Output → MinZ) for errors
No syntax highlighting?
- Ensure the file has a
.minzor.mzextension - Check that the extension is installed and enabled
SLD file empty?
- The source file might only contain
asmblocks (no MinZ-level statements to map) - Check that
--emit-sldflag is passed to the compiler
DeZog not stopping at breakpoints?
- Ensure the
.sldfile path inlaunch.jsonmatches the actual file - Verify the SLD has entries for the line where the breakpoint is set