zed-p8

A Zed extension for the PICO-8 fantasy console. The goal is reasonable editor support for the entire .p8 cartridge file format and for PICO-8's Lua dialect — even where PICO-8 deviates from standard Lua 5.2 (compound assignments, ? print shorthand, single-line if (cond) ..., !=, binary literals, peek operators, and so on).

Status — v0.1 scaffold

Working today:

  • A small tree-sitter grammar (p8_cart, in this repo's root) that parses the .p8 cartridge container: the magic header line, version line, and the named sections __lua__, __gfx__, __gff__, __label__, __map__, __sfx__, __music__. Unknown __name__ markers are accepted as a fallback unknown_section.
  • A Zed language definition Pico-8 Cartridge (file suffix .p8) that uses this grammar for outline, section-marker highlighting, and an outline view.
  • An injection that hands the body of the __lua__ section to Zed's built-in Lua language for syntax highlighting.

Known limitations:

  • PICO-8 Lua dialect is not fully parsed. The injected grammar is plain Lua 5.2, which does not understand ? (print shorthand), += and friends, !=, 0b... literals, the \ integer-divide operator, the @/%/$ peek prefixes, or the single-line if (cond) stmt / while (cond) stmt forms. Code that uses any of those will show parse-error highlighting in those regions only — surrounding code remains correctly highlighted. See Roadmap below.
  • No language server. No completion, hover docs, or diagnostics for PICO-8 builtins yet. See Roadmap.
  • No .p8.png support. Only the plain-text .p8 format is handled.

Repository layout

zed-p8/
  extension.toml             ← Zed extension manifest
  grammar.js                 ← tree-sitter-p8-cart grammar source
  src/                       ← generated parser ( committed; regenerate after grammar.js edits )
  package.json               ← tree-sitter-cli devDependency
  tree-sitter.json           ← tree-sitter-cli config ( auto-managed )
  languages/
    pico-8-cart/             ← Pico-8 Cartridge language files
      config.toml
      highlights.scm
      injections.scm
      outline.scm
  examples/
    hello.p8                 ← minimal test cart
  references/                ← upstream PICO-8 manual + Zed docs links

The cart grammar lives at the repo root rather than as a separate sibling repository. This keeps everything in one place during early development; if the grammar grows or wants to be reused outside Zed it can be split out later — the only file that needs to move with it is grammar.js plus the generated src/, and the [grammars.p8_cart] URL in extension.toml would need updating.

Local development

Prerequisites: Node.js (for tree-sitter-cli) and Zed. Rust is NOT required unless/until we add a language-server harness.

Edit-and-reload loop

  1. Edit grammar.js.

  2. Regenerate the parser:

    npx tree-sitter generate
    
  3. Sanity-check on a real cart:

    npx tree-sitter parse examples/hello.p8
    
  4. Commit. The [grammars.p8_cart] block in extension.toml references this repo by file:// URL and pins a commit SHA — Zed clones the grammar from that pinned revision, so changes only take effect after they're committed.

  5. Update extension.toml's rev field to the new SHA, then in Zed run zed: install dev extension (or click Install Dev Extension on the Extensions page) and select this directory. Reinstall after every commit that should be picked up.

    Logs: zed: open log. Run zed --foreground for live stdout.

Editing language queries

Files under languages/pico-8-cart/ (highlights.scm, injections.scm, outline.scm) are loaded directly by Zed — no regeneration needed. Reinstall the dev extension to pick up changes.

Roadmap

v0.2 — PICO-8 Lua dialect grammar

Fork tree-sitter-grammars/tree-sitter-lua into tree-sitter-pico8 and add the dialect extensions documented in the PICO-8 manual:

  • Compound-assignment operators: += -= *= /= \= %= ^= ..= &= |= ^^= <<= >>= >>>= <<>= >><=
  • != as alias for ~=
  • \ (integer divide) and the rotate / logical-shift operators <<> >>< >>>
  • Binary literals 0b... and hex fractional literals 0x1.4p0 style
  • Single-line if (cond) stmt and while (cond) stmt ( no then/do/end )
  • ? as a statement-level shorthand for print
  • The peek-prefix unary operators @addr %addr $addr

Then add a second language Pico-8 Lua here (separate from Zed's built-in Lua) and switch injections.scm to inject pico-8-lua instead of lua.

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 .p8 section markers and only analyzes the __lua__ body )
  • Per-cart diagnostics

This will require a Rust component ( the zed_extension_api crate ) to download the language-server binary and define 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-server against their #include-d .lua files.
  • Highlight rules for hex sections (__gfx__, __map__, __sfx__, etc.) so palette indices and note pitches show up distinctly.
  • Snippets for common idioms (for x=0,127 do ... end, the _init/_update/ _draw triad).

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

License

0BSD — see LICENSE.

S
Description
The Pico-8 dialect of Lua for the Zed IDE.
Readme 0BSD 99 KiB
Languages
C 81.1%
C++ 13.6%
JavaScript 3.6%
Tree-sitter Query 1.7%