Skip to content

Latest commit

 

History

History
275 lines (217 loc) · 9.08 KB

File metadata and controls

275 lines (217 loc) · 9.08 KB

Warning: This plugin was developed with the assistance of Claude Code. Use at your own risk.

sweep.nvim

AI-powered code completions for Neovim using the sweep-next-edit model. Inspired by cursortab.nvim.

Runs a local Python proxy (sweep_proxy.py) that loads the model via llama-cpp-python and communicates with Neovim over a Unix domain socket (with HTTP fallback).

Why sweep.nvim

cursortab.nvim routes requests through a compiled Go server over HTTP before they reach the model. sweep.nvim eliminates that middleman:

cursortab:  Neovim → HTTP → Go server → HTTP → llama.cpp server → model
sweep.nvim: Neovim → Unix socket → Python proxy → model

The Unix domain socket skips all TCP stack overhead and HTTP parsing. Combined with llama-cpp-python running the model in-process (with flash attention and full GPU KV-cache offload enabled by default), round-trip latency is significantly lower — particularly noticeable on short FIM completions where the model is fast but transport overhead dominates.

The proxy is also a single shared process — all open Neovim instances connect to the same socket, so the model is only loaded into memory once regardless of how many editors are running.

sweep.nvim also requires no extra language runtime to build: no Go toolchain, just Python.

Features

  • FIM completions — inline ghost text at the cursor in insert mode
  • Edit predictions — next-edit suggestions in normal mode, shown as virtual-text diffs
  • Dual transport — Unix socket (low latency) with automatic HTTP fallback
  • Smart debounce — stale responses are discarded when new input arrives
  • Blink.cmp integration — hides ghost text while the completion menu is open
  • Cache — avoids duplicate requests for the same context
  • Edit-history context — recent diffs are fed to the model for better next-edit accuracy
  • Treesitter context — enclosing scope and imports included in prompts

Requirements

  • Neovim 0.10+
  • Python 3.10+ with llama-cpp-python, fastapi, uvicorn
  • The sweep-next-edit GGUF model (see Model below)
  • YueScript — only if rebuilding from source

Installation

1. Install with lazy.nvim

Compiled Lua is included in the repo — no build step required:

{
    "c0r73x/sweep.nvim",
    event = { "VeryLazy", "InsertEnter", "BufReadPost", "BufNewFile" },
    config = function()
        require("sweep").setup({})
    end,
}

If you want to rebuild from the YueScript sources, add build = "make".

3. Set up the proxy

Install Python dependencies:

pip install llama-cpp-python fastapi uvicorn

Model

Download the GGUF model into proxy/models/:

mkdir -p proxy/models
# Example with huggingface-cli:
huggingface-cli download \
    sweepai/sweep-next-edit \
    sweep-next-edit-1.5b.q8_0.v2.gguf \
    --local-dir proxy/models

Run the proxy

The plugin will automatically start the proxy when Neovim loads (provider.auto_start = true by default), so you don't need to start it manually or set up a system service. Just make sure provider.proxy_script points to the correct path (defaults to the plugin's own proxy/sweep_proxy.py inside the lazy data directory). Set provider.model_path to the absolute path of your GGUF model file; if unset the proxy looks for it relative to the script.

The proxy is a single persistent process shared across all Neovim instances. If it is already running when a second instance starts, the new instance connects to the existing socket rather than spawning a duplicate.

If you prefer to manage the proxy yourself, you can disable auto-start and run it manually:

python3 proxy/sweep_proxy.py

The proxy listens on:

  • Unix socket: $XDG_RUNTIME_DIR/sweep.sock (or /tmp/sweep-<uid>.sock)
  • HTTP: http://127.0.0.1:5555

System service (optional)

If you want the proxy to start at login independently of Neovim, service templates are provided.

Linux (systemd):

cp proxy/sweep-proxy.service ~/.config/systemd/user/sweep-proxy.service
# Edit WorkingDirectory and ExecStart to match your paths
systemctl --user enable --now sweep-proxy

macOS (LaunchAgent):

