A floating vim.ui.input buffer that auto-resizes to fit its contents.
0

Configure Feed

Select the types of activity you want to include in your feed.

cleanup config

r0nsha (Jun 27, 2025, 1:19 PM +0300) 47eaccad 80276380

+45 -26
+45 -26
lua/wrapinput.lua
··· 1 1 ---@class wrapinput.Config 2 - ---@field default string 2 + ---@field width wrapinput.Limits 3 + ---@field height wrapinput.Limits 3 4 ---@field padding integer 4 - ---@field max_width integer 5 - ---@field max_height integer 6 5 ---@field win vim.api.keyset.win_config 7 6 8 - local group = vim.api.nvim_create_augroup("wrapinput.nvim", { clear = true }) 7 + ---@class wrapinput.Limits 8 + ---@field min integer 9 + ---@field max integer 9 10 10 - local M = {} 11 + local group = vim.api.nvim_create_augroup("wrapinput.nvim", { clear = true }) 11 12 12 13 ---@type wrapinput.Config 13 14 local defaults = { 14 - default = "", 15 - padding = 10, 16 - max_width = 50, 17 - max_height = 6, 15 + padding = 5, 16 + width = { min = 20, max = 60 }, 17 + height = { min = 1, max = 6 }, 18 18 win = { 19 19 title = "Input: ", 20 20 style = "minimal", ··· 25 25 }, 26 26 } 27 27 28 + ---@param value number 29 + ---@param min number 30 + ---@param max number 31 + ---@return number 32 + local function clamp(value, min, max) 33 + return math.min(math.max(value, min), max) 34 + end 35 + 28 36 ---@return vim.api.keyset.win_config 29 37 local function get_relative_win_config() 30 38 local curr_win = vim.api.nvim_get_current_win() ··· 60 68 return lines 61 69 end 62 70 71 + ---@param option string 72 + ---@param winnr integer 73 + local function set_option_if_globally_enabled(option, winnr) 74 + if vim.api.nvim_get_option_value(option, { scope = "global" }) then 75 + vim.api.nvim_set_option_value(option, true, { win = winnr }) 76 + end 77 + end 78 + 63 79 ---@param winnr integer 64 80 ---@param bufnr integer 65 81 ---@param config wrapinput.Config ··· 68 84 local line = table.concat(text, "") 69 85 70 86 if line == "" then 71 - vim.api.nvim_win_set_width(winnr, config.padding) 87 + vim.api.nvim_win_set_width(winnr, clamp(config.padding, config.width.min, config.width.max)) 72 88 vim.api.nvim_win_set_height(winnr, 1) 73 89 return 74 90 end 75 91 76 - local lines = split_wrapped_lines(line, config.max_width) 92 + local lines = split_wrapped_lines(line, config.width.max) 77 93 78 94 local lens = vim.tbl_map(function(l) 79 95 return vim.fn.strdisplaywidth(l) 80 96 end, lines) 81 - local width = math.max(unpack(lens)) + config.padding 82 - width = width > config.max_width and config.max_width or width 83 - vim.api.nvim_win_set_width(winnr, width + 1) 97 + local width = clamp(math.max(unpack(lens)) + config.padding + #lines, config.width.min, config.width.max + #lines) 98 + vim.api.nvim_win_set_width(winnr, width) 84 99 85 - local height = #lines 86 - height = height > config.max_height and config.max_height or height 100 + local height = clamp(#lines, config.height.min, config.height.max) 87 101 vim.api.nvim_win_set_height(winnr, height) 102 + 103 + if height > 1 then 104 + set_option_if_globally_enabled("number", winnr) 105 + set_option_if_globally_enabled("relativenumber", winnr) 106 + end 88 107 end 89 108 90 109 ---@param winnr integer ··· 133 152 map("n", "q", close) 134 153 end 135 154 155 + local M = {} 156 + 136 157 ---@param config wrapinput.Config 137 158 ---@param opts table 138 159 ---@param on_confirm fun(input: string?) 139 160 function M.input(config, opts, on_confirm) 140 - config = vim.tbl_deep_extend("force", defaults, config, opts, { win = { title = opts.prompt } }) 161 + config = vim.tbl_deep_extend("force", defaults, config, { win = { title = opts.prompt } }) 162 + local default = opts.default or "" 141 163 on_confirm = on_confirm or function() end 142 164 143 - config = vim.tbl_deep_extend( 144 - "keep", 145 - config, 146 - { win = get_relative_win_config() }, 147 - { win = { width = vim.fn.strdisplaywidth(config.default) + config.padding } } 148 - ) 165 + local width = clamp(vim.fn.strdisplaywidth(default) + config.padding, config.width.min, config.width.max) 166 + vim.notify("width: " .. tostring(width)) 167 + config = vim.tbl_deep_extend("keep", config, { win = get_relative_win_config() }, { win = { width = width } }) 149 168 150 169 -- Create buffer and floating window. 151 170 local bufnr = vim.api.nvim_create_buf(false, true) 152 - set_options({ buftype = "prompt", bufhidden = "wipe", textwidth = config.max_width }, { buf = bufnr }) 171 + set_options({ buftype = "prompt", bufhidden = "wipe", textwidth = config.width.max }, { buf = bufnr }) 153 172 vim.fn.prompt_setprompt(bufnr, "") 154 173 155 174 local winnr = vim.api.nvim_open_win(bufnr, true, config.win) 156 175 set_options({ wrap = true, linebreak = true, winhighlight = "Search:None" }, { win = winnr }) 157 176 158 177 -- write default value and put cursor at the end 159 - vim.api.nvim_buf_set_text(bufnr, 0, 0, 0, 0, { config.default }) 178 + vim.api.nvim_buf_set_text(bufnr, 0, 0, 0, 0, { default }) 160 179 vim.cmd("startinsert") 161 - vim.api.nvim_win_set_cursor(winnr, { 1, vim.str_utfindex(config.default, "utf-8") + 1 }) 180 + vim.api.nvim_win_set_cursor(winnr, { 1, vim.str_utfindex(default, "utf-8") + 1 }) 162 181 163 182 resize(winnr, bufnr, config) 164 183