diff options
Diffstat (limited to 'runtime/lua/tohtml.lua')
-rw-r--r-- | runtime/lua/tohtml.lua | 90 |
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) |