diff options
author | altermo <107814000+altermo@users.noreply.github.com> | 2024-07-11 18:16:51 +0200 |
---|---|---|
committer | Christian Clason <c.clason@uni-graz.at> | 2024-07-16 15:07:40 +0200 |
commit | 118ae7e5ed6cfab6a49ec70c21da2b850161289c (patch) | |
tree | cabb27fa81e8d73fe2f9ec3176b94472411f3d5d | |
parent | a5d4e3467d4568e5ac804f8178dda054f5360b15 (diff) | |
download | rneovim-118ae7e5ed6cfab6a49ec70c21da2b850161289c.tar.gz rneovim-118ae7e5ed6cfab6a49ec70c21da2b850161289c.tar.bz2 rneovim-118ae7e5ed6cfab6a49ec70c21da2b850161289c.zip |
fix(tohtml): support ranges again
-rw-r--r-- | runtime/doc/lua.txt | 4 | ||||
-rw-r--r-- | runtime/lua/tohtml.lua | 90 | ||||
-rw-r--r-- | runtime/plugin/tohtml.lua | 4 | ||||
-rw-r--r-- | test/functional/plugin/tohtml_spec.lua | 38 |
4 files changed, 94 insertions, 42 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 57796a4716..c1ffc41c24 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -4412,7 +4412,7 @@ vim.text.hexencode({str}) *vim.text.hexencode()* Lua module: tohtml *vim.tohtml* -: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. @@ -4434,6 +4434,8 @@ tohtml.tohtml({winid}, {opt}) *tohtml.tohtml.tohtml()* • {width}? (`integer`, default: 'textwidth' if non-zero or window width otherwise) Width used for items which are either right aligned or repeat a character infinitely. + • {range}? (`integer[]`, default: entire buffer) Range of + rows to use. Return: ~ (`string[]`) 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) diff --git a/runtime/plugin/tohtml.lua b/runtime/plugin/tohtml.lua index 79f2794a40..0cb4562938 100644 --- a/runtime/plugin/tohtml.lua +++ b/runtime/plugin/tohtml.lua @@ -5,8 +5,8 @@ vim.g.loaded_2html_plugin = true vim.api.nvim_create_user_command('TOhtml', function(args) local outfile = args.args ~= '' and args.args or vim.fn.tempname() .. '.html' - local html = require('tohtml').tohtml() + local html = require('tohtml').tohtml(0, { range = { args.line1, args.line2 } }) vim.fn.writefile(html, outfile) vim.cmd.split(outfile) vim.bo.filetype = 'html' -end, { bar = true, nargs = '?' }) +end, { bar = true, nargs = '?', range = '%' }) diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index be5bada901..827db8c0f3 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -176,6 +176,44 @@ describe(':TOhtml', function() }, fn.readfile(out_file)) end) + it('expected internal html generated from range', function() + insert([[ + line1 + line2 + line3 + ]]) + local ns = api.nvim_create_namespace '' + api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 1, end_row = 1, hl_group = 'Visual' }) + exec('set termguicolors') + local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui') + local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui') + exec_lua [[ + local html = vim.cmd'2,2TOhtml' + ]] + local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf()) + eq({ + '<!DOCTYPE html>', + '<html>', + '<head>', + '<meta charset="UTF-8">', + '<title></title>', + ('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')), + '<style>', + '* {font-family: monospace}', + ('body {background-color: %s; color: %s}'):format(bg, fg), + '.Visual {background-color: #9b9ea4}', + '</style>', + '</head>', + '<body style="display: flex">', + '<pre><span class="Visual">', + 'l</span>ine2', + '', + '</pre>', + '</body>', + '</html>', + }, fn.readfile(out_file)) + end) + it('highlight attributes generated', function() --Make sure to uncomment the attribute in `html_syntax_match()` exec('hi LINE gui=' .. table.concat({ |