You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nvim-libmodal/lua/libmodal/src/utils/Popup.lua

86 lines
2.6 KiB
Lua

--- @class libmodal.utils.Popup
--- @field private buffer number the number of the window which this popup is rendered on.
--- @field private input_chars table<string> the characters input by the user.
--- @field private window number the number of the window which this popup is rendered on.
local Popup = require('libmodal/src/utils/classes').new()
--- @param window number
--- @return boolean `true` if the window is non-`nil` and `nvim_win_is_valid`
local function valid(window)
return window and vim.api.nvim_win_is_valid(window)
end
--- Close `self.window`
--- The `self` is inert after calling this.
--- @param keep_buffer boolean `self.buffer` is passed to `nvim_buf_delete` unless `keep_buffer` is `false`
function Popup:close(keep_buffer)
if valid(self.window) then
vim.api.nvim_win_close(self.window, false)
end
self.window = nil
if not keep_buffer then
vim.api.nvim_buf_delete(self.buffer, {force = true})
self.buffer = nil
self.input_chars = nil
end
end
--- Attempt to open this popup. If the popup was already open, close it and re-open it.
function Popup:open(config)
if not config then
config =
{
anchor = 'SW',
col = vim.go.columns - 1,
focusable = false,
height = 1,
relative = 'editor',
row = vim.go.lines - vim.go.cmdheight - 1,
style = 'minimal',
width = 1
}
end
if valid(self.window) then
self:close(true)
end
self.window = vim.api.nvim_open_win(self.buffer, false, config)
end
--- Display `input_bytes` in `self.buffer`
--- @param input_bytes table<number> a list of character codes to display
function Popup:refresh(input_bytes)
-- The user simply typed one more character onto the last one.
if #input_bytes == #self.input_chars + 1 then
self.input_chars[#input_bytes] = string.char(input_bytes[#input_bytes])
elseif #input_bytes == 1 then -- the user's typing was reset by a parser.
self.input_chars = {string.char(input_bytes[1])}
else -- other tries to optimize this procedure fell through, so do it the hard way.
self.input_chars = {}
for i, byte in ipairs(input_bytes) do
self.input_chars[i] = string.char(byte)
end
end
vim.api.nvim_buf_set_lines(self.buffer, 0, 1, true, {table.concat(self.input_chars)})
-- Close and reopen the window if it was not already open.
if not valid(self.window) or vim.api.nvim_win_get_tabpage(self.window) ~= vim.api.nvim_get_current_tabpage() then
self:open()
end
vim.api.nvim_win_set_width(self.window, #self.input_chars)
end
return
{
new = function(config)
local self = setmetatable({buffer = vim.api.nvim_create_buf(false, true), input_chars = {}}, Popup)
self:open(config)
return self
end
}