infinite.pm — VS Code extension
Language support for Infinite Process Modeling (infinite.pm) inside VS Code: ipmt syntax highlighting, hover, diagnostics, semantic colors for event / thing / concept nodes, and embed-on-save that keeps committed SVG diagrams in sync with their source.
Features
- Syntax highlighting for
.ipmt files and for ```ipmt fences inside any Markdown document. Editor pane and markdown preview share the same Go-side tokenizer (ipm-rpc → pkg/ipmtokens), so the two panes paint identical colors token-for-token.
- Fence meta and pragma aware: an ipmt fence can carry meta tokens after the language id (
```ipmt embed=false, ```ipmt unresolved, …), and the first non-empty line of a block can be a # ipmt: pragma. The meta tokens are tolerated so the fence still highlights as ipmt, and the pragma paints as an ordinary ipmt comment. ```ipmt-invalid fences mark deliberate negative examples and are intentionally not highlighted as ipmt. What these selectors mean to the engine is documented in ipm-tools (docs/ipmt-unresolved.md).
- Semantic colors distinguish event (orange), thing (green), and concept (blue) nodes regardless of theme. Edge arrows are bold by SST relation (Leads-to orange, Part-of green, eXpresses blue, Near-to gray);
::e/::t/::c markers are bold; tooltips and relation letters are normal weight. All colors come from the palette source of truth in the ipm-tools repo (pkg/ipmtokens/palette.json) and are code-generated by scripts/gen-palette.ts into src/palette.gen.ts, package.json (editor pane), and media/ipm-preview.css (markdown preview).
- Diagnostics in the Problems panel — parse errors and the IPMV* validation findings from
pkg/ipm/validate.
- Hover documentation for
::e/::t/::c/::a/::tip markers and all arrow forms (-->, <--, ---, --::P-->, etc.).
- Embed on save: saving a
.md file with ipmt blocks triggers the LSP server's ipm.embed command. Committed SVGs under _ipm/ get refreshed; marker hashes update; the markdown preview reloads the new diagrams automatically.
- Include refresh: saving (or otherwise writing) a
.ipmt file re-embeds every Markdown file that pulls it in via <!-- ipm-include -->, scoped to the git repository containing it (falling back to the workspace folder). Dirty buffers are skipped, writes are debounced ~150ms, and the whole path is gated by ipm.embedOnSave — note this writes committed SVGs across the repo, not just the file you saved.
- Live SVG refresh as you type: the LSP's
ipm.embedBuffer renders every ipmt block in the open buffer (in-memory, no disk write) and the preview swaps the rendered <img> for a data: URL until the next save. Gated by ipm.liveRefresh.
- LSP auto-restart when the
ipm-rpc binary file changes — useful while iterating on the server (go install ./cmd/ipm-rpc). Gated by ipm.restartOnBinaryChange.
.ipmt preview pane — clicking the "Open Preview to the Side" icon on a .ipmt file opens a webview that renders the parsed SVG and re-renders as you type. The SVG is rendered in-memory by ipm.embedBuffer and never written to disk — for .ipmt files the source itself IS the graph. The preview supports pan + zoom with the same UX as VS Code's built-in image preview: mouse wheel to zoom centered on the cursor; Ctrl/Cmd + = / - / 0 to step in / step out / reset; click to step zoom (Shift+click for the other direction); drag to pan; a bottom-right zoom indicator that appears while zoomed (click to reset). Vectors stay crisp at every zoom level because the SVG element is resized on each step rather than CSS-scaled. Your zoom/pan persists across debounced edits.
Installation
Releases go to the
infinite-pm publisher
on the Visual Studio Marketplace and to Open VSX (for
VSCodium, Cursor, Windsurf, Gitpod, code-server), plus a GitHub release carrying
one .vsix per platform with SHA256SUMS and build provenance — see
RELEASING.md. Until a version is listed there, get a .vsix one
of two ways:
- From CI — the
package job of every green build uploads one per platform as
a workflow artifact (kept 14 days; needs access to the repo's Actions tab). The
files are target-qualified, e.g. vscode-infinite-pm-linux-x64-0.4.1.vsix.
- Build it yourself — see Development below (needs the sibling
ipm-tools checkout), then npm run package.
Install whichever you obtained:
code --install-extension vscode-infinite-pm-<target>-X.Y.Z.vsix
The extension's LSP features are powered by a Go binary, ipm-rpc, which is
bundled in the published .vsix — there's nothing extra to install.
Each build is platform-specific (linux-amd64, darwin-arm64, …) and ships the
matching ipm-rpc under bin/<os>-<arch>/; the extension uses it automatically.
(If you run multiple VS Code profiles, make sure code points at the one you want — --install-extension lands in whichever profile the resolved code binary targets.)
Bringing your own ipm-rpc (optional — for development against a local build):
set ipm.serverPath to a binary you built, or put one on your PATH with
go install github.com/infinite-pm/ipm-tools/cmd/ipm-rpc@latest. Both override the
bundled copy. Or open this workspace in VS Code, press F5, and run the extension
in a development host.
Workspace trust. The extension declares limited support for restricted
workspaces. Opening an untrusted folder gives you full highlighting (grammars are
static), but the ipm-rpc server is not started and embed-on-save writes nothing —
starting the server spawns an executable, and embedding writes SVGs into your
folder. Trust the folder ("Workspaces: Manage Workspace Trust") and the server
starts immediately, no reload needed. This is also why ipm.serverPath is a
machine-overridable setting: a repository you clone cannot point the extension at
an executable of its choosing.
If no ipm-rpc can be resolved (e.g. an unsupported platform with no bundled
binary and none on PATH), the extension still provides syntax highlighting via its
TextMate grammar — you just don't get the LSP-driven features (diagnostics, hover,
semantic colors, embed-on-save, live refresh, and the .ipmt preview — which
renders an "ipm-rpc not running" banner instead). A one-shot notification explains this when it happens.
Settings
| Setting |
Default |
Meaning |
ipm.serverPath |
"" |
Path to the ipm-rpc binary. (machine-overridable: settable per user or per remote machine, never by a workspace.) If empty, the extension searches PATH for ipm-rpc; if still not found, falls back to the ipm-rpc bundled in the extension's bin/<os>-<arch>/ directory. |
ipm.embedOnSave |
true |
When you save a .md file with ipmt blocks, refresh the committed SVGs and marker hashes via ipm.embed. |
ipm.embedDebounceMs |
0 |
Debounce period before embed-on-save fires. 0 = no debounce; embed runs on every save. Raise to e.g. 800 if you save rapidly during editing. |
ipm.liveRefresh |
true |
Refresh ipmt diagrams in the markdown preview as you type (no save needed). Renders are in-memory via ipm.embedBuffer; the on-disk SVGs are untouched until you save and ipm.embed runs. |
ipm.liveRefreshDebounceMs |
300 |
Idle time (ms) after the last keystroke before live-refresh fires. 0 = re-render on every change (heavier). |
ipm.restartOnBinaryChange |
true |
Watch the resolved ipm-rpc binary path; auto-restart the LSP client when the binary file changes (e.g. after go install ./cmd/ipm-rpc). Disable if your platform's fs.watch gives spurious events. |
Commands
| Command palette entry |
What it does |
| infinite.pm: Restart Language Server |
Stops the LSP client and starts it again (re-reading the configured ipm-rpc binary). |
| infinite.pm: Show Server Info (path + version) |
Shows the resolved binary path, its --version output, and the current LSP connection state via a notification + the output channel. |
| infinite.pm: Open Preview |
(.ipmt files only) Replaces the active source pane with a webview rendering the SVG. The source tab is closed; click "Show Source" to bring it back. Icon: a bundled SVG (media/preview-{light,dark}.svg) modelled on markdown's in-place preview icon. |
| infinite.pm: Open Preview to the Side |
(.ipmt files only) Same as above but opens beside the source pane — both stay visible. Icon: $(open-preview) (same codicon markdown uses for side preview). |
| infinite.pm: Reopen as source file |
(visible only when an ipmt preview is the active panel) Flips back from the preview to the source text document in the same column; the preview tab is closed. Title + icon ($(file-code)) mirror VS Code Insiders' current "back to source" action. |
| infinite.pm: Force Re-embed Current File |
(markdown files only) Runs ipm.embed on the active .md file immediately, regardless of the ipm.embedOnSave setting — refreshes its committed SVGs and marker hashes on demand. The file is saved first if dirty (ipm.embed reads from disk); invoked from a focused markdown preview it targets the most recently active markdown file. |
| infinite.pm: Force Re-embed All Markdown Files in Workspace |
Runs ipm.embed across every markdown file in the workspace (excluding node_modules), refreshing all committed SVGs and marker hashes. Asks for confirmation first, then runs under a cancellable progress notification. |
| infinite.pm: Force Re-embed All Markdown Files in Current Repo |
Like the workspace command — same confirmation and cancellable progress — but scoped to the git repository containing the active editor. |
| infinite.pm: Copy Path |
(ipmt preview panel only) Copies the absolute path of the source .ipmt file to the clipboard. Also on the preview's title bar / context menu. |
| infinite.pm: Copy Relative Path |
(ipmt preview panel only) Copies the workspace-relative path of the source .ipmt file. Also on the preview's title bar / context menu. |
| infinite.pm: Reveal in Explorer View |
(ipmt preview panel only) Reveals the source .ipmt file in the Explorer. Also on the preview's title bar / context menu. |
The editor title bar of a .ipmt file shows two distinct preview icons (in-place + side-by-side); the preview pane shows the "back to source" icon. The icons + behavior mirror VS Code's markdown preview UX so muscle memory carries over.
What gets contributed to VS Code
- A new language:
ipmt (file extension .ipmt).
- Two TextMate grammars: one for standalone
.ipmt files, one for markdown injection. (These are the cold-start fallback when ipm-rpc isn't running; once the LSP is up, semantic tokens take over.)
- 10 custom semantic token types:
ipmEvent, ipmThing, ipmConcept, ipmRelation, ipmArrow, ipmTypeMarker, ipmComment, ipmString, ipmTooltip, ipmUnresolved.
- 7 token modifiers:
alias, hasAlias, marker, leadsTo, partOf, expresses, nearTo.
- Default color customizations (generated from the ipm-tools palette): event=orange, thing=green, concept=blue, arrows bold, kind markers bold, tooltips yellow italic.
- An LSP client that connects to
ipm-rpc.
- A
workspace.onDidSaveTextDocument listener that runs ipm.embed for saved markdown files (gated by ipm.embedOnSave).
- A live-refresh listener (onChange / onOpen / activation-time scan) that calls
ipm.embedBuffer to paint in-memory SVG data URLs into the markdown preview before save (gated by ipm.liveRefresh).
- A markdown-it fence-renderer override that uses LSP-emitted tokens (piggybacked on each
ipm.embedBuffer response) to paint ipmt code blocks in the markdown preview with the exact same palette as the editor pane.
Development
Building from source requires a checkout of
ipm-tools next to this repo
(../ipm-tools) — the palette codegen reads its source of truth from there
(see below).
npm install
npm run gen-palette # regenerate from ../ipm-tools/pkg/ipmtokens/palette.json
npm run gen-palette:check # CI guard — exits non-zero on drift
npm run build # webpack production bundle (runs gen-palette:check first)
npm run watch # auto-rebuild on changes
npm test # node:test + tsx against the in-tree unit tests (runs gen-palette:check first)
npm run package # produce the .vsix (warns if bin/<goos>-<goarch>/ipm-rpc is absent,
# in which case the vsix relies on PATH / ipm.serverPath)
npm run ci # local equivalent of the CI pipeline
Press F5 from VS Code to launch a development host with the extension loaded.
The token palette's single source of truth lives in the ipm-tools repo at pkg/ipmtokens/palette.json. scripts/gen-palette.ts reads it (from the sibling ../ipm-tools) and generates src/palette.gen.ts, the editor.semanticTokenColorCustomizations.rules in package.json, and the .ipm-* classes in media/ipm-preview.css. The drift check (gen-palette:check) runs before every build and test, so editing a generated file or the palette without regenerating is caught immediately. To change colors, edit palette.json in ipm-tools and run npm run gen-palette.
- ipm-tools —
ipm-rpc language server, md-embed CLI, ipmt parser, SVG renderer, validator.
- ipm-intro — newcomer documentation for the modeling notation.
- infinite.pm — the project.
Replaces vscode-ipm-preview
This extension supersedes the older vscode-ipm-preview. If you used it: uninstall the old extension and migrate any custom settings under ipm-preview.* to their ipm.* equivalents.
Authors & credits
Created and maintained by mj41, spec-driven / "vibe-coded"
with help from Claude (Opus) and other AI coding agents. See AUTHORS.md.
License
See LICENSE.