有时 Neovim 编辑文件时,想快速让 AI 修改某一部分,之前一般都是额外一个窗口打开 OpenCode,然后 @ 指定文件的 <filename>:L<begin>-<end> 告诉它关注哪些行,比较麻烦。
最近抽时间研究了 Neovim 的 AI 插件这块,因为我本身重度使用 OpenCode,因此选择这块除了通用了 AI 插件,还关注了 Neovim 的 OpenCode 插件。
经过初步调研,选择了几个目标插件,分别配置和使用后,最终选择了 Sidekick 插件。
测试的插件有:
avante.nvim[1] : Neovim 原生 UI,目前 Neovim 社区最推荐的 AI 插件之一 codecompanion.nvim[2] : Neovim 原生 UI,也是社区最推荐的插件之一,比 avante 更 geek 化一些,适合非常深度的 Vim/Neovim 使用者,我用了一阵子,不太习惯 sidekick.nvim[3] : 除了支持 OpenCode,还支持 Codex-CLI、Claude Code、Gemini(要关闭了,估计近期会支持 Antigravity-CLI)。 nickjvandyke/opencode.nvim[4] : 内嵌 OpenCode TUI sudo-tee/opencode.nvim[5] : 二次开发,Neovim 原生 UI 调用 OpenCode
选择的原因很简单,虽然我也是 Vim/Neovim 重度使用者,但是同样也习惯 OpenCode 的 TUI,因此两者兼顾下,我完全不需要一个习惯的过程,体验很丝滑。其次,除了 OpenCode,我还使用 Codex-CLI、Claude Code等,Sidekick 支持这些对我来说简直就是完美。
#Sidekick 是什么
Sidekick 是 folke(LazyVim 作者)的新作。主要功能有两方面:
NES(Next Edit Suggestions):基于 Copilot LSP 的智能编辑建议,需要 Copilot 订阅,我没有,所以配置里关闭了这个功能。 AI CLI Terminal:在 Neovim 右侧开一个终端窗口,跑 OpenCode、Codex-CLI、Claude Code、Gemini 这些 AI 终端。和在终端里直接跑一模一样,只是不用离开编辑器。
这个定位和 Avante、CodeCompanion 完全不同。后两者是在 Neovim 里做原生 Chat UI。Sidekick 不做这件事,它只管把 AI CLI 嵌进 Neovim,协助把上下文发给 AI。
#安装与配置
Sidekick 要求 Neovim ≥ 0.11.2,推荐 snacks.nvim 做 prompt / tool 选择器。用 lazy.nvim 安装:
{"folke/sidekick.nvim",opts = {nes = { enabled = false },cli = {watch = true,win={layout="right",split={width=80} },mux={enabled=false },picker = "snacks",},},}
几个关键配置项:
nes.enabled:是否启用 NES。如果只用 AI CLI 功能,不需要 Copilot 就关掉cli.watch:AI 改完文件 Neovim 自动重载,很实用cli.win.layout:终端窗口位置,"right"是右侧侧边栏cli.mux.enabled:会话持久化,通过 tmux/zellij 让 AI CLI 进程在 Neovim 关闭后继续跑。日常false即可,重启 opencode 再选个历史 session 就行。
#核心快捷键
Sidekick 官方 lazy.nvim 示例里的快捷键前缀是 <leader>a,我为了避免和其他插件冲突,改成了 <leader>s。下面用 <prefix> 表示这个前缀——官方示例 <prefix> = <leader>a,我的配置 <prefix> = <leader>s。
<prefix>a | |||
<prefix>s | |||
<prefix>d | |||
<prefix>t | {this} | ||
<prefix>f | {file} | ||
<prefix>v | |||
<prefix>p | |||
<prefix>c | |||
<c-h> |
官方示例里有一个 <c-.>,用于从代码区 focus 到 Sidekick 终端;Sidekick 终端窗口内也默认绑定了 <c-.>,作用是隐藏终端。但这个键在终端模式下有个硬伤——Ctrl+<X> 在标准 ASCII 中没有对应控制字符,iTerm2/Ghostty 等终端直接发送 0x2E(普通 .),Neovim 无法区分 Ctrl+. 和 .,终端模式下按了只会输出一个点。目前我没有找到解决办法,所以我把跳转改成了 <c-h>:代码区按 <c-h> 跳到右侧 Sidekick 终端,终端内按 <c-h> 跳回左侧代码区,双向一步到位,这样也不用配置下面的 <c-h/j/k/l> 了。
其余就是将发送 {this}、{file}、{selection}、快捷打开 opencode 做了一些快捷键绑定,日常最常用的就三个:<prefix>a 打开面板,<c-h> 跳转,<prefix>p 选 prompt。
额外提一下,关于终端窗口内的快捷键,官方给了配置样例,但是这块不太建议配置,因为 TERMINAL 模式下,各个 AI CLI 有自己的一些快捷键,在 Neovim 层面做一些快捷键绑定,容易与 AI CLI 自己的快捷键冲突。
q | |
<c-q> | |
<c-.> | |
<c-z> | |
<c-h/j/k/l> | |
<c-p> | |
<c-f> | |
<c-b> |
#上下文变量与 Prompt Library
Sidekick 发给 AI 的「上下文」通常不是整份文件内容。Normal 模式下 {this} 会解析成当前位置引用(如 @src/main.lua:L32-55),AI CLI 收到后自己去读文件和工作区;Visual 模式下会在位置引用后追加选区文本。AI 的理解能力来自 OpenCode 等工具本身,Sidekick 主要负责传位置、选区、诊断等上下文。
几个常用的上下文变量:
{this} | |
{file} | |
{selection} | |
{diagnostics} | |
{function} |
{function|line} 这种写法是回退语法——先尝试 {function},失败就用 {line}。
Prompt Library 是 Sidekick 内置的 prompt 模板,通过 <prefix>p 选择。几个常用的:
explain | "Explain {this}" |
fix | "Can you fix {this}?" |
diagnostics | "Can you help me fix the diagnostics in {file}?\n{diagnostics}" |
review | "Can you review {file} for any issues or improvements?" |
tests | "Can you write tests for {this}?" |
也可以自定义 prompt:
cli = {prompts = {refactor = "Please refactor {this} to be more maintainable",security = "Review {file} for security vulnerabilities",},}
#外部会话
<prefix>s 选择工具时,比如 OpenCode,可能出现两条:
opencode [tmux:0] | |
opencode |
外部会话的典型用法:先在终端下手动启动 opencode,再切到 Neovim 用 <prefix>s 选外部会话 attach 上去。之后通过发送如 {this} 把代码相关部分发过去,会自动注入到 opencode 会话的编辑窗口。
比如我让 OpenCode 开发一个项目,然后另一个窗口用 Neovim 打开某个代码查看时,发现有一些地方需要改动,通过外部会话 attach 上去,直接选择文本发到绑定的 OpenCode 对话里让其修改。
#遇到的小坑
#鼠标滚轮失效
我的 Neovim 全局 mouse="" 禁用鼠标。但 Sidekick 终端里跑着 opencode TUI,滚轮翻页需要用到鼠标。mouse="" 让 Neovim 丢弃了鼠标事件,Sidekick 的滚轮监听收不到。
解决分两步。第一步:终端窗口打开时局部开鼠标,加 TermOpen autocmd:
vim.api.nvim_create_autocmd("TermOpen", {callback = function()vim.opt_local.mouse = "a"end,})
这样滚轮能用了,但会导致左边代码区的 mouse 也开启了,因此还需要下面。
第二步:加 WinEnter 白名单——每次切窗口时判断,终端类窗口开鼠标,其他窗口强制重置:
vim.api.nvim_create_autocmd("WinEnter", {callback = function()ifvim.bo.buftype=="terminal"orvim.bo.filetype=="sidekick_terminal"thenvim.opt_local.mouse = "a"elsevim.opt_local.mouse = ""endend,})
#非 tmux 下的外部会话看不到
Sidekick 对 OpenCode 的非 tmux 外部会话发现依赖 lsof 找有 TCP 监听端口的 opencode 进程。目前排查的结果是,从 OpenCode v1.1.10 起,TUI 模式默认不再启动 HTTP server(因为安全漏洞),lsof 找不到端口,非 tmux 下的 opencode 就发现不了。
这个暂时没找到解决方案,不过我一般都是在 tmux 下干活,因此问题不大,用了一阵子,偶尔一次没开 tmux 时使用,发现了这个问题。
#最后
Sidekick 本质就是:让 AI CLI 和 Neovim 无缝协作,同时保留了 AI CLI 工具的原生体验。因此,如果习惯了 AI CLI 工具自己的交互模式,同时又想嵌入到 Neovim 里使用,Sidekick 真的就是一个神器!
Over……
https://github.com/yetone/avante.nvim ↩ https://github.com/olimorris/codecompanion.nvim ↩ https://github.com/folke/sidekick.nvim ↩ https://github.com/nickjvandyke/opencode.nvim ↩ https://github.com/sudo-tee/opencode.nvim ↩
夜雨聆风