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') 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