Something went wrong. Try again.
Expand your neovim sense with small UI components
Something went wrong. Try again.
5.7 kB · 186 lines
Lua
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187local log = require("sense.log")local utf8 = require("lua-utf8")
local M = {}
---@private---@param name string---@param wininfo vim.fn.getwininfo.ret.item---@param lines string[]---@param highlights sense.ui.Highlight[]---@param win_opts vim.api.keyset.win_configfunction M.restore_and_open_win(name, wininfo, lines, highlights, win_opts) local ok, fwinid = pcall(vim.tbl_get, vim.w, wininfo.winid, name) if not ok then -- TODO: log error about vim.w.__index error here: log.debug("error while reading window variables in", wininfo.winid, fwinid) fwinid = nil end M.ui_guard(function() if #lines == 0 then log.debug("nothing to render, abort") if fwinid and vim.api.nvim_win_is_valid(fwinid) then log.debug("close window:", fwinid) vim.api.nvim_win_close(fwinid, true) end return end local bufnr assert(win_opts.width > 0, "width should be positive at this point") if fwinid and vim.api.nvim_win_is_valid(fwinid) then vim.api.nvim_win_set_config(fwinid, win_opts) bufnr = vim.api.nvim_win_get_buf(fwinid) else fwinid, bufnr = M.open_win_buf(win_opts) vim.w[wininfo.winid][name] = fwinid end M.set_lines(bufnr, lines, highlights) end)end
---Render lines & highlights on buffer---@param buf number---@param lines string[]---@param highlights sense.ui.Highlight[]function M.set_lines(buf, lines, highlights) vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) for _, highlight in ipairs(highlights) do vim.api.nvim_buf_add_highlight( buf, 0, highlight.hl_group, highlight.line, highlight.col_start, highlight.col_end ) endend
---Fixed version of nvim_open_win---@param buffer integer---@param enter boolean---@param config vim.api.keyset.win_config---@return integerfunction M.nvim_open_win(buffer, enter, config) log.debug("utils.nvim_open_win") local win = vim.api.nvim_open_win(buffer, enter, config) if config.relative == "win" then if config.win == 0 then config.win = vim.api.nvim_get_current_win() end -- HACK: close windows when parent window is closed -- WHY IS THIS NOT A DEFAULT BEHAVIOR vim.api.nvim_create_autocmd("WinClosed", { group = vim.api.nvim_create_augroup("sense.fix_nvim_open_win", { clear = false }), callback = function(ev) if ev.match == tostring(config.win) then if vim.api.nvim_win_is_valid(win) then log.debug("close dangling window:", win) vim.api.nvim_win_close(win, true) end return true end end, desc = "Close floating window associated to window when closed", }) end return winend
---@private---Open window with scratch buffer---@param win_config vim.api.keyset.win_configfunction M.open_win_buf(win_config) log.debug("open_win_buf with", win_config) win_config = vim.tbl_deep_extend("force", win_config, { focusable = false, style = "minimal", zindex = 10, }) local buf = vim.api.nvim_create_buf(false, true) vim.bo[buf].buftype = "nofile" local win = M.nvim_open_win(buf, false, win_config) log.debug("window opened") return win, bufend
---@param str string---@param max_width integer---@return string, integerfunction M.truncate_line(str, max_width) local full_width = vim.fn.strdisplaywidth(str) if vim.fn.strdisplaywidth(str) <= max_width then return str, full_width end max_width = max_width - 1 local result = {} full_width = 0 for _, code in utf8.codes(str) do local char = utf8.char(code) local w = vim.fn.strdisplaywidth(char) if full_width + w > max_width then break end table.insert(result, char) full_width = full_width + w end return table.concat(result) .. "…", full_width + 1end
---Calculate size given as integer or ratio---@param size number---@param base integer---@return integerfunction M.calc_size_config(size, base) if size < 1 then return math.floor(base * size) else return math.floor(size) endend
--- Suppress errors that may occur while render windows.------ The E523 error (Not allowed here) happens when 'secure' operations--- (including buffer or window management) are invoked while textlock is held--- or the Neovim UI is blocking. See #68.------ Also ignore E11 (Invalid in command-line window), which is thrown when--- Fidget tries to close the window while a command-line window is focused.--- See #136.------ This utility provides a workaround to simply supress the error.--- All other errors will be re-thrown.------ (Thanks @wookayin and @0xAdk!)--- NOTE(boltless): Copied from fidget.nvim------@param callable fun()---@return boolean suppressed_errorfunction M.ui_guard(callable) local whitelist = { "E11: Invalid in command%-line window", "E523: Not allowed here", "E565: Not allowed to change", }
local ok, err = pcall(callable) if ok then return true end
if type(err) ~= "string" then -- Don't know how to deal with this kind of error object error(err) end
for _, msg in ipairs(whitelist) do if string.find(err, msg) then return false end end
error(err)end
return M