local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local thelpers = require('test.functional.terminal.helpers') local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim local testprg, command = helpers.testprg, helpers.command local nvim_prog_abs = helpers.nvim_prog_abs local eq, eval = helpers.eq, helpers.eval local funcs = helpers.funcs local nvim_set = helpers.nvim_set local is_os = helpers.is_os local skip = helpers.skip describe(':terminal highlight', function() local screen before_each(function() clear() screen = Screen.new(50, 7) screen:set_default_attr_ids({ [1] = {foreground = 45}, [2] = {background = 46}, [3] = {foreground = 45, background = 46}, [4] = {bold = true, italic = true, underline = true, strikethrough = true}, [5] = {bold = true}, [6] = {foreground = 12}, [7] = {bold = true, reverse = true}, [8] = {background = 11}, [9] = {foreground = 130}, [10] = {reverse = true}, [11] = {background = 11}, [12] = {bold = true, underdouble = true}, [13] = {italic = true, undercurl = true}, }) screen:attach({rgb=false}) command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) feed('i') screen:expect([[ tty ready | {10: } | | | | | {5:-- TERMINAL --} | ]]) end) local function descr(title, attr_num, set_attrs_fn) local function sub(s) local str = s:gsub('NUM', attr_num) return str end describe(title, function() before_each(function() set_attrs_fn() thelpers.feed_data('text') thelpers.clear_attrs() thelpers.feed_data('text') end) local function pass_attrs() skip(is_os('win')) screen:expect(sub([[ tty ready | {NUM:text}text{10: } | | | | | {5:-- TERMINAL --} | ]])) end it('will pass the corresponding attributes', pass_attrs) it('will pass the corresponding attributes on scrollback', function() skip(is_os('win')) pass_attrs() local lines = {} for i = 1, 8 do table.insert(lines, 'line'..tostring(i)) end table.insert(lines, '') thelpers.feed_data(lines) screen:expect([[ line4 | line5 | line6 | line7 | line8 | {10: } | {5:-- TERMINAL --} | ]]) feed('gg') screen:expect(sub([[ ^tty ready | {NUM:text}textline1 | line2 | line3 | line4 | line5 | | ]])) end) end) end descr('foreground', 1, function() thelpers.set_fg(45) end) descr('background', 2, function() thelpers.set_bg(46) end) descr('foreground and background', 3, function() thelpers.set_fg(45) thelpers.set_bg(46) end) descr('bold, italics, underline and strikethrough', 4, function() thelpers.set_bold() thelpers.set_italic() thelpers.set_underline() thelpers.set_strikethrough() end) descr('bold and underdouble', 12, function() thelpers.set_bold() thelpers.set_underdouble() end) descr('italics and undercurl', 13, function() thelpers.set_italic() thelpers.set_undercurl() end) end) it(':terminal highlight has lower precedence than editor #9964', function() clear() local screen = Screen.new(30, 4) screen:set_default_attr_ids({ -- "Normal" highlight emitted by the child nvim process. N_child = {foreground = tonumber('0x4040ff'), background = tonumber('0xffff40'), fg_indexed=true, bg_indexed=true}, -- "Search" highlight in the parent nvim process. S = {background = Screen.colors.Green, italic = true, foreground = Screen.colors.Red}, -- "Question" highlight in the parent nvim process. -- note: bg is indexed as it comes from the (cterm) child, while fg isn't as it comes from (rgb) parent Q = {background = tonumber('0xffff40'), bold = true, foreground = Screen.colors.SeaGreen4, bg_indexed=true}, }) screen:attach({rgb=true}) -- Child nvim process in :terminal (with cterm colors). funcs.termopen({ nvim_prog_abs(), '-n', '-u', 'NORC', '-i', 'NONE', '--cmd', nvim_set, '+hi Normal ctermfg=Blue ctermbg=Yellow', '+norm! ichild nvim', '+norm! oline 2', }) screen:expect([[ {N_child:^child nvim }| {N_child:line 2 }| {N_child: }| | ]]) command('hi Search gui=italic guifg=Red guibg=Green cterm=italic ctermfg=Red ctermbg=Green') feed('/nvim') screen:expect([[ {N_child:child }{S:^nvim}{N_child: }| {N_child:line 2 }| {N_child: }| /nvim | ]]) command('syntax keyword Question line') screen:expect([[ {N_child:child }{S:^nvim}{N_child: }| {Q:line}{N_child: 2 }| {N_child: }| /nvim | ]]) end) describe(':terminal highlight forwarding', function() local screen before_each(function() clear() screen = Screen.new(50, 7) screen:set_rgb_cterm(true) screen:set_default_attr_ids({ [1] = {{reverse = true}, {reverse = true}}, [2] = {{bold = true}, {bold = true}}, [3] = {{fg_indexed = true, foreground = tonumber('0xe0e000')}, {foreground = 3}}, [4] = {{foreground = tonumber('0xff8000')}, {}}, }) screen:attach() command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) feed('i') screen:expect([[ tty ready | {1: } | | | | | {2:-- TERMINAL --} | ]]) end) it('will handle cterm and rgb attributes', function() skip(is_os('win')) thelpers.set_fg(3) thelpers.feed_data('text') thelpers.feed_termcode('[38:2:255:128:0m') thelpers.feed_data('color') thelpers.clear_attrs() thelpers.feed_data('text') screen:expect{grid=[[ tty ready | {3:text}{4:color}text{1: } | | | | | {2:-- TERMINAL --} | ]]} end) end) describe(':terminal highlight with custom palette', function() local screen before_each(function() clear() screen = Screen.new(50, 7) screen:set_default_attr_ids({ [1] = {foreground = tonumber('0x123456')}, -- no fg_indexed when overridden [2] = {foreground = 12}, [3] = {bold = true, reverse = true}, [5] = {background = 11}, [6] = {foreground = 130}, [7] = {reverse = true}, [8] = {background = 11}, [9] = {bold = true}, }) screen:attach({rgb=true}) nvim('set_var', 'terminal_color_3', '#123456') command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) feed('i') screen:expect([[ tty ready | {7: } | | | | | {9:-- TERMINAL --} | ]]) end) it('will use the custom color', function() skip(is_os('win')) thelpers.set_fg(3) thelpers.feed_data('text') thelpers.clear_attrs() thelpers.feed_data('text') screen:expect([[ tty ready | {1:text}text{7: } | | | | | {9:-- TERMINAL --} | ]]) end) end) describe('synIDattr()', function() local screen before_each(function() clear() screen = Screen.new(50, 7) command('highlight Normal ctermfg=252 guifg=#ff0000 guibg=Black') -- Salmon #fa8072 Maroon #800000 command('highlight Keyword ctermfg=79 guifg=Salmon guisp=Maroon cterm=strikethrough gui=strikethrough') end) it('returns cterm-color if RGB-capable UI is _not_ attached', function() eq('252', eval('synIDattr(hlID("Normal"), "fg")')) eq('252', eval('synIDattr(hlID("Normal"), "fg#")')) eq('', eval('synIDattr(hlID("Normal"), "bg")')) eq('', eval('synIDattr(hlID("Normal"), "bg#")')) eq('79', eval('synIDattr(hlID("Keyword"), "fg")')) eq('79', eval('synIDattr(hlID("Keyword"), "fg#")')) eq('', eval('synIDattr(hlID("Keyword"), "sp")')) eq('', eval('synIDattr(hlID("Keyword"), "sp#")')) end) it('returns gui-color if "gui" arg is passed', function() eq('Black', eval('synIDattr(hlID("Normal"), "bg", "gui")')) eq('Maroon', eval('synIDattr(hlID("Keyword"), "sp", "gui")')) end) it('returns gui-color if RGB-capable UI is attached', function() screen:attach({rgb=true}) eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")')) eq('Black', eval('synIDattr(hlID("Normal"), "bg")')) eq('Salmon', eval('synIDattr(hlID("Keyword"), "fg")')) eq('Maroon', eval('synIDattr(hlID("Keyword"), "sp")')) end) it('returns #RRGGBB value for fg#/bg#/sp#', function() screen:attach({rgb=true}) eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg#")')) eq('#000000', eval('synIDattr(hlID("Normal"), "bg#")')) eq('#fa8072', eval('synIDattr(hlID("Keyword"), "fg#")')) eq('#800000', eval('synIDattr(hlID("Keyword"), "sp#")')) end) it('returns color number if non-GUI', function() screen:attach({rgb=false}) eq('252', eval('synIDattr(hlID("Normal"), "fg")')) eq('79', eval('synIDattr(hlID("Keyword"), "fg")')) end) it('returns "1" if group has given highlight attribute', function() local hl_attrs = { 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed', 'strikethrough' } for _,hl_attr in ipairs(hl_attrs) do local context = 'using ' .. hl_attr .. ' attr' command('highlight Keyword cterm=' .. hl_attr .. ' gui=' .. hl_attr) eq('', eval('synIDattr(hlID("Normal"), "'.. hl_attr .. '")'), context) eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '")'), context) eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '", "gui")'), context) end end) end) describe('fg/bg special colors', function() local screen before_each(function() clear() screen = Screen.new(50, 7) command('highlight Normal ctermfg=145 ctermbg=16 guifg=#ff0000 guibg=Black') command('highlight Visual ctermfg=bg ctermbg=fg guifg=bg guibg=fg guisp=bg') end) it('resolve to "Normal" values', function() eq(eval('synIDattr(hlID("Normal"), "bg")'), eval('synIDattr(hlID("Visual"), "fg")')) eq(eval('synIDattr(hlID("Normal"), "bg#")'), eval('synIDattr(hlID("Visual"), "fg#")')) eq(eval('synIDattr(hlID("Normal"), "fg")'), eval('synIDattr(hlID("Visual"), "bg")')) eq(eval('synIDattr(hlID("Normal"), "fg#")'), eval('synIDattr(hlID("Visual"), "bg#")')) eq('bg', eval('synIDattr(hlID("Visual"), "fg", "gui")')) eq('bg', eval('synIDattr(hlID("Visual"), "fg#", "gui")')) eq('fg', eval('synIDattr(hlID("Visual"), "bg", "gui")')) eq('fg', eval('synIDattr(hlID("Visual"), "bg#", "gui")')) eq('bg', eval('synIDattr(hlID("Visual"), "sp", "gui")')) eq('bg', eval('synIDattr(hlID("Visual"), "sp#", "gui")')) end) it('resolve to "Normal" values in RGB-capable UI', function() screen:attach({rgb=true}) eq('bg', eval('synIDattr(hlID("Visual"), "fg")')) eq(eval('synIDattr(hlID("Normal"), "bg#")'), eval('synIDattr(hlID("Visual"), "fg#")')) eq('fg', eval('synIDattr(hlID("Visual"), "bg")')) eq(eval('synIDattr(hlID("Normal"), "fg#")'), eval('synIDattr(hlID("Visual"), "bg#")')) eq('bg', eval('synIDattr(hlID("Visual"), "sp")')) eq(eval('synIDattr(hlID("Normal"), "bg#")'), eval('synIDattr(hlID("Visual"), "sp#")')) end) it('resolve after the "Normal" group is modified', function() screen:attach({rgb=true}) local new_guibg = '#282c34' local new_guifg = '#abb2bf' command('highlight Normal guifg='..new_guifg..' guibg='..new_guibg) eq(new_guibg, eval('synIDattr(hlID("Visual"), "fg#")')) eq(new_guifg, eval('synIDattr(hlID("Visual"), "bg#")')) eq(new_guibg, eval('synIDattr(hlID("Visual"), "sp#")')) end) end)