local api = vim.api local format_meta = { load_hl = function(self, content, line, col) local space = self.space for _, item in ipairs(self.items) do item:load_hl(content, line, col) col = col + #item.text + space end end } local content = { newline = function(self, value) if not self.modifiable then error('content can not add newline now') end self.size = self.size + 1 self.lines[self.size] = value end, newhl = function(self, opt) if not self.modifiable then error('content can not add newline now') end self.hl_size = self.hl_size + 1 self.highlights[self.hl_size] = opt end, wipe = function(self) local clear = require('table.clear') clear(self.lines) clear(self.highlights) self.size = 0 self.hl_size = 0 end, ---将内容连接上对应的窗口 ---@param self table content对象 ---@param offset integer 起始行 attach = function(self, offset) if self.size == 0 then return end offset = offset or 0 self.window:bufset('modifiable', true) local window = self.window --- NOTE : 使用-1 则需要按顺序设置 api.nvim_buf_set_lines(window.bufnr, offset, -1, true, self.lines) local hl for i = 1, self.hl_size do hl = self.highlights[i] api.nvim_buf_add_highlight(window.bufnr, window.hl, hl.name, offset + hl.line, hl._start, hl._end) end self.window:bufset('modifiable', false) end, actual_height = function(self, wrap) wrap = wrap or self.window:option('wrap') if wrap then local height = 0 local width = self.window.width local lines = self.lines for i = 1, self.size do height = height + math.max(1, (math.ceil(lines[i]:width() / width))) end return height else return self.size end end, format = function(self, ...) local nodes = { ... } local size = #nodes assert(size > 1, 'check items size') local width = 0 local strs = {} for i, node in ipairs(nodes) do local str = node.text strs[i] = str width = width + str:width() end local space = math.floor(((self.window.width - width) / (size - 1))) assert(space > 0, 'try to expand the window') local interval = (' '):rep(space) return setmetatable({ text = table.concat(strs, interval), items = nodes, space = space, }, { __index = format_meta }) end, center = function(self, item) local space = bit.rshift(self.window.width - item.text:width(), 1) item.text = (' '):rep(space) .. item.text local load_hl = item.load_hl item.load_hl = function(this, content, line, col) load_hl(this, content, line, col + space) end return item end, addline = function(self, ...) local strs = {} local col = 0 for i, node in ipairs { ... } do local str = node.text strs[i] = str node:load_hl(self, self.size, col) col = col + #str end self:newline(table.concat(strs)) end } ---content的构造函数 ---@param window table 链接的窗口 ---@return table 构造好的content return function(window) vim.validate { window = { window, 't' }, } return setmetatable({ modifiable = true, window = window, size = 0, hl_size = 0, lines = {}, highlights = {}, }, { __index = content }) end