Skip to content

Neovim Completion

Use this workflow when you want SQL object completion in Neovim while keeping database access deliberate.

After reading it, you should be able to configure tonic.nvim, seed metadata intentionally, trigger <C-x><C-u>, and diagnose why completion is empty without exposing secrets or opening a live connection from insert mode.

tonic.nvim is a thin Neovim adapter. It owns buffer-local editor integration, starts tonic serve --stdio, and sends completion requests. Tonic core owns target resolution, query-file context rules, metadata semantics, and the completion.items response shape.

You need:

  • tonic on your $PATH.
  • A saved target such as warehouse, app-dev, or scratch.
  • tonic.nvim installed in Neovim with nui.nvim.
  • Inspect metadata already cached for the objects you want to complete.

Saved targets can use environment-backed secrets; the examples below use placeholder target names and do not require real credentials in files. See Project-Local Targets for a repo-local target pattern.

Enable native completion in require("tonic").setup:

require("tonic").setup({
cmd = { "tonic", "serve", "--stdio" },
completion = {
enabled = true,
filetypes = { "sql" },
request_timeout = nil,
},
})

completion.filetypes controls which normal buffers receive tonic’s buffer-local completefunc. The default is SQL buffers. completion.request_timeout overrides the global RPC timeout for completion; leave it as nil to use the normal request_timeout fallback.

If your SQL buffers use another filetype, add it explicitly:

require("tonic").setup({
completion = {
enabled = true,
filetypes = { "sql", "mysql", "plsql" },
},
})

Tell tonic which target and context applies

Section titled “Tell tonic which target and context applies”

Completion resolves the statement at the cursor using the same query-file metadata rules as execution. Prefer visible directives in the SQL file when the target or context should travel with the artifact:

-- tonic-file: target=warehouse context.catalog=ANALYTICS context.namespace=PUBLIC
select *
from ord

You can also pick a buffer fallback target with :Tonic target. Per-statement directives and reusable handles follow the normal query-file rules; see Query Files and Directives instead of memorizing every placement rule.

Native completion is cache-only. It reads existing persistent inspect cache data and does not open targets, ping targets, run SQL, or refresh metadata while you are typing.

Seed or refresh metadata outside insert-mode completion when you intentionally want live database access:

Terminal window
tonic inspect catalogs --target warehouse --refresh
tonic inspect namespaces --target warehouse --context catalog=ANALYTICS --refresh
tonic inspect tables --target warehouse --context catalog=ANALYTICS --context namespace=PUBLIC --refresh
tonic inspect views --target warehouse --context catalog=ANALYTICS --context namespace=PUBLIC --refresh
tonic inspect columns orders --target warehouse --context catalog=ANALYTICS --context namespace=PUBLIC --refresh

Inside Neovim, the catalog browser also has an explicit refresh action for metadata browsing. Normal browser expansion can use cached inspect data, while refresh is the deliberate live boundary.

See inspect for CLI metadata commands and serve for the long-lived stdio service used by the plugin.

In insert mode, use Neovim’s native user-completion flow:

<C-x><C-u>

You can map that key sequence yourself if you prefer a shorter binding. Tonic sets completefunc only on configured buffers, so it does not replace completion globally.

Completion sends one completion.items JSON-RPC request to the running stdio server. The request includes the current buffer text, cursor position, path metadata, optional fallback target, context, and autocommit fallback. The detailed wire shape lives in Serve JSON-RPC.

When cached metadata and statement context are unambiguous, completion may suggest:

  • catalogs
  • namespaces
  • tables
  • views
  • columns for conservative, alias-aware table or view sources

Common unquoted aliases are supported. For example, after FROM orders o, FROM orders AS o, or JOIN customers c, completion after o. or c. can return cached columns when the source object resolves to one table or view.

Completion is intentionally conservative. Ambiguous aliases, unresolved objects, unsupported source syntax, stale cache rows, malformed cache payloads, missing column metadata, and cache misses produce no suggestions instead of guesses.

Completion failures should not interrupt typing.

SituationEditor behaviorWhere to look
Unsupported tonic server without completion.itemsEmpty completion list:checkhealth tonic optional completion warning
tonic serve --stdio unavailable or exitsEmpty completion list:Tonic status, :checkhealth tonic, or restart the client
Completion request timeoutEmpty completion listcompletion.request_timeout or the global request timeout
Malformed completion responseEmpty completion listNon-fatal plugin diagnostics and health checks
Cache miss, stale cache row, malformed cache row, or ambiguous aliasEmpty completion listRefresh inspect metadata intentionally or simplify the statement context

Public completion degradation is intentionally quiet: the JSON-RPC result is { "items": [] }, and Neovim shows no items. Internal cache diagnostics are not exposed as editor completion items.

Invalid request shapes, malformed directives, invalid context overrides, and unresolved targets are structured JSON-RPC errors at the service boundary. They are reference behavior for clients and tests, not normal user-facing completion suggestions.

When completion is missing or empty, check these surfaces in order:

  1. Run :checkhealth tonic and confirm the CLI handshake succeeds. Completion support is reported separately because older tonic servers may still support required plugin startup and browsing methods.
  2. Ask the server for server.capabilities if you are debugging the JSON-RPC boundary; the method list should include completion.items.
  3. Confirm the current buffer has tonic’s buffer-local completefunc by checking :setlocal completefunc?.
  4. Confirm the buffer filetype is included in completion.filetypes.
  5. Refresh inspect metadata intentionally with tonic inspect ... --refresh or the browser refresh action.
  6. Re-trigger <C-x><C-u> after the cache contains the catalog, namespace, object, or column metadata you expect.

This keeps the live boundary explicit: inspect and browser refresh can contact the database; native completion only reads the persistent cache.

  • Serve JSON-RPC documents completion.items, server.capabilities, and JSON-RPC error shapes.
  • serve documents tonic serve --stdio and the service method list.
  • inspect documents metadata cache refresh commands.
  • Query Files explains how SQL files carry target and context intent.
  • Directives is the canonical directive syntax reference.