From 815bb2ce6cdc359115a7e65021a21c3347e8a5f6 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Wed, 23 Nov 2022 16:10:46 +0100 Subject: [PATCH] feat(text): multiline support and pattern highlights --- lua/lazy/view/text.lua | 86 ++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/lua/lazy/view/text.lua b/lua/lazy/view/text.lua index fed3d13..15fd56a 100644 --- a/lua/lazy/view/text.lua +++ b/lua/lazy/view/text.lua @@ -1,9 +1,11 @@ local Config = require("lazy.core.config") ----@alias TextSegment {str: string, hl?:string, extmark?:table} +---@alias TextSegment {str: string, hl?:string|Extmark} +---@alias Extmark {hl_group?:string, col?:number, end_col?:number} ---@class Text ---@field _lines TextSegment[][] +---@field padding number local Text = {} function Text.new() @@ -16,17 +18,30 @@ function Text.new() end ---@param str string ----@param hl? string|table -function Text:append(str, hl) +---@param hl? string|Extmark +---@param opts? {indent?: number, prefix?: string} +function Text:append(str, hl, opts) + opts = opts or {} if #self._lines == 0 then self:nl() end - table.insert(self._lines[#self._lines], { - str = str, - hl = type(hl) == "string" and hl or nil, - extmark = type(hl) == "table" and hl or nil, - }) + local lines = vim.split(str, "\n") + for l, line in ipairs(lines) do + if opts.prefix then + line = opts.prefix .. line + end + if opts.indent then + line = string.rep(" ", opts.indent) .. line + end + if l > 1 then + self:nl() + end + table.insert(self._lines[#self._lines], { + str = line, + hl = hl, + }) + end return self end @@ -36,12 +51,11 @@ function Text:nl() return self end -function Text:render(buf, padding) - padding = padding or 0 +function Text:render(buf) local lines = {} for _, line in ipairs(self._lines) do - local str = (" "):rep(padding) + local str = (" "):rep(self.padding) for _, segment in ipairs(line) do str = str .. segment.str @@ -53,20 +67,21 @@ function Text:render(buf, padding) vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) for l, line in ipairs(self._lines) do - local col = padding + local col = self.padding for _, segment in ipairs(line) do local width = vim.fn.strlen(segment.str) - if segment.hl then - vim.api.nvim_buf_set_extmark(buf, Config.ns, l - 1, col, { - hl_group = segment.hl, - end_col = col + width, - }) - end + local extmark = segment.hl + if extmark then + if type(extmark) == "string" then + extmark = { hl_group = extmark, end_col = col + width } + end + ---@cast extmark Extmark - if segment.extmark then - vim.api.nvim_buf_set_extmark(buf, Config.ns, l - 1, col, segment.extmark) + local extmark_col = extmark.col or col + extmark.col = nil + vim.api.nvim_buf_set_extmark(buf, Config.ns, l - 1, extmark_col, extmark) end col = col + width @@ -74,6 +89,37 @@ function Text:render(buf, padding) end end +---@param patterns table +function Text:highlight(patterns) + local col = self.padding + local last = self._lines[#self._lines] + ---@type TextSegment? + local text + for s, segment in ipairs(last) do + if s == #last then + text = segment + break + end + col = col + vim.fn.strlen(segment.str) + end + if text then + for pattern, hl in pairs(patterns) do + local from, to, match = text.str:find(pattern) + while from do + if match then + from, to = text.str:find(match, from, true) + end + self:append("", { + col = col + from - 1, + end_col = col + to, + hl_group = hl, + }) + from, to = text.str:find(pattern, to + 1) + end + end + end +end + function Text:trim() while #self._lines > 0 and #self._lines[1] == 0 do table.remove(self._lines, 1)