MCPcopy Index your code
hub / github.com/cursortab/cursortab.nvim

github.com/cursortab/cursortab.nvim @v0.8.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.8.0 ↗ · + Follow
1,582 symbols 5,446 edges 111 files 831 documented · 53%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

cursortab.nvim

A Neovim plugin that provides edit completions and cursor predictions.

[!NOTE]

Help improve completions by contributing anonymous usage data to our open dataset. Set contribute_data = true in your config to opt in. No code content or file paths are collected — see the schema.

<img src="https://github.com/cursortab/cursortab.nvim/raw/v0.8.0/assets/demo.gif" width="600">

Requirements

  • Go 1.25.0+ (for building the server component)
  • Neovim 0.8+ (for the plugin)

Installation

Recommended starting points:

  • Best hosted: Mercury API
  • Best local next-edit: Zeta-2
  • Fastest local: Qwen3.5-0.8B with the inline provider, or Sweep 1.5B/0.5B with the sweep provider

Pick a provider below, then use the matching setup() call in your plugin config. See Providers for all available options.

Mercury API (hosted, no local GPU needed)

  1. Get an API key from Inception Labs
  2. Set the environment variable:

bash export MERCURY_AI_TOKEN="your-api-key-here"

Zeta-2 (local next-edit prediction)

Run llama.cpp:

llama-server -hf bartowski/zed-industries_zeta-2-GGUF:Q8_0 --port 8000

Qwen3.5-0.8B/Sweep (fastest local)

Run llama.cpp:

llama-server -hf unsloth/Qwen3.5-0.8B-GGUF:Q8_0 --port 8000
# llama-server -hf sweepai/sweep-next-edit-0.5b --port 8000
# llama-server -hf sweepai/sweep-next-edit-1.5b --port 8000

Using lazy.nvim

{
  "cursortab/cursortab.nvim",
  -- version = "*",  -- Use latest tagged version for more stability
  lazy = false,      -- The server is already lazy loaded
  build = "cd server && go build",
  config = function()
    require("cursortab").setup({
      provider = {
        -- Mercury API (hosted)
        type = "mercuryapi",
        api_key_env = "MERCURY_AI_TOKEN",

        -- Zeta-2 (best local)
        -- type = "zeta-2",
        -- url = "http://localhost:8000",

        -- Qwen3.5-0.8B (fastest local, defaults to "inline")
        -- url = "http://localhost:8000",

        -- sweep-next-edit-0.5B/1.5B (fastest local)
        -- type = "sweep",
        -- url = "http://localhost:8000",
      },
    })
  end,
}

Using packer.nvim

use {
  "cursortab/cursortab.nvim",
  -- tag = "*",  -- Use latest tagged version for more stability
  run = "cd server && go build",
  config = function()
    require("cursortab").setup({
      provider = {
        type = "mercuryapi",
        api_key_env = "MERCURY_AI_TOKEN",
      },
    })
  end
}

Configuration

Full config

