feat: Allow inline buttons and popup confirmation for both ACP and normal Providers (#2760)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
@@ -505,6 +505,8 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_
|
|||||||
-- Examples:
|
-- Examples:
|
||||||
-- auto_approve_tool_permissions = false, -- Show permission prompts for all tools
|
-- auto_approve_tool_permissions = false, -- Show permission prompts for all tools
|
||||||
-- auto_approve_tool_permissions = {"bash", "replace_in_file"}, -- Auto-approve specific tools only
|
-- auto_approve_tool_permissions = {"bash", "replace_in_file"}, -- Auto-approve specific tools only
|
||||||
|
---@type "popup" | "inline_buttons"
|
||||||
|
confirmation_ui_style = "inline_buttons",
|
||||||
},
|
},
|
||||||
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
||||||
enabled = true, -- toggle logging entirely
|
enabled = true, -- toggle logging entirely
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ _请参见 [config.lua#L9](./lua/avante/config.lua) 以获取完整配置_
|
|||||||
auto_add_current_file = true, -- 打开新聊天时是否自动添加当前文件。默认为 true。
|
auto_add_current_file = true, -- 打开新聊天时是否自动添加当前文件。默认为 true。
|
||||||
enable_cursor_planning_mode = false, -- 是否启用 Cursor 规划模式。默认为 false。
|
enable_cursor_planning_mode = false, -- 是否启用 Cursor 规划模式。默认为 false。
|
||||||
enable_claude_text_editor_tool_mode = false, -- 是否启用 Claude 文本编辑器工具模式。
|
enable_claude_text_editor_tool_mode = false, -- 是否启用 Claude 文本编辑器工具模式。
|
||||||
|
---@type "popup" | "inline_buttons"
|
||||||
|
confirmation_ui_style = "inline_buttons",
|
||||||
},
|
},
|
||||||
mappings = {
|
mappings = {
|
||||||
--- @class AvanteConflictMappings
|
--- @class AvanteConflictMappings
|
||||||
|
|||||||
@@ -517,6 +517,10 @@ M._defaults = {
|
|||||||
enable_fastapply = false,
|
enable_fastapply = false,
|
||||||
include_generated_by_commit_line = false, -- Controls if 'Generated-by: <provider/model>' line is added to git commit message
|
include_generated_by_commit_line = false, -- Controls if 'Generated-by: <provider/model>' line is added to git commit message
|
||||||
auto_add_current_file = true, -- Whether to automatically add the current file when opening a new chat
|
auto_add_current_file = true, -- Whether to automatically add the current file when opening a new chat
|
||||||
|
--- popup is the original yes,all,no in a floating window
|
||||||
|
--- inline_buttons is the new inline buttons in the sidebar
|
||||||
|
---@type "popup" | "inline_buttons"
|
||||||
|
confirmation_ui_style = "inline_buttons",
|
||||||
},
|
},
|
||||||
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
||||||
enabled = true, -- toggle logging entirely
|
enabled = true, -- toggle logging entirely
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ local Providers = require("avante.providers")
|
|||||||
local LLMToolHelpers = require("avante.llm_tools.helpers")
|
local LLMToolHelpers = require("avante.llm_tools.helpers")
|
||||||
local LLMTools = require("avante.llm_tools")
|
local LLMTools = require("avante.llm_tools")
|
||||||
local History = require("avante.history")
|
local History = require("avante.history")
|
||||||
local Highlights = require("avante.highlights")
|
local HistoryRender = require("avante.history.render")
|
||||||
|
local ACPConfirmAdapter = require("avante.ui.acp_confirm_adapter")
|
||||||
|
|
||||||
---@class avante.LLM
|
---@class avante.LLM
|
||||||
local M = {}
|
local M = {}
|
||||||
@@ -49,10 +50,9 @@ function M.summarize_memory(prev_memory, history_messages, cb)
|
|||||||
cb(nil)
|
cb(nil)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local Render = require("avante.history.render")
|
|
||||||
local conversation_items = vim
|
local conversation_items = vim
|
||||||
.iter(history_messages)
|
.iter(history_messages)
|
||||||
:map(function(msg) return msg.message.role .. ": " .. Render.message_to_text(msg, history_messages) end)
|
:map(function(msg) return msg.message.role .. ": " .. HistoryRender.message_to_text(msg, history_messages) end)
|
||||||
:totable()
|
:totable()
|
||||||
local conversation_text = table.concat(conversation_items, "\n")
|
local conversation_text = table.concat(conversation_items, "\n")
|
||||||
local user_prompt = "Here is the conversation so far:\n"
|
local user_prompt = "Here is the conversation so far:\n"
|
||||||
@@ -1040,33 +1040,9 @@ function M._stream_acp(opts)
|
|||||||
Utils.error("Avante sidebar not found")
|
Utils.error("Avante sidebar not found")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
---@cast tool_call avante.acp.ToolCall
|
---@cast tool_call avante.acp.ToolCall
|
||||||
local items = vim
|
|
||||||
.iter(options)
|
|
||||||
:map(function(item)
|
|
||||||
local icon = item.kind == "allow_once" and "" or ""
|
|
||||||
if item.kind == "allow_always" then icon = "" end
|
|
||||||
local hl = nil
|
|
||||||
if item.kind == "reject_once" or item.kind == "reject_always" then
|
|
||||||
hl = Highlights.BUTTON_DANGER_HOVER
|
|
||||||
end
|
|
||||||
return {
|
|
||||||
id = item.optionId,
|
|
||||||
name = item.name,
|
|
||||||
icon = icon,
|
|
||||||
hl = hl,
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
:totable()
|
|
||||||
sidebar.permission_button_options = items
|
|
||||||
sidebar.permission_handler = function(id)
|
|
||||||
callback(id)
|
|
||||||
sidebar.scroll = true
|
|
||||||
sidebar.permission_button_options = nil
|
|
||||||
sidebar.permission_handler = nil
|
|
||||||
sidebar._history_cache_invalidated = true
|
|
||||||
sidebar:update_content("")
|
|
||||||
end
|
|
||||||
local message = tool_call_messages[tool_call.toolCallId]
|
local message = tool_call_messages[tool_call.toolCallId]
|
||||||
if not message then
|
if not message then
|
||||||
message = add_tool_call_message(tool_call)
|
message = add_tool_call_message(tool_call)
|
||||||
@@ -1076,7 +1052,29 @@ function M._stream_acp(opts)
|
|||||||
message.acp_tool_call = vim.tbl_deep_extend("force", message.acp_tool_call, tool_call)
|
message.acp_tool_call = vim.tbl_deep_extend("force", message.acp_tool_call, tool_call)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
on_messages_add({ message })
|
on_messages_add({ message })
|
||||||
|
|
||||||
|
local description = HistoryRender.get_tool_display_name(message)
|
||||||
|
LLMToolHelpers.confirm(description, function(ok)
|
||||||
|
local acp_mapped_options = ACPConfirmAdapter.map_acp_options(options)
|
||||||
|
|
||||||
|
if ok and opts.session_ctx and opts.session_ctx.always_yes then
|
||||||
|
callback(acp_mapped_options.all)
|
||||||
|
elseif ok then
|
||||||
|
callback(acp_mapped_options.yes)
|
||||||
|
else
|
||||||
|
callback(acp_mapped_options.no)
|
||||||
|
end
|
||||||
|
|
||||||
|
sidebar.scroll = true
|
||||||
|
sidebar._history_cache_invalidated = true
|
||||||
|
sidebar:update_content("")
|
||||||
|
end, {
|
||||||
|
focus = true,
|
||||||
|
skip_reject_prompt = true,
|
||||||
|
permission_options = options,
|
||||||
|
}, opts.session_ctx, tool_call.kind)
|
||||||
end,
|
end,
|
||||||
on_read_file = function(path, line, limit, callback)
|
on_read_file = function(path, line, limit, callback)
|
||||||
local abs_path = Utils.to_absolute_path(path)
|
local abs_path = Utils.to_absolute_path(path)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
local Utils = require("avante.utils")
|
local Utils = require("avante.utils")
|
||||||
local Path = require("plenary.path")
|
local Path = require("plenary.path")
|
||||||
|
local Config = require("avante.config")
|
||||||
|
local ACPConfirmAdapter = require("avante.ui.acp_confirm_adapter")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -19,9 +21,34 @@ function M.get_abs_path(rel_path)
|
|||||||
return p
|
return p
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type avante.acp.PermissionOption[]
|
||||||
|
local default_permission_options = {
|
||||||
|
{ optionId = "allow_always", name = "Allow Always", kind = "allow_always" },
|
||||||
|
{ optionId = "allow_once", name = "Allow", kind = "allow_once" },
|
||||||
|
{ optionId = "reject_once", name = "Reject", kind = "reject_once" },
|
||||||
|
}
|
||||||
|
|
||||||
|
---@param callback fun(option_id: string)
|
||||||
|
---@param confirm_opts avante.ui.ConfirmOptions
|
||||||
|
function M.confirm_inline(callback, confirm_opts)
|
||||||
|
local sidebar = require("avante").get()
|
||||||
|
local items =
|
||||||
|
ACPConfirmAdapter.generate_buttons_for_acp_options(confirm_opts.permission_options or default_permission_options)
|
||||||
|
|
||||||
|
sidebar.permission_button_options = items
|
||||||
|
sidebar.permission_handler = function(id)
|
||||||
|
callback(id)
|
||||||
|
sidebar.scroll = true
|
||||||
|
sidebar.permission_button_options = nil
|
||||||
|
sidebar.permission_handler = nil
|
||||||
|
sidebar._history_cache_invalidated = true
|
||||||
|
sidebar:update_content("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@param message string
|
---@param message string
|
||||||
---@param callback fun(yes: boolean, reason?: string)
|
---@param callback fun(response: boolean, reason?: string)
|
||||||
---@param confirm_opts? { focus?: boolean }
|
---@param confirm_opts? avante.ui.ConfirmOptions
|
||||||
---@param session_ctx? table
|
---@param session_ctx? table
|
||||||
---@param tool_name? string -- Optional tool name to check against tool_permissions config
|
---@param tool_name? string -- Optional tool name to check against tool_permissions config
|
||||||
---@return avante.ui.Confirm | nil
|
---@return avante.ui.Confirm | nil
|
||||||
@@ -32,7 +59,6 @@ function M.confirm(message, callback, confirm_opts, session_ctx, tool_name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check behaviour.auto_approve_tool_permissions config for auto-approval
|
-- Check behaviour.auto_approve_tool_permissions config for auto-approval
|
||||||
local Config = require("avante.config")
|
|
||||||
local auto_approve = Config.behaviour.auto_approve_tool_permissions
|
local auto_approve = Config.behaviour.auto_approve_tool_permissions
|
||||||
|
|
||||||
-- If auto_approve is true, auto-approve all tools
|
-- If auto_approve is true, auto-approve all tools
|
||||||
@@ -46,6 +72,20 @@ function M.confirm(message, callback, confirm_opts, session_ctx, tool_name)
|
|||||||
callback(true)
|
callback(true)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Config.behaviour.confirmation_ui_style == "inline_buttons" then
|
||||||
|
M.confirm_inline(function(option_id)
|
||||||
|
if option_id == "allow" or option_id == "allow_once" or option_id == "allow_always" then
|
||||||
|
if option_id == "allow_always" and session_ctx then session_ctx.always_yes = true end
|
||||||
|
|
||||||
|
callback(true)
|
||||||
|
else
|
||||||
|
callback(false, option_id)
|
||||||
|
end
|
||||||
|
end, confirm_opts or {})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local Confirm = require("avante.ui.confirm")
|
local Confirm = require("avante.ui.confirm")
|
||||||
local sidebar = require("avante").get()
|
local sidebar = require("avante").get()
|
||||||
if not sidebar or not sidebar.containers.input or not sidebar.containers.input.winid then
|
if not sidebar or not sidebar.containers.input or not sidebar.containers.input.winid then
|
||||||
|
|||||||
@@ -118,8 +118,6 @@ vim.g.avante_login = vim.g.avante_login
|
|||||||
---@field is_calling boolean | nil
|
---@field is_calling boolean | nil
|
||||||
---@field original_content AvanteLLMMessageContent | nil
|
---@field original_content AvanteLLMMessageContent | nil
|
||||||
---@field acp_tool_call? avante.acp.ToolCall
|
---@field acp_tool_call? avante.acp.ToolCall
|
||||||
---@field permission_options? avante.acp.PermissionOption[]
|
|
||||||
---@field is_permission_confirming? boolean
|
|
||||||
|
|
||||||
---@class AvanteLLMToolResult
|
---@class AvanteLLMToolResult
|
||||||
---@field tool_name string
|
---@field tool_name string
|
||||||
|
|||||||
65
lua/avante/ui/acp_confirm_adapter.lua
Normal file
65
lua/avante/ui/acp_confirm_adapter.lua
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
local Highlights = require("avante.highlights")
|
||||||
|
|
||||||
|
---@class avante.ui.ConfirmAdapter
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
---@class avante.ui.ACPConfirmAdapter.ACPMappedOptions
|
||||||
|
---@field yes? string
|
||||||
|
---@field all? string
|
||||||
|
---@field no? string
|
||||||
|
|
||||||
|
---Converts the ACP permission options to confirmation popup-compatible format (yes/all/no)
|
||||||
|
---@param options avante.acp.PermissionOption[]
|
||||||
|
---@return avante.ui.ACPConfirmAdapter.ACPMappedOptions
|
||||||
|
function M.map_acp_options(options)
|
||||||
|
local option_map = { yes = nil, all = nil, no = nil }
|
||||||
|
|
||||||
|
for _, opt in ipairs(options) do
|
||||||
|
if opt.kind == "allow_once" then
|
||||||
|
option_map.yes = opt.optionId
|
||||||
|
elseif opt.kind == "allow_always" then
|
||||||
|
option_map.all = opt.optionId
|
||||||
|
elseif opt.kind == "reject_once" then
|
||||||
|
option_map.no = opt.optionId
|
||||||
|
|
||||||
|
-- elseif opt.kind == "reject_always" then
|
||||||
|
-- ignore, no 4th option in the confirm popup yet
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return option_map
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class avante.ui.ACPConfirmAdapter.ButtonOption
|
||||||
|
---@field id string
|
||||||
|
---@field icon string
|
||||||
|
---@field name string
|
||||||
|
---@field hl? string
|
||||||
|
|
||||||
|
---@param options avante.acp.PermissionOption[]
|
||||||
|
---@return avante.ui.ACPConfirmAdapter.ButtonOption[]
|
||||||
|
function M.generate_buttons_for_acp_options(options)
|
||||||
|
local items = vim
|
||||||
|
.iter(options)
|
||||||
|
:map(function(item)
|
||||||
|
---@cast item avante.acp.PermissionOption
|
||||||
|
local icon = item.kind == "allow_once" and "" or ""
|
||||||
|
if item.kind == "allow_always" then icon = "" end
|
||||||
|
local hl = nil
|
||||||
|
if item.kind == "reject_once" or item.kind == "reject_always" then hl = Highlights.BUTTON_DANGER_HOVER end
|
||||||
|
---@type avante.ui.ACPConfirmAdapter.ButtonOption
|
||||||
|
local button = {
|
||||||
|
id = item.optionId,
|
||||||
|
name = item.name,
|
||||||
|
icon = icon,
|
||||||
|
hl = hl,
|
||||||
|
}
|
||||||
|
return button
|
||||||
|
end)
|
||||||
|
:totable()
|
||||||
|
-- Sort to have "allow" first, then "allow always", then "reject"
|
||||||
|
table.sort(items, function(a, b) return a.name < b.name end)
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -15,19 +15,27 @@ local Config = require("avante.config")
|
|||||||
---@field _popup NuiPopup | nil
|
---@field _popup NuiPopup | nil
|
||||||
---@field _prev_winid number | nil
|
---@field _prev_winid number | nil
|
||||||
---@field _ns_id number | nil
|
---@field _ns_id number | nil
|
||||||
|
---@field _skip_reject_prompt boolean | nil
|
||||||
local M = {}
|
local M = {}
|
||||||
M.__index = M
|
M.__index = M
|
||||||
|
|
||||||
|
---@class avante.ui.ConfirmOptions
|
||||||
|
---@field container_winid? number
|
||||||
|
---@field focus? boolean | nil
|
||||||
|
---@field skip_reject_prompt? boolean ACP doesn't support reject reason
|
||||||
|
---@field permission_options? avante.acp.PermissionOption[] ACP permission options to show in the confirm popup
|
||||||
|
|
||||||
---@param message string
|
---@param message string
|
||||||
---@param callback fun(type: "yes" | "all" | "no", reason?: string)
|
---@param callback fun(type: "yes" | "all" | "no", reason?: string)
|
||||||
---@param opts { container_winid: number, focus?: boolean }
|
---@param opts avante.ui.ConfirmOptions
|
||||||
---@return avante.ui.Confirm
|
---@return avante.ui.Confirm
|
||||||
function M:new(message, callback, opts)
|
function M:new(message, callback, opts)
|
||||||
local this = setmetatable({}, M)
|
local this = setmetatable({}, M)
|
||||||
this.message = message
|
this.message = message or ""
|
||||||
this.callback = callback
|
this.callback = callback
|
||||||
this._container_winid = opts.container_winid or vim.api.nvim_get_current_win()
|
this._container_winid = opts.container_winid or vim.api.nvim_get_current_win()
|
||||||
this._focus = opts.focus
|
this._focus = opts.focus
|
||||||
|
this._skip_reject_prompt = opts.skip_reject_prompt
|
||||||
this._ns_id = vim.api.nvim_create_namespace("avante_confirm")
|
this._ns_id = vim.api.nvim_create_namespace("avante_confirm")
|
||||||
return this
|
return this
|
||||||
end
|
end
|
||||||
@@ -35,12 +43,12 @@ end
|
|||||||
function M:open()
|
function M:open()
|
||||||
if self._popup then return end
|
if self._popup then return end
|
||||||
self._prev_winid = vim.api.nvim_get_current_win()
|
self._prev_winid = vim.api.nvim_get_current_win()
|
||||||
local message = self.message
|
local message = self.message or ""
|
||||||
local callback = self.callback
|
local callback = self.callback
|
||||||
|
|
||||||
local win_width = 60
|
local win_width = 60
|
||||||
|
|
||||||
local focus_index = 3 -- 1 = Yes, 2 = All Yes, 3 = No
|
local focus_index = 1 -- 1 = Yes, 2 = All Yes, 3 = No
|
||||||
|
|
||||||
local BUTTON_NORMAL = Highlights.BUTTON_DEFAULT
|
local BUTTON_NORMAL = Highlights.BUTTON_DEFAULT
|
||||||
local BUTTON_FOCUS = Highlights.BUTTON_DEFAULT_HOVER
|
local BUTTON_FOCUS = Highlights.BUTTON_DEFAULT_HOVER
|
||||||
@@ -61,21 +69,26 @@ function M:open()
|
|||||||
{ " - input ", commentfg },
|
{ " - input ", commentfg },
|
||||||
{ " " },
|
{ " " },
|
||||||
})
|
})
|
||||||
|
|
||||||
local buttons_line = Line:new({
|
local buttons_line = Line:new({
|
||||||
{ " [Y]es ", function() return focus_index == 1 and BUTTON_FOCUS or BUTTON_NORMAL end },
|
{ " [Y]es ", function() return focus_index == 1 and BUTTON_FOCUS or BUTTON_NORMAL end },
|
||||||
{ " " },
|
{ " " },
|
||||||
{ " [A]ll yes ", function() return focus_index == 2 and BUTTON_FOCUS or BUTTON_NORMAL end },
|
{ " [A]ll yes ", function() return focus_index == 2 and BUTTON_FOCUS or BUTTON_NORMAL end },
|
||||||
{ " " },
|
{ " " },
|
||||||
{ " [N]o ", function() return focus_index == 3 and BUTTON_FOCUS or BUTTON_NORMAL end },
|
{ " [N]o ", function() return focus_index == 3 and BUTTON_FOCUS or BUTTON_NORMAL end },
|
||||||
})
|
})
|
||||||
|
|
||||||
local buttons_content = tostring(buttons_line)
|
local buttons_content = tostring(buttons_line)
|
||||||
local buttons_start_col = math.floor((win_width - #buttons_content) / 2)
|
local buttons_start_col = math.floor((win_width - #buttons_content) / 2)
|
||||||
|
|
||||||
local yes_button_pos = buttons_line:get_section_pos(1, buttons_start_col)
|
local yes_button_pos = buttons_line:get_section_pos(1, buttons_start_col)
|
||||||
local all_button_pos = buttons_line:get_section_pos(3, buttons_start_col)
|
local all_button_pos = buttons_line:get_section_pos(3, buttons_start_col)
|
||||||
local no_button_pos = buttons_line:get_section_pos(5, buttons_start_col)
|
local no_button_pos = buttons_line:get_section_pos(5, buttons_start_col)
|
||||||
|
|
||||||
local buttons_line_content = string.rep(" ", buttons_start_col) .. buttons_content
|
local buttons_line_content = string.rep(" ", buttons_start_col) .. buttons_content
|
||||||
local keybindings_line_num = 5 + #vim.split(message, "\n")
|
local keybindings_line_num = 5 + #vim.split(message, "\n")
|
||||||
local buttons_line_num = 2 + #vim.split(message, "\n")
|
local buttons_line_num = 2 + #vim.split(message, "\n")
|
||||||
|
|
||||||
local content = vim
|
local content = vim
|
||||||
.iter({
|
.iter({
|
||||||
"",
|
"",
|
||||||
@@ -157,12 +170,19 @@ function M:open()
|
|||||||
callback("yes")
|
callback("yes")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if focus_index == 2 then
|
if focus_index == 2 then
|
||||||
self:close()
|
self:close()
|
||||||
Utils.notify("Accept all")
|
|
||||||
callback("all")
|
callback("all")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self._skip_reject_prompt then
|
||||||
|
self:close()
|
||||||
|
callback("no")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local prompt_input = PromptInput:new({
|
local prompt_input = PromptInput:new({
|
||||||
submit_callback = function(input)
|
submit_callback = function(input)
|
||||||
self:close()
|
self:close()
|
||||||
|
|||||||
93
tests/ui/acp_confirm_adapter_spec.lua
Normal file
93
tests/ui/acp_confirm_adapter_spec.lua
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
local ACPConfirmAdapter = require("avante.ui.acp_confirm_adapter")
|
||||||
|
|
||||||
|
describe("ACPConfirmAdapter", function()
|
||||||
|
describe("map_acp_options", function()
|
||||||
|
it("should ignore reject_always", function()
|
||||||
|
local options = { { kind = "reject_always", optionId = "opt4" } }
|
||||||
|
local result = ACPConfirmAdapter.map_acp_options(options)
|
||||||
|
assert.is_nil(result.yes)
|
||||||
|
assert.is_nil(result.all)
|
||||||
|
assert.is_nil(result.no)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should map multiple options correctly", function()
|
||||||
|
local options = {
|
||||||
|
{ kind = "allow_once", optionId = "yes_id" },
|
||||||
|
{ kind = "allow_always", optionId = "all_id" },
|
||||||
|
{ kind = "reject_once", optionId = "no_id" },
|
||||||
|
{ kind = "reject_always", optionId = "ignored_id" },
|
||||||
|
}
|
||||||
|
local result = ACPConfirmAdapter.map_acp_options(options)
|
||||||
|
assert.equals("yes_id", result.yes)
|
||||||
|
assert.equals("all_id", result.all)
|
||||||
|
assert.equals("no_id", result.no)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should handle empty options", function()
|
||||||
|
local options = {}
|
||||||
|
local result = ACPConfirmAdapter.map_acp_options(options)
|
||||||
|
assert.is_nil(result.yes)
|
||||||
|
assert.is_nil(result.all)
|
||||||
|
assert.is_nil(result.no)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("generate_buttons_for_acp_options", function()
|
||||||
|
it("should generate buttons with correct properties for each option kind", function()
|
||||||
|
local options = {
|
||||||
|
{ kind = "allow_once", optionId = "opt1", name = "Allow" },
|
||||||
|
{ kind = "allow_always", optionId = "opt2", name = "Allow always" },
|
||||||
|
{ kind = "reject_once", optionId = "opt3", name = "Reject" },
|
||||||
|
{ kind = "reject_always", optionId = "opt4", name = "Reject always" },
|
||||||
|
}
|
||||||
|
local result = ACPConfirmAdapter.generate_buttons_for_acp_options(options)
|
||||||
|
assert.equals(4, #result)
|
||||||
|
|
||||||
|
for _, button in ipairs(result) do
|
||||||
|
assert.is_not_nil(button.id)
|
||||||
|
assert.is_not_nil(button.name)
|
||||||
|
assert.is_not_nil(button.icon)
|
||||||
|
assert.is_string(button.icon)
|
||||||
|
|
||||||
|
if button.name == "Reject" or button.name == "Reject always" then
|
||||||
|
assert.is_not_nil(button.hl)
|
||||||
|
else
|
||||||
|
assert.is_nil(button.hl)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should handle multiple options and sort by name", function()
|
||||||
|
local options = {
|
||||||
|
{ kind = "reject_once", optionId = "opt3", name = "Reject" },
|
||||||
|
{ kind = "allow_once", optionId = "opt1", name = "Allow" },
|
||||||
|
{ kind = "allow_always", optionId = "opt2", name = "Allow always" },
|
||||||
|
}
|
||||||
|
local result = ACPConfirmAdapter.generate_buttons_for_acp_options(options)
|
||||||
|
assert.equals(3, #result)
|
||||||
|
assert.equals("Allow", result[1].name)
|
||||||
|
assert.equals("Allow always", result[2].name)
|
||||||
|
assert.equals("Reject", result[3].name)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should handle empty options", function()
|
||||||
|
local options = {}
|
||||||
|
local result = ACPConfirmAdapter.generate_buttons_for_acp_options(options)
|
||||||
|
assert.equals(0, #result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should preserve all button properties", function()
|
||||||
|
local options = {
|
||||||
|
{ kind = "allow_once", optionId = "id1", name = "Button 1" },
|
||||||
|
{ kind = "reject_once", optionId = "id2", name = "Button 2" },
|
||||||
|
}
|
||||||
|
local result = ACPConfirmAdapter.generate_buttons_for_acp_options(options)
|
||||||
|
assert.equals(2, #result)
|
||||||
|
for _, button in ipairs(result) do
|
||||||
|
assert.is_not_nil(button.id)
|
||||||
|
assert.is_not_nil(button.name)
|
||||||
|
assert.is_not_nil(button.icon)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
Reference in New Issue
Block a user