146 lines
4.0 KiB
Lua
146 lines
4.0 KiB
Lua
|
local M = {}
|
||
|
M.__index = M
|
||
|
|
||
|
local get_width = vim.fn.strdisplaywidth
|
||
|
-- local get_width = vim.fn.strwidth
|
||
|
-- local get_width = vim.api.nvim_strwidth
|
||
|
|
||
|
---@alias block table add_hl(key, hl_name)
|
||
|
---返回分配的块状区域, e_col 设置为-1则为末尾
|
||
|
---@param s_row integer 起始行
|
||
|
---@param s_col integer 起始列
|
||
|
---@param height integer 行数
|
||
|
---@param width integer 块的宽度
|
||
|
---@return block
|
||
|
function M:alloc_block(s_row, s_col, height, width)
|
||
|
-- -1为到行尾
|
||
|
width = width == -1 and self.width or width
|
||
|
local e_col = s_col + width
|
||
|
|
||
|
local block = {
|
||
|
add_hl = function(key, hl_name)
|
||
|
table.insert(self.highlight[s_row + key], {
|
||
|
name = hl_name,
|
||
|
_start = s_col,
|
||
|
_end = e_col,
|
||
|
})
|
||
|
end
|
||
|
}
|
||
|
|
||
|
return setmetatable(block, {
|
||
|
-- 访问该表的操作, 映射成lines
|
||
|
__index = function(_, key)
|
||
|
assert(0 < key and key <= height)
|
||
|
--- FIXME : Unicode stirng sub
|
||
|
return self.lines[s_row + key]:sub(s_col, e_col)
|
||
|
end,
|
||
|
|
||
|
__newindex = function(_, key, value)
|
||
|
assert(0 < key and key <= height)
|
||
|
local wid = get_width(value)
|
||
|
if wid > width then
|
||
|
error('check out the str width: Max ->' .. self.width .. ' str ->' .. wid)
|
||
|
else
|
||
|
value = value .. (' '):rep(width - wid)
|
||
|
end
|
||
|
|
||
|
local line = s_row + key - 1
|
||
|
self.lines[line] = self.lines[line]:sub(1, s_col - 1) .. value .. self.lines[line]:sub(e_col + 1)
|
||
|
end,
|
||
|
})
|
||
|
end
|
||
|
|
||
|
function M:alloc_newline()
|
||
|
self.len = self.len + 1
|
||
|
local items = {}
|
||
|
local len = 0
|
||
|
local size = 0
|
||
|
return {
|
||
|
add_item = function(item, highlight)
|
||
|
size = size + 1
|
||
|
local wid = get_width(item)
|
||
|
items[size] = { item, highlight }
|
||
|
len = len + wid
|
||
|
end,
|
||
|
|
||
|
load_line = function()
|
||
|
local space = math.floor((self.width - len) / (size - 1))
|
||
|
assert(space > 0)
|
||
|
local interval = (' '):rep(space)
|
||
|
local value = ''
|
||
|
local function load_item(index)
|
||
|
if items[index][2] then
|
||
|
local _start = #value
|
||
|
local _end = _start + #items[index][2]
|
||
|
table.insert(self.highlights[self.len], {
|
||
|
name = items[index][2],
|
||
|
_start = _start,
|
||
|
_end = _end
|
||
|
})
|
||
|
end
|
||
|
value = value .. items[index][1]
|
||
|
end
|
||
|
|
||
|
load_item(1)
|
||
|
for i = 2, size do
|
||
|
value = value .. interval
|
||
|
load_item(i)
|
||
|
end
|
||
|
|
||
|
self.lines[self.len] = value
|
||
|
end
|
||
|
}
|
||
|
end
|
||
|
|
||
|
function M:addline(text, highlight)
|
||
|
self.len = self.len + 1
|
||
|
if highlight then
|
||
|
table.insert(self.highlights[self.len], {
|
||
|
name = highlight,
|
||
|
_start = 1,
|
||
|
_end = -1
|
||
|
})
|
||
|
end
|
||
|
self.lines[self.len] = text
|
||
|
end
|
||
|
|
||
|
-- 窗口宽度
|
||
|
function M:new(width)
|
||
|
vim.validate {
|
||
|
width = { width, 'n' }
|
||
|
}
|
||
|
local default = (' '):rep(width) -- default value is empty line
|
||
|
local new_content = {
|
||
|
width = width,
|
||
|
len = 0,
|
||
|
highlights = setmetatable({}, { -- always has default value
|
||
|
__index = function(tbl, key)
|
||
|
tbl[key] = {}
|
||
|
return tbl[key]
|
||
|
end
|
||
|
}),
|
||
|
|
||
|
}
|
||
|
|
||
|
new_content.lines = setmetatable({}, {
|
||
|
__index = function(tbl, key)
|
||
|
tbl[key] = default
|
||
|
return tbl[key]
|
||
|
end,
|
||
|
|
||
|
__newindex = function(tbl, key, value)
|
||
|
if value then
|
||
|
for _ = new_content.len + 1, key - 1 do
|
||
|
rawset(tbl, key, '')
|
||
|
end
|
||
|
|
||
|
rawset(tbl, key, value)
|
||
|
new_content.len = key
|
||
|
end
|
||
|
end
|
||
|
})
|
||
|
return setmetatable(new_content, self)
|
||
|
end
|
||
|
|
||
|
return M
|