local api = vim.api local display = require('Trans.util.display') ---@class win ---@field winid integer window handle ---@field width integer ---@field height integer ---@field ns integer namespace for highlight ---@field animation table window animation ---@field buf buf buffer for attached local window = {} ---Change window attached buffer ---@param buf buf function window:set_buf(buf) api.nvim_win_set_buf(self.winid, buf.bufnr) self.buf = buf end ---Check window valid ---@return boolean function window:is_valid() return api.nvim_win_is_valid(self.winid) end ---Set window option ---@param option string option name ---@param value any function window:set(option, value) if self:is_valid() then api.nvim_win_set_option(self.winid, option, value) end end ---@param name string option name ---@return any function window:option(name) return api.nvim_win_get_option(self.winid, name) end ---@param height integer function window:set_height(height) api.nvim_win_set_height(self.winid, height) self.height = height end ---@param width integer function window:set_width(width) api.nvim_win_set_width(self.winid, width) self.width = width end ---Expand window [width | height] value ---@param opts table ---|'field'string [width | height] ---|'target'integer ---@return function function window:expand(opts) self:lock() local field = opts.field local target = opts.target local cur = self[field] local times = math.abs(target - cur) local wrap = self:option('wrap') self:set('wrap', false) local interval = opts.interval or self.animation.interval local method = api['nvim_win_set_' .. field] local winid = self.winid local frame = target > cur and function(_, cur_times) method(winid, cur + cur_times) end or function(_, cur_times) method(winid, cur - cur_times) end local run = display { times = times, frame = frame, interval = interval, } run(function() self:set('wrap', wrap) self[field] = target self:unlock() end) return run end ---Close window ---@return function run run until close done function window:try_close() local field = ({ slid = 'width', fold = 'height', })[self.animation.close] --- 播放动画 local run = self:expand { field = field, target = 1, } run(function() api.nvim_win_close(self.winid, true) end) return run end ---lock window [open | close] operation function window:lock() while self.busy do vim.wait(50) end self.busy = true end function window:unlock() self.busy = false end ---设置窗口本地的高亮组 ---@param name string 高亮组的名称 ---@param opts table 高亮选项 function window:set_hl(name, opts) api.nvim_set_hl(self.ns, name, opts) end ---buffer:addline() helper function ---@param node table ---@return table node formatted node function window:center(node) local text = node[1] local width = text:width() local win_width = self.width local space = math.max(math.floor((win_width - width) / 2), 0) node[1] = (' '):rep(space) .. text return node end ---@private window.__index = window ---@class win_opts ---@field buf buf buffer for attached ---@field height integer ---@field width integer ---@field col integer ---@field row integer ---@field border string ---@field title string | nil | table ---@field relative string ---@field ns integer namespace for highlight ---@field zindex? integer ---@field enter? boolean cursor should [enter] window ---@field animation table window animation ---window constructor ---@param opts win_opts ---@return table ---@return function return function(opts) assert(type(opts) == 'table') local ns = opts.ns local buf = opts.buf local col = opts.col local row = opts.row local title = opts.title local width = opts.width local enter = opts.enter or false local height = opts.height local border = opts.border local zindex = opts.zindex local relative = opts.relative local animation = opts.animation local open = animation.open local field = ({ slid = 'width', fold = 'height', })[open] local win_opt = { title_pos = nil, focusable = false, style = 'minimal', zindex = zindex, width = width, height = height, col = col, row = row, border = border, title = title, relative = relative, } if field then win_opt[field] = 1 end if win_opt.title then win_opt.title_pos = 'center' end local win = setmetatable({ buf = buf, ns = ns, height = win_opt.height, width = win_opt.width, animation = animation, winid = api.nvim_open_win(buf.bufnr, enter, win_opt), }, window) api.nvim_win_set_hl_ns(win.winid, win.ns) win:set_hl('Normal', { link = 'TransWin' }) win:set_hl('FloatBorder', { link = 'TransBorder' }) return win, win:expand { field = field, target = opts[field], } end