Skip to content

abaayd01/handball.nvim

Repository files navigation

🏐 handball.nvim

Throw code to OpenCode from Neovim — seamless AI-powered code review and editing

handball.nvim is a Neovim plugin that connects your editor to OpenCode, enabling you to send code selections to an AI agent for review, refactoring, or questions. Queue multiple requests, keep working, and get notified when changes are ready.

✨ Features

  • 🚀 Non-blocking workflow — Queue multiple review prompts while continuing to edit
  • 📦 FIFO queue — Requests execute in order, one at a time (single-flight)
  • 🔄 Auto-refresh — Changed buffers reload automatically when AI work completes
  • 📊 Status line — Visual indicators for request state and queue depth
  • 🎯 Visual selection — Send any code block with <leader>or
  • 🔗 Session linking — One-time setup per repository
  • Async HTTP — Built on Neovim 0.10+ vim.system() API

📋 Requirements

  • Neovim 0.10+ (required for vim.system() async API)
  • OpenCode CLI installed and in PATH
  • curl (for HTTP requests)

📦 Installation

Using lazy.nvim

{
  "abaayd01/handball.nvim",
  config = function()
    -- Plugin auto-loads with default keymaps
  end,
}
use 'abaayd01/handball.nvim'

Manual Installation

git clone https://github.com/abaayd01/handball.nvim.git \
  ~/.config/nvim/pack/plugins/start/handball.nvim

🚀 Quick Start

  1. Start OpenCode server:

    opencode serve --port 8080
  2. Link your session (one-time per repo):

    :OpenCodeLinkSession

    Or use <leader>os

  3. Send code for review:

    • Visually select code (v, V, or <C-v>)
    • Press <leader>or
    • Enter your prompt (e.g., "refactor this for clarity")

🎮 Usage

The "Review Sweep" Workflow

Perfect for code reviews or refactoring sessions:

  1. Open a file and visually select code
  2. Press <leader>or and describe what you want
  3. Continue immediately — the request is queued and runs in the background
  4. Submit more prompts anytime — they queue up
  5. Watch the status line for progress
  6. Buffers auto-refresh when each request completes

How queuing works:

  • First request starts immediately
  • Subsequent requests queue and execute FIFO
  • Context (file, line range, selected text) is captured at submission time
  • Cancel anytime with <leader>oc

Available Commands

Command Description
:OpenCodeLinkSession Select and link to an OpenCode session
:OpenCodeCheckSession Show linked session status
:OpenCodeCancel Cancel the active request

Default Keymaps

Keymap Mode Description
<leader>or Visual Send selected code to OpenCode
<leader>os Normal Link/check OpenCode session
<leader>oc Normal Cancel active request

📊 Status Line Integration

Show OpenCode status in your status line:

-- Using lualine
require('lualine').setup {
  sections = {
    lualine_x = {
      { require('handball.ui').statusline, cond = require('handball').status_detail().is_active }
    }
  }
}

Or manually:

-- In your statusline configuration
%{luaeval('require("handball.ui").statusline()')}

Status indicators:

  • ⏳ submitted - Request sent to server
  • ⚙️ processing - Server is working
  • ✓ completed - Request finished successfully
  • ✗ failed - Request failed
  • ⊘ cancelled - Request was cancelled
  • (N) - Number of queued requests waiting

🔧 Configuration

Currently uses sensible defaults:

  • Server: http://localhost:8080
  • Timeout: 5 minutes
  • Poll interval: 2 seconds
  • Keymap leader: <leader>

Future versions will support user configuration.

🎨 Autocmd Events

Hook into plugin lifecycle for custom behavior:

-- On request completion
vim.api.nvim_create_autocmd("User", {
  pattern = "OpenCodeRequestComplete",
  callback = function(args)
    local data = args.data
    print(string.format("✓ %d files changed", #data.files_changed))
  end,
})

-- On request cancellation
vim.api.nvim_create_autocmd("User", {
  pattern = "OpenCodeRequestCancelled",
  callback = function(args)
    print("Request cancelled")
  end,
})

Event data:

  • OpenCodeRequestComplete: { status, files_changed[], session_id, queue_remaining }
  • OpenCodeRequestCancelled: { job_id }

🏗️ Architecture

┌─────────────────────────────────────────────────────────┐
│  User Action    →  Plugin Orchestrator  →  OpenCode   │
│  (select code)      (handball/init.lua)   (localhost) │
└─────────────────────────────────────────────────────────┘

Modules:

  • api.lua — Async HTTP client using vim.system()
  • state.lua — Request state machine and FIFO queue
  • init.lua — Main orchestration and queue scheduler
  • ui.lua — Notifications and status line
  • context.lua — Visual selection extraction
  • session.lua — Session persistence (.git/opencode-neovim-session)
  • plugin/handball.lua — Commands and keymaps

🐛 Troubleshooting

"OpenCode server not running"

Start the server:

opencode serve --port 8080
"Not in a git repository"

The plugin stores session links in .git/opencode-neovim-session. Navigate to a git repository first.

"Empty response from server"

Check:

  1. Server running on port 8080
  2. No firewall blocking localhost:8080
  3. At least one OpenCode session created
"No code selected"

Ensure you're in visual mode (v, V, or <C-v>) before pressing <leader>or.

📝 License

MIT © abaayd01


Made with 🏐 for the OpenCode community

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors