Haskell Inspector — VS Code extension
Inspect heaps of running Haskell programs from VS Code. The extension
discovers live debuggees (and saved snapshots / eventlogs), then opens
the haskell-inspector
web UI inline in a webview. It also contributes a haskell-inspector
debug type, so the inspector can run as a debug session with VS Code's
Call Stack panel cross-linked to the web view.
Requirements
- The
haskell-inspector binary on PATH, or pointed at via the
haskellInspector.executable / haskellInspector.executables
settings.
- A debuggee instrumented with the
haskell-inspector-connector
library. The connector announces the process by writing a
<pid>-<prog>.desc descriptor file (JSON: connection address, PID,
cwd, executable path) to a conventional directory; the extension
discovers targets by scanning that directory.
Using it
- Activity bar (shown by default): a Haskell Inspector container
with a Targets pane (live processes and snapshots, split into
Project / System) and an Eventlogs pane (workspace
*.eventlog
files plus recently opened files). Click a row to open it. A badge
counts live programs available to inspect.
- Command palette: all commands live under the
Haskell Inspector: category — Show… opens the target picker,
Open Eventlog File… inspects an eventlog post-mortem,
Open Current Inspector in Browser moves the focused inspector tab
into your browser (works over Remote-SSH via VS Code's port
forwarding).
- Editor title button / status bar entry: optional extra entry
points, hidden by default (
haskellInspector.editorTitleButton,
haskellInspector.statusBar).
Debug sessions (DAP)
Add a launch configuration of type haskell-inspector:
{
"type": "haskell-inspector",
"request": "attach",
"name": "Haskell Inspector: attach (auto-discover)",
"descriptor": "auto"
}
With "descriptor": "auto" (or omitted) each F5 attaches to the
freshest live debuggee. A specific target can be pinned by pointing
descriptor at its .desc descriptor file, or snapshot at a
ghc-debug snapshot.
While a session runs, the debug toolbar offers Open Web View for
Debug Session and Start/Stop Sampling buttons; selecting a thread
in the Call Stack panel focuses the same thread in the web view.
Settings
| Setting |
Default |
Description |
haskellInspector.activityBar |
shown |
Show the activity-bar view container. |
haskellInspector.editorTitleButton |
hidden |
Editor-title button behaviour: smart, submenu, picker, or hidden. |
haskellInspector.statusBar |
hidden |
Show a status-bar entry that opens the menu. |
haskellInspector.showAll |
false |
Picker lists every discovered target, not just this workspace's. |
haskellInspector.executable |
haskell-inspector |
Path or PATH-resolved name of the inspector binary. |
haskellInspector.executables |
[] |
List of {name, path, default} binaries; the default: true entry wins. |
haskellInspector.customCss |
(empty) |
CSS file appended after the web UI's stylesheet, passed as --custom-css. |
haskellInspector.descriptorDirectory |
(empty) |
Override the descriptor discovery directory. Empty = standard XDG location. |
haskellInspector.snapshotDirectory |
(empty) |
Override the snapshot discovery directory. |
haskellInspector.socketDirectory |
(empty) |
Override the unix-socket directory swept for orphaned sockets. |
haskellInspector.environment |
{} |
Extra environment variables for the spawned inspector process. |
Path-valued settings support ~, ${HOME}, and ${workspaceFolder}
(first folder; use ${workspaceFolder:name} to address a specific
folder of a multi-root workspace).
Building
npm install
npm run compile
Then press F5 in this folder to launch an Extension Development Host,
or package with vsce package for a .vsix you can
code --install-extension.
Implementation notes
The extension never talks to the debuggee directly. It scans the
conventional discovery directories
($XDG_DATA_HOME/haskell-inspector/{descriptors,snapshots,s};
%APPDATA% on Windows), filters by workspace, then spawns
haskell-inspector --web --port 0 with --descriptor <file>
(--snapshot / --eventlog for files) and reads the OS-assigned port
back from the binary's stdout announcement. The web UI is hosted in a
WebviewPanel whose portMapping lets the inner iframe reach the
spawned server's loopback port. Debug sessions use the same binary
with --with-dap; DAP runs over stdio, so there the web port is read
from a --web-port-file instead of stdout.
On activation the extension also runs a one-shot sweep that removes
stale descriptors, orphaned sockets, and stranded lockfiles left
behind by debuggees that exited uncleanly (mirroring the inspector's
own cleanup policy, for the case where no inspector process is
running).
Remote development (SSH / WSL / Dev Containers)
The extension host runs on the remote machine, so target discovery,
spawning, and the descriptor sweep all happen on the remote
filesystem, and directory-override settings must name remote paths.
The webview reaches the remote server through
vscode.env.asExternalUri, which sets up VS Code's port forwarding
automatically — no manual configuration needed, for the inline view
and for Open Current Inspector in Browser alike.
Multi-root workspaces
All folders of a multi-root workspace participate: a target counts as
"Project" when its working directory or executable is inside any open
folder, eventlog discovery spans every folder, and eventlog rows are
prefixed with their folder name when more than one is open. A bare
${workspaceFolder} in settings means the first folder;
${workspaceFolder:name} addresses a specific one.
Untrusted workspaces
The extension stays fully functional in VS Code's Restricted Mode,
but the settings that choose the executed binary, its environment,
and swept directories are then only honoured from user-level settings
— a workspace-committed .vscode/settings.json cannot make the
extension execute an arbitrary binary or delete files. See
capabilities.untrustedWorkspaces in package.json for the exact
list.