目前 Neovim 中的 AI 插件,比较火的就属 avante.nvim 和 codecompanion.nvim 了,经过简单的测试我选择了后者。
因为 avante.nvim 相对来说有些复杂,依赖组件过多,侵略性较强, 光 readme 中列出的 Key Bindings 就有好多。
还用到了 Leader 键, 我不是很喜欢被强制快捷键,如果与我的习惯键冲突就麻烦了,让我改我一时又不知道改成什么🫤,心理负担较重。
加上他的界面与我的审美也有冲突,界面好多默认元素无法删除,在我的小屏幕下看着比较难受。
而 Code Companion 就比较简洁键,几乎没有全局快捷键,也没有多余界面元素,安装成功后只会多出 4 条命令,如果需要可以自己来设置快捷键,入门毫无负担。
但相对在功能上可能会不如 avante。
我之前做了一个视频介绍如何使用和配置,并且集成 DeepSeek 和 Copilot 双 AI, 可以先了解一下。
https://www.bilibili.com/video/BV1ExNke9Een/?aid=113986687205...
这里再介绍一些高级配置。
如何设置中文问话中文回答
默认无论用中文还是英文提问,都会得到英文回答,想要得到中文回答,需要设置 opts 项 language 如下:
require("codecompanion").setup({
adapters = { ..... },
strategies = { ..... },
opts = {
language = "Chinese",
},
})
修复视频中第三方 DeeepSeek 源,显示思考的过程
前面的视频中我们继承了 openai_compatible
adapter,由于 openai 兼容是不会显示思考过程的,有些时候 DeepSeek 反应慢其实是在思考,并不是真的慢,只是没有显示出来,
如果想要显示思考的过程必须继承 deepseek
adapter 才行。 例如自定义 siliconflow 适配器,应该如下
siliconflow_r1 = function()
return require("codecompanion.adapters").extend("deepseek", {
name = "siliconflow_r1",
url = "https://api.siliconflow.cn/v1/chat/completions",
env = {
api_key = function()
return os.getenv("DEEPSEEK_API_KEY_S")
end,
},
schema = {
model = {
default = "deepseek-ai/DeepSeek-R1",
choices = {
["deepseek-ai/DeepSeek-R1"] = { opts = { can_reason = true } },
"deepseek-ai/DeepSeek-V3",
},
},
},
})
end,
aliyun_deepseek = function()
return require("codecompanion.adapters").extend("deepseek", {
name = "aliyun_deepseek",
url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
env = {
api_key = function()
return os.getenv("DEEPSEEK_API_ALIYUN")
end,
},
schema = {
model = {
default = "deepseek-r1",
choices = {
["deepseek-r1"] = { opts = { can_reason = true } },
},
},
},
})
end,
聊天窗口的 markdown 渲染
默认是没有渲染 markdown 的,需要手动安装 render-markdown.nvim
并指定 ft codecompanion
{
"MeanderingProgrammer/render-markdown.nvim",
ft = { "markdown", "codecompanion" },
},
自定义快捷键
自定义快捷键只需要映射到对应命令或者对应的方法即可,例如 :CodeCompanionChat
命令,或对应的方法 require("codecompanion").chat()
.
比如我只定义了这两个快捷键,注意这里的 [keymap 是我的自定义函数](https://github.com/nshen/InsisVim/blob/f91579548d888cd27aa019f10b60be201cd8ecf1/lua/insis/utils/global.lua#L25
)
keymap({ "n", "v", "x" }, "<leader>cc", function()
require("codecompanion").toggle()
end)
keymap({ "n", "v", "x" }, "<leader>cp", ":CodeCompanionActions<CR>")
自定义 promps
可以参考系统自带的promps来修改,比如这个 Explain
我把他全部改为了中文,并且指定用阿里云的deepseek来解释:
-- 放到setup函数中
prompt_library = {
["DeepSeek Explain In Chinese"] = {
strategy = "chat",
description = "中文解释代码",
opts = {
index = 5,
is_default = true,
is_slash_cmd = false,
modes = { "v" },
short_name = "explain in chinese",
auto_submit = true,
user_prompt = false,
stop_context_insertion = true,
adapter = {
name = "aliyun_deepseek",
model = "deepseek-r1",
},
},
prompts = {
{
role = "system",
content = [[当被要求解释代码时,请遵循以下步骤:
1. 识别编程语言。
2. 描述代码的目的,并引用该编程语言的核心概念。
3. 解释每个函数或重要的代码块,包括参数和返回值。
4. 突出说明使用的任何特定函数或方法及其作用。
5. 如果适用,提供该代码如何融入更大应用程序的上下文。]],
opts = {
visible = false,
},
},
{
role = "user",
content = function(context)
local input = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line)
return string.format(
[[请解释 buffer %d 中的这段代码:
\`\`\`%s
%s
\`\`\`
]],
context.bufnr,
context.filetype,
input
)
end,
opts = {
contains_code = true,
},
},
},
},
}
注意要去掉上边代码块 string.format 里的\\\
反斜杠,网页里不加反斜杠会被当成 markdown 结束,是渲染的渲染问题
用 fidget 实现状态提醒
fidget 就是 LSP 加载时常用的右下角的状态提醒,由于 codecompanion 开始和结束都有对应事件,所以可以使用fidget来提醒
我参考了这个讨论 实现了一个简化版
local fidget = pRequire("fidget")
local handler
if fidget then
-- Attach:
vim.api.nvim_create_autocmd({ "User" }, {
pattern = "CodeCompanionRequest*",
group = vim.api.nvim_create_augroup("CodeCompanionHooks", {}),
callback = function(request)
if request.match == "CodeCompanionRequestStarted" then
if handler then
handler.message = "Abort."
handler:cancel()
handler = nil
end
handler = fidget.progress.handle.create({
title = "",
message = "Thinking...",
lsp_client = { name = "CodeCompanion" },
})
elseif request.match == "CodeCompanionRequestFinished" then
if handler then
handler.message = "Done."
handler:finish()
handler = nil
end
end
end,
})
end
以上就是我目前的所有配置,附加一个使用技巧,在聊天框中如果遇到大语言模型回复卡住,
可以在聊天框中按 q
取消,按 gx
清空聊天记录,然后按 ga
来快速切换其他模型。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。