local M = {} ---@param win integer ---@return boolean local function has_border(win) local b = vim.api.nvim_win_get_config(win).border if not b or b == "none" or b == "" then return false end if type(b) == "table" and #b == 0 then return false end return true end ---@param lines string[] ---@param opts? { min_width?: integer, padding?: integer } ---@return integer width ---@return integer height function M.size_for(lines, opts) opts = opts or {} local width = 1 for _, l in ipairs(lines) do local w = vim.api.nvim_strwidth(l) if w > width then width = w end end width = math.min( math.max(width + (opts.padding or 1), opts.min_width or 30), 100, vim.o.columns - 4 ) local height = math.min(math.max(#lines, 1), 20, math.floor(vim.o.lines / 2)) return width, height end ---@param pbuf integer ---@param win integer ---@param ns integer function M.paint_overflow(pbuf, win, ns) vim.schedule(function() if not vim.api.nvim_buf_is_valid(pbuf) or not vim.api.nvim_win_is_valid(win) then return end vim.api.nvim_buf_clear_namespace(pbuf, ns, 0, -1) local total = vim.api.nvim_buf_line_count(pbuf) local top, bottom = unpack(vim.api.nvim_win_call(win, function() return { vim.fn.line("w0"), vim.fn.line("w$") } end)) ---@cast top integer ---@cast bottom integer local needs_top = top > 1 local needs_bottom = bottom < total if has_border(win) then pcall(vim.api.nvim_win_set_config, win, { title = needs_top and { { "▲ ", "FloatBorder" } } or "", title_pos = needs_top and "right" or nil, footer = needs_bottom and { { "▼ ", "FloatBorder" } } or "", footer_pos = needs_bottom and "right" or nil, }) return end if needs_top then pcall(vim.api.nvim_buf_set_extmark, pbuf, ns, top - 1, 0, { virt_text = { { "▲ ", "GitPopupEnd" } }, virt_text_pos = "right_align", }) end if needs_bottom then pcall(vim.api.nvim_buf_set_extmark, pbuf, ns, bottom - 1, 0, { virt_text = { { "▼ ", "GitPopupEnd" } }, virt_text_pos = "right_align", }) end end) end return M