Common Lisp development environment for Neovim — LSP + interactive debugger powered by Sextant.
- LSP: completions, go-to-definition, find references, hover, document symbols, semantic tokens, diagnostics
- REPL: evaluate expressions in a live SBCL image from the debug console
- Debugger: condition/restart system mapped to DAP — stack frames, variable inspection, restart invocation
- Single process: LSP and DAP run simultaneously in the same SBCL image, sharing full introspection
Sextant requires SBCL and Quicklisp to build from source.
# Debian/Ubuntu
sudo apt install sbcl
# macOS
brew install sbcl
# Arch
sudo pacman -S sbclcurl -O https://beta.quicklisp.org/quicklisp.lisp
sbcl --load quicklisp.lisp --eval '(quicklisp-quickdist:install :path "~/quicklisp/")' --eval '(ql:add-to-init-file)' --quitgit clone https://github.com/parenworks/sextant.git
cd sextant
make buildThis produces a sextant binary. Either add it to your PATH or pass the path in the plugin config.
Using lazy.nvim:
{
"parenworks/sextant.nvim",
dependencies = {
"neovim/nvim-lspconfig",
"mfussenegger/nvim-dap", -- optional, for debugger/REPL
"rcarriga/nvim-dap-ui", -- optional, for debugger UI
"nvim-neotest/nvim-nio", -- required by nvim-dap-ui
},
ft = "lisp",
opts = {},
}require("sextant").setup({
-- Path to sextant binary (auto-detected if on PATH)
cmd = nil,
-- DAP server port (sextant listens on this for debugger connections)
dap_port = 6009,
-- Filetypes to activate on
filetypes = { "lisp" },
-- Root patterns for project detection
root_patterns = { ".git", "*.asd", "*.asdf" },
})Open any .lisp file — LSP starts automatically.
gd— go to definitiongr— find referencesK— hover documentation<leader>ss— document symbols
| Command | Keymap | Description |
|---|---|---|
:SextantAttach |
<leader>dc |
Attach debugger to live SBCL image |
:SextantLaunch |
Launch current file in debugger | |
:SextantRepl |
Toggle REPL console | |
:SextantDisconnect |
<leader>dx |
Disconnect debugger |
| Keymap | Description |
|---|---|
<leader>db |
Toggle breakpoint |
<leader>dc |
Continue / Start debug session |
<leader>di |
Step into |
<leader>do |
Step over |
<leader>dO |
Step out |
<leader>dr |
Run to cursor |
<leader>ds |
Restart session |
<leader>de |
Eval expression under cursor |
<leader>du |
Toggle DAP UI |
In the debug console (:SextantRepl or :DapToggleRepl):
;; Evaluate any Common Lisp expression
(+ 1 2)
(defun greet (name) (format nil "Hello, ~a!" name))
(greet "world")
;; Load a file into the live image
(load "myproject.lisp")
;; When stopped on an error:
:restarts ;; show available restarts
:restart 0 ;; invoke restart by indexSextant runs as a single SBCL process:
- LSP communicates over stdio (standard Neovim LSP transport)
- DAP listens on a TCP socket (default port 6009)
Both share the same Lisp image, so definitions loaded via the REPL are immediately available to LSP features like go-to-definition and completions.
When a condition (error) is signaled, Sextant's debugger hook intercepts it and sends a DAP stopped event. The DAP UI shows the stack trace, local variables, and available restarts — the full Common Lisp condition/restart system exposed through your editor.
MIT