mirror of
https://github.com/neovim/neovim
synced 2025-07-20 03:02:17 +00:00
fix(tohtml): properly handle multiple hl groups #29012
Problem: :TOhtml doesn't properly handle virtual text when it has multiple highlight groups. It also improperly calculates position offset for multi-byte virt_text characters. Solution: Apply the `vim.api.nvim_strwidth` broadly to properly calculate character offset, and handle the cases where the `hl` argument can be a table of multiple hl groups.
This commit is contained in:
@ -188,6 +188,8 @@ local background_color_cache = nil
|
|||||||
--- @type string?
|
--- @type string?
|
||||||
local foreground_color_cache = nil
|
local foreground_color_cache = nil
|
||||||
|
|
||||||
|
local len = vim.api.nvim_strwidth
|
||||||
|
|
||||||
--- @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
--- @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
--- @param color "background"|"foreground"|integer
|
--- @param color "background"|"foreground"|integer
|
||||||
--- @return string?
|
--- @return string?
|
||||||
@ -312,9 +314,12 @@ local function style_line_insert_virt_text(style_line, col, val)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param state vim.tohtml.state
|
--- @param state vim.tohtml.state
|
||||||
--- @param hl string|integer|nil
|
--- @param hl string|integer|string[]|integer[]?
|
||||||
--- @return nil|integer
|
--- @return nil|integer
|
||||||
local function register_hl(state, hl)
|
local function register_hl(state, hl)
|
||||||
|
if type(hl) == 'table' then
|
||||||
|
hl = hl[#hl]
|
||||||
|
end
|
||||||
if type(hl) == 'nil' then
|
if type(hl) == 'nil' then
|
||||||
return
|
return
|
||||||
elseif type(hl) == 'string' then
|
elseif type(hl) == 'string' then
|
||||||
@ -537,7 +542,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces)
|
|||||||
else
|
else
|
||||||
style_line_insert_virt_text(styletable[row + 1], col + 1, { i[1], hlid })
|
style_line_insert_virt_text(styletable[row + 1], col + 1, { i[1], hlid })
|
||||||
end
|
end
|
||||||
virt_text_len = virt_text_len + #i[1]
|
virt_text_len = virt_text_len + len(i[1])
|
||||||
end
|
end
|
||||||
if extmark[4].virt_text_pos == 'overlay' then
|
if extmark[4].virt_text_pos == 'overlay' then
|
||||||
styletable_insert_range(state, row + 1, col + 1, row + 1, col + virt_text_len + 1, HIDE_ID)
|
styletable_insert_range(state, row + 1, col + 1, row + 1, col + virt_text_len + 1, HIDE_ID)
|
||||||
@ -782,7 +787,7 @@ local function styletable_statuscolumn(state)
|
|||||||
statuscolumn,
|
statuscolumn,
|
||||||
{ winid = state.winid, use_statuscol_lnum = row, highlights = true }
|
{ winid = state.winid, use_statuscol_lnum = row, highlights = true }
|
||||||
)
|
)
|
||||||
local width = vim.api.nvim_strwidth(status.str)
|
local width = len(status.str)
|
||||||
if width > minwidth then
|
if width > minwidth then
|
||||||
minwidth = width
|
minwidth = width
|
||||||
end
|
end
|
||||||
@ -797,7 +802,7 @@ local function styletable_statuscolumn(state)
|
|||||||
for k, v in ipairs(hls) do
|
for k, v in ipairs(hls) do
|
||||||
local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil)
|
local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil)
|
||||||
if k == #hls then
|
if k == #hls then
|
||||||
text = text .. (' '):rep(minwidth - vim.api.nvim_strwidth(str))
|
text = text .. (' '):rep(minwidth - len(str))
|
||||||
end
|
end
|
||||||
if text ~= '' then
|
if text ~= '' then
|
||||||
local hlid = register_hl(state, v.group)
|
local hlid = register_hl(state, v.group)
|
||||||
@ -817,7 +822,6 @@ local function styletable_listchars(state)
|
|||||||
local function utf8_sub(str, i, j)
|
local function utf8_sub(str, i, j)
|
||||||
return vim.fn.strcharpart(str, i - 1, j and j - i + 1 or nil)
|
return vim.fn.strcharpart(str, i - 1, j and j - i + 1 or nil)
|
||||||
end
|
end
|
||||||
local len = vim.api.nvim_strwidth
|
|
||||||
--- @type table<string,string>
|
--- @type table<string,string>
|
||||||
local listchars = vim.opt_local.listchars:get()
|
local listchars = vim.opt_local.listchars:get()
|
||||||
local ids = setmetatable({}, {
|
local ids = setmetatable({}, {
|
||||||
|
@ -287,7 +287,13 @@ describe(':TOhtml', function()
|
|||||||
0,
|
0,
|
||||||
{ virt_text = { { 'foo' } }, virt_text_pos = 'overlay' }
|
{ virt_text = { { 'foo' } }, virt_text_pos = 'overlay' }
|
||||||
)
|
)
|
||||||
api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' })
|
api.nvim_buf_set_extmark(
|
||||||
|
0,
|
||||||
|
ns,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
{ virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' }
|
||||||
|
)
|
||||||
--api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'})
|
--api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'})
|
||||||
run_tohtml_and_assert(screen)
|
run_tohtml_and_assert(screen)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user