aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/tohtml.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/tohtml.lua')
-rw-r--r--runtime/lua/tohtml.lua90
1 files changed, 51 insertions, 39 deletions
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
---<pre>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<integer,[integer,integer,string]>
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<integer,any>
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, '<pre>')
+ 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, '</pre>')
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)