From 2ed6423c7e9d4911343d3e2049908f4b78ec7a55 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 12:56:32 +0200 Subject: fix(tohtml): replace ipairs with pairs --- runtime/lua/tohtml.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 505de720ba..5a6fc77e5c 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -521,7 +521,7 @@ local function _styletable_extmarks_virt_text(state, extmark) hl_mode = 'blend', hl_group = 'combine', } - for opt, val in ipairs(not_supported) do + for opt, val in pairs(not_supported) do if extmark[4][opt] == val then vim.notify_once( ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) -- cgit From 8cd9feb50166202bf55315934f14f74e63c8fcb4 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 13:08:57 +0200 Subject: fix(tohtml): ignore lsp inlay hints --- runtime/lua/tohtml.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 5a6fc77e5c..f7d8538b8f 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -481,10 +481,17 @@ end --- @param state vim.tohtml.state --- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} -local function _styletable_extmarks_virt_text(state, extmark) +--- @param namespaces table +local function _styletable_extmarks_virt_text(state, extmark, namespaces) if not extmark[4].virt_text then return end + ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only + ---generated in visible lines, and not in the whole buffer. + if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then + vim.notify_once('Info(TOhtml): lsp inlay hints are not supported, HTML may be incorrect') + return + end local styletable = state.style --- @type integer,integer local row, col = extmark[2], extmark[3] @@ -586,7 +593,7 @@ local function styletable_extmarks(state) _styletable_extmarks_conceal(state, v) end for _, v in ipairs(extmarks) do - _styletable_extmarks_virt_text(state, v) + _styletable_extmarks_virt_text(state, v, namespaces) end for _, v in ipairs(extmarks) do _styletable_extmarks_virt_lines(state, v) -- cgit From 88c7997503e12088e134ba663fe352399f8fa104 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 13:28:14 +0200 Subject: fix(tohtml): show how many warnings are hidden --- runtime/lua/tohtml.lua | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index f7d8538b8f..0fc349e86d 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -57,6 +57,26 @@ --- @field [3] any[][] virt_text --- @field [4] any[][] overlay_text +--- @type string[] +local notifications = {} + +---@param msg string +local function notify(msg) + if #notifications == 0 then + vim.schedule(function() + if #notifications > 1 then + vim.notify( + ('TOhtml: %s (+ %d more warnings)'):format(notifications[1], tostring(#notifications - 1)) + ) + elseif #notifications == 1 then + vim.notify('TOhtml: ' .. notifications[1]) + end + notifications = {} + end) + end + table.insert(notifications, msg) +end + local HIDE_ID = -1 -- stylua: ignore start local cterm_8_to_hex={ @@ -215,7 +235,7 @@ local function cterm_to_hex(colorstr) if hex then cterm_color_cache[color] = hex else - vim.notify_once("Info(TOhtml): Couldn't get terminal colors, using fallback") + notify("Couldn't get terminal colors, using fallback") local t_Co = tonumber(vim.api.nvim_eval('&t_Co')) if t_Co <= 8 then cterm_color_cache = cterm_8_to_hex @@ -241,7 +261,7 @@ local function get_background_color() end local hex = try_query_terminal_color('background') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal background colors, using fallback") + notify("Couldn't get terminal background colors, using fallback") hex = vim.o.background == 'light' and '#ffffff' or '#000000' end background_color_cache = hex @@ -259,7 +279,7 @@ local function get_foreground_color() end local hex = try_query_terminal_color('foreground') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal foreground colors, using fallback") + notify("Couldn't get terminal foreground colors, using fallback") hex = vim.o.background == 'light' and '#000000' or '#ffffff' end foreground_color_cache = hex @@ -467,7 +487,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_semantic_tokens') then - vim.notify_once('Info(TOhtml): lsp semantic tokens are not supported, HTML may be incorrect') + notify('lsp semantic tokens are not supported, HTML may be incorrect') return end local srow, scol, erow, ecol = @@ -489,7 +509,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then - vim.notify_once('Info(TOhtml): lsp inlay hints are not supported, HTML may be incorrect') + notify('lsp inlay hints are not supported, HTML may be incorrect') return end local styletable = state.style @@ -530,9 +550,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) } for opt, val in pairs(not_supported) do if extmark[4][opt] == val then - vim.notify_once( - ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) - ) + notify(('extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val)) end end end @@ -618,9 +636,7 @@ local function styletable_folds(state) end end if has_folded and type(({ pcall(vim.api.nvim_eval, vim.o.foldtext) })[2]) == 'table' then - vim.notify_once( - 'Info(TOhtml): foldtext returning a table is half supported, HTML may be incorrect' - ) + notify('foldtext returning a table with highlights is not supported, HTML may be incorrect') end end -- cgit From eb37241d38ad35b9e6bfac6379dd10e60aa0350c Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 26 May 2024 10:27:12 -0700 Subject: 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. --- runtime/lua/tohtml.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 0fc349e86d..5e145950b7 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -188,6 +188,8 @@ local background_color_cache = nil --- @type string? local foreground_color_cache = nil +local len = vim.api.nvim_strwidth + --- @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands --- @param color "background"|"foreground"|integer --- @return string? @@ -312,9 +314,12 @@ local function style_line_insert_virt_text(style_line, col, val) end --- @param state vim.tohtml.state ---- @param hl string|integer|nil +--- @param hl string|integer|string[]|integer[]? --- @return nil|integer local function register_hl(state, hl) + if type(hl) == 'table' then + hl = hl[#hl] + end if type(hl) == 'nil' then return elseif type(hl) == 'string' then @@ -537,7 +542,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) else style_line_insert_virt_text(styletable[row + 1], col + 1, { i[1], hlid }) end - virt_text_len = virt_text_len + #i[1] + virt_text_len = virt_text_len + len(i[1]) end 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) @@ -782,7 +787,7 @@ local function styletable_statuscolumn(state) statuscolumn, { 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 minwidth = width end @@ -797,7 +802,7 @@ local function styletable_statuscolumn(state) for k, v in ipairs(hls) do local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil) if k == #hls then - text = text .. (' '):rep(minwidth - vim.api.nvim_strwidth(str)) + text = text .. (' '):rep(minwidth - len(str)) end if text ~= '' then local hlid = register_hl(state, v.group) @@ -817,7 +822,6 @@ local function styletable_listchars(state) local function utf8_sub(str, i, j) return vim.fn.strcharpart(str, i - 1, j and j - i + 1 or nil) end - local len = vim.api.nvim_strwidth --- @type table local listchars = vim.opt_local.listchars:get() local ids = setmetatable({}, { -- cgit From 6e8a728e3dad747d0c46dc47a530b76e8997bc08 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 20:35:37 +0200 Subject: refactor: fix luals type warnings --- runtime/lua/tohtml.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 5e145950b7..120247ed4e 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -65,9 +65,7 @@ local function notify(msg) if #notifications == 0 then vim.schedule(function() if #notifications > 1 then - vim.notify( - ('TOhtml: %s (+ %d more warnings)'):format(notifications[1], tostring(#notifications - 1)) - ) + vim.notify(('TOhtml: %s (+ %d more warnings)'):format(notifications[1], #notifications - 1)) elseif #notifications == 1 then vim.notify('TOhtml: ' .. notifications[1]) end -- cgit From 8cbb1f20e557461c8417583a7f69d53aaaef920b Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Tue, 4 Jun 2024 09:06:02 -0400 Subject: refactor(lua): use tuple syntax everywhere #29111 --- runtime/lua/tohtml.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 120247ed4e..a67e1c69e2 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -46,7 +46,7 @@ --- @field [integer] vim.tohtml.line (integer: (1-index, exclusive)) --- @class (private) vim.tohtml.line ---- @field virt_lines {[integer]:{[1]:string,[2]:integer}[]} +--- @field virt_lines {[integer]:[string,integer][]} --- @field pre_text string[][] --- @field hide? boolean --- @field [integer] vim.tohtml.cell? (integer: (1-index, exclusive)) @@ -481,7 +481,7 @@ local function styletable_treesitter(state) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] --- @param namespaces table local function _styletable_extmarks_highlight(state, extmark, namespaces) if not extmark[4].hl_group then @@ -503,7 +503,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] --- @param namespaces table local function _styletable_extmarks_virt_text(state, extmark, namespaces) if not extmark[4].virt_text then @@ -559,7 +559,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] local function _styletable_extmarks_virt_lines(state, extmark) ---TODO(altermo) if the fold start is equal to virt_line start then the fold hides the virt_line if not extmark[4].virt_lines then @@ -580,7 +580,7 @@ local function _styletable_extmarks_virt_lines(state, extmark) end --- @param state vim.tohtml.state ---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} +--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any] local function _styletable_extmarks_conceal(state, extmark) if not extmark[4].conceal or state.opt.conceallevel == 0 then return @@ -648,7 +648,7 @@ local function styletable_conceal(state) local bufnr = state.bufnr vim.api.nvim_buf_call(bufnr, function() for row = 1, state.buflen do - --- @type table + --- @type table local conceals = {} local line_len_exclusive = #vim.fn.getline(row) + 1 for col = 1, line_len_exclusive do -- cgit From aa6b9c677d83d76d448c3bb0973bf8d14bfdf922 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 8 Jun 2024 21:40:18 +0200 Subject: refactor: use `vim._with` where possible This mostly means replacing `nvim_buf_call` and `nvim_win_call` with `vim._with`. --- runtime/lua/tohtml.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index a67e1c69e2..37ad60b436 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -646,7 +646,7 @@ end --- @param state vim.tohtml.state local function styletable_conceal(state) local bufnr = state.bufnr - vim.api.nvim_buf_call(bufnr, function() + vim._with({ buf = bufnr }, function() for row = 1, state.buflen do --- @type table local conceals = {} @@ -764,7 +764,7 @@ local function styletable_statuscolumn(state) if foldcolumn:match('^auto') then local max = tonumber(foldcolumn:match('^%w-:(%d)')) or 1 local maxfold = 0 - vim.api.nvim_buf_call(state.bufnr, function() + vim._with({ buf = state.bufnr }, function() for row = 1, vim.api.nvim_buf_line_count(state.bufnr) do local foldlevel = vim.fn.foldlevel(row) if foldlevel > maxfold then @@ -1291,7 +1291,7 @@ local styletable_funcs = { --- @param state vim.tohtml.state local function state_generate_style(state) - vim.api.nvim_win_call(state.winid, function() + vim._with({ win = state.winid }, function() for _, fn in ipairs(styletable_funcs) do --- @type string? local cond -- cgit From 25db0a1385377ec28fd6e4ca3553c79ce5cb80e4 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Tue, 16 Jul 2024 05:09:24 +0200 Subject: fix(tohtml): extmark text may be out of bounds --- runtime/lua/tohtml.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 37ad60b436..7bb4a26ad6 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -519,9 +519,12 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) --- @type integer,integer local row, col = extmark[2], extmark[3] if - extmark[4].virt_text_pos == 'inline' - or extmark[4].virt_text_pos == 'eol' - or extmark[4].virt_text_pos == 'overlay' + row < state.buflen + and ( + extmark[4].virt_text_pos == 'inline' + or extmark[4].virt_text_pos == 'eol' + or extmark[4].virt_text_pos == 'overlay' + ) then if extmark[4].virt_text_pos == 'eol' then style_line_insert_virt_text(styletable[row + 1], #vim.fn.getline(row + 1) + 1, { ' ' }) @@ -1144,7 +1147,13 @@ local function extend_pre(out, state) local line = vim.api.nvim_buf_get_lines(state.bufnr, row - 1, row, false)[1] or '' local s = '' s = s .. _pre_text_to_html(state, row) - for col = 1, #line + 1 do + local true_line_len = #line + 1 + for k in pairs(style_line) do + if type(k) == 'number' and k > true_line_len then + true_line_len = k + end + end + for col = 1, true_line_len do local cell = style_line[col] --- @type table? local char @@ -1191,7 +1200,7 @@ local function extend_pre(out, state) char = cell[4][#cell[4]] end - if col == #line + 1 and not char then + if col == true_line_len and not char then break end -- cgit From 118ae7e5ed6cfab6a49ec70c21da2b850161289c Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Thu, 11 Jul 2024 18:16:51 +0200 Subject: fix(tohtml): support ranges again --- runtime/lua/tohtml.lua | 90 ++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 39 deletions(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 7bb4a26ad6..a4b5a741bc 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -1,6 +1,6 @@ --- @brief ---
help
----:TOhtml {file}                                                       *:TOhtml*
+---:[range]TOhtml {file}                                                *:TOhtml*
 ---Converts the buffer shown in the current window to HTML, opens the generated
 ---HTML in a new split window, and saves its contents to {file}. If {file} is not
 ---given, a temporary file (created by |tempname()|) is used.
