mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 12:45:17 -07:00
fix(tohtml): support ranges again
This commit is contained in:
parent
a5d4e3467d
commit
118ae7e5ed
@ -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[]`)
|
||||
|
@ -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)
|
||||
|
@ -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 = '%' })
|
||||
|
@ -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({
|
||||
|
Loading…
Reference in New Issue
Block a user