2024-04-20 08:44:13 -07:00
|
|
|
local t = require('test.testutil')
|
|
|
|
local n = require('test.functional.testnvim')()
|
2024-02-26 12:42:51 -07:00
|
|
|
local Screen = require('test.functional.ui.screen')
|
|
|
|
|
2024-04-20 08:44:13 -07:00
|
|
|
local clear = n.clear
|
|
|
|
local exec = n.exec
|
|
|
|
local exec_lua = n.exec_lua
|
2024-04-08 02:03:20 -07:00
|
|
|
local eq = t.eq
|
2024-04-20 08:44:13 -07:00
|
|
|
local fn = n.fn
|
|
|
|
local api = n.api
|
|
|
|
local insert = n.insert
|
2024-02-26 12:42:51 -07:00
|
|
|
|
|
|
|
local function html_syntax_match()
|
|
|
|
local styles =
|
|
|
|
vim.split(api.nvim_exec2([[/<style>/+,/<\/style>/-p]], { output = true }).output, '\n')
|
|
|
|
local attrnames = {
|
|
|
|
['font%-weight: bold'] = 'bold',
|
|
|
|
['text%-decoration%-line: [^;]*underline'] = 'underline',
|
|
|
|
['font%-style: italic'] = 'italic',
|
|
|
|
['text%-decoration%-line: [^;]*line%-through'] = 'strikethrough',
|
|
|
|
}
|
|
|
|
local hls = {}
|
|
|
|
for _, style in ipairs(styles) do
|
|
|
|
local attr = {}
|
|
|
|
for match, attrname in pairs(attrnames) do
|
|
|
|
if style:find(match) then
|
|
|
|
---@type boolean
|
|
|
|
attr[attrname] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if style:find('text%-decoration%-style: wavy') and attr.underline then
|
|
|
|
---@type boolean
|
|
|
|
attr.underline = nil
|
|
|
|
attr.undercurl = true
|
|
|
|
end
|
2024-08-29 09:36:33 -07:00
|
|
|
attr.sp = style:match('text%-decoration%-color: #(%x+)')
|
|
|
|
if attr.sp then
|
|
|
|
attr.sp = tonumber(attr.sp, 16)
|
|
|
|
end
|
2024-02-26 12:42:51 -07:00
|
|
|
attr.bg = style:match('background%-color: #(%x+)')
|
|
|
|
if attr.bg then
|
|
|
|
attr.bg = tonumber(attr.bg, 16)
|
|
|
|
end
|
|
|
|
attr.fg = style:match('[^%-]color: #(%x+)')
|
|
|
|
if attr.fg then
|
|
|
|
attr.fg = tonumber(attr.fg, 16)
|
|
|
|
end
|
|
|
|
if style:match('^%.(%w+)') then
|
|
|
|
---@type table
|
|
|
|
hls[style:match('^%.(%w+)')] = attr
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local whitelist = {
|
|
|
|
'fg',
|
|
|
|
'bg',
|
2024-08-29 09:36:33 -07:00
|
|
|
'sp',
|
2024-02-26 12:42:51 -07:00
|
|
|
--'blend',
|
|
|
|
'bold',
|
|
|
|
--'standout',
|
|
|
|
'underline',
|
|
|
|
'undercurl',
|
|
|
|
--'underdouble',
|
|
|
|
--'underdotted',
|
|
|
|
--'underdashed',
|
|
|
|
'strikethrough',
|
|
|
|
'italic',
|
|
|
|
--'reverse',
|
|
|
|
--'nocombine',
|
|
|
|
}
|
|
|
|
for name, attrs_old in
|
|
|
|
pairs(api.nvim_get_hl(0, { link = true }) --[[@as table<string,table>]])
|
|
|
|
do
|
|
|
|
---@type table
|
|
|
|
local other = hls[name:gsub('%.', '-'):gsub('@', '-')]
|
|
|
|
if other then
|
|
|
|
local attrs = {}
|
|
|
|
for _, attrname in ipairs(whitelist) do
|
|
|
|
---@type table
|
|
|
|
attrs[attrname] = attrs_old[attrname]
|
|
|
|
end
|
|
|
|
eq(attrs, other)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return hls
|
|
|
|
end
|
|
|
|
|
|
|
|
local function html_to_extmarks()
|
|
|
|
local buf = api.nvim_get_current_buf()
|
|
|
|
local ns = api.nvim_create_namespace 'test-namespace'
|
|
|
|
api.nvim_buf_clear_namespace(buf, ns, 0, -1)
|
|
|
|
exec 'silent! norm! ggd/^<pre>$\rddG3dk'
|
|
|
|
local stack = {}
|
|
|
|
exec [[set filetype=]]
|
|
|
|
exec [[silent! %s/</¤/g]]
|
|
|
|
exec [[silent! %s/"/"/g]]
|
|
|
|
exec [[silent! %s/&/\&/g]]
|
|
|
|
exec [[silent! %s/>/>/g]]
|
|
|
|
exec [[silent! %s/</</g]]
|
|
|
|
for _, match in
|
|
|
|
ipairs(
|
|
|
|
fn.matchbufline(buf, [[¤span class="\([^"]\+\)">\|¤/span>]], 1, '$', { submatches = true }) --[[@as (table[])]]
|
|
|
|
)
|
|
|
|
do
|
|
|
|
if match.text == '¤/span>' then
|
|
|
|
local val = table.remove(stack)
|
|
|
|
api.nvim_buf_set_extmark(buf, ns, val.lnum - 1, val.byteidx, {
|
|
|
|
hl_group = val.submatches[1],
|
|
|
|
end_row = match.lnum - 1,
|
|
|
|
end_col = match.byteidx,
|
|
|
|
})
|
|
|
|
else
|
|
|
|
table.insert(stack, match)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
exec [[silent! %s/¤\/span>//g]]
|
|
|
|
exec [[silent! %s/¤span[^>]*>//g]]
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param screen test.functional.ui.screen
|
|
|
|
---@param func function?
|
|
|
|
local function run_tohtml_and_assert(screen, func)
|
|
|
|
exec('norm! ggO-;')
|
2024-03-07 19:24:46 -07:00
|
|
|
screen:expect({ any = vim.pesc('-^;') })
|
|
|
|
exec('norm! :\rh')
|
|
|
|
screen:expect({ any = vim.pesc('^-;') })
|
|
|
|
local expected = screen:get_snapshot()
|
2024-02-26 12:42:51 -07:00
|
|
|
do
|
|
|
|
(func or exec)('TOhtml')
|
|
|
|
end
|
|
|
|
exec('only')
|
|
|
|
html_syntax_match()
|
|
|
|
html_to_extmarks()
|
2024-03-07 19:24:46 -07:00
|
|
|
exec('norm! gg0f;')
|
|
|
|
screen:expect({ any = vim.pesc('-^;') })
|
|
|
|
exec('norm! :\rh')
|
|
|
|
screen:expect({ grid = expected.grid, attr_ids = expected.attr_ids })
|
2024-02-26 12:42:51 -07:00
|
|
|
end
|
|
|
|
|
2024-08-20 07:29:27 -07:00
|
|
|
---@param guifont boolean
|
2024-09-08 03:15:13 -07:00
|
|
|
local function test_generates_html(guifont, expect_font)
|
2024-08-20 07:29:27 -07:00
|
|
|
insert([[line]])
|
|
|
|
exec('set termguicolors')
|
|
|
|
local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
|
|
|
|
local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
|
2024-09-08 03:15:13 -07:00
|
|
|
local tmpfile = t.tmpname()
|
|
|
|
|
|
|
|
exec_lua(
|
|
|
|
[[
|
|
|
|
local guifont, outfile = ...
|
|
|
|
local html = (guifont
|
|
|
|
and require('tohtml').tohtml(0,{title="title"})
|
|
|
|
or require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }}))
|
|
|
|
vim.fn.writefile(html, outfile)
|
|
|
|
vim.cmd.split(outfile)
|
|
|
|
]],
|
|
|
|
guifont,
|
|
|
|
tmpfile
|
|
|
|
)
|
|
|
|
|
2024-08-20 07:29:27 -07:00
|
|
|
local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
|
|
|
|
eq({
|
|
|
|
'<!DOCTYPE html>',
|
|
|
|
'<html>',
|
|
|
|
'<head>',
|
|
|
|
'<meta charset="UTF-8">',
|
|
|
|
'<title>title</title>',
|
|
|
|
('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
|
|
|
|
'<style>',
|
2024-09-08 03:15:13 -07:00
|
|
|
('* {font-family: %s,monospace}'):format(expect_font),
|
2024-08-20 07:29:27 -07:00
|
|
|
('body {background-color: %s; color: %s}'):format(bg, fg),
|
|
|
|
'</style>',
|
|
|
|
'</head>',
|
|
|
|
'<body style="display: flex">',
|
|
|
|
'<pre>',
|
|
|
|
'line',
|
|
|
|
'',
|
|
|
|
'</pre>',
|
|
|
|
'</body>',
|
|
|
|
'</html>',
|
|
|
|
}, fn.readfile(out_file))
|
|
|
|
end
|
|
|
|
|
2024-02-26 12:42:51 -07:00
|
|
|
describe(':TOhtml', function()
|
|
|
|
--- @type test.functional.ui.screen
|
|
|
|
local screen
|
|
|
|
before_each(function()
|
|
|
|
clear({ args = { '--clean' } })
|
|
|
|
screen = Screen.new(80, 80)
|
|
|
|
screen:attach({ term_name = 'xterm' })
|
|
|
|
exec('colorscheme default')
|
|
|
|
end)
|
|
|
|
|
2024-09-08 03:15:13 -07:00
|
|
|
it('generates html with given font', function()
|
|
|
|
test_generates_html(false, '"dumyfont","anotherfont"')
|
2024-08-20 07:29:27 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it("generates html, respects 'guifont'", function()
|
2024-09-08 03:15:13 -07:00
|
|
|
exec_lua [[vim.o.guifont='Font,Escape\\,comma, Ignore space after comma']]
|
|
|
|
test_generates_html(true, '"Font","Escape,comma","Ignore space after comma"')
|
2024-02-26 12:42:51 -07:00
|
|
|
end)
|
|
|
|
|
2024-09-08 03:15:13 -07:00
|
|
|
it('generates html from range', function()
|
2024-07-11 09:16:51 -07:00
|
|
|
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)
|
|
|
|
|
2024-09-08 03:15:13 -07:00
|
|
|
it('generates highlight attributes', function()
|
2024-02-26 12:42:51 -07:00
|
|
|
--Make sure to uncomment the attribute in `html_syntax_match()`
|
2024-08-29 09:36:33 -07:00
|
|
|
exec('hi LINE guisp=#00ff00 gui=' .. table.concat({
|
2024-02-26 12:42:51 -07:00
|
|
|
'bold',
|
|
|
|
'underline',
|
|
|
|
'italic',
|
|
|
|
'strikethrough',
|
|
|
|
}, ','))
|
|
|
|
exec('hi UNDERCURL gui=undercurl')
|
|
|
|
exec('syn keyword LINE line')
|
|
|
|
exec('syn keyword UNDERCURL undercurl')
|
|
|
|
insert('line\nundercurl')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('syntax', function()
|
|
|
|
insert [[
|
|
|
|
function main()
|
|
|
|
print("hello world")
|
|
|
|
end
|
|
|
|
]]
|
|
|
|
exec('set termguicolors')
|
|
|
|
exec('syntax enable')
|
|
|
|
exec('setf lua')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('diff', function()
|
|
|
|
exec('set diffopt=')
|
|
|
|
insert [[
|
|
|
|
diffadd
|
|
|
|
nochage
|
|
|
|
diffchange1
|
|
|
|
]]
|
|
|
|
exec('new')
|
|
|
|
insert [[
|
|
|
|
nochage
|
|
|
|
diffchange2
|
|
|
|
diffremove
|
|
|
|
]]
|
|
|
|
exec('set diff')
|
|
|
|
exec('close')
|
|
|
|
exec('set diff')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('treesitter', function()
|
|
|
|
insert [[
|
|
|
|
function main()
|
|
|
|
print("hello world")
|
|
|
|
end
|
|
|
|
]]
|
|
|
|
exec('setf lua')
|
|
|
|
exec_lua('vim.treesitter.start()')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('matchadd', function()
|
|
|
|
insert [[
|
|
|
|
line
|
|
|
|
]]
|
|
|
|
fn.matchadd('Visual', 'line')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
describe('conceallevel', function()
|
|
|
|
local function run(level)
|
|
|
|
insert([[
|
|
|
|
line0
|
|
|
|
line1
|
|
|
|
line2
|
|
|
|
line3
|
|
|
|
]])
|
|
|
|
local ns = api.nvim_create_namespace ''
|
|
|
|
fn.matchadd('Conceal', 'line1', 3, 5, { conceal = 'a' })
|
|
|
|
api.nvim_buf_set_extmark(0, ns, 2, 0, { conceal = 'a', end_col = 5 })
|
|
|
|
exec(':syntax match Conceal "line3" conceal cchar=a')
|
|
|
|
exec('set conceallevel=' .. level)
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end
|
|
|
|
it('conceallevel=0', function()
|
|
|
|
run(0)
|
|
|
|
end)
|
|
|
|
it('conceallevel=1', function()
|
|
|
|
run(1)
|
|
|
|
end)
|
|
|
|
it('conceallevel=2', function()
|
|
|
|
run(2)
|
|
|
|
end)
|
|
|
|
it('conceallevel=3', function()
|
|
|
|
run(3)
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
describe('extmarks', function()
|
|
|
|
it('virt_text', function()
|
|
|
|
insert [[
|
|
|
|
line1
|
|
|
|
line2
|
|
|
|
line3
|
|
|
|
line4
|
|
|
|
]]
|
|
|
|
local ns = api.nvim_create_namespace ''
|
|
|
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text = { { 'foo' } } })
|
|
|
|
api.nvim_buf_set_extmark(
|
|
|
|
0,
|
|
|
|
ns,
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
{ virt_text = { { 'foo' } }, virt_text_pos = 'overlay' }
|
|
|
|
)
|
2024-05-26 10:27:12 -07:00
|
|
|
api.nvim_buf_set_extmark(
|
|
|
|
0,
|
|
|
|
ns,
|
|
|
|
2,
|
|
|
|
0,
|
|
|
|
{ virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' }
|
|
|
|
)
|
2024-02-26 12:42:51 -07:00
|
|
|
--api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'})
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
2024-03-07 19:24:46 -07:00
|
|
|
it('highlight', function()
|
2024-02-26 12:42:51 -07:00
|
|
|
insert [[
|
|
|
|
line1
|
|
|
|
]]
|
|
|
|
local ns = api.nvim_create_namespace ''
|
|
|
|
api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 2, hl_group = 'Visual' })
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
it('virt_line', function()
|
|
|
|
insert [[
|
|
|
|
line1
|
|
|
|
line2
|
|
|
|
]]
|
|
|
|
local ns = api.nvim_create_namespace ''
|
|
|
|
api.nvim_buf_set_extmark(0, ns, 1, 0, { end_col = 2, virt_lines = { { { 'foo' } } } })
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('listchars', function()
|
|
|
|
exec('setlocal list')
|
|
|
|
exec(
|
|
|
|
'setlocal listchars=eol:$,tab:<->,space:-,multispace:++,lead:_,leadmultispace:##,trail:&,nbsp:%'
|
|
|
|
)
|
|
|
|
fn.setline(1, '\tfoo\t')
|
|
|
|
fn.setline(2, ' foo foo ')
|
|
|
|
fn.setline(3, ' foo foo ')
|
2024-03-04 04:08:23 -07:00
|
|
|
fn.setline(4, 'foo\194\160 \226\128\175foo')
|
2024-02-26 12:42:51 -07:00
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
exec('new|only')
|
|
|
|
fn.setline(1, '\tfoo\t')
|
|
|
|
exec('setlocal list')
|
|
|
|
exec('setlocal listchars=tab:a-')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('folds', function()
|
|
|
|
insert([[
|
|
|
|
line1
|
|
|
|
line2
|
|
|
|
]])
|
|
|
|
exec('set foldtext=foldtext()')
|
|
|
|
exec('%fo')
|
|
|
|
run_tohtml_and_assert(screen)
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('statuscol', function()
|
|
|
|
local function run()
|
|
|
|
local buf = api.nvim_get_current_buf()
|
|
|
|
run_tohtml_and_assert(screen, function()
|
|
|
|
exec_lua [[
|
|
|
|
local outfile = vim.fn.tempname() .. '.html'
|
|
|
|
local html = require('tohtml').tohtml(0,{number_lines=true})
|
|
|
|
vim.fn.writefile(html, outfile)
|
|
|
|
vim.cmd.split(outfile)
|
|
|
|
]]
|
|
|
|
end)
|
|
|
|
api.nvim_set_current_buf(buf)
|
|
|
|
end
|
|
|
|
insert([[
|
|
|
|
line1
|
|
|
|
line2
|
|
|
|
]])
|
|
|
|
exec('setlocal relativenumber')
|
|
|
|
run()
|
|
|
|
exec('setlocal norelativenumber')
|
|
|
|
exec('setlocal number')
|
|
|
|
run()
|
|
|
|
exec('setlocal relativenumber')
|
|
|
|
run()
|
|
|
|
exec('setlocal signcolumn=yes:2')
|
|
|
|
run()
|
|
|
|
exec('setlocal foldcolumn=2')
|
|
|
|
run()
|
|
|
|
exec('setlocal norelativenumber')
|
|
|
|
run()
|
|
|
|
exec('setlocal signcolumn=no')
|
|
|
|
run()
|
|
|
|
end)
|
|
|
|
end)
|