@@ -40,7 +40,8 @@
 --- @field winid integer
 --- @field bufnr integer
 --- @field width integer
---- @field buflen integer
+--- @field start integer
+--- @field end_ integer
 
 --- @class (private) vim.tohtml.styletable
 --- @field [integer] vim.tohtml.line (integer: (1-index, exclusive))
@@ -393,7 +394,7 @@ end
 
 --- @param state vim.tohtml.state
 local function styletable_syntax(state)
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     local prev_id = 0
     local prev_col = nil
     for col = 1, #vim.fn.getline(row) + 1 do
@@ -413,7 +414,7 @@ end
 --- @param state vim.tohtml.state
 local function styletable_diff(state)
   local styletable = state.style
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     local style_line = styletable[row]
     local filler = vim.fn.diff_filler(row)
     if filler ~= 0 then
@@ -423,7 +424,7 @@ local function styletable_diff(state)
         { { fill:rep(state.width), register_hl(state, 'DiffDelete') } }
       )
     end
-    if row == state.buflen + 1 then
+    if row == state.end_ + 1 then
       break
     end
     local prev_id = 0
@@ -465,7 +466,9 @@ local function styletable_treesitter(state)
     if not query then
       return
     end
-    for capture, node, metadata in query:iter_captures(root, buf_highlighter.bufnr, 0, state.buflen) do
+    for capture, node, metadata in
+      query:iter_captures(root, buf_highlighter.bufnr, state.start - 1, state.end_)
+    do
       local srow, scol, erow, ecol = node:range()
       --- @diagnostic disable-next-line: invisible
       local c = q._query.captures[capture]
