diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c3388f5..5fd31d1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -61,7 +61,6 @@ body: -- build = "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false" -- for windows dependencies = { "nvim-treesitter/nvim-treesitter", - "stevearc/dressing.nvim", "nvim-lua/plenary.nvim", "MunifTanjim/nui.nvim", }, diff --git a/.github/workflows/.luarc.json b/.github/workflows/.luarc.json index f328c1c..b3f2afb 100644 --- a/.github/workflows/.luarc.json +++ b/.github/workflows/.luarc.json @@ -14,6 +14,7 @@ "$DEPS_PATH/lazy.nvim/lua", "$DEPS_PATH/nvim-treesitter/lua", "$DEPS_PATH/dressing.nvim/lua", + "$DEPS_PATH/snacks.nvim/lua", "$DEPS_PATH/plenary.nvim/lua", "$DEPS_PATH/nui.nvim/lua", "$DEPS_PATH/mini.pick/lua", diff --git a/.github/workflows/lua.yaml b/.github/workflows/lua.yaml index ffcd73c..1cbf934 100644 --- a/.github/workflows/lua.yaml +++ b/.github/workflows/lua.yaml @@ -82,9 +82,10 @@ jobs: DEPS=( "folke/neodev.nvim" "nvim-treesitter/nvim-treesitter" - "stevearc/dressing.nvim" "nvim-lua/plenary.nvim" "MunifTanjim/nui.nvim" + "stevearc/dressing.nvim" + "folke/snacks.nvim" "echasnovski/mini.nvim" "nvim-telescope/telescope.nvim" "hrsh7th/nvim-cmp" diff --git a/README.md b/README.md index bd7b584..ccbd694 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,6 @@ For building binary if you wish to build from source, then `cargo` is required. -- build = "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false" -- for windows dependencies = { "nvim-treesitter/nvim-treesitter", - "stevearc/dressing.nvim", "nvim-lua/plenary.nvim", "MunifTanjim/nui.nvim", --- The below dependencies are optional, @@ -105,6 +104,8 @@ For building binary if you wish to build from source, then `cargo` is required. "nvim-telescope/telescope.nvim", -- for file_selector provider telescope "hrsh7th/nvim-cmp", -- autocompletion for avante commands and mentions "ibhagwan/fzf-lua", -- for file_selector provider fzf + "stevearc/dressing.nvim", -- for input provider dressing + "folke/snacks.nvim", -- for input provider snacks "nvim-tree/nvim-web-devicons", -- or echasnovski/mini.icons "zbirenbaum/copilot.lua", -- for providers='copilot' { @@ -146,7 +147,6 @@ For building binary if you wish to build from source, then `cargo` is required. " Deps Plug 'nvim-treesitter/nvim-treesitter' -Plug 'stevearc/dressing.nvim' Plug 'nvim-lua/plenary.nvim' Plug 'MunifTanjim/nui.nvim' Plug 'MeanderingProgrammer/render-markdown.nvim' @@ -156,6 +156,8 @@ Plug 'hrsh7th/nvim-cmp' Plug 'nvim-tree/nvim-web-devicons' "or Plug 'echasnovski/mini.icons' Plug 'HakonHarnes/img-clip.nvim' Plug 'zbirenbaum/copilot.lua' +Plug 'stevearc/dressing.nvim' " for enhanced input UI +Plug 'folke/snacks.nvim' " for modern input UI " Yay, pass source=true if you want to build from source Plug 'yetone/avante.nvim', { 'branch': 'main', 'do': 'make' } @@ -178,7 +180,6 @@ add({ monitor = 'main', depends = { 'nvim-treesitter/nvim-treesitter', - 'stevearc/dressing.nvim', 'nvim-lua/plenary.nvim', 'MunifTanjim/nui.nvim', 'echasnovski/mini.icons' @@ -209,7 +210,6 @@ end) -- Required plugins use 'nvim-treesitter/nvim-treesitter' - use 'stevearc/dressing.nvim' use 'nvim-lua/plenary.nvim' use 'MunifTanjim/nui.nvim' use 'MeanderingProgrammer/render-markdown.nvim' @@ -219,6 +219,8 @@ end) use 'nvim-tree/nvim-web-devicons' -- or use 'echasnovski/mini.icons' use 'HakonHarnes/img-clip.nvim' use 'zbirenbaum/copilot.lua' + use 'stevearc/dressing.nvim' -- for enhanced input UI + use 'folke/snacks.nvim' -- for modern input UI -- Avante.nvim with build process use { @@ -285,8 +287,18 @@ require('copilot').setup ({ require('render-markdown').setup ({ -- use recommended settings from above }) -require('avante').setup ({ - -- Your config here! +require('avante').setup({ + -- Example: Using snacks.nvim as input provider + input = { + provider = "snacks", -- "native" | "dressing" | "snacks" + provider_opts = { + -- Snacks input configuration + title = "Avante Input", + icon = " ", + placeholder = "Enter your API key...", + }, + }, + -- Your other config here! }) ``` @@ -497,6 +509,95 @@ To create a customized selector provider, you can specify a customized function } ``` +### Input Provider Configuration + +Avante.nvim supports multiple input providers for user input (like API key entry). You can configure which provider to use: + +
+ Native Input Provider (Default) + +```lua +{ + input = { + provider = "native", -- Uses vim.ui.input + provider_opts = {}, + } +} +``` + +
+ +
+ Dressing.nvim Input Provider + +For enhanced input UI with better styling and features: + +```lua +{ + input = { + provider = "dressing", + provider_opts = {}, + } +} +``` + +You'll need to install dressing.nvim: +```lua +-- With lazy.nvim +{ "stevearc/dressing.nvim" } +``` + +
+ +
+ Snacks.nvim Input Provider (Recommended) + +For modern, feature-rich input UI: + +```lua +{ + input = { + provider = "snacks", + provider_opts = { + -- Additional snacks.input options + title = "Avante Input", + icon = " ", + }, + } +} +``` + +You'll need to install snacks.nvim: +```lua +-- With lazy.nvim +{ "folke/snacks.nvim" } +``` + +
+ +
+ Custom Input Provider + +To create a customized input provider, you can specify a function: + +```lua +{ + input = { + ---@param input avante.ui.Input + provider = function(input) + local title = input.title ---@type string + local default = input.default ---@type string + local conceal = input.conceal ---@type boolean + local on_submit = input.on_submit ---@type fun(result: string|nil): nil + + --- your customized input logic here + end, + } +} +``` + +
+ Choose a selector other that native, the default as that currently has an issue For lazyvim users copy the full config for blink.cmp from the website or extend the options diff --git a/README_zh.md b/README_zh.md index e622010..99d4374 100644 --- a/README_zh.md +++ b/README_zh.md @@ -82,7 +82,7 @@ -- build = "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false" -- 对于 Windows dependencies = { "nvim-treesitter/nvim-treesitter", - "stevearc/dressing.nvim", + "nvim-lua/plenary.nvim", "MunifTanjim/nui.nvim", --- 以下依赖项是可选的, @@ -131,7 +131,7 @@ " 依赖项 Plug 'nvim-treesitter/nvim-treesitter' -Plug 'stevearc/dressing.nvim' + Plug 'nvim-lua/plenary.nvim' Plug 'MunifTanjim/nui.nvim' Plug 'MeanderingProgrammer/render-markdown.nvim' @@ -163,7 +163,7 @@ add({ monitor = 'main', depends = { 'nvim-treesitter/nvim-treesitter', - 'stevearc/dressing.nvim', + 'nvim-lua/plenary.nvim', 'MunifTanjim/nui.nvim', 'echasnovski/mini.icons' @@ -194,7 +194,7 @@ end) -- 必需插件 use 'nvim-treesitter/nvim-treesitter' - use 'stevearc/dressing.nvim' + use 'nvim-lua/plenary.nvim' use 'MunifTanjim/nui.nvim' use 'MeanderingProgrammer/render-markdown.nvim' diff --git a/lua/avante/api.lua b/lua/avante/api.lua index b559cd4..48da87a 100644 --- a/lua/avante/api.lua +++ b/lua/avante/api.lua @@ -20,6 +20,15 @@ function M.switch_selector_provider(target_provider) }) end +---@param target_provider avante.InputProvider +function M.switch_input_provider(target_provider) + require("avante.config").override({ + input = { + provider = target_provider, + }, + }) +end + ---@param target avante.ProviderName function M.switch_provider(target) require("avante.providers").refresh(target) end diff --git a/lua/avante/config.lua b/lua/avante/config.lua index a6c36b8..34cc039 100644 --- a/lua/avante/config.lua +++ b/lua/avante/config.lua @@ -2,6 +2,7 @@ ---we add a default var_accessor for this table to config values. ---@alias WebSearchEngineProviderResponseBodyFormatter fun(body: table): (string, string?) +---@alias avante.InputProvider "native" | "dressing" | "snacks" | fun(input: avante.ui.Input): nil local Utils = require("avante.utils") @@ -556,6 +557,10 @@ M._defaults = { provider_opts = {}, exclude_auto_select = {}, -- List of items to exclude from auto selection }, + input = { + provider = "native", + provider_opts = {}, + }, suggestion = { debounce = 600, throttle = 600, diff --git a/lua/avante/health.lua b/lua/avante/health.lua index 5902a2d..9935eff 100644 --- a/lua/avante/health.lua +++ b/lua/avante/health.lua @@ -12,10 +12,6 @@ function M.check() path = "nvim-treesitter/nvim-treesitter", module = "nvim-treesitter", }, - ["dressing.nvim"] = { - path = "stevearc/dressing.nvim", - module = "dressing", - }, ["plenary.nvim"] = { path = "nvim-lua/plenary.nvim", module = "plenary", @@ -41,6 +37,24 @@ function M.check() H.warn("No icons plugin found (nvim-web-devicons or mini.icons). Icons will not be displayed") end + -- Check input UI provider + local input_provider = Config.input and Config.input.provider or "native" + if input_provider == "dressing" then + if Utils.has("dressing.nvim") or Utils.has("dressing") then + H.ok("Found configured input provider: dressing.nvim") + else + H.error("Input provider is set to 'dressing' but dressing.nvim is not installed") + end + elseif input_provider == "snacks" then + if Utils.has("snacks.nvim") or Utils.has("snacks") then + H.ok("Found configured input provider: snacks.nvim") + else + H.error("Input provider is set to 'snacks' but snacks.nvim is not installed") + end + else + H.ok("Using native input provider (no additional dependencies required)") + end + -- Check Copilot if configured if Config.provider and Config.provider == "copilot" then if Utils.has("copilot.lua") or Utils.has("copilot.vim") or Utils.has("copilot") then diff --git a/lua/avante/providers/init.lua b/lua/avante/providers/init.lua index 9682409..d27ec3d 100644 --- a/lua/avante/providers/init.lua +++ b/lua/avante/providers/init.lua @@ -3,13 +3,6 @@ local api, fn = vim.api, vim.fn local Config = require("avante.config") local Utils = require("avante.utils") -local DressingConfig = { - conceal_char = "*", - filetype = "DressingInput", - close_window = function() require("dressing.input").close() end, -} -local DressingState = { winid = nil, input_winid = nil, input_bufnr = nil } - ---@class avante.Providers ---@field openai AvanteProviderFunctor ---@field claude AvanteProviderFunctor @@ -78,7 +71,7 @@ function E.setup(opts) end end - local function mount_dressing_buffer() + local function mount_input_ui() vim.defer_fn(function() -- only mount if given buffer is not of buftype ministarter, dashboard, alpha, qf local exclude_filetypes = { @@ -93,46 +86,30 @@ function E.setup(opts) "gitcommit", "gitrebase", "DressingInput", + "snacks_input", "noice", } if not vim.tbl_contains(exclude_filetypes, vim.bo.filetype) and not opts.provider.is_env_set() then - DressingState.winid = api.nvim_get_current_win() - vim.ui.input({ default = "", prompt = "Enter " .. var .. ": " }, on_confirm) - for _, winid in ipairs(api.nvim_list_wins()) do - local bufnr = api.nvim_win_get_buf(winid) - if vim.bo[bufnr].filetype == DressingConfig.filetype then - DressingState.input_winid = winid - DressingState.input_bufnr = bufnr - vim.wo[winid].conceallevel = 2 - vim.wo[winid].concealcursor = "nvi" - break - end - end - - local prompt_length = api.nvim_strwidth(fn.prompt_getprompt(DressingState.input_bufnr)) - api.nvim_buf_call( - DressingState.input_bufnr, - function() - vim.cmd(string.format( - [[ - syn region SecretValue start=/^/ms=s+%s end=/$/ contains=SecretChar - syn match SecretChar /./ contained conceal %s - ]], - prompt_length, - "cchar=*" - )) - end - ) + local Input = require("avante.ui.input") + local input = Input:new({ + provider = Config.input.provider, + title = "Enter " .. var .. ": ", + default = "", + conceal = true, -- Password input should be concealed + provider_opts = Config.input.provider_opts, + on_submit = on_confirm, + }) + input:open() end end, 200) end - if refresh then return mount_dressing_buffer() end + if refresh then return mount_input_ui() end api.nvim_create_autocmd("User", { pattern = E.REQUEST_LOGIN_PATTERN, - callback = mount_dressing_buffer, + callback = mount_input_ui, }) end diff --git a/lua/avante/ui/input/init.lua b/lua/avante/ui/input/init.lua new file mode 100644 index 0000000..7c92ab8 --- /dev/null +++ b/lua/avante/ui/input/init.lua @@ -0,0 +1,48 @@ +local Utils = require("avante.utils") + +---@class avante.ui.InputOption +---@field provider avante.InputProvider +---@field title string +---@field default string | nil +---@field completion string | nil +---@field provider_opts table | nil +---@field on_submit fun(result: string | nil) +---@field conceal boolean | nil -- Whether to conceal input (for passwords) + +---@class avante.ui.Input +---@field provider avante.InputProvider +---@field title string +---@field default string | nil +---@field completion string | nil +---@field provider_opts table | nil +---@field on_submit fun(result: string | nil) +---@field conceal boolean | nil +local Input = {} +Input.__index = Input + +---@param opts avante.ui.InputOption +function Input:new(opts) + local o = {} + setmetatable(o, Input) + o.provider = opts.provider + o.title = opts.title + o.default = opts.default or "" + o.completion = opts.completion + o.provider_opts = opts.provider_opts or {} + o.on_submit = opts.on_submit + o.conceal = opts.conceal or false + return o +end + +function Input:open() + if type(self.provider) == "function" then + self.provider(self) + return + end + + local ok, provider = pcall(require, "avante.ui.input.providers." .. self.provider) + if not ok then Utils.error("Unknown input provider: " .. self.provider) end + provider.show(self) +end + +return Input diff --git a/lua/avante/ui/input/providers/dressing.lua b/lua/avante/ui/input/providers/dressing.lua new file mode 100644 index 0000000..c192546 --- /dev/null +++ b/lua/avante/ui/input/providers/dressing.lua @@ -0,0 +1,66 @@ +local api = vim.api +local fn = vim.fn + +local M = {} + +---@param input avante.ui.Input +function M.show(input) + local ok, dressing_input = pcall(require, "dressing.input") + if not ok then + vim.notify("dressing.nvim not found, falling back to native input", vim.log.levels.WARN) + require("avante.ui.input.providers.native").show(input) + return + end + + -- Store state for concealing functionality + local state = { winid = nil, input_winid = nil, input_bufnr = nil } + + local function setup_concealing() + if not input.conceal then return end + + vim.defer_fn(function() + -- Find the dressing input window + for _, winid in ipairs(api.nvim_list_wins()) do + local bufnr = api.nvim_win_get_buf(winid) + if vim.bo[bufnr].filetype == "DressingInput" then + state.input_winid = winid + state.input_bufnr = bufnr + vim.wo[winid].conceallevel = 2 + vim.wo[winid].concealcursor = "nvi" + + -- Set up concealing syntax + local prompt_length = api.nvim_strwidth(fn.prompt_getprompt(state.input_bufnr)) + api.nvim_buf_call( + state.input_bufnr, + function() + vim.cmd(string.format( + [[ + syn region SecretValue start=/^/ms=s+%s end=/$/ contains=SecretChar + syn match SecretChar /./ contained conceal cchar=* + ]], + prompt_length + )) + end + ) + break + end + end + end, 50) + end + + -- Enhanced functionality for concealed input + vim.ui.input({ + prompt = input.title, + default = input.default, + completion = input.completion, + }, function(result) + input.on_submit(result) + -- Close the dressing input window after submission if we have concealing + if input.conceal then pcall(dressing_input.close) end + end) + + -- Set up concealing if needed + setup_concealing() +end + +return M diff --git a/lua/avante/ui/input/providers/native.lua b/lua/avante/ui/input/providers/native.lua new file mode 100644 index 0000000..84792fb --- /dev/null +++ b/lua/avante/ui/input/providers/native.lua @@ -0,0 +1,23 @@ +local M = {} + +---@param input avante.ui.Input +function M.show(input) + local opts = { + prompt = input.title, + default = input.default, + completion = input.completion, + } + + -- Note: Native vim.ui.input doesn't support concealing + -- For password input, users should use dressing or snacks providers + if input.conceal then + vim.notify_once( + "Native input provider doesn't support concealed input. Consider using 'dressing' or 'snacks' provider for password input.", + vim.log.levels.WARN + ) + end + + vim.ui.input(opts, input.on_submit) +end + +return M diff --git a/lua/avante/ui/input/providers/snacks.lua b/lua/avante/ui/input/providers/snacks.lua new file mode 100644 index 0000000..a280e95 --- /dev/null +++ b/lua/avante/ui/input/providers/snacks.lua @@ -0,0 +1,23 @@ +local M = {} + +---@param input avante.ui.Input +function M.show(input) + local ok, snacks_input = pcall(require, "snacks.input") + if not ok then + vim.notify("snacks.nvim not found, falling back to native input", vim.log.levels.WARN) + require("avante.ui.input.providers.native").show(input) + return + end + + local opts = vim.tbl_deep_extend("force", { + prompt = input.title, + default = input.default, + }, input.provider_opts) + + -- Add concealing support if needed + if input.conceal then opts.password = true end + + snacks_input(opts, input.on_submit) +end + +return M diff --git a/lua/avante/ui/selector/providers/snacks.lua b/lua/avante/ui/selector/providers/snacks.lua index 1940fe2..3cd5fac 100644 --- a/lua/avante/ui/selector/providers/snacks.lua +++ b/lua/avante/ui/selector/providers/snacks.lua @@ -37,7 +37,6 @@ function M.show(selector) preview = selector.get_preview_content and "preview" or nil, layout = { preset = "default", - preview = selector.get_preview_content ~= nil, }, confirm = function(picker) if completed then return end diff --git a/plugin/avante.lua b/plugin/avante.lua index c5690b8..96db02d 100644 --- a/plugin/avante.lua +++ b/plugin/avante.lua @@ -129,6 +129,15 @@ cmd( desc = "avante: switch selector provider", } ) +cmd("SwitchInputProvider", function(opts) require("avante.api").switch_input_provider(vim.trim(opts.args or "")) end, { + nargs = 1, + desc = "avante: switch input provider", + complete = function(_, line, _) + local prefix = line:match("AvanteSwitchInputProvider%s*(.*)$") or "" + local providers = { "native", "dressing", "snacks" } + return vim.tbl_filter(function(key) return key:find(prefix, 1, true) == 1 end, providers) + end, +}) cmd("Clear", function(opts) local arg = vim.trim(opts.args or "") arg = arg == "" and "history" or arg