Reorganize into grammars/<name>/ subdirs ( Zed's [grammars.*] supports a `path` field, so both grammars ship from this repo without a sibling- repo split ). Vendor tree-sitter-lua as the fork base for tree-sitter- pico8-lua; upstream MIT license preserved at grammars/pico-8-lua/ UPSTREAM-LICENSE.md. Dialect features added: != as ~= alias, \ integer divide, ^^ binary xor, >>> / <<> / >>< shifts and rotates, compound-assignment statements, memory peek prefixes @ % $ (% coexists with binary modulo), single-line `if (cond) stmt [else stmt]` and `while (cond) stmt`, statement-level print shorthand ?, and `#include path` directives. Identifier rule no longer accepts ! ? @ $ ( upstream did ). Pico-8 Lua language ( languages/pico-8-lua/, suffix .p8lua ) ships highlights with the full ~110 PICO-8 builtins as @function.builtin. The cart injection now hands __lua__ bodies to pico-8-lua, so .p8 carts and bare .p8lua files share the dialect-aware grammar. Examples updated to exercise the dialect end-to-end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zed-p8
A Zed extension for the PICO-8 fantasy
console. Reasonable editor support for the entire .p8 cartridge file format
and for PICO-8's Lua dialect — including the parts where PICO-8 deviates from
standard Lua 5.2 (compound assignments, ? print shorthand, single-line
if (cond) ..., !=, 0b... binary literals, integer divide \, peek
operators @/%/$, the rotate/logical-shift family <<> / >>< / >>>,
and #include).
Status — v0.2
Working today:
tree-sitter-p8-cart(grammars/p8-cart/) — parses the.p8cartridge container: the magic header line,versionline, and the named sections__lua__,__gfx__,__gff__,__label__,__map__,__sfx__,__music__. Unknown__name__markers fall through tounknown_section.tree-sitter-pico8-lua(grammars/pico-8-lua/) — fork oftree-sitter-grammars/tree-sitter-luawith the PICO-8 dialect added. Handles every dialect form the manual documents: see Dialect coverage below. Upstream attribution is preserved ingrammars/pico-8-lua/UPSTREAM-LICENSE.md.Pico-8 Cartridgelanguage (languages/pico-8-cart/, suffix.p8) — config, marker highlights, outline view, and an injection that hands the__lua__body to the Pico-8 Lua grammar.Pico-8 Lualanguage (languages/pico-8-lua/, suffix.p8lua) — config, dialect-aware highlights with PICO-8 builtins recognized, brackets, indents, outline.
The .p8lua suffix is the convention for bare Pico-8 Lua source files — the
ones pulled into a cart via #include. Plain .lua files are intentionally
not claimed by this extension, so users who keep stock Lua files alongside
their PICO-8 work continue to get standard Lua treatment.
Dialect coverage
| Feature | Status |
|---|---|
!= ( alias for ~= ) |
✓ |
Compound assignment: += -= *= /= %= \= ^= ..= &= |= ^^= <<= >>= >>>= <<>= >><= |
✓ |
Integer divide \ and modulo % ( binary ) |
✓ |
Bitwise XOR ^^ ( binary, in addition to upstream's ~ ) |
✓ |
Logical shift right >>>, rotate left <<>, rotate right >>< |
✓ |
Hex literals with fractional part: 0x11.4000 |
✓ |
Binary literals: 0b1010 |
✓ |
Memory peek prefix unary: @addr, %addr, $addr |
✓ |
Single-line if (cond) stmt [else stmt] ( no then/end ) |
✓ |
Single-line while (cond) stmt ( no do/end ) |
✓ |
? print shorthand statement |
✓ |
#include path directive |
✓ |
_init / _update / _update60 / _draw highlighted as builtins |
✓ |
Known limitations
- No language server. No completion, hover docs, or diagnostics for
PICO-8 builtins yet — only a static
function.builtinhighlight on recognized names. See Roadmap. - No
.p8.pngsupport. Only the plain-text.p8format is handled — the PNG-steganography variant is out of scope for a text-focused IDE extension. - Hex sections are unhighlighted blobs.
__gfx__,__map__,__sfx__,__gff__,__music__,__label__parse as opaque line bodies. Roadmap v0.4 covers per-section highlighters.
Repository layout
zed-p8/
extension.toml ← Zed extension manifest
package.json ← workspace root; hosts tree-sitter-cli
grammars/
p8-cart/ ← cart-format tree-sitter grammar
grammar.js
tree-sitter.json
src/ ← generated parser ( committed )
pico-8-lua/ ← Pico-8 Lua dialect tree-sitter grammar
grammar.js
tree-sitter.json
package.json ← marks this dir as ESM for node
src/ ← generated parser + scanner.c ( committed )
UPSTREAM-LICENSE.md ← MIT, tree-sitter-lua by Munif Tanjim
languages/
pico-8-cart/ ← Pico-8 Cartridge language files
config.toml
highlights.scm
injections.scm ← injects pico-8-lua into __lua__ body
outline.scm
pico-8-lua/ ← Pico-8 Lua language files
config.toml
highlights.scm
brackets.scm
indents.scm
injections.scm
outline.scm
examples/
hello.p8 ← minimal test cart
references/ ← upstream PICO-8 manual + Zed doc links
Both grammars live in subdirectories of this same repository. Zed's
[grammars.*] block supports a path field, so the extension manifest
points each grammar at this repo's git URL plus the relevant subdir.
Local development
Prerequisites: Node.js ( for tree-sitter-cli ) and Zed. Rust is not
required unless / until we add a language-server harness ( v0.3 ).
npm install # one-time, installs tree-sitter-cli
Edit a grammar and reload
-
Edit
grammars/<name>/grammar.js. -
Regenerate from the grammar's directory:
( cd grammars/p8-cart && npx tree-sitter generate ) # or ( cd grammars/pico-8-lua && npx tree-sitter generate ) -
Sanity-check by parsing a sample file:
( cd grammars/p8-cart && npx tree-sitter parse ../../examples/hello.p8 ) ( cd grammars/pico-8-lua && npx tree-sitter parse path/to/file.p8lua ) -
Commit the regenerated
src/parser.calong with the grammar change. Zed clones the grammar repo at the SHA inextension.toml, so changes only take effect after a commit. -
Update the
revfield of the affected[grammars.*]block(s) inextension.tomlto the new SHA, then in Zed runzed: install dev extension( or Install Dev Extension on the Extensions page ) and select this directory. Reinstall after every commit that should be picked up.Logs:
zed: open log. Runzed --foregroundfor live stdout.
Edit only language queries
Files under languages/*/ ( highlights.scm, injections.scm, etc. )
are loaded directly by Zed — no regeneration step needed. Reinstall the
dev extension to pick up changes.
Tests
Sample carts live under examples/. Use tree-sitter parse directly for
verification — corpus-style tree-sitter test is not currently set up
because the cart grammar's strict extras: [] doesn't tolerate the
leading newline that the test harness prepends to each fixture.
Roadmap
v0.3 — Language server integration
Wire up japhib/pico8-ls ( or whichever
PICO-8 LSP is most maintained at the time ) for:
- Completion of PICO-8 builtins (
spr,circfill,btn,flr, … ). - Signature help and hover docs sourced from the manual.
- Cart-aware analysis — the LSP already understands
.p8section markers and only analyzes the__lua__body. - Per-cart diagnostics.
This requires a Rust component ( the zed_extension_api crate ) that
downloads the LSP binary and defines language_server_command.
See Zed's developing-extensions docs.
v0.4 — Polish
- LuaCATS / EmmyLua stub file enumerating PICO-8's ~110 globals, for users
who'd rather wire up
lua-language-serveragainst their#include-d.p8luafiles. - Per-section highlighters for the hex blocks:
__gfx__colored by palette index,__sfx__/__music__parsed as note streams,__map__as tile indices,__gff__as flag bytes. - Snippets for common idioms ( the
_init/_update/_drawtriad,for x=0,127 do … end, palette swap setup, etc. ).
References
- PICO-8 manual:
references/pico-8_manual.txt - Zed extension docs: see links in
references/zed-doc-links.md - Cart file-format spec ( community wiki, not in the official manual ): https://pico-8.fandom.com/wiki/P8FileFormat
- Upstream Lua grammar: https://github.com/tree-sitter-grammars/tree-sitter-lua
( MIT, by Munif Tanjim — preserved in
grammars/pico-8-lua/UPSTREAM-LICENSE.md)
License
The cart grammar and the Zed extension files are 0BSD ( see LICENSE ).
The PICO-8 Lua grammar is a fork of MIT-licensed tree-sitter-lua; the
upstream license is preserved at grammars/pico-8-lua/UPSTREAM-LICENSE.md
and applies to the derived files in that directory.