Prepare for Zed extension registry submission - #1
Merged
Conversation
Zed's extension builder compiles extensions with wasm32-wasip2 (see crates/extension/src/extension_builder.rs), not wasip1, so the local and CI "does the extension still compile" check was exercising a target Zed no longer builds with.
uri_of_path escaped every byte outside the unreserved set, but LSP clients (Zed via the url crate) leave sub-delims and ":@" alone. For a file whose name contains one of them — "Q1(2026).taskpaper", "work+home.taskpaper" — our URI string differed from the client's for the same file. Documents are keyed by URI string, so the two spellings looked like two documents. In a workspace-wide tag rename that meant the open buffer's edits and the same file's on-disk edits were emitted under both keys and both applied, the second set against ranges the first had already shifted. It also left a stale duplicate in the diagnostics panel.
We ship taskpaper-ls binaries for two Windows targets, but the URI helpers were POSIX-only: path_of_uri turned "file:///C:/Users/..." into "/C:/Users/...", and uri_of_path split on "/" only, so a "C:\..." path became a single percent-encoded segment. The workspace index is built from the root URI, so on Windows it came back empty: no cross-file diagnostics, no project symbols, no workspace-wide tag rename, no usage counts in tag completion. Per-buffer features were unaffected, which is why it degraded quietly. Handle the drive-letter path and the UNC authority form, and split on both separators when building a URI. The "\" separator stays Windows-only since it is a legal filename character elsewhere.
The README is the extension's listing page, so it can no longer open with "not yet on the Zed extension registry" and dev-extension install steps. Lead with registry install, spell out the binary resolution order (including that the language server is downloaded from GitHub releases on first use, and that everything else works without it), and keep the checkout instructions as the fallback. Also note once that shortcuts are written for macOS, and fix the keymap snippet: Zed's keymap file is an array of context blocks.
tree-sitter.json's metadata.version lands in generated parser.c as .metadata.patch_version, so keeping it in lockstep made every release a grammar change: regenerate, push, re-pin [grammars.taskpaper] commit, push again, then tag. The grammar is pinned by commit, so the lockstep bought nothing. Bump it only when the grammar itself changes. Also document the zed-industries/extensions submission flow, since the version in that repo's extensions.toml has to match extension.toml at the submitted commit.
Covers the unreleased highlighting fix (notes under a done task keep the comment style; a done project's name stays bold) plus the fixes on this branch. The registry entry's version must match extension.toml at the submitted commit, so the submission points here rather than at v0.3.3. tree-sitter.json stays at 0.3.3: the grammar is unchanged, so the pin in extension.toml stands.
There was a problem hiding this comment.
Pull request overview
Prepares the TaskPaper Zed extension for registry submission by aligning build tooling with Zed’s current WASM target, fixing file-URI/path handling (incl. Windows + escaping consistency), and updating release/versioning and documentation to match the intended publish flow.
Changes:
- Switch extension WASM build target from
wasm32-wasip1towasm32-wasip2in bootstrap scripts, pixi tasks, and CI. - Rework
file://URI ⇄ native path conversion to match client escaping behavior and correctly support Windows drive-letter and UNC paths (plus new tests). - Update README and maintainer/versioning guidance for registry submission and release tagging.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| scripts/bootstrap-rust.sh | Installs the wasm32-wasip2 target used by Zed’s extension builder. |
| README.md | Updates install/usage docs for registry-first flow and clarifies LS binary resolution. |
| pixi.toml | Bumps version and updates the local/CI “build wasm” check to wasm32-wasip2. |
| MAINTAINER.md | Revises versioning guidance (decoupling tree-sitter metadata) and documents registry submission steps. |
| extension.toml | Bumps extension version to 0.3.4. |
| crates/taskpaper-ls/src/workspace.rs | Fixes URI escaping + Windows drive/UNC handling; adds round-trip tests. |
| crates/taskpaper-ls/Cargo.toml | Bumps crate version to 0.3.4. |
| Cargo.toml | Bumps root package version to 0.3.4. |
| Cargo.lock | Updates locked package versions for 0.3.4. |
| .github/workflows/ci.yml | Updates installed wasm target to wasm32-wasip2 for Linux/macOS CI jobs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Review asked why "^" and "\" are not escaped. They are not in the url crate's path set, so escaping them would create the very mismatch the previous commit removed. What actually happens is narrower and worth recording: WHATWG allows characters RFC 3986 forbids, lsp_types::Uri is RFC 3986-strict, so those names have no URI spelling both ends agree on and uri_of_path returns None. Callers already skip such files.
Every handler reached its params through `extract(...)?`, so a message
whose params failed to deserialize propagated out of main_loop and exited
the process. That is reachable, not theoretical: a .taskpaper file whose
name holds a character RFC 3986 forbids ("a^b.taskpaper") gets a URI that
lsp_types::Uri rejects, so opening it killed the server rather than
skipping the file. The same applied to a workspace root such as
"notes[2026]", via initialize.
Requests now answer InvalidParams to the request's id, notifications log
and drop (there is no id to answer), and unparseable initialize params
cost the workspace root instead of the session. The rename handler's
own invalid-tag-name error folds into the same path.
The regression test drives main_loop over an in-memory connection: it
fails on the previous commit with RecvError, the channel having gone away
with the server.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Independent review pass ahead of submitting to the Zed extension registry, plus the fixes it turned up. Six atomic commits.
What was already fine
extension.tomlhas every required field;id = "taskpaper"is unclaimed in the registry and contains nozed/extensionsubstring;commitis an accepted alias forrev; MITLICENSEsits at the repo root (mandatory since Oct 2025); the language server is downloaded rather than shipped;zed_extension_api = "0.7.0"is current;grammars/andtarget/are gitignored; the grammar pin is pushed and the grammar is unchanged since it.Fixes
wasm32-wasip2— Zed's extension builder compiles with wasip2 (crates/extension/src/extension_builder.rs:29), so the pre-publish "does it still compile" check inpixi.toml/CI was exercising a target Zed no longer uses. Verified locally that the exact command Zed runs (cargo build --release --target wasm32-wasip2at the repo root) builds only the root package and landszed_taskpaper.wasmwhere the builder looks for it.URI escaping —
uri_of_pathescaped everything outside the unreserved set; clients (Zed via theurlcrate) leave sub-delims and:@alone. ForQ1(2026).taskpaperorwork+home.taskpaperour URI string differed from Zed's for the same file. Documents are keyed by URI string, so a workspace-wide tag rename emitted the open buffer's edits and the same file's on-disk edits under two keys — both applied, the second against ranges the first had already shifted.Windows paths — we ship binaries for two Windows targets, but
path_of_uriturnedfile:///C:/Users/...into/C:/Users/...anduri_of_pathsplit on/only. The workspace index is built from the root URI, so on Windows it came back empty: no cross-file diagnostics, no project symbols, no workspace rename, no completion usage counts. Per-buffer features were unaffected, which is why it degraded quietly. Drive-letter and UNC forms both handled now;\stays a separator only on Windows since it is a legal filename character elsewhere.README — it is the registry listing page, so it can no longer open with "not yet on the Zed extension registry". Registry install first, explicit binary-resolution order (including the GitHub-releases download on first use and that everything else works without it), checkout instructions as fallback, one note that shortcuts are macOS-flavoured, and the keymap snippet fixed to be an array of context blocks.
Versioning —
tree-sitter.json'smetadata.versionlands in generatedparser.cas.metadata.patch_version, so keeping it in lockstep made every release a grammar change (regenerate, push, re-pin, push, tag). The grammar is pinned by commit, so the lockstep bought nothing. It now moves only when the grammar does;0.3.4is a one-commit bump with no re-pin. MAINTAINER.md also gains thezed-industries/extensionssubmission flow.Verification
pixi run cigreen (25/25 corpus, 24 Rust tests, clippy-D warnings, both builds). The Windows-gated code and its two tests type-check undercargo check --target x86_64-pc-windows-msvc --workspace --all-targets, but thePathBufround-trip assertions only run on the Windows CI job — that is the check to watch here.Reviewed, not changed
.taskpaperfile a second time inpublish_workspace_diagnostics; both run before the main loop, so a large repo delays the first responses. Depth caps at 8 and symlinks are followed.Indexnever drops files deleted on disk; nodidChangeWatchedFilesregistration.handle_requestpropagates a params-deserialize failure out ofmain_loop, exiting the server.textEdit, so withword_characters = ["@", "-"]the replace range is client-derived.scanner.c:callocinexternal_scanner_createis not null-checked.After merge
git tag v0.3.4 && git push origin v0.3.4so the release assets exist, then open thezed-industries/extensionsPR against this commit withversion = "0.3.4".