@@ -519,7 +522,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces)
   --- @type integer,integer
   local row, col = extmark[2], extmark[3]
   if
-    row < state.buflen
+    row < vim.api.nvim_buf_line_count(state.bufnr)
     and (
       extmark[4].virt_text_pos == 'inline'
       or extmark[4].virt_text_pos == 'eol'
@@ -628,7 +631,7 @@ end
 local function styletable_folds(state)
   local styletable = state.style
   local has_folded = false
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     if vim.fn.foldclosed(row) > 0 then
       has_folded = true
       styletable[row].hide = true
@@ -650,7 +653,7 @@ end
 local function styletable_conceal(state)
   local bufnr = state.bufnr
   vim._with({ buf = bufnr }, function()
-    for row = 1, state.buflen do
+    for row = state.start, state.end_ do
       --- @type table
       local conceals = {}
       local line_len_exclusive = #vim.fn.getline(row) + 1
@@ -768,7 +771,7 @@ local function styletable_statuscolumn(state)
       local max = tonumber(foldcolumn:match('^%w-:(%d)')) or 1
       local maxfold = 0
       vim._with({ buf = state.bufnr }, function()
-        for row = 1, vim.api.nvim_buf_line_count(state.bufnr) do
+        for row = state.start, state.end_ do
           local foldlevel = vim.fn.foldlevel(row)
           if foldlevel > maxfold then
             maxfold = foldlevel
@@ -783,7 +786,7 @@ local function styletable_statuscolumn(state)
 
   --- @type table
   local statuses = {}
-  for row = 1, state.buflen do
+  for row = state.start, state.end_ do
     local status = vim.api.nvim_eval_statusline(
       statuscolumn,
       { winid = state.winid, use_statuscol_lnum = row, highlights = true }
@@ -833,7 +836,7 @@ local function styletable_listchars(state)
   })
 
   if listchars.eol then
-    for row = 1, state.buflen do
+    for row = state.start, state.end_ do
       local style_line = state.style[row]
       style_line_insert_overlay_char(
         style_line,
@@ -1127,16 +1130,22 @@ end
 local function extend_pre(out, state)
   local styletable = state.style
   table.insert(out, '
')
+  local out_start = #out
   local hide_count = 0
   --- @type integer[]
   local stack = {}
 
+  local before = ''
+  local after = ''
   local function loop(row)
+    local inside = row <= state.end_ and row >= state.start
     local style_line = styletable[row]
     if style_line.hide and (styletable[row - 1] or {}).hide then
       return
     end
-    _extend_virt_lines(out, state, row)
+    if inside then
+      _extend_virt_lines(out, state, row)
+    end
     --Possible improvement (altermo):
     --Instead of looping over all the buffer characters per line,
     --why not loop over all the style_line cells,
@@ -1146,7 +1155,9 @@ local function extend_pre(out, state)
     end
     local line = vim.api.nvim_buf_get_lines(state.bufnr, row - 1, row, false)[1] or ''
     local s = ''
-    s = s .. _pre_text_to_html(state, row)
+    if inside then
+      s = s .. _pre_text_to_html(state, row)
+    end
     local true_line_len = #line + 1
     for k in pairs(style_line) do
       if type(k) == 'number' and k > true_line_len then
@@ -1193,7 +1204,7 @@ local function extend_pre(out, state)
           end
         end
 
-        if cell[3] then
+        if cell[3] and inside then
           s = s .. _virt_text_to_html(state, cell)
         end
 
@@ -1204,7 +1215,7 @@ local function extend_pre(out, state)
         break
       end
 
-      if hide_count == 0 then
+      if hide_count == 0 and inside then
         s = s
           .. _char_to_html(
             state,
@@ -1213,12 +1224,20 @@ local function extend_pre(out, state)
           )
       end
     end
-    table.insert(out, s)
+    if row > state.end_ + 1 then
+      after = after .. s
+    elseif row < state.start then
+      before = s .. before
+    else
+      table.insert(out, s)
+    end
   end
 
-  for row = 1, state.buflen + 1 do
+  for row = 1, vim.api.nvim_buf_line_count(state.bufnr) + 1 do
     loop(row)
   end
+  out[out_start] = out[out_start] .. before
+  out[#out] = out[#out] .. after
   assert(#stack == 0, 'an open HTML tag was never closed')
   table.insert(out, '
') end @@ -1250,6 +1269,7 @@ local function global_state_to_state(winid, global_state) if not width or width < 1 then width = vim.api.nvim_win_get_width(winid) end + local range = opt.range or { 1, vim.api.nvim_buf_line_count(bufnr) } local state = setmetatable({ winid = winid == 0 and vim.api.nvim_get_current_win() or winid, opt = vim.wo[winid], @@ -1257,7 +1277,8 @@ local function global_state_to_state(winid, global_state) bufnr = bufnr, tabstop = (' '):rep(vim.bo[bufnr].tabstop), width = width, - buflen = vim.api.nvim_buf_line_count(bufnr), + start = range[1], + end_ = range[2], }, { __index = global_state }) return state --[[@as vim.tohtml.state]] end @@ -1316,35 +1337,22 @@ local function state_generate_style(state) end) end ---- @param winid integer[]|integer +--- @param winid integer --- @param opt? vim.tohtml.opt --- @return string[] local function win_to_html(winid, opt) - if type(winid) == 'number' then - winid = { winid } - end - --- @cast winid integer[] - assert(#winid > 0, 'no window specified') opt = opt or {} - local title = table.concat( - vim.tbl_map(vim.api.nvim_buf_get_name, vim.tbl_map(vim.api.nvim_win_get_buf, winid)), - ',' - ) + local title = vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(winid)) + local global_state = opt_to_global_state(opt, title) - --- @type vim.tohtml.state[] - local states = {} - for _, i in ipairs(winid) do - local state = global_state_to_state(i, global_state) - state_generate_style(state) - table.insert(states, state) - end + local state = global_state_to_state(winid, global_state) + state_generate_style(state) + local html = {} extend_html(html, function() extend_head(html, global_state) extend_body(html, function() - for _, state in ipairs(states) do - extend_pre(html, state) - end + extend_pre(html, state) end) end) return html @@ -1371,6 +1379,10 @@ local M = {} --- infinitely. --- (default: 'textwidth' if non-zero or window width otherwise) --- @field width? integer +--- +--- Range of rows to use. +--- (default: entire buffer) +--- @field range? integer[] --- Converts the buffer shown in the window {winid} to HTML and returns the output as a list of string. --- @param winid? integer Window to convert (defaults to current window) -- cgit From 59baa5e8a1f9e71b82f28c2723ccc558370b6fc0 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 29 Aug 2024 09:36:33 -0700 Subject: fix(tohtml): apply sp color if present #30110 Problem: Things like underlines are always given a default foreground highlight regardless of the value of `sp`. Solution: Check for `sp` first, and apply that color to the text decoration color if it exists. Limitations: If there is no value of `sp`, vim applies a text decoration color that matches the foreground of the text. This is still not implemented (and seems like a much more complex problem): in TOhtml, the underline will still be given a default foreground highlight. --- runtime/lua/tohtml.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index a4b5a741bc..6a5bd6de9d 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -1003,6 +1003,7 @@ local function extend_style(out, state) --TODO(altermo) use local namespace (instead of global 0) local fg = vim.fn.synIDattr(hlid, 'fg#') local bg = vim.fn.synIDattr(hlid, 'bg#') + local sp = vim.fn.synIDattr(hlid, 'sp#') local decor_line = {} if vim.fn.synIDattr(hlid, 'underline') ~= '' then table.insert(decor_line, 'underline') @@ -1020,6 +1021,8 @@ local function extend_style(out, state) ['font-weight'] = vim.fn.synIDattr(hlid, 'bold') ~= '' and 'bold' or nil, ['text-decoration-line'] = not vim.tbl_isempty(decor_line) and table.concat(decor_line, ' ') or nil, + -- TODO(ribru17): fallback to displayed text color if sp not set + ['text-decoration-color'] = sp ~= '' and cterm_to_hex(sp) or nil, --TODO(altermo) if strikethrough and undercurl then the strikethrough becomes wavy ['text-decoration-style'] = vim.fn.synIDattr(hlid, 'undercurl') ~= '' and 'wavy' or nil, } -- cgit From e37404f7fecc5f57e4f3df4cf5ba0adec67bfbb3 Mon Sep 17 00:00:00 2001 From: yayoyuyu <112897090+yayoyuyu@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:29:27 +0900 Subject: fix(tohtml): enclose font-family names in quotation marks Font-family names must be enclosed in quotation marks to ensure that fonts are applied correctly when there are spaces in the name. Fix an issue where multiple fonts specified in `vim.o.guifont` are inserted as a single element, treating them as a single font. Support for escaping commas with backslash and ignoring spaces after a comma. ref `:help 'guifont'` --- runtime/lua/tohtml.lua | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'runtime/lua/tohtml.lua') diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 6a5bd6de9d..ed42b28725 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -1293,9 +1293,25 @@ local function opt_to_global_state(opt, title) local fonts = {} if opt.font then fonts = type(opt.font) == 'string' and { opt.font } or opt.font --[[@as (string[])]] + for i, v in pairs(fonts) do + fonts[i] = ('"%s"'):format(v) + end elseif vim.o.guifont:match('^[^:]+') then - table.insert(fonts, vim.o.guifont:match('^[^:]+')) + -- Example: + -- Input: "Font,Escape\,comma, Ignore space after comma" + -- Output: { "Font","Escape,comma","Ignore space after comma" } + local prev = '' + for name in vim.gsplit(vim.o.guifont:match('^[^:]+'), ',', { trimempty = true }) do + if vim.endswith(name, '\\') then + prev = prev .. vim.trim(name:sub(1, -2) .. ',') + elseif vim.trim(name) ~= '' then + table.insert(fonts, ('"%s%s"'):format(prev, vim.trim(name))) + prev = '' + end + end end + -- Generic family names (monospace here) must not be quoted + -- because the browser recognizes them as font families. table.insert(fonts, 'monospace') --- @type vim.tohtml.state.global local state = { -- cgit