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.
92 lines
2.9 KiB
Lua
92 lines
2.9 KiB
Lua
2 years ago
|
--- @class libmodal.utils.Popup
|
||
2 years ago
|
--- @field private buffer_number integer the number of the window which this popup is rendered on.
|
||
2 years ago
|
--- @field private input_chars string[] the characters input by the user.
|
||
2 years ago
|
--- @field private window_number integer the number of the window which this popup is rendered on.
|
||
2 years ago
|
local Popup = require('libmodal.utils.classes').new()
|
||
2 years ago
|
|
||
|
--- @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`
|
||
2 years ago
|
--- @return nil
|
||
2 years ago
|
function Popup:close(keep_buffer)
|
||
2 years ago
|
if valid(self.window_number) then
|
||
|
vim.api.nvim_win_close(self.window_number, false)
|
||
2 years ago
|
end
|
||
|
|
||
2 years ago
|
self.window_number = nil
|
||
2 years ago
|
|
||
|
if not keep_buffer then
|
||
2 years ago
|
vim.api.nvim_buf_delete(self.buffer_number, {force = true})
|
||
|
self.buffer_number = nil
|
||
2 years ago
|
self.input_chars = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
2 years ago
|
--- @return libmodal.utils.Popup
|
||
|
function Popup.new(config)
|
||
2 years ago
|
local self = setmetatable({buffer_number = vim.api.nvim_create_buf(false, true), input_chars = {}}, Popup)
|
||
2 years ago
|
self:open(config)
|
||
|
return self
|
||
|
end
|
||
|
|
||
2 years ago
|
--- attempt to open this popup. If the popup was already open, close it and re-open it.
|
||
2 years ago
|
--- @return nil
|
||
2 years ago
|
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',
|
||
2 years ago
|
width = 1,
|
||
2 years ago
|
}
|
||
|
end
|
||
|
|
||
2 years ago
|
if valid(self.window_number) then
|
||
2 years ago
|
self:close(true)
|
||
|
end
|
||
|
|
||
2 years ago
|
self.window_number = vim.api.nvim_open_win(self.buffer_number, false, config)
|
||
2 years ago
|
|
||
|
-- HACK: the window always pops up with the wrong width, but this makes it work :shrug:
|
||
2 years ago
|
vim.api.nvim_win_set_width(self.window_number, config.width)
|
||
2 years ago
|
end
|
||
|
|
||
2 years ago
|
--- display `input_bytes` in `self.buffer`
|
||
2 years ago
|
--- @param input_bytes number[] a list of character codes to display
|
||
2 years ago
|
--- @return nil
|
||
2 years ago
|
function Popup:refresh(input_bytes)
|
||
2 years ago
|
-- the user simply typed one more character onto the last one.
|
||
2 years ago
|
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
|
||
|
|
||
2 years ago
|
vim.api.nvim_buf_set_lines(self.buffer_number, 0, 1, true, {table.concat(self.input_chars)})
|
||
2 years ago
|
|
||
2 years ago
|
-- close and reopen the window if it was not already open.
|
||
2 years ago
|
if not valid(self.window_number) or vim.api.nvim_win_get_tabpage(self.window_number) ~= vim.api.nvim_get_current_tabpage() then
|
||
2 years ago
|
self:open()
|
||
|
end
|
||
|
|
||
2 years ago
|
vim.api.nvim_win_set_width(self.window_number, #self.input_chars)
|
||
2 years ago
|
end
|
||
|
|
||
2 years ago
|
return Popup
|