- Lua 99.8%
- Shell 0.2%
| dev | ||
| doc | ||
| lua/tonic | ||
| plugin | ||
| tests | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| VERSION | ||
tonic.nvim
Neovim client for tonic serve --stdio.
tonic.nvim is a separate plugin repo that treats tonic as the stable execution engine and uses Neovim + nui.nvim for the editor UX.
Requirements
- Neovim
>= 0.12 MunifTanjim/nui.nvimtonicon your$PATH(plugin defaults currently require tonic>= 0.0.3)
Installation
lazy.nvim
{
url = "https://forgejo.fairlabs.dev/ferrumboll/tonic.nvim.git",
name = "tonic.nvim",
dependencies = {
"MunifTanjim/nui.nvim",
},
config = function()
require("tonic").setup()
end,
}
Commands
:Tonic runRuns the current statement.:'<,'>Tonic runRunsexact selected text + top file directives.:Tonic run-bufferRuns the full buffer.:Tonic browseOpens the catalog browser rooted at configured targets.:Tonic browse-toggleToggles the catalog browser for the current buffer.:Tonic targetOpens anui.menupicker and stores the fallback target invim.b.tonic_target.:Tonic targetsShows the available tonic targets.:Tonic statusShows the current client and buffer status.:Tonic restartRestarts the backgroundtonic serve --stdioprocess.:checkhealth tonicVerifies the plugin,nui.nvim, and thetonicCLI handshake.
Behavior
Current Statement
Tonic run in normal mode sends the full buffer to query.planArtifact, finds the statement covering the cursor, and then executes that exact statement index with query.executeArtifact.
Visual Selection
Tonic run in visual mode builds a synthetic artifact from:
- leading
-- tonic-file:and-- tonic-bind:directives before the first SQL statement - the exact selected text
For v0.1.0 this is intentionally strict:
- partial statement selections may fail
- per-statement
-- tonic:overrides only apply if that directive line is inside the selection
Results UI
tonic.nvim uses:
nui.splitfor the persistent bottom results panenui.menufor target selectionnui.popupfor status and detail views- native
vim.notify(...)notifications for errors and warnings, which integrate with UIs likenoice.nvim
The table view trims wide cells to keep the results buffer readable. In the results buffer, press K on any data cell to inspect the full untrimmed value in a popup.
Catalog Browser
:Tonic browse opens a persistent tree browser rooted at all configured targets, then catalog, namespace, table, view, and column navigation.
The browser is intentionally lazy in v0.1.8:
- target, catalog, namespace, table, and view children load when expanded
- moving the cursor only updates the selected node and does not make background requests
?opens a help popup with browser-local key hints for the selected nodeKopens a hover-style popup near the cursor with the selected node metadata, descriptions, loaded columns, DDL, or view definitiondfetches DDL when the backend supports it and shows it in the popupvfetches view SQL for view nodes and shows it in the popupFwrites or replaces the top-filetonic-filedirective using canonicalcontext.catalogandcontext.namespacefieldsBinserts a new top-filetonic-binddirective with an auto-generated handle likewarehouse-1,warehouse-2,warehouse-3
Browser keymaps:
<CR>orlto expand the current nodehto collapse the current node or move to its parent?to open browser helpKto open details for the selected noderto refresh the selected nodeRto rebuild the browser from the current target listdto load DDL in a popup when supportedvto load a view definition in a popup for view nodesFto add or replace the file-scopedtonic-filedirectiveBto append a file-scopedtonic-binddirectiveqto close the browser
Configuration
require("tonic").setup({
cmd = { "tonic", "serve", "--stdio" },
minimum_tonic_version = "0.0.3",
browser = {
request_timeout = 30000,
position = "left",
size = { width = 36 },
popup = {
size = { width = 72, height = 20 },
},
help_popup = {
size = { width = 44, height = 14 },
},
},
highlight = {
enabled = true,
filetypes = { "sql" },
},
request_timeout = 10000,
startup_timeout = 5000,
result = {
position = "bottom",
size = "35%",
enter = false,
focusable = true,
max_cell_width = 40,
},
})
request_timeout controls query RPC calls such as planning and execution. browser.request_timeout is used for browser metadata requests like catalogs, schemas, tables, views, DDL, and view definitions, so you can allow slower introspection without slowing normal query runs.
minimum_tonic_version lets the plugin reject older tonic serve binaries during the startup capability handshake before any commands run.
Browser inspect metadata is now cached persistently by tonic itself. Configure the cache path and TTL in tonic config, not in tonic.nvim, and use browser refresh (r) when you want to force a live refetch from the source database.
Directive Highlighting
tonic.nvim highlights directive comments in enabled filetypes without LSP or Tree-sitter.
By default it applies buffer-local extmark highlights for:
tonic,tonic-file, andtonic-binddirective names- directive keys like
target,handle,autocommit, andcontext.schema =and:operators- directive values
- invalid tokens or invalid fields for that directive kind
The default filetype list is { "sql" }, and you can override it with highlight.filetypes.
Recommended Keymaps
vim.keymap.set("n", "<leader>tr", "<cmd>Tonic run<CR>", { desc = "Tonic run statement" })
vim.keymap.set("x", "<leader>tr", ":Tonic run<CR>", { desc = "Tonic run selection" })
vim.keymap.set("n", "<leader>tb", "<cmd>Tonic run-buffer<CR>", { desc = "Tonic run buffer" })
vim.keymap.set("n", "<leader>tc", "<cmd>Tonic browse-toggle<CR>", { desc = "Tonic toggle catalog browser" })
vim.keymap.set("n", "<leader>tt", "<cmd>Tonic target<CR>", { desc = "Tonic pick target" })
vim.keymap.set("n", "<leader>tl", "<cmd>Tonic targets<CR>", { desc = "Tonic list targets" })
vim.keymap.set("n", "<leader>ts", "<cmd>Tonic status<CR>", { desc = "Tonic status" })
vim.keymap.set("n", "<leader>tx", "<cmd>Tonic restart<CR>", { desc = "Tonic restart" })
Note: the visual-mode mapping intentionally uses :Tonic run<CR> instead of <cmd>... so Neovim preserves the visual range and tonic.nvim receives :'<,'>Tonic run.
Development
Run the headless tests with:
nvim --headless -u tests/minimal_init.lua -c "lua require('tonic.tests.run').run()"
For interactive plugin development, this repo ships with an isolated lazy.nvim config that installs lazy.nvim and nui.nvim under repo-local XDG paths.
Launch it with:
./dev/run.sh
This uses:
XDG_CONFIG_HOME=$REPO/devXDG_DATA_HOME=$REPO/.dataXDG_STATE_HOME=$REPO/.stateXDG_CACHE_HOME=$REPO/.cache
The dev config lives in dev/nvim/ and loads:
MunifTanjim/nui.nvim- the local
tonic.nvimplugin from this repo
The isolated dev config also ships with these default keymaps:
<leader>trto run the current statement in normal mode, or the exact selection in visual mode<leader>tbto run the full buffer<leader>tcto open the catalog browser<leader>ttto pick a fallback target<leader>tlto list targets<leader>tsto show status<leader>txto restart the backgroundtonic serveprocess
0.1.12
- Show inspect descriptions in browser details when
tonicprovides them, including Snowflake object comments exposed as descriptions.
0.1.11
- Enforce a minimum supported
tonicversion during theserver.capabilitieshandshake so newer plugin features fail fast with a clear compatibility error. - Add semver compatibility tests and document the plugin-side
minimum_tonic_versionsetting.
0.1.10
- Make browser refresh (
r) force live inspect refetches so it can bypass tonic's persistent metadata cache when needed. - Keep normal browser expansion on tonic's default cached inspect path while leaving cache TTL policy in tonic config.
0.1.9
- Switch tonic.nvim errors from
nui.popupwindows to nativevim.notify(...)notifications for better integration with UIs likenoice.nvim. - Add
browser.request_timeoutso browser metadata inspection can use a separate timeout from query execution.
0.1.8
- Replace the split preview pane in
:Tonic browsewith a tree-only browser plus popup-driven details onK. - Add browser-local key help on
?, with context-aware hints similar to Neo-tree.
0.1.7
- Rework
:Tonic browseinto a target-first tree so browsing starts from the configured targets without a target picker popup. - Add
FandBbrowser actions to write top-filetonic-fileandtonic-binddirectives, with canonical scope fields and auto-generated bind handles.
0.1.6
- Add
:Tonic browse, a persistent split-based catalog browser with a tree pane and preview pane built onnui.layoutandnui.tree. - Add lazy inspection for catalogs, namespaces, tables, views, columns, DDL, and view definitions with browser-specific keymaps and health reporting.
0.1.5
- Keep table cells trimmed in the results pane while adding
Kto inspect the full value of the cell under the cursor. - Preserve full row values in results metadata so popup inspection can show untrimmed strings and structured values.
0.1.4
- Add built-in directive highlighting for
tonic,tonic-file, andtonic-bindcomments using Lua parsing and extmark highlights. - Add configuration for highlighted filetypes and parser tests for directive tokens and rendered extmarks.
0.1.3
- Update the README installation snippet to use the Forgejo
tonic.nvimrepository URL.
0.1.2
- Add default
tonic.nvimkeymaps to the isolated dev config. - Document recommended user keymaps in the README.
0.1.1
- Add a repo-local
lazy.nvimdevelopment config and launcher script for isolatednui.nvimand plugin testing.
0.1.0
- Add a runner-first MVP around a persistent
tonic serve --stdioJSON-RPC client. - Add current statement, visual selection, and full-buffer execution flows with
nui.nvimstatus, target, result, and error UIs.