Trans.nvim/lua/Trans/window.lua
2023-02-18 13:13:32 +08:00

224 lines
5.2 KiB
Lua

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