local address = '127.0.0.1:' .. tostring( 7000 + math.random( 1, 500 ) ) local server = vim.system( { vim.v.progpath, '--headless', '--noplugin', '-u', 'tests/minimal_init.lua', '--listen', address, }, {} ) local channel local connected = vim.wait( 20000, function() local ok, value = pcall( vim.fn.sockconnect, 'tcp', address, { rpc = true, } ) if ok and value ~= 0 then channel = value; return true end return false end, 50 ) if not connected then server:kill( 'sigterm' ); error( 'capture test server unavailable' ) end local remote = function( code ) return vim.rpcrequest( channel, 'nvim_exec_lua', code, {} ) end local ui_channel = vim.fn.sockconnect( 'tcp', address, { on_data = function() end, } ) local ui = function( method, arguments ) vim.fn.chansend( ui_channel, vim.mpack.encode( { 2, method, arguments or {}, } ) ) end local ok, failure = xpcall( function() assert( not remote [[return require('bugabinga.pivi.bridge').handle {action='capture'}.ok]] ) ui( 'nvim_ui_attach', { 80, 24, { rgb = true, ext_linegrid = true, }, } ) assert( vim.wait( 5000, function() return remote [[return #vim.api.nvim_list_uis()]] == 1 end, 10 ) ) local result = remote [==[ vim.o.laststatus = 0 vim.o.showtabline = 0 vim.o.cmdheight = 1 vim.wo.number = false vim.wo.relativenumber = false vim.wo.signcolumn = 'no' vim.wo.foldcolumn = '0' vim.wo.conceallevel = 2 vim.wo.concealcursor = 'n' local buffer = vim.api.nvim_get_current_buf() vim.api.nvim_buf_set_lines(buffer, 0, -1, false, {'alpha SECRET omega', '界é', 'third'}) vim.cmd 'syntax match CaptureHidden /SECRET/ conceal cchar=*' vim.api.nvim_set_hl(0, 'CaptureVirtual', {fg=0x123456, bg=0xabcdef, bold=true}) local ns = vim.api.nvim_create_namespace('capture-test') vim.api.nvim_buf_set_extmark(buffer, ns, 2, 0, { virt_text={{'VIRTUAL', 'CaptureVirtual'}}, virt_text_pos='eol', }) vim.cmd 'vsplit' local float = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(float, 0, -1, false, {'FLOAT'}) vim.api.nvim_open_win(float, false, {relative='editor', row=6, col=3, width=12, height=2, border='single'}) local tick = vim.api.nvim_buf_get_changedtick(buffer) _G.CAPTURE_TEST = {buffer=buffer, tick=tick} local answer = require('bugabinga.pivi.bridge').handle {action='capture'} assert(answer.ok, answer.error) assert(tick == vim.api.nvim_buf_get_changedtick(buffer), 'capture modified buffer') return answer.capture ]==] local capture = dofile 'lua/bugabinga/pivi/capture.lua' result = capture.capture( address, result ) assert( vim.wait( 5000, function() return remote [[return #vim.api.nvim_list_uis()]] == 1 end, 10 ) ) assert( remote [[return vim.api.nvim_buf_get_changedtick(CAPTURE_TEST.buffer) == CAPTURE_TEST.tick]] ) assert( result.width == 80 and result.height == 24 ) assert( #result.windows == 3 ) assert( result.coordinate_base == 1 ) assert( result.cursor.row >= 1 and result.cursor.col >= 1 ) local text = {} for _, row in ipairs( result.rows ) do text[#text + 1] = row.text local width = 0 for _, run in ipairs( row.runs ) do assert( run.col == width + 1 ) assert( result.styles[run.style] ) width = width + run.width end assert( width == 80 ) end text = table.concat( text, '\n' ) for _, expected in ipairs( {'alpha * omega', '界é', 'VIRTUAL', 'FLOAT', '┌'} ) do assert( text:find( expected, 1, true ), 'rendered grid missing ' .. expected ) end assert( not text:find( 'SECRET', 1, true ), 'capture leaked concealed source text' ) local styled = false for _, attributes in pairs( result.styles ) do if attributes.foreground == 0x123456 and attributes.background == 0xabcdef and attributes.bold then styled = true end end assert( styled, 'effective virtual text style missing' ) ui( 'nvim_ui_set_option', { 'ext_popupmenu', true, } ) assert( vim.wait( 5000, function() return remote [[return vim.api.nvim_list_uis()[1].ext_popupmenu]] end, 10 ) ) local external = remote [[return require('bugabinga.pivi.capture').info().external]] assert( vim.list_contains( external, 'ext_popupmenu' ) ) ui( 'nvim_ui_detach' ) assert( vim.wait( 5000, function() return remote [[return #vim.api.nvim_list_uis()]] == 0 end, 10 ) ) ui( 'nvim_ui_attach', { 80, 24, { ext_linegrid = true, ext_multigrid = true, }, } ) assert( vim.wait( 5000, function() return remote [[return #vim.api.nvim_list_uis()]] == 1 end, 10 ) ) local composed = remote [[return require('bugabinga.pivi.bridge').handle {action='capture'}]] assert( composed.ok, composed.error ) local found = false for _, row in ipairs( capture.capture( address, composed.capture ).rows ) do if row.text:find( 'FLOAT', 1, true ) then found = true end end assert( found, 'multigrid UI capture lost float composition' ) end, function( problem ) return debug.traceback( vim.inspect( problem ), 2 ) end ) pcall( vim.rpcnotify, channel, 'nvim_command', 'qa!' ) local exited = server:wait( 5000 ) if not ok then io.stderr:write( exited.stderr or '' ) end if not ok then io.stderr:write( tostring( failure ) .. '\n' ); vim.cmd 'cquit 1' end print( 'capture: rendered Unicode, conceal, virtual text, styles, split, float, cursor, external UI, multigrid composition, headless refusal passed' )