Editor setup — LSP, formatter, linter #
One command installs everything for the editors it detects:
./tools/setup-editors.sh # all detected editors
./tools/setup-editors.sh --nvim # Neovim/Vim only
./tools/setup-editors.sh --vscode # VS Code / Cursor only
./tools/setup-editors.sh --emacs # Emacs only
The script first builds a ReleaseFast binary (zig build -Doptimize=ReleaseFast)
and installs editor files from editors/. It is idempotent — safe to re-run
after every git pull so the installed binary always matches your checkout.
Re-running it also migrates away any config left behind by older versions
(stale Neovim after/ftplugin/rinne.lua files are removed automatically).
Language server features (rinne lsp) #
The server speaks JSON-RPC over stdio and reuses the real compiler
pipeline, so diagnostics are exactly what rinne run would report.
| Capability | What you get |
|---|---|
| Diagnostics | Parse and compile errors on open/change (full sync), published after a short typing settle window. Ranges land on the real error line/column and extend to the end of the offending token — never a false underline of line 1. |
| Hover | Docs for ~48 builtins (len, push, json_parse, tcp_listen, llm_load, …), including namespace calls like std.print. |
| Completion | Keywords, all builtins with snippet insertions, plus document-local fn/const/var declarations. Trigger character . filters module members (std./ai./llm./net./c.) to imported namespaces. |
| Formatting | textDocument/formatting runs the same formatter as rinne fmt, in-process — no shell-outs. |
| Document symbols | Flat symbol list for the outline: functions, constants, variables. |
| Definition | Same-file go-to-definition for top-level declarations. |
What gets installed where #
| Editor | Files |
|---|---|
| Neovim / Vim | ~/.config/nvim/{lua/rinne,ftplugin,plugin,ftdetect,syntax,indent,queries,snippets} + tree-sitter parser |
| VS Code | packaged .vsix via vsce + code --install-extension (falls back to opening the folder) |
| Cursor | copied to ~/.cursor/extensions/rinne-vscode |
| Emacs | ~/.emacs.d/lisp/{rinne-mode.el,rinne-setup.el} |
Neovim #
The plugin uses Neovim's built-in LSP framework (requires nvim ≥ 0.11) and no third-party LSP manager:
lua/rinne/init.luaregisters the server viavim.lsp.config['rinne'](cmd = {bin, "lsp"},filetypes = {"rinne"},root_markers = {"build.zig.zon", ".git"}) and enables it withvim.lsp.enable.- Binary resolution order:
require("rinne").setup({ bin = ... })override →vim.g.rinne_path→rinneon$PATH.
Keymaps (set in ftplugin/rinne.lua for .rg buffers):
K— hover docsgd— go-to-definition (same file)<leader>lf— format buffer via LSP
Format-on-save is on by default (vim.g.rinne_fmt_on_save ~= 0) and runs
through the LSP capability in a BufWritePre autocmd — mirroring how the
official zig.vim gates g:zig_fmt_autosave. Disable it with:
vim.g.rinne_fmt_on_save = 0
lazy.nvim / manual install #
Point your plugin manager at this repo's editors/nvim directory:
{
dir = vim.fn.stdpath("config") .. "/rinne-nvim", -- or a git URL once hosted
ft = "rinne",
config = function() require("rinne").setup() end,
}
Or without a plugin manager, run tools/setup-editors.sh --nvim, which copies
the same layout into ~/.config/nvim/ site directories.
Verify the attachment with :checkhealth vim.lsp while a .rg file is open.
Vim (no LSP) #
Syntax, indentation, ftdetect and snippets work in plain Vim too; only the LSP-backed features need Neovim ≥ 0.11.
VS Code / Cursor #
Install the extension (script handles it). Grammar + language configuration
ship in editors/vscode/; manual route: npm i -g @vscode/vsce, then
cd editors/vscode && vsce package && code --install-extension *.vsix.
Formatting is exposed through the same LSP capability — bind
editor.action.formatDocument or enable format-on-save.
Emacs #
rinne-setup.el registers rinne-mode, wires eglot:
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs '(rinne-mode . ("~/path/to/rinne" "lsp"))))
and adds a before-save-hook that formats .rg buffers.
Formatter CLI (rinne fmt) #
rinne fmt FILE # format in place (comment-preserving, idempotent)
rinne fmt --check FILE # exit 1 + "would be reformatted" when dirty
The editor paths above all use the identical formatter core, so CLI and LSP output can never disagree.
Linter (rinne lint) #
rinne lint src/**/*.rg # warnings, never errors (exit 0)
Checks: unused variables, unused function parameters, unreachable code after
return/break/continue.
Performance #
Build ReleaseFast for daily editor use — the server is a compiled binary with zero runtime dependencies, and every JSON-RPC message is handled from a reset arena allocator, so memory stays flat across long sessions:
zig build -Doptimize=ReleaseFast
(tools/setup-editors.sh does this for you.)
Troubleshooting #
- LSP diagnostics stale after pulling new commits — re-run
tools/setup-editors.sh; the installed config points at the freshly built binary. - No completions/hover — make sure the file has an
.rgextension so the server attaches (ftdetecthandles this in nvim), then check:checkhealth vim.lsp. - Server won't start on nvim < 0.11 — the plugin targets the native
vim.lsp.config/vim.lsp.enableAPIs; upgrade or use an eglot-based setup (see Emacs section). fmt --checkfails in CI but passes locally — your local binary differs from CI's; both must be built from the same commit.