Tooling and Editor Integration
mino's tooling is three independent, composable pieces. Each speaks a standard protocol. Each works standalone. Use any combination.
| Tool | What | Protocol |
|---|---|---|
| tree-sitter-mino | Syntax highlighting, brackets, folding | tree-sitter |
| mino-lsp | Diagnostics, completion, hover | LSP (JSON-RPC over stdio) |
| mino-nrepl | Interactive eval, REPL | nREPL (bencode over TCP) |
No mino-specific client code is needed. Any editor that supports tree-sitter, LSP, or nREPL can use the corresponding tool directly.
Syntax Highlighting
tree-sitter-mino is a tree-sitter grammar for mino. It provides syntax highlighting, bracket matching, structural navigation, and code folding in any editor that supports tree-sitter.
Neovim
Add mino to your nvim-treesitter configuration:
local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
parser_config.mino = {
install_info = {
url = "https://github.com/leifericf/tree-sitter-mino",
files = { "src/parser.c" },
branch = "main",
},
filetype = "mino",
}
vim.filetype.add({ extension = { mino = "mino" } })Then run :TSInstall mino.
Helix
Add to ~/.config/helix/languages.toml:
[[language]]
name = "mino"
scope = "source.mino"
file-types = ["mino"]
comment-token = ";"
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "mino"
source = { git = "https://github.com/leifericf/tree-sitter-mino", rev = "main" }Then run hx --grammar fetch && hx --grammar build.
Emacs (29+)
(add-to-list 'treesit-language-source-alist
'(mino "https://github.com/leifericf/tree-sitter-mino"))
(treesit-install-language-grammar 'mino)Zed
Create a language extension or add mino to your settings with the grammar pointed at the tree-sitter-mino repository.
Structural Editing
Paredit and parinfer work out of the box with mino files. mino uses standard balanced brackets (), [], and {}, so every editor's structural editing support applies without any additional configuration.
mino-lsp
mino-lsp is a Language Server Protocol server for mino. It provides real-time diagnostics, symbol completion, and hover documentation. It is a small C program that links against mino.c and communicates over stdin/stdout using JSON-RPC. No runtime dependencies beyond mino itself.
Features
| Feature | Description |
|---|---|
| Diagnostics | Parse and eval errors shown inline as you type. |
| Completion | Symbol suggestions filtered by prefix. |
| Hover | Type and docstring for the symbol under the cursor. |
Build
git clone --recursive https://github.com/leifericf/mino-lsp.git
cd mino-lsp
makeThis produces a single mino-lsp binary.
Editor Setup
Neovim (nvim-lspconfig)
local configs = require("lspconfig.configs")
configs.mino = {
default_config = {
cmd = { "mino-lsp" },
filetypes = { "mino" },
root_dir = function(fname)
return vim.fs.dirname(fname)
end,
},
}
require("lspconfig").mino.setup({})Helix
Add to ~/.config/helix/languages.toml:
[language-server.mino-lsp]
command = "mino-lsp"
[[language]]
name = "mino"
language-servers = ["mino-lsp"]Emacs (eglot)
(add-to-list 'eglot-server-programs '(mino-mode "mino-lsp"))VS Code
Install a generic LSP client extension and point it at the mino-lsp binary.
Zed
Add mino-lsp as the language server in a mino language extension.
mino-nrepl
mino-nrepl is a standalone nREPL server for mino. It is a small C program that links against mino.c and implements the nREPL wire protocol (bencode over TCP). No JVM, no runtime dependencies beyond mino itself.
Build
git clone --recursive https://github.com/leifericf/mino-nrepl.git
cd mino-nrepl
makeThis produces a single mino-nrepl binary.
Run
cd your-project/
mino-nrepl # random port, written to .nrepl-port
mino-nrepl --port 7888 # fixed portThe server writes a .nrepl-port file to the current directory on startup and removes it on shutdown. Editors that support nREPL auto-detect this file.
Editor Setup
Conjure (Neovim)
Conjure auto-connects when it finds .nrepl-port in the project directory. Start mino-nrepl, open a file, and evaluate with <localleader>ee (current form) or <localleader>eb (current buffer).
vim-fireplace (Vim)
vim-fireplace reads .nrepl-port automatically. Evaluate the innermost form with cpp or a visual selection with cp.
CIDER (Emacs)
Run M-x cider-connect-clj, enter localhost and the port number. Basic eval, completion, and inline results work out of the box. Advanced features that depend on cider-nrepl middleware are not available.
Calva (VS Code)
Open the Command Palette and choose Calva: Connect to a Running REPL Server. Select Generic as the project type, then enter the host and port.
Cursive (IntelliJ)
Go to Run > Edit Configurations > + > Remote REPL. Set the host and port, then connect. Cursive will use the nREPL connection for evaluation.
Supported Operations
mino-nrepl implements the following nREPL operations:
| Op | Description |
|---|---|
clone | Create a new session. |
close | Close a session. |
describe | List server capabilities. |
eval | Evaluate code in a session. |
completions | Symbol completion by prefix. |
load-file | Evaluate file contents. |
ls-sessions | List active sessions. |
Guide for Tools Developers
If you are building editor plugins, developer tools, or integrations that work with mino, two standard protocols give you ready-made communication layers. You do not need to parse mino output or invent a custom protocol.
LSP (mino-lsp)
mino-lsp speaks standard LSP over stdin/stdout. Launch the mino-lsp binary as a subprocess, send JSON-RPC 2.0 messages with Content-Length framing, and receive responses on stdout. Any LSP client library works without modification.
Supported methods: initialize, textDocument/didOpen, textDocument/didChange, textDocument/didClose, textDocument/completion, textDocument/hover.
The server pushes textDocument/publishDiagnostics notifications whenever a document is opened or changed.
nREPL (mino-nrepl)
Connecting
Connect a TCP socket to the host and port. If .nrepl-port exists in the project directory, read it to discover the port number. The server listens on 127.0.0.1 by default.
Wire format
All messages are bencode dictionaries. Bencode is a simple binary format with four types:
| Type | Encoding | Example |
|---|---|---|
| String | length : data | 5:hello |
| Integer | i number e | i42e |
| List | l items e | l5:helloi42ee |
| Dictionary | d key/value pairs e | d3:foo3:bare |
Many languages have bencode libraries. A minimal encoder and decoder is roughly 50 lines in most languages.
Message structure
Every request is a bencode dictionary with at least an "op" field. Most ops also require "id" (for correlating responses) and "session" (from a prior clone).
Every response includes "status", a list that always contains "done" when the operation is complete.
Typical session lifecycle
1. Connect TCP socket to server
2. Send: {"op" "clone" "id" "1"}
Recv: {"id" "1" "new-session" "<uuid>" "status" ["done"]}
3. Send: {"op" "eval" "id" "2" "session" "<uuid>" "code" "(+ 1 2)"}
Recv: {"id" "2" "session" "<uuid>" "ns" "user" "value" "3" "status" ["done"]}
4. Send: {"op" "close" "id" "3" "session" "<uuid>"}
Recv: {"id" "3" "session" "<uuid>" "status" ["done"]}
5. DisconnectEvaluating code
Send an eval op with a "code" field containing the mino source. The server responds with:
- On success: a
"value"field containing the printed result, plus"ns"set to"user". - On error: an
"err"field with the error message and"status"containing"error".
If the evaluated code produces side-effect output (via println or prn), the server sends a separate message with an "out" field before the result message.
Completions
Send a completions op with a "prefix" field. The server returns a "completions" list of dictionaries, each with a "candidate" field:
Send: {"op" "completions" "id" "4" "prefix" "ma" "session" "<uuid>"}
Recv: {"id" "4" "completions" [{"candidate" "map"}
{"candidate" "map?"}
{"candidate" "macroexpand"}
{"candidate" "macroexpand-1"}]
"status" ["done"]}Existing nREPL client libraries
Most languages already have nREPL client libraries that handle bencode and the message protocol for you:
- Python: nrepl-python-client
- JavaScript/TypeScript: nrepl-client
- Go: nrepl/bencode + TCP socket
- Emacs Lisp: built into CIDER
- Vim script / Lua: built into Conjure and vim-fireplace
Using one of these libraries, connecting to mino-nrepl is identical to connecting to any other nREPL server. No mino-specific client code is needed.
Source
The full source for mino-nrepl is at github.com/leifericf/mino-nrepl. It is roughly 1,400 lines of C99 with no dependencies beyond mino itself.