The language server
cohdl lsp speaks the Language Server Protocol — the JSON-RPC
protocol editors use to talk to compilers — over stdio. It is a thin
frontend over the exact same pipeline cohdl check runs: the same
dependency resolution, the same checks, the same diagnostics. Nothing is
re-implemented for the editor, so the editor and the CLI can never disagree
about whether a design is correct.
-
Diagnostics as you type. On open, change and save, the
server re-checks the file's containing project: it walks up to
cohdl.toml, resolves and lock-verifies every direct dependency, and falls back to single-file-plus-std when there is no manifest. The published diagnostics are field-for-field the onescohdl check --jsonreports — an equivalence test suite holds the two to that. Unsaved edits count: buffer contents override the on-disk file. A project that fails to load — a bad manifest, a broken lock — is reported as a visible editor message, never as a deceptively clean file. -
Hover. Over an
implblock: the resolved pin-to-requirement mappings. Over a pin declaration or use site: its connection obligation and role. Over a unit literal: its unit type and the allowed prefixes. Over a part: its MPN, manufacturer, resolved footprint and reference documents. Over pads, mount holes,useimports,placestatements and physics attributes: the resolved facts of each. - Go to definition. A device, trait, function, part, footprint or pad name at any reference site jumps to its declaration — including declarations that live in a dependency's source. Instance and pin references resolve the same way.
-
Find references. On a trait or device name: every
implinvolving it, across the project and its loaded dependencies.
Beyond those four capabilities the server also offers keyword completion — the contextual grammar words and attribute names. Every request re-runs the full check from scratch; there is no incremental compilation, which is acceptable at the scale of current designs. Code actions, rename, semantic tokens and workspace symbols are deliberately out of scope. The server runs on POSIX hosts.
VS Code
The VS Code extension is thin packaging over the server, and that is the
point: it adds no diagnostics or compiler behavior of its
own. It registers the .cohdl file type, ships a hand-authored
TextMate grammar for syntax color — the one thing the LSP protocol has no
verb for — and spawns cohdl lsp through
vscode-languageclient when the first CoHDL file opens. A
grammar-coverage test in CI asserts that every keyword and literal class gets
a real scope rather than falling through to unstyled text.
There is exactly one setting: cohdl.path, the path to the
cohdl binary. It defaults to cohdl, resolved via
PATH; point it at a workspace build if needed:
{
"cohdl.path": "${workspaceFolder}/target/debug/cohdl"
}
If the binary cannot be started, the extension shows a visible error notification — never a silently blank Problems panel.
The extension is on the
Visual Studio Marketplace
as conol.cohdl — install it from the extensions view, or grab
the plain .vsix attached to each
vscode-v* release. It is only a client for
cohdl lsp, so it needs the compiler installed; if
cohdl is not on VS Code's PATH, point the
cohdl.path setting at the binary.
Any LSP editor
Editors other than VS Code do not need a package at all — a launch
configuration is enough. Point any LSP client at cohdl lsp,
associate the cohdl file type with the .cohdl
extension, and use cohdl.toml as the project-root marker. For a
generic LSP client, the entire configuration is:
{
"command": ["/path/to/cohdl", "lsp"],
"languageId": "cohdl",
"filetypes": ["cohdl"],
"rootPatterns": ["cohdl.toml"]
}
With Neovim's built-in LSP client:
vim.api.nvim_create_autocmd("FileType", {
pattern = "cohdl",
callback = function()
vim.lsp.start({
name = "cohdl",
cmd = { "/path/to/cohdl", "lsp" },
root_dir = vim.fs.dirname(vim.fs.find({ "cohdl.toml" }, { upward = true })[1]),
})
end,
})
vim.filetype.add({ extension = { cohdl = "cohdl" } })
Formatting
CoHDL has exactly one formatter and exactly one canonical form.
cohdl fmt rewrites a file or directory into that form, and
cohdl fmt --check verifies without writing — the usual CI gate.
Because the canonical form is defined by the toolchain rather than by taste,
there are no style options to configure and no formatting debates to have.
The language server does not expose formatting over LSP today, so editors
run the CLI directly: wire cohdl fmt as your editor's external
formatter or as a format-on-save hook.