Poke databases from your nvim like a professional idiot.
  • Lua 99.8%
  • Shell 0.2%
Find a file
2026-04-25 20:17:32 +02:00
dev feat(browser): tonic browse 2026-04-20 10:03:26 +02:00
doc feat(browser): add directives to file 2026-04-20 14:23:55 +02:00
lua/tonic feat(browser): show inspect descriptions 2026-04-25 20:17:32 +02:00
plugin feat: Init 2026-04-19 21:11:53 +02:00
tests feat: Init 2026-04-19 21:11:53 +02:00
.gitignore feat(dev): dev setup 2026-04-19 21:19:23 +02:00
LICENSE feat: Init 2026-04-19 21:11:53 +02:00
README.md feat(browser): show inspect descriptions 2026-04-25 20:17:32 +02:00
VERSION feat(browser): show inspect descriptions 2026-04-25 20:17:32 +02:00

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.nvim
  • tonic on 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 run Runs the current statement.
  • :'<,'>Tonic run Runs exact selected text + top file directives.
  • :Tonic run-buffer Runs the full buffer.
  • :Tonic browse Opens the catalog browser rooted at configured targets.
  • :Tonic browse-toggle Toggles the catalog browser for the current buffer.
  • :Tonic target Opens a nui.menu picker and stores the fallback target in vim.b.tonic_target.
  • :Tonic targets Shows the available tonic targets.
  • :Tonic status Shows the current client and buffer status.
  • :Tonic restart Restarts the background tonic serve --stdio process.
  • :checkhealth tonic Verifies the plugin, nui.nvim, and the tonic CLI 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:

  1. leading -- tonic-file: and -- tonic-bind: directives before the first SQL statement
  2. 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.split for the persistent bottom results pane
  • nui.menu for target selection
  • nui.popup for status and detail views
  • native vim.notify(...) notifications for errors and warnings, which integrate with UIs like noice.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 node
  • K opens a hover-style popup near the cursor with the selected node metadata, descriptions, loaded columns, DDL, or view definition
  • d fetches DDL when the backend supports it and shows it in the popup
  • v fetches view SQL for view nodes and shows it in the popup
  • F writes or replaces the top-file tonic-file directive using canonical context.catalog and context.namespace fields
  • B inserts a new top-file tonic-bind directive with an auto-generated handle like warehouse-1, warehouse-2, warehouse-3

Browser keymaps:

  • <CR> or l to expand the current node
  • h to collapse the current node or move to its parent
  • ? to open browser help
  • K to open details for the selected node
  • r to refresh the selected node
  • R to rebuild the browser from the current target list
  • d to load DDL in a popup when supported
  • v to load a view definition in a popup for view nodes
  • F to add or replace the file-scoped tonic-file directive
  • B to append a file-scoped tonic-bind directive
  • q to 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, and tonic-bind directive names
  • directive keys like target, handle, autocommit, and context.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.

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/dev
  • XDG_DATA_HOME=$REPO/.data
  • XDG_STATE_HOME=$REPO/.state
  • XDG_CACHE_HOME=$REPO/.cache

The dev config lives in dev/nvim/ and loads:

  • MunifTanjim/nui.nvim
  • the local tonic.nvim plugin from this repo

The isolated dev config also ships with these default keymaps:

  • <leader>tr to run the current statement in normal mode, or the exact selection in visual mode
  • <leader>tb to run the full buffer
  • <leader>tc to open the catalog browser
  • <leader>tt to pick a fallback target
  • <leader>tl to list targets
  • <leader>ts to show status
  • <leader>tx to restart the background tonic serve process

0.1.12

  • Show inspect descriptions in browser details when tonic provides them, including Snowflake object comments exposed as descriptions.

0.1.11

  • Enforce a minimum supported tonic version during the server.capabilities handshake so newer plugin features fail fast with a clear compatibility error.
  • Add semver compatibility tests and document the plugin-side minimum_tonic_version setting.

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.popup windows to native vim.notify(...) notifications for better integration with UIs like noice.nvim.
  • Add browser.request_timeout so browser metadata inspection can use a separate timeout from query execution.

0.1.8

  • Replace the split preview pane in :Tonic browse with a tree-only browser plus popup-driven details on K.
  • Add browser-local key help on ?, with context-aware hints similar to Neo-tree.

0.1.7

  • Rework :Tonic browse into a target-first tree so browsing starts from the configured targets without a target picker popup.
  • Add F and B browser actions to write top-file tonic-file and tonic-bind directives, 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 on nui.layout and nui.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 K to 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, and tonic-bind comments 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.nvim repository URL.

0.1.2

  • Add default tonic.nvim keymaps to the isolated dev config.
  • Document recommended user keymaps in the README.

0.1.1

  • Add a repo-local lazy.nvim development config and launcher script for isolated nui.nvim and plugin testing.

0.1.0

  • Add a runner-first MVP around a persistent tonic serve --stdio JSON-RPC client.
  • Add current statement, visual selection, and full-buffer execution flows with nui.nvim status, target, result, and error UIs.