Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

Editor setup

Harn ships a capable language server, harn-lsp, that powers diagnostics, completions, go-to-definition, hover, rename, formatting, and code actions. The install script puts harn-lsp on your PATH alongside harn and harn-dap, so any editor with a generic LSP client can light up Harn support by pointing at that one binary.

harn-lsp takes no arguments and speaks the Language Server Protocol over stdin/stdout. Every editor below launches it the same way — harn-lsp with no flags — and maps the .harn file extension to the harn language id.

For the full capability matrix (every LSP feature, the DAP debugger, and the tree-sitter grammar) see Editor integration.

VS Code#

The bundled extension in editors/vscode/ adds syntax highlighting, snippets, the language server, the debugger, and Harn commands. Install it from source until a registry release is available.

Install the extension from source#

Install the Harn toolchain first. Then clone the Harn repository, build a VSIX package, and install it:

git clone https://github.com/burin-labs/harn.git
cd harn/editors/vscode
npm ci
npm run compile
npx @vscode/vsce package --out harn-lang.vsix
code --install-extension harn-lang.vsix

You can instead run Extensions: Install from VSIX... from the command palette and select harn-lang.vsix.

The extension starts harn-lsp from your PATH by default. Set harn.lspPath in your settings if the binary lives somewhere else.

Format on save#

The extension formats .harn files and applies Harn autofixes when you save. It doesn't change save behavior for other languages. To make those settings explicit or restore them after a workspace override, add this block to your VS Code settings.json:

{
  "[harn]": {
    "editor.defaultFormatter": "burin-labs.harn-lang",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll.harn": "always"
    }
  }
}

Open a .harn file and run Format Document With... once. Select Harn Language if VS Code asks you to choose a formatter. Change the file's spacing and save it. The extension should reformat the file. If Harn reports an autofix, saving should apply it.

If formatting does not run, open View: Output, select Harn Language Server, and confirm that harn-lsp started. Set harn.lspPath to the full binary path when VS Code cannot find it through PATH.

Cursor and other VS Code forks#

Build the VSIX with the commands above. Install it with cursor --install-extension harn-lang.vsix, or use Extensions: Install from VSIX... from the command palette. The same format-on-save settings work in Cursor.

.harn.prompt files#

Files ending in .harn.prompt or .prompt open as Harn Prompt templates. The extension gives them:

  • Highlighting for directives ({{ if }}, {{ for }}, {{ include }}, {{ section }}, {{ raw }}), {{# comments #}}, literals, filters, and the built-in section names.
  • Folding for {{ if }} / {{ for }} / {{ section }} / {{ raw }} blocks and their matching {{ end }} / {{ endsection }} / {{ endraw }}.
  • {{}} auto-closing and surrounding, plus {{# / #}} as the comment pair so Toggle Comment works inside a template.

The keyword, filter, and section vocabulary in that grammar is generated from the runtime's template engine, so the editor accepts exactly what harness.fs.render_prompt(...) does. Contributors changing the template language should edit crates/harn-vm/src/stdlib/template/vocabulary.rs and run make gen-prompt-grammar rather than hand-editing the grammar; CI fails on drift.

Neovim#

Neovim's built-in LSP client (0.11+) can start harn-lsp directly. First register the .harn filetype, then configure and enable the server. Add this to your config (for example ~/.config/nvim/init.lua):

-- Map the .harn extension to a `harn` filetype.
vim.filetype.add({ extension = { harn = "harn" } })

-- Configure the Harn language server (harn-lsp must be on your PATH).
vim.lsp.config("harn", {
  cmd = { "harn-lsp" },
  filetypes = { "harn" },
  root_markers = { "harn.toml", ".git" },
})
vim.lsp.enable("harn")

On older Neovim releases that ship nvim-lspconfig, the equivalent is:

vim.filetype.add({ extension = { harn = "harn" } })

local configs = require("lspconfig.configs")
local lspconfig = require("lspconfig")
if not configs.harn then
  configs.harn = {
    default_config = {
      cmd = { "harn-lsp" },
      filetypes = { "harn" },
      root_dir = lspconfig.util.root_pattern("harn.toml", ".git"),
    },
  }
end
lspconfig.harn.setup({})

Open any .harn file and run :LspInfo (or :checkhealth lsp) to confirm the harn client attached. Diagnostics, gd (go-to-definition), K (hover), and vim.lsp.buf.format() will all work through harn-lsp.

Zed#

Zed configures external language servers through its settings.json (Zed → Settings, or ~/.config/zed/settings.json). Map the .harn extension to a language and register harn-lsp as its server:

{
  "file_types": {
    "Harn": ["harn"]
  },
  "lsp": {
    "harn-lsp": {
      "binary": {
        "path": "harn-lsp",
        "arguments": []
      }
    }
  },
  "languages": {
    "Harn": {
      "language_servers": ["harn-lsp"]
    }
  }
}

Zed resolves a bare path against your PATH, so the installed harn-lsp binary is picked up with no absolute path. Reopen a .harn file and the Harn language server starts automatically, giving you diagnostics, completions, hover, and go-to-definition.

Other editors#

Any editor with a generic LSP client — Helix, Emacs (eglot/lsp-mode), Sublime Text (LSP), Kate — follows the same recipe: launch harn-lsp with no arguments for .harn files. See Editor integration for the full capability list and the tree-sitter grammar that adds syntax highlighting in tree-sitter-based editors.