Repository navigation
vscode: the Activity Bar panel, the verbs, and tests against a real engine - #3
Merged
Merged
Conversation
…checkout The extension appeared in the marketplace pane as `pol`, flagged "invalid extensions detected", offering to Install Locally a thing that was not there. An install made before "rename: pol becomes writ" is a symlink named pol.pol-0.1.0 pointing into a directory the rename took away. VS Code scans its extensions directory, cannot read a manifest through a dangling link, and reports the extension as invalid — naming `pol`, which the user cannot remove from the UI, because there is nothing behind it to uninstall. The entry in extensions.json outlives the directory and is what keeps re-reporting it. install.sh only ever removed writ.writ-0.1.0, so nothing cleaned this up: the rename shipped without a migration path, and every pre-rename install stayed broken and visible. It now purges legacy ids on INSTALL as well as uninstall — the person hitting this is installing the new extension, not remembering an old one — and tests `-e` OR `-L`, because `-e` is false for exactly the dangling case being cleaned. The removal is of the link, never through it, which would delete a live checkout. Underneath that sat a second failure the first one hid. candidates() joined the relative default onto workspace folders only, so the split into separate writ/ and writ-vscode/ repositories broke it: the natural thing to open is the directory holding both, and the default then resolves against a folder with no _build in it. The extension said "no language server" with a perfectly good one a single directory down — the same symptom as never having built it, which sends you off to check the wrong thing entirely. It now also tries checkouts one level below each workspace folder, identified by dune-project rather than by being named `writ`. One level, deliberately: this must not become a walk of the workspace, which on a large tree would cost more than it saves. install.sh had the same blind spot from the other side, looking only at $here/../.. for the engine — which in the split layout is the directory containing both repositories and never the engine itself. It now accepts $WRIT_REPO, ../.., or ../writ. Its verify step no longer pipes into an empty command name when there is no server to verify, which reported a shell error about "" rather than the thing that was actually true. TESTED, because all of this fails silently. test-resolve.js gains the split layout, exercised against a real directory tree: that a checkout one level down is found, that the workspace root still wins, that a sibling which is not a checkout is not guessed at, that the nested build still beats PATH, and that a workspace folder which does not exist is survivable rather than fatal at activation. The legacy purge was checked by recreating the dangling symlink and re-running the installer against it. Also: package-lock.json still called the package politics-constructor, and the run-path comments still named tooling/vscode/, which no longer exists.
…t of the .vsix The grammar's comments said .afk-flow/check-grammar.py asserts the guard, effect and rules-builtin alternations against the engine, and told the reader to keep them as whole ( | ) alternatives so that it could. No such script is in this repository, or in writ's. The word lists are still right — they match `guard_words` and `builtins` in core/syntax/rules_parser.ml, checked by hand here — but a comment promising a check that does not run is worse than no comment at all: it is exactly why nobody notices when the grammar drifts from the engine. The formatting rule stays, now with the reason that is actually true: so the sets can be diffed against that list by eye, and so a word added to the engine is visibly missing here. Only the "comment" fields changed. Every match regex is untouched, so nothing about the highlighting moves. .vscodeignore additionally keeps the tests, install.sh, the lockfile, .mailmap and .github/ out of a .vsix — shipping the installer inside the thing it installs is a loop that can only confuse, and the rest is repository plumbing that is invisible in the source tree and rides along unnoticed. docs/ stays in deliberately, because README.md embeds docs/images/writ-mark-200.png and the marketplace page loses its mark without it, as do LICENSE, NOTICE and AUTHORS, which ship with the work. VERIFIED with vsce rather than reasoned about, which is how .mailmap and .github/ were found at all — nothing else lists them. `vsce package` now yields 340 files, of which exactly fourteen are this extension's: the manifest, the client, the grammar, the language configuration, the icon, the README and its images, and the notices. The other 326 are node_modules and vsce's own two generated manifests.
… step Three things this extension could not do, and one of them was the reason the other two mattered. THE PANEL. The extension bundles no engine and downloads none: it resolves a `writ-lsp` at activation, from a checkout's `_build` or from PATH. Every way that can go wrong produces the same symptom — an editor that highlights and says nothing else — and the causes want different fixes. The extension said one of them once, in a toast, at activation, and then never again. Now there is a place to look: which server, which version, whether the two are in step, and the button for whichever thing is wrong. THE VERBS. writ is a command-line tool that answers questions; the extension exposed none of them. check, show, derive and compare, from the panel, the title bar, the context menus and the palette — each running the `writ` that belongs to the SAME install as the language server, derived from the resolved server rather than looked up on PATH. An editor whose "check this file" disagreed with its own squiggles would be worse than having no command at all. THE VERSION. It lived in three hand-kept copies here and had nothing to do with writ's, which dune generates. install.sh now derives its extension id from the manifest instead of holding one — installing under a stale id lands the new extension beside the old one, both manifests valid, and VS Code loads whichever it scans first. scripts/version.sh checks what is left, and `--from-writ` sets it from a checkout's dune-project. This is worth enforcing now that the panel shows a mismatch: a forgotten bump is a warning on somebody's working install. Staleness is the part no version comparison can reach. writ's version moves only when someone bumps it, so a server built before this morning's edit reports exactly the same version as a current one — the two agree, and the agreement is the misleading half. src/staleness.js compares times instead, and the build is a Task rather than a terminal because only a task reports whether it succeeded, and only a build that succeeded may clear the warning. extension.js is now the wiring; the behaviour is six modules under src/, none of which touches the vscode API outside its own register(). The two existing tests move to test/ and lose their module-loader stubs — nothing needed them once the workspace folders and the restart were arguments — and two new ones join them: the verdict (shown to users as a warning, so being wrong means telling someone their good install is broken) and the manifest (which nothing typechecks: a command contributed but not registered appears in the palette and does nothing). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The other test files check this repository's JavaScript, and none of them would notice the engine changing underneath it. That coupling is the one most likely to break silently: a capability writ-lsp stops advertising, or a flag the CLI renames, leaves the extension running and doing nothing. test/engine.test.js spawns the writ-lsp the extension would find and speaks LSP to it over vscode-jsonrpc (already installed as the client's transport): initialize and its serverInfo, full sync, hover, outline and completion advertised, diagnostics on a good and a broken model, the outline, hover, completion, and shutdown. It then runs every command-line shape src/commands.js builds - check, check --claims, show --at, derive, derive --why, compare - and asserts the CLI accepted each one (exit 0 or 1, never 2). With no writ-lsp, or no node_modules, it prints a skip and passes, so scripts/test.sh still needs nothing installed. WRIT_E2E_REQUIRED=1 turns a skip into a failure; writ's downstream image sets it. Against writ main the two serverInfo checks fail: the server does not send it yet, though engine.js and the panel read it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test: the extension against a real engine
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
What
This brings
activity-bar-paneltomain, which has fallen behind:DEVELOPING.md.scripts/test.shand five plain-node test files, includingtest/engine.test.jsfrom test: the extension against a real engine #2. That test drives the realwrit-lspand runs every command line the verbs build.maincurrently has noscripts/ortest/at all. Until this merges, writ's downstream CI prints a skip for the extension instead of testing it.Merge order
Merge writ-lang/writ#13 first. It makes
writ-lspreportserverInfo. writ's downstream job runs this repository's tests against writmainwithWRIT_E2E_REQUIRED=1, and without #13 the twoserverInfochecks fail. Every writ PR would go red until #13 lands.Verified
scripts/test.shgives manifest 45, resolve 21, status 30 and watcher 8 checks. The engine test skips withoutnode_modulesor a server.🤖 Generated with Claude Code