# zed-p8 A Zed extension for the [PICO-8](https://www.lexaloffle.com/pico-8.php) 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: ```sh npx tree-sitter generate ``` 3. Sanity-check on a real cart: ```sh 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`](https://github.com/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`](https://github.com/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](https://zed.dev/docs/extensions/developing-extensions). ### 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`.