Editor Setup (Neovim)
This chapter shows a working Neovim/LazyVim setup for Shape with:
- LSP (
shape-lsp) - Tree-sitter highlighting + foreign language injection (
tree-sitter-shape) - comment support (
//) sogc/comment actions work
1. Install the LSP Binary
Section titled “1. Install the LSP Binary”Option A: cargo (works everywhere)
cargo install shape-lspOption B: Mason (pending registry PR)
:MasonInstall shape-lsp2. Install the Tree-sitter Parser
Section titled “2. Install the Tree-sitter Parser”Option A: Build from source (works now)
cd shape/tree-sitter-shapecc -shared -fPIC -O2 -o parser/shape.so src/parser.c -I srcThis produces shape/tree-sitter-shape/parser/shape.so.
Option B: nvim-treesitter (coming soon — pending upstream PR)
:TSInstall shape3. LazyVim Plugin Config
Section titled “3. LazyVim Plugin Config”Create ~/.config/nvim/lua/plugins/shape.lua:
return { -- tree-sitter-shape: parser/shape.so + queries/shape/{highlights,injections}.scm -- Neovim discovers both automatically via runtimepath. -- Set this to the tree-sitter-shape directory in your Shape checkout. { dir = vim.fn.expand("~/src/shape/tree-sitter-shape"), name = "tree-sitter-shape-local", lazy = false, config = function() vim.filetype.add({ extension = { shape = "shape" } }) vim.treesitter.language.register("shape", "shape") vim.api.nvim_create_autocmd("FileType", { pattern = "shape", callback = function() vim.treesitter.start() end, }) end, },
{ "neovim/nvim-lspconfig", opts = function() vim.lsp.config.shape = { cmd = { "shape-lsp" }, filetypes = { "shape" }, root_markers = { ".git", "shape.toml" }, -- Inlay-hint settings forwarded as initializationOptions. -- Shape-unique categories (e.g. bindingStorageClass) are -- OFF by default; flip to true to opt in. init_options = { shape = { inlayHints = { enable = true, -- bindingStorageClass = { enable = true }, -- Shape-unique opt-in }, }, }, }
vim.lsp.enable("shape")
-- Optional: enable inlay hints globally (Neovim 0.10+) pcall(vim.lsp.inlay_hint.enable, true) end, },
{ "nvim-treesitter/nvim-treesitter", opts = function(_, opts) -- Ensure Python parser is installed for foreign block injection opts.ensure_installed = opts.ensure_installed or {} if not vim.tbl_contains(opts.ensure_installed, "python") then table.insert(opts.ensure_installed, "python") end end, },
{ "numToStr/Comment.nvim", opts = {}, init = function() vim.api.nvim_create_autocmd("FileType", { pattern = "shape", callback = function() -- Fixes: "Option 'commentstring' is empty" vim.bo.commentstring = "// %s" end, }) end, },}Adjust the dir path to point to tree-sitter-shape in your local Shape checkout.
4. How It Works
Section titled “4. How It Works”The tree-sitter-shape directory is added to Neovim’s runtimepath. Neovim discovers:
parser/shape.so— the compiled parser (you build this yourself)queries/shape/highlights.scm— Shape syntax highlightingqueries/shape/injections.scm— foreign language injection (Python, etc.)
The injection query is generic — it reads the language name from fn <language> name(...) { } and injects the matching tree-sitter parser. Any foreign language with an installed tree-sitter parser gets syntax highlighting automatically.
5. Verify Setup
Section titled “5. Verify Setup”Open a .shape file and run:
:set ft?:LspInfo:InspectTree:set commentstring?Expected:
- filetype is
shape shapeLSP is attached:InspectTreeshows the tree-sitter parse tree (includingforeign_bodynodes)- commentstring is
// %s
6. Rebuilding After Grammar Changes
Section titled “6. Rebuilding After Grammar Changes”When the tree-sitter grammar is updated, rebuild the parser:
cd shape/tree-sitter-shapetree-sitter generate # regenerates src/parser.c from grammar.jscc -shared -fPIC -O2 -o parser/shape.so src/parser.c -I srcThen restart Neovim.
7. Common Issues
Section titled “7. Common Issues”No LSP features (hover/completion/diagnostics)
Section titled “No LSP features (hover/completion/diagnostics)”- verify
shape-lspis on your$PATH(installed viacargo install shape-lsp) - update to latest version:
cargo install shape-lsp --forceForeign blocks have hover but no syntax highlighting
Section titled “Foreign blocks have hover but no syntax highlighting”Tree-sitter injection handles syntax highlighting; the LSP handles hover/completions. For injection to work:
parser/shape.somust be built and in the runtimepath.- The foreign language’s tree-sitter parser must be installed (e.g.,
:TSInstall python). vim.treesitter.start()must run for shape buffers (the config above does this).
Option 'commentstring' is empty
Section titled “Option 'commentstring' is empty”- ensure the
FileType shapeautocmd above is active - reopen file or run
:set commentstring=//\ %s
No Tree-sitter highlighting at all
Section titled “No Tree-sitter highlighting at all”- check that
parser/shape.soexists in thetree-sitter-shapedirectory - check
:lua print(vim.treesitter.language.get_lang("shape"))returns"shape" - check
:lua print(vim.treesitter.highlighter.active[vim.api.nvim_get_current_buf()] ~= nil)returnstrue
8. Inlay Hint Settings
Section titled “8. Inlay Hint Settings”The Shape LSP honors a shape.* settings tree forwarded via the
init_options slot (see the lspconfig block in §3) or — for live updates —
via workspace/didChangeConfiguration. The inlay-hint master is ON by
default; Shape-unique opt-in categories are OFF by default so the
editor stays uncluttered:
| Setting | Default | Description |
|---|---|---|
shape.inlayHints.enable | true | Master toggle. |
shape.inlayHints.typeHints | true | Inferred type hints on let bindings. |
shape.inlayHints.parameterHints | true | Parameter-name hints at call sites. |
shape.inlayHints.variableTypeHints | true | Inferred variable types where elided. |
shape.inlayHints.returnTypeHints | true | Inferred return-type hints on fn declarations. |
shape.inlayHints.chainHints | true | Intermediate-type hints on method-chain expressions. |
shape.inlayHints.bindingStorageClass.enable | false (opt-in) | Shape-unique: surfaces the compiler’s BindingStorageClass (Direct / UniqueHeap / SharedCow / SharedAtomic / SharedAtomicMut) inline. Rendered with [… approx]. |
9. Notes
Section titled “9. Notes”- LSP and runtime use the same module/loader architecture; keep your
shape-lspup to date (cargo install shape-lsp --force) when testing language changes.