cp proxy/com.user.sweep-proxy.plist.template \
    ~/Library/LaunchAgents/com.user.sweep-proxy.plist
# Edit paths inside the plist to match your environment
launchctl load ~/Library/LaunchAgents/com.user.sweep-proxy.plist

Configuration

All options and their defaults:

require("sweep").setup({
    enabled = true,
    log_level = "warn",  -- "debug" | "info" | "warn" | "error"

    keymaps = {
        accept         = "<Tab>",   -- accept FIM completion
        sweep          = "<Tab>",   -- accept edit prediction
        partial_accept = false,     -- accept word-by-word (key or false)
        reject         = false,     -- explicit reject (ESC always rejects)
        trigger        = false,     -- manual trigger (false = auto only)
    },

    ui = {
        completions = {
            addition_style = "highlight",  -- "highlight" | "inline"
            fg_opacity     = 1.0,
        },
        jump = {
            enabled      = false,   -- cursor-jump indicator
            symbol       = " ",
            text         = " TAB ",
            show_distance = true,
        },
    },

    behavior = {
        idle_completion_delay   = 50,    -- ms after typing stops
        text_change_debounce    = 50,    -- ms debounce for TextChangedI
        edit_prediction_delay   = 1000,  -- ms in normal mode before edit prediction
        ignore_filetypes        = { ... },
        ignore_gitignored       = false,
        enabled_modes           = { "i", "n" },
        min_line_length         = 0,
        max_file_lines          = 10000,
        hide_on_cursor_move     = true,
    },

    provider = {
        url                = "http://127.0.0.1:5555",
        mode               = "auto",   -- "auto" | "fim" | "edit"
        max_tokens         = 512,
        fim_max_tokens     = 128,
        max_fim_lines      = 4,
        temperature        = 0.0,
        top_p              = 1.0,
        top_k              = 50,
        repeat_penalty     = 1.0,
        completion_timeout = 5000,     -- ms
        auto_start         = true,
        proxy_script       = vim.fn.stdpath("data") .. "/lazy/sweep.nvim/proxy/sweep_proxy.py",
        model_path         = nil,      -- Path to GGUF model (nil = proxy default)
    },

    context = {
        window_radius      = 10,   -- lines above/below cursor (21 total)
        max_edit_history   = 6,    -- recent edit hunks in prompt
        max_context_files  = 3,    -- recently visited files for context
        context_file_lines = 60,   -- max lines per context file
        initial_file_lines = 300,  -- lines from original file in prompt
    },

    blink = {
        enabled    = true,
        ghost_text = true,
    },
})

Commands

Command Description
:SweepStatus Show plugin status and cache stats
:SweepCache Show cache statistics
:SweepReload Reload plugin (preserves options)
:SweepHide Hide current completion
:SweepToggle Toggle enabled/disabled
:SweepEdit Manually trigger edit prediction

Highlight Groups

Group Default link Purpose
SweepCompletion Comment FIM ghost text
SweepAddition DiffAdd Added lines in edit preview
SweepDeletion DiffDelete Removed lines in edit preview
SweepModification DiffText Changed lines in edit preview
SweepJumpSymbol Identifier Jump indicator symbol
SweepJumpText (custom) Jump indicator label

Lualine component

A minimal lualine component is available:

-- In your lualine config:
local sweep_component = require("sweep.lualine")

lualine.setup({
    sections = {
        lualine_x = { sweep_component },
    },
})

Shows ● SW when the proxy is connected, ○ SW when offline, and a spinner while a request is in flight.

Architecture

Neovim                         proxy/sweep_proxy.py
  │                                    │
  │── sweep.client (Unix socket) ─────▶│ llama-cpp-python
  │   (fallback: HTTP via curl)        │   sweep-next-edit model
  │                                    │
  │◀─ FIM text / updated lines ────────│
  │
  ├── sweep.ui       ghost text / virtual diff
  ├── sweep.buffer   context snapshot & diff
  ├── sweep.cache    LRU result cache
  ├── sweep.tracker  edit history & recent files
  └── sweep.config   defaults & highlight setup

License

MIT — see LICENSE.