mirror of https://github.com/folke/lazy.nvim.git
feat(text): multiline support and pattern highlights
This commit is contained in:
parent
68a8d57b5b
commit
815bb2ce6c
|
@ -1,9 +1,11 @@
|
||||||
local Config = require("lazy.core.config")
|
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
|
---@class Text
|
||||||
---@field _lines TextSegment[][]
|
---@field _lines TextSegment[][]
|
||||||
|
---@field padding number
|
||||||
local Text = {}
|
local Text = {}
|
||||||
|
|
||||||
function Text.new()
|
function Text.new()
|
||||||
|
@ -16,17 +18,30 @@ function Text.new()
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param str string
|
---@param str string
|
||||||
---@param hl? string|table
|
---@param hl? string|Extmark
|
||||||
function Text:append(str, hl)
|
---@param opts? {indent?: number, prefix?: string}
|
||||||
|
function Text:append(str, hl, opts)
|
||||||
|
opts = opts or {}
|
||||||
if #self._lines == 0 then
|
if #self._lines == 0 then
|
||||||
self:nl()
|
self:nl()
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(self._lines[#self._lines], {
|
local lines = vim.split(str, "\n")
|
||||||
str = str,
|
for l, line in ipairs(lines) do
|
||||||
hl = type(hl) == "string" and hl or nil,
|
if opts.prefix then
|
||||||
extmark = type(hl) == "table" and hl or nil,
|
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
|
return self
|
||||||
end
|
end
|
||||||
|
@ -36,12 +51,11 @@ function Text:nl()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function Text:render(buf, padding)
|
function Text:render(buf)
|
||||||
padding = padding or 0
|
|
||||||
local lines = {}
|
local lines = {}
|
||||||
|
|
||||||
for _, line in ipairs(self._lines) do
|
for _, line in ipairs(self._lines) do
|
||||||
local str = (" "):rep(padding)
|
local str = (" "):rep(self.padding)
|
||||||
|
|
||||||
for _, segment in ipairs(line) do
|
for _, segment in ipairs(line) do
|
||||||
str = str .. segment.str
|
str = str .. segment.str
|
||||||
|
@ -53,20 +67,21 @@ function Text:render(buf, padding)
|
||||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||||
|
|
||||||
for l, line in ipairs(self._lines) do
|
for l, line in ipairs(self._lines) do
|
||||||
local col = padding
|
local col = self.padding
|
||||||
|
|
||||||
for _, segment in ipairs(line) do
|
for _, segment in ipairs(line) do
|
||||||
local width = vim.fn.strlen(segment.str)
|
local width = vim.fn.strlen(segment.str)
|
||||||
|
|
||||||
if segment.hl then
|
local extmark = segment.hl
|
||||||
vim.api.nvim_buf_set_extmark(buf, Config.ns, l - 1, col, {
|
if extmark then
|
||||||
hl_group = segment.hl,
|
if type(extmark) == "string" then
|
||||||
end_col = col + width,
|
extmark = { hl_group = extmark, end_col = col + width }
|
||||||
})
|
end
|
||||||
end
|
---@cast extmark Extmark
|
||||||
|
|
||||||
if segment.extmark then
|
local extmark_col = extmark.col or col
|
||||||
vim.api.nvim_buf_set_extmark(buf, Config.ns, l - 1, col, segment.extmark)
|
extmark.col = nil
|
||||||
|
vim.api.nvim_buf_set_extmark(buf, Config.ns, l - 1, extmark_col, extmark)
|
||||||
end
|
end
|
||||||
|
|
||||||
col = col + width
|
col = col + width
|
||||||
|
@ -74,6 +89,37 @@ function Text:render(buf, padding)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param patterns table<string,string>
|
||||||
|
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()
|
function Text:trim()
|
||||||
while #self._lines > 0 and #self._lines[1] == 0 do
|
while #self._lines > 0 and #self._lines[1] == 0 do
|
||||||
table.remove(self._lines, 1)
|
table.remove(self._lines, 1)
|
||||||
|
|
Loading…
Reference in New Issue