- 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, thetonicCLI handshake, catalog browser methods, and optional native completion support.
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.
When tonic returns ordered artifact events, the results pane renders tonic-print report text in source order around statement results. This supports query files such as:
-- tonic-print: # Daily sales report
-- tonic-print:
-- tonic-print-begin
-- ## Notes
--
-- - Generated for finance
-- tonic-print-end
select * from reports.daily_sales;
Report comments require tonic 0.8.0 or newer.
Catalog Browser
:Tonic browse opens a persistent tree browser rooted at all configured targets, then catalog, namespace, table, view, and column navigation. For MySQL targets, databases are shown as catalogs and expand directly to table/view groups because MySQL does not expose a separate namespace scope.
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
Native Completion
tonic.nvim registers Neovim's native user completion for configured SQL-like buffers by setting a buffer-local completefunc. Trigger it with Neovim's built-in <C-x><C-u> completion flow or map that key sequence yourself.
Completion is optional against older tonic servers. :checkhealth tonic reports completion.items separately from required startup and catalog browser methods: missing completion support is a warning, not a plugin startup failure. During editing, unsupported servers, request failures, timeouts, or malformed completion responses quietly produce an empty completion list instead of popups or interrupted typing.
The plugin calls only the completion.items JSON-RPC method for completion. It does not call catalog browser inspect methods, does not request live refresh, and relies on tonic core's cache-only completion semantics. Configure inspect cache path and TTL in tonic config, and use browser refresh when you intentionally want live metadata refetch for browsing.
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 },
},
},
completion = {
enabled = true,
filetypes = { "sql" },
request_timeout = nil,
},
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. completion.request_timeout overrides the global timeout for native completion requests; leave it as nil to use request_timeout.
completion.enabled controls buffer-local native completion registration, and completion.filetypes selects which normal buffers receive tonic's completefunc. The default enables SQL buffers only.
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,tonic-bind,tonic-print,tonic-print-begin, andtonic-print-enddirective 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.14
- Render
tonic-printquery-file report events in the results pane while preserving legacy statement rendering when no report text is present. - Highlight
tonic-print,tonic-print-begin, andtonic-print-enddirective comments in SQL buffers.
0.1.13
- Add native completion health diagnostics that warn when optional
completion.itemssupport is unavailable without failing plugin startup. - Document
<C-x><C-u>completion usage, completion configuration, timeout behavior, cache-only semantics, and quiet degradation for older or unavailable servers.
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.