require("cursortab").setup({
  enabled = true,
  log_level = "info",  -- "trace", "debug", "info", "warn", "error"
  state_dir = vim.fn.stdpath("state") .. "/cursortab",  -- Directory for runtime files (log, socket, pid)
  contribute_data = false,  -- Opt-in: send anonymous metrics to train a better gating model

  keymaps = {
    accept = "<Tab>",           -- Keymap to accept completion, or false to disable
    partial_accept = "<S-Tab>", -- Keymap to partially accept, or false to disable
    trigger = false,            -- Keymap to manually trigger completion, or false to disable
  },

  ui = {
    completions = {
      addition_style = "dimmed",  -- "dimmed" or "highlight"
      fg_opacity = 0.6,           -- opacity for completion overlays (0=invisible, 1=fully visible)
    },
    jump = {
      symbol = "",              -- Symbol shown for jump points
      text = " TAB ",            -- Text displayed after jump symbol
      show_distance = true,      -- Show line distance for off-screen jumps
    },
  },

  behavior = {
    idle_completion_delay = 50,  -- Delay in ms after idle to trigger completion (-1 to disable)
    text_change_debounce = 50,   -- Debounce in ms after text change to trigger completion (-1 to disable)
    max_visible_lines = 12,      -- Max visible lines per completion (0 to disable)
    disabled_in = {},                         -- Tree-sitter scopes to suppress completions (e.g., { "comment", "string" })
    enabled_modes = { "insert", "normal" },  -- Modes where completions are active
    cursor_prediction = {
      enabled = true,            -- Show jump indicators after completions
      auto_advance = true,       -- When no changes, show cursor jump to last line
      proximity_threshold = 2,   -- Min lines apart to show cursor jump (0 to disable)
    },
    ignore_paths = {             -- Glob patterns for files to skip completions
      "*.min.js",
      "*.min.css",
      "*.map",
      "*-lock.json",
      "*.lock",
      "*.sum",
      "*.csv",
      "*.tsv",
      "*.parquet",
      "*.zip",
      "*.tar",
      "*.gz",
      "*.pem",
      "*.key",
      ".env",
      ".env.*",
      "*.log",
    },
    ignore_filetypes = { "", "terminal" }, -- Filetypes to skip completions
    ignore_gitignored = true,    -- Skip files matched by .gitignore
  },

  provider = {
    type = "inline",                      -- Provider: "inline", "fim", "sweep", "zeta", "zeta-2", "copilot", or "mercuryapi"
    url = "http://localhost:8000",        -- URL of the provider server
    api_key_env = "",                     -- Env var name for API key (e.g., "OPENAI_API_KEY")
    model = "",                           -- Model name
    temperature = 0.0,                    -- Sampling temperature
    context_size = 0,                     -- Max input context in tokens (0 = use max_tokens; inline/fim default: 1024)
    max_tokens = 512,                     -- Max tokens to generate (inline default: 64, fim default: 128)
    top_k = 50,                           -- Top-k sampling
    completion_timeout = 5000,            -- Timeout in ms for completion requests
    max_diff_history_tokens = 512,        -- Max tokens for diff history (0 = no limit)
    completion_path = "/v1/completions",  -- API endpoint path
    -- fim_tokens is optional. Omit (the default) to use OpenAI prompt+suffix
    -- format (e.g. DeepSeek). Set it to opt into tokenized FIM:
    --   fim_tokens = {
    --     prefix = "<|fim_prefix|>",
    --     suffix = "<|fim_suffix|>",
    --     middle = "<|fim_middle|>",
    --     repo_name = "<|repo_name|>",     -- optional; auto-detected for Qwen
    --     file_sep = "<|file_sep|>",       -- optional; auto-detected for Qwen
    --   },
    privacy_mode = true,                  -- Don't send telemetry to provider
  },

  blink = {
    enabled = false,    -- Enable blink source
    ghost_text = true,  -- Show native ghost text alongside blink menu
  },

  debug = {
    immediate_shutdown = false,  -- Shutdown daemon immediately when no clients
  },
})

You can also run :help cursortab-config to see the configuration.

Highlight Groups

The plugin defines the following highlight groups with default = true, so you can override them in your colorscheme or config:

Group Default Purpose
CursorTabDeletion bg = "#4f2f2f" Background for deleted text
CursorTabAddition bg = "#394f2f" Background for added text
CursorTabModification bg = "#282e38" Background for modified text
CursorTabCompletion fg = "#80899c" Foreground for completion text
CursorTabJumpSymbol fg = "#373b45" Jump indicator symbol
CursorTabJumpText bg = "#373b45", fg = "#bac1d1" Jump indicator text

To customize, set the highlight before or after calling setup():

vim.api.nvim_set_hl(0, "CursorTabAddition", { bg = "#1a3a1a" })

Providers

The plugin supports seven AI provider backends: Inline, FIM, Sweep, Zeta-2, Zeta (legacy), Copilot, and Mercury API.

Provider Hosted Multi-line Multi-edit Cursor Prediction Streaming Model
inline Any base model
fim Any FIM-capable
sweep Sweep Next-Edit family
zeta-2 zeta-2 (SeedCoder-8B)
zeta zeta (Qwen2.5-Coder)
copilot GitHub Copilot
mercuryapi mercury-edit-2

Context Per Provider:

Context inline fim sweep zeta-2 zeta copilot mercuryapi
Buffer content
Edit history ✓°
Previous file state
LSP diagnostics ✓°
Treesitter context ✓°
Git diff context ✓°
Recent files ✓°
User actions

° FIM cross-file context requires repo-level tokens (repo_name, file_sep). Auto-detected for Qwen models; set manually for other models that support them.

Benchmarks

