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:
@@ -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