feat: implement user-defined text shortcuts (#2512)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
78
README.md
78
README.md
@@ -642,11 +642,65 @@ For lazyvim users copy the full config for blink.cmp from the website or extend
|
||||
|
||||
For other users just add a custom provider
|
||||
|
||||
### Available Completion Sources
|
||||
|
||||
Avante.nvim provides several completion sources that can be integrated with blink.cmp:
|
||||
|
||||
#### Mentions (`@` trigger)
|
||||
Mentions allow you to quickly reference specific features or add files to the chat context:
|
||||
|
||||
- `@codebase` - Enable project context and repository mapping
|
||||
- `@diagnostics` - Enable diagnostics information
|
||||
- `@file` - Open file selector to add files to chat context
|
||||
- `@quickfix` - Add files from quickfix list to chat context
|
||||
- `@buffers` - Add open buffers to chat context
|
||||
|
||||
#### Slash Commands (`/` trigger)
|
||||
Built-in slash commands for common operations:
|
||||
|
||||
- `/help` - Show help message with available commands
|
||||
- `/init` - Initialize AGENTS.md based on current project
|
||||
- `/clear` - Clear chat history
|
||||
- `/new` - Start a new chat
|
||||
- `/compact` - Compact history messages to save tokens
|
||||
- `/lines <start>-<end> <question>` - Ask about specific lines
|
||||
- `/commit` - Generate commit message for changes
|
||||
|
||||
#### Shortcuts (`#` trigger)
|
||||
Shortcuts provide quick access to predefined prompt templates. You can customize these in your config:
|
||||
|
||||
```lua
|
||||
{
|
||||
shortcuts = {
|
||||
{
|
||||
name = "refactor",
|
||||
description = "Refactor code with best practices",
|
||||
details = "Automatically refactor code to improve readability, maintainability, and follow best practices while preserving functionality",
|
||||
prompt = "Please refactor this code following best practices, improving readability and maintainability while preserving functionality."
|
||||
},
|
||||
{
|
||||
name = "test",
|
||||
description = "Generate unit tests",
|
||||
details = "Create comprehensive unit tests covering edge cases, error scenarios, and various input conditions",
|
||||
prompt = "Please generate comprehensive unit tests for this code, covering edge cases and error scenarios."
|
||||
},
|
||||
-- Add more custom shortcuts...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When you type `#refactor` in the input, it will automatically be replaced with the corresponding prompt text.
|
||||
|
||||
### Configuration Example
|
||||
|
||||
Here's a complete blink.cmp configuration example with all Avante sources:
|
||||
|
||||
```lua
|
||||
default = {
|
||||
...
|
||||
"avante_commands",
|
||||
"avante_mentions",
|
||||
"avante_shortcuts",
|
||||
"avante_files",
|
||||
}
|
||||
```
|
||||
@@ -670,6 +724,12 @@ For other users just add a custom provider
|
||||
module = "blink.compat.source",
|
||||
score_offset = 1000, -- show at a higher priority than lsp
|
||||
opts = {},
|
||||
},
|
||||
avante_shortcuts = {
|
||||
name = "avante_shortcuts",
|
||||
module = "blink.compat.source",
|
||||
score_offset = 1000, -- show at a higher priority than lsp
|
||||
opts = {},
|
||||
}
|
||||
...
|
||||
}
|
||||
@@ -679,24 +739,6 @@ For other users just add a custom provider
|
||||
|
||||
## Usage
|
||||
|
||||
### @mentions
|
||||
|
||||
avante.nvim supports the following @mentions to help you reference different parts of your codebase:
|
||||
|
||||
| Mention | Description |
|
||||
| -------------- | ----------------------------------- |
|
||||
| `@codebase` | Include the entire codebase context |
|
||||
| `@diagnostics` | Include current diagnostic issues |
|
||||
| `@file` | Include the current file |
|
||||
| `@quickfix` | Include the quickfix list |
|
||||
| `@buffers` | Include all open buffers |
|
||||
|
||||
You can use these mentions in your conversations with avante.nvim to provide relevant context. For example:
|
||||
|
||||
- `@file what are the issues in this code?` - analyzes the current file
|
||||
- `@codebase explain the project structure` - looks at the entire codebase
|
||||
- `@diagnostics how do I fix these errors?` - helps resolve diagnostic issues
|
||||
|
||||
### Basic Functionality
|
||||
|
||||
Given its early stage, `avante.nvim` currently supports the following basic functionalities:
|
||||
|
||||
60
README_zh.md
60
README_zh.md
@@ -509,11 +509,65 @@ _请参见 [config.lua#L9](./lua/avante/config.lua) 以获取完整配置_
|
||||
|
||||
对于其他用户,只需添加自定义提供者
|
||||
|
||||
### 可用的补全项
|
||||
|
||||
Avante.nvim 提供了多个可以与 blink.cmp 集成的补全项:
|
||||
|
||||
#### 提及功能 (`@` 触发器)
|
||||
提及功能允许您快速引用特定功能或将文件添加到聊天上下文:
|
||||
|
||||
- `@codebase` - 启用项目上下文和仓库映射
|
||||
- `@diagnostics` - 启用诊断信息
|
||||
- `@file` - 打开文件选择器以将文件添加到聊天上下文
|
||||
- `@quickfix` - 将快速修复列表中的文件添加到聊天上下文
|
||||
- `@buffers` - 将打开的缓冲区添加到聊天上下文
|
||||
|
||||
#### 斜杠命令 (`/` 触发器)
|
||||
内置斜杠命令用于常见操作:
|
||||
|
||||
- `/help` - 显示可用命令的帮助信息
|
||||
- `/init` - 基于当前项目初始化 AGENTS.md
|
||||
- `/clear` - 清除聊天历史
|
||||
- `/new` - 开始新聊天
|
||||
- `/compact` - 压缩历史消息以节省令牌
|
||||
- `/lines <start>-<end> <question>` - 询问特定行的问题
|
||||
- `/commit` - 为更改生成提交消息
|
||||
|
||||
#### 快捷方式 (`#` 触发器)
|
||||
快捷方式提供对预定义提示模板的快速访问。您可以在配置中自定义这些:
|
||||
|
||||
```lua
|
||||
{
|
||||
shortcuts = {
|
||||
{
|
||||
name = "refactor",
|
||||
description = "使用最佳实践重构代码",
|
||||
details = "自动重构代码以提高可读性、可维护性,并遵循最佳实践,同时保持功能不变",
|
||||
prompt = "请按照最佳实践重构此代码,提高可读性和可维护性,同时保持功能不变。"
|
||||
},
|
||||
{
|
||||
name = "test",
|
||||
description = "生成单元测试",
|
||||
details = "创建全面的单元测试,涵盖边界情况、错误场景和各种输入条件",
|
||||
prompt = "请为此代码生成全面的单元测试,涵盖边界情况和错误场景。"
|
||||
},
|
||||
-- 添加更多自定义快捷方式...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当您在输入中键入 `#refactor` 时,它将自动替换为相应的提示文本。
|
||||
|
||||
### 配置示例
|
||||
|
||||
以下是包含所有 Avante 源的完整 blink.cmp 配置示例:
|
||||
|
||||
```lua
|
||||
default = {
|
||||
...
|
||||
"avante_commands",
|
||||
"avante_mentions",
|
||||
"avante_shortcuts",
|
||||
"avante_files",
|
||||
}
|
||||
```
|
||||
@@ -537,6 +591,12 @@ _请参见 [config.lua#L9](./lua/avante/config.lua) 以获取完整配置_
|
||||
module = "blink.compat.source",
|
||||
score_offset = 1000, -- 显示优先级高于 lsp
|
||||
opts = {},
|
||||
},
|
||||
avante_shortcuts = {
|
||||
name = "avante_shortcuts",
|
||||
module = "blink.compat.source",
|
||||
score_offset = 1000, -- 显示优先级高于 lsp
|
||||
opts = {},
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
@@ -676,6 +676,8 @@ M._defaults = {
|
||||
custom_tools = {},
|
||||
---@type AvanteSlashCommand[]
|
||||
slash_commands = {},
|
||||
---@type AvanteShortcut[]
|
||||
shortcuts = {},
|
||||
}
|
||||
|
||||
---@type avante.Config
|
||||
|
||||
@@ -496,11 +496,14 @@ function M.setup(opts)
|
||||
|
||||
cmp.register_source("avante_prompt_mentions", require("cmp_avante.mentions"):new(Utils.get_mentions))
|
||||
|
||||
cmp.register_source("avante_shortcuts", require("cmp_avante.shortcuts"):new())
|
||||
|
||||
cmp.setup.filetype({ "AvanteInput" }, {
|
||||
enabled = true,
|
||||
sources = {
|
||||
{ name = "avante_commands" },
|
||||
{ name = "avante_mentions" },
|
||||
{ name = "avante_shortcuts" },
|
||||
{ name = "avante_files" },
|
||||
},
|
||||
})
|
||||
|
||||
@@ -2446,6 +2446,10 @@ function Sidebar:create_input_container()
|
||||
end
|
||||
end
|
||||
|
||||
-- Process shortcut replacements
|
||||
local new_content, has_shortcuts = Utils.extract_shortcuts(request)
|
||||
if has_shortcuts then request = new_content end
|
||||
|
||||
local selected_filepaths = self.file_selector:get_selected_filepaths()
|
||||
|
||||
---@type AvanteSelectedCode | nil
|
||||
|
||||
@@ -521,3 +521,9 @@ vim.g.avante_login = vim.g.avante_login
|
||||
---@alias AvanteMentions "codebase" | "diagnostics" | "file" | "quickfix" | "buffers"
|
||||
---@alias AvanteMentionCallback fun(args: string, cb?: fun(args: string): nil): nil
|
||||
---@alias AvanteMention {description: string, command: AvanteMentions, details: string, shorthelp?: string, callback?: AvanteMentionCallback}
|
||||
|
||||
---@class AvanteShortcut
|
||||
---@field name string
|
||||
---@field details string
|
||||
---@field description string
|
||||
---@field prompt string
|
||||
|
||||
@@ -1076,6 +1076,98 @@ function M.get_chat_mentions()
|
||||
return mentions
|
||||
end
|
||||
|
||||
---@return AvanteShortcut[]
|
||||
function M.get_shortcuts()
|
||||
local Config = require("avante.config")
|
||||
|
||||
-- Built-in shortcuts
|
||||
local builtin_shortcuts = {
|
||||
{
|
||||
name = "refactor",
|
||||
description = "Refactor code with best practices",
|
||||
details = "Automatically refactor code to improve readability, maintainability, and follow best practices while preserving functionality",
|
||||
prompt = "Please refactor this code following best practices, improving readability and maintainability while preserving functionality.",
|
||||
},
|
||||
{
|
||||
name = "test",
|
||||
description = "Generate unit tests",
|
||||
details = "Create comprehensive unit tests covering edge cases, error scenarios, and various input conditions",
|
||||
prompt = "Please generate comprehensive unit tests for this code, covering edge cases and error scenarios.",
|
||||
},
|
||||
{
|
||||
name = "document",
|
||||
description = "Add documentation",
|
||||
details = "Add clear and comprehensive documentation including function descriptions, parameter explanations, and usage examples",
|
||||
prompt = "Please add clear and comprehensive documentation to this code, including function descriptions, parameter explanations, and usage examples.",
|
||||
},
|
||||
{
|
||||
name = "debug",
|
||||
description = "Add debugging information",
|
||||
details = "Add comprehensive debugging information including logging statements, error handling, and debugging utilities",
|
||||
prompt = "Please add comprehensive debugging information to this code, including logging statements, error handling, and debugging utilities.",
|
||||
},
|
||||
{
|
||||
name = "optimize",
|
||||
description = "Optimize performance",
|
||||
details = "Analyze and optimize code for better performance considering time complexity, memory usage, and algorithmic improvements",
|
||||
prompt = "Please analyze and optimize this code for better performance, considering time complexity, memory usage, and algorithmic improvements.",
|
||||
},
|
||||
{
|
||||
name = "security",
|
||||
description = "Security review",
|
||||
details = "Perform a security review identifying potential vulnerabilities, security best practices, and recommendations for improvement",
|
||||
prompt = "Please perform a security review of this code, identifying potential vulnerabilities, security best practices, and recommendations for improvement.",
|
||||
},
|
||||
}
|
||||
|
||||
local user_shortcuts = Config.shortcuts or {}
|
||||
local result = {}
|
||||
|
||||
-- Create a map of builtin shortcuts by name for quick lookup
|
||||
local builtin_map = {}
|
||||
for _, shortcut in ipairs(builtin_shortcuts) do
|
||||
builtin_map[shortcut.name] = shortcut
|
||||
end
|
||||
|
||||
-- Process user shortcuts first (they take precedence)
|
||||
for _, user_shortcut in ipairs(user_shortcuts) do
|
||||
if builtin_map[user_shortcut.name] then
|
||||
-- User has overridden a builtin shortcut
|
||||
table.insert(result, user_shortcut)
|
||||
builtin_map[user_shortcut.name] = nil -- Remove from builtin map
|
||||
else
|
||||
-- User has added a new shortcut
|
||||
table.insert(result, user_shortcut)
|
||||
end
|
||||
end
|
||||
|
||||
-- Add remaining builtin shortcuts that weren't overridden
|
||||
for _, builtin_shortcut in pairs(builtin_map) do
|
||||
table.insert(result, builtin_shortcut)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
---@param content string
|
||||
---@return string new_content
|
||||
---@return boolean has_shortcuts
|
||||
function M.extract_shortcuts(content)
|
||||
local shortcuts = M.get_shortcuts()
|
||||
local new_content = content
|
||||
local has_shortcuts = false
|
||||
|
||||
for _, shortcut in ipairs(shortcuts) do
|
||||
local pattern = "#" .. shortcut.name
|
||||
if content:match(pattern) then
|
||||
has_shortcuts = true
|
||||
new_content = new_content:gsub(pattern, shortcut.prompt)
|
||||
end
|
||||
end
|
||||
|
||||
return new_content, has_shortcuts
|
||||
end
|
||||
|
||||
---@param path string
|
||||
---@param set_current_buf? boolean
|
||||
---@return integer bufnr
|
||||
|
||||
51
lua/cmp_avante/shortcuts.lua
Normal file
51
lua/cmp_avante/shortcuts.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
local api = vim.api
|
||||
|
||||
---@class ShortcutsSource : cmp.Source
|
||||
local ShortcutsSource = {}
|
||||
ShortcutsSource.__index = ShortcutsSource
|
||||
|
||||
function ShortcutsSource:new()
|
||||
local instance = setmetatable({}, ShortcutsSource)
|
||||
return instance
|
||||
end
|
||||
|
||||
function ShortcutsSource:is_available() return vim.bo.filetype == "AvanteInput" end
|
||||
|
||||
function ShortcutsSource.get_position_encoding_kind() return "utf-8" end
|
||||
|
||||
function ShortcutsSource:get_trigger_characters() return { "#" } end
|
||||
|
||||
function ShortcutsSource:get_keyword_pattern() return [[\%(@\|#\|/\)\k*]] end
|
||||
|
||||
function ShortcutsSource:complete(_, callback)
|
||||
local Utils = require("avante.utils")
|
||||
local kind = require("cmp").lsp.CompletionItemKind.Variable
|
||||
local shortcuts = Utils.get_shortcuts()
|
||||
|
||||
local items = {}
|
||||
for _, shortcut in ipairs(shortcuts) do
|
||||
table.insert(items, {
|
||||
label = "#" .. shortcut.name,
|
||||
kind = kind,
|
||||
detail = shortcut.details,
|
||||
data = {
|
||||
name = shortcut.name,
|
||||
prompt = shortcut.prompt,
|
||||
details = shortcut.details,
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
callback({
|
||||
items = items,
|
||||
isIncomplete = false,
|
||||
})
|
||||
end
|
||||
|
||||
function ShortcutsSource:execute(item, callback)
|
||||
-- ShortcutsSource should only provide completion, not perform replacement
|
||||
-- The actual shortcut replacement is handled in sidebar.lua handle_submit function
|
||||
callback()
|
||||
end
|
||||
|
||||
return ShortcutsSource
|
||||
Reference in New Issue
Block a user