Measured on 50 scenarios (25 quality + 25 suppress) using the eval harness. Sorted by Score (higher = better):

  • ScoredeltaChrF × gateScore / 100 where gateScore = 2 × showRate × quietRate / (showRate + quietRate) (harmonic mean / F1). Combines edit quality with gating behavior into a single metric.
  • deltaChrF — edit quality when shown (character n-gram F-score on the diff region)
  • Show rate — fraction of quality scenarios where a completion was shown
  • Quiet rate — fraction of suppress scenarios where the provider correctly produced nothing
Target Type Score deltaChrF Show rate Quiet rate p50 (ms) p90 (ms)
zeta-2 zeta-2 0.61 65.4 92% 96% 551 833
zeta zeta 0.56 62.4 88% 92% 413 662
mercuryapi mercuryapi 0.49 61.8 92% 69% 332 393
qwen3.6-27B fim 0.23 32.0 60% 92% 214 455
sweep-next-edit-7B sweep 0.23 46.0 64% 40% 270 515
qwen3.5-0.8B fim 0.21 37.3 80% 44% 137 226
sweep-next-edit-1.5B sweep 0.21 43.7 68% 36% 157 258
qwen3.5-2B fim 0.20 35.1 80% 44% 185 429
qwen3.5-4B fim 0.18 28.7 64% 64% 357 730
copilot copilot 0.13 22.3 40% 100% 351 915
sweep-next-edit-0.5B sweep 0.10 23.0 52% 40% 126 207
qwen3.6-35B-A3B fim 0.10 19.2 40% 80% 113 411

Inline Provider (Default)

Details

Single-line completion using any OpenAI-compatible /v1/completions endpoint.

require("cursortab").setup({
  provider = {
    type = "inline",
    url = "http://localhost:8000",
  },
})
llama-server -hf unsloth/Qwen3.5-0.8B-GGUF:Q8_0 --port 8000

FIM Provider

Details

Fill-in-the-Middle multi-line completion. Compatible with Qwen, DeepSeek-Co

Extension points exported contracts — how you extend this code

Timer (Interface)
Timer represents a timer that can be stopped. [4 implementers]
server/engine/engine.go
HTTPTransportSetter (Interface)
HTTPTransportSetter is implemented by clients that allow their outgoing HTTP transport to be replaced. Used by the eval [4 …
server/provider/provider.go
Sender (Interface)
Sender is the interface that providers implement to send metrics to their backend. Implementations should handle unsuppo [3 …
server/metrics/metrics.go
Batch (Interface)
Batch represents deferred editor operations [3 implementers]
server/buffer/client.go
DiffEntry (Interface)
DiffEntry interface for token limiting - matches types.DiffEntry [2 implementers]
server/utils/utils.go
Provider (Interface)
Provider defines the interface that all AI providers must implement. Implemented by inline.Provider, sweep.Provider, zet [4 …
server/engine/types.go
LSPBuffer (Interface)
LSPBuffer is the minimum set of buffer methods the Copilot provider needs. NvimBuffer satisfies this interface via duck [2 …
server/provider/copilot/copilot.go
Clock (Interface)
Clock provides time-related operations for dependency injection. [3 implementers]
server/engine/engine.go

Core symbols most depended-on inside this repo

AddLine
called by 163
server/text/incremental.go
ComputeDiff
called by 96
server/text/diff.go
String
called by 88
server/engine/types.go
ChangesMap
called by 82
server/text/diff.go
JoinLines
called by 78
server/text/staging.go
CreateStages
called by 57
server/text/staging.go
Debug
called by 51
server/logger/logger.go
Close
called by 48
server/logger/logger.go

Shape

Function 938
Method 447
Struct 155
TypeAlias 19
Interface 18
FuncType 5

Languages

Go100%

Modules by API surface

server/text/staging_test.go77 symbols
server/text/diff_test.go71 symbols
server/engine/types.go68 symbols
server/buffer/buffer.go57 symbols
server/text/incremental_test.go56 symbols
server/provider/zeta2/zeta2_test.go51 symbols
server/engine/engine_mocks_test.go46 symbols
server/text/grouping_test.go39 symbols
server/eval/harness/buffer.go37 symbols
server/engine/engine.go36 symbols
server/provider/provider.go34 symbols
server/text/e2e_test.go32 symbols

For agents

$ claude mcp add cursortab.nvim \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page