local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local source = helpers.source local ok = helpers.ok local command = helpers.command describe('external cmdline', function() local screen local last_level = 0 local cmdline = {} local block = nil before_each(function() clear() cmdline, block = {}, nil screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_on_event_handler(function(name, data) if name == "cmdline_show" then local content, pos, firstc, prompt, indent, level = unpack(data) ok(level > 0) cmdline[level] = {content=content, pos=pos, firstc=firstc, prompt=prompt, indent=indent} last_level = level elseif name == "cmdline_hide" then local level = data[1] cmdline[level] = nil elseif name == "cmdline_special_char" then local char, shift, level = unpack(data) cmdline[level].special = {char, shift} elseif name == "cmdline_pos" then local pos, level = unpack(data) cmdline[level].pos = pos elseif name == "cmdline_block_show" then block = data[1] elseif name == "cmdline_block_append" then block[#block+1] = data[1] elseif name == "cmdline_block_hide" then block = nil end end) end) after_each(function() screen:detach() end) local function expect_cmdline(level, expected) local attr_ids = screen._default_attr_ids local attr_ignore = screen._default_attr_ignore local actual = '' for _, chunk in ipairs(cmdline[level] and cmdline[level].content or {}) do local attrs, text = chunk[1], chunk[2] if screen:_equal_attrs(attrs, {}) then actual = actual..text else local attr_id = screen:_get_attr_id(attr_ids, attr_ignore, attrs) actual = actual..'{' .. attr_id .. ':' .. text .. '}' end end eq(expected, actual) end it('works', function() feed(':') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq(1, last_level) eq({{ content = { { {}, "" } }, firstc = ":", indent = 0, pos = 0, prompt = "" }}, cmdline) end) feed('sign') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "sign" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) feed('') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "sign" } }, firstc = ":", indent = 0, pos = 3, prompt = "" }}, cmdline) end) feed('') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "sin" } }, firstc = ":", indent = 0, pos = 2, prompt = "" }}, cmdline) end) feed('') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({}, cmdline) end) end) it("works with input()", function() feed(':call input("input", "default")') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "default" } }, firstc = "", indent = 0, pos = 7, prompt = "input" }}, cmdline) end) feed('') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({}, cmdline) end) end) it("works with special chars and nested cmdline", function() feed(':xx') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "xx" } }, firstc = ":", indent = 0, pos = 2, prompt = "", special = {'"', true}, }}, cmdline) end) feed('=') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "xx" } }, firstc = ":", indent = 0, pos = 2, prompt = "", special = {'"', true}, },{ content = { { {}, "" } }, firstc = "=", indent = 0, pos = 0, prompt = "", }}, cmdline) end) feed('1+2') local expectation = {{ content = { { {}, "xx" } }, firstc = ":", indent = 0, pos = 2, prompt = "", special = {'"', true}, },{ content = { { {}, "1+2" } }, firstc = "=", indent = 0, pos = 3, prompt = "", }} screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq(expectation, cmdline) end) -- erase information, so we check if it is retransmitted cmdline = {} command("redraw!") -- redraw! forgets cursor position. Be OK with that, as UI should indicate -- focus is at external cmdline anyway. screen:expect([[ | ~ | ~ | ~ | ^ | ]], nil, nil, function() eq(expectation, cmdline) end) feed('') screen:expect([[ | ~ | ~ | ~ | ^ | ]], nil, nil, function() eq({{ content = { { {}, "xx3" } }, firstc = ":", indent = 0, pos = 3, prompt = "", }}, cmdline) end) feed('') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({}, cmdline) end) end) it("works with function definitions", function() feed(':function Foo()') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "" } }, firstc = ":", indent = 2, pos = 0, prompt = "", }}, cmdline) eq({{{{}, 'function Foo()'}}}, block) end) feed('line1') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{{{}, 'function Foo()'}}, {{{}, ' line1'}}}, block) end) block = {} command("redraw!") screen:expect([[ | ~ | ~ | ~ | ^ | ]], nil, nil, function() eq({{{{}, 'function Foo()'}}, {{{}, ' line1'}}}, block) end) feed('endfunction') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq(nil, block) end) end) it("works with cmdline window", function() feed(':make') screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "make" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) feed('') screen:expect([[ | [No Name] | :make^ | [Command Line] | | ]], nil, nil, function() eq({}, cmdline) end) -- nested cmdline feed(':yank') screen:expect([[ | [No Name] | :make^ | [Command Line] | | ]], nil, nil, function() eq({nil, { content = { { {}, "yank" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) cmdline = {} command("redraw!") screen:expect([[ | [No Name] | :make | [Command Line] | ^ | ]], nil, nil, function() eq({nil, { content = { { {}, "yank" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) feed("") screen:expect([[ | [No Name] | :make^ | [Command Line] | | ]], nil, nil, function() eq({}, cmdline) end) feed("") screen:expect([[ | [No Name] | :make^ | [Command Line] | | ]], nil, nil, function() eq({{ content = { { {}, "make" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) cmdline = {} command("redraw!") screen:expect([[ | ~ | ~ | ~ | ^ | ]], nil, nil, function() eq({{ content = { { {}, "make" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) end) it('works with inputsecret()', function() feed(":call inputsecret('secret:')abc123") screen:expect([[ ^ | ~ | ~ | ~ | | ]], nil, nil, function() eq({{ content = { { {}, "******" } }, firstc = "", indent = 0, pos = 6, prompt = "secret:" }}, cmdline) end) end) it('works with highlighted cmdline', function() source([[ highlight RBP1 guibg=Red highlight RBP2 guibg=Yellow highlight RBP3 guibg=Green highlight RBP4 guibg=Blue let g:NUM_LVLS = 4 function RainBowParens(cmdline) let ret = [] let i = 0 let lvl = 0 while i < len(a:cmdline) if a:cmdline[i] is# '(' call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) let lvl += 1 elseif a:cmdline[i] is# ')' let lvl -= 1 call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) endif let i += 1 endwhile return ret endfunction map :let x = input({'prompt':'>','highlight':'RainBowParens'}) "map :let x = input({'prompt':'>'}) ]]) screen:set_default_attr_ids({ RBP1={background = Screen.colors.Red}, RBP2={background = Screen.colors.Yellow}, RBP3={background = Screen.colors.Green}, RBP4={background = Screen.colors.Blue}, EOB={bold = true, foreground = Screen.colors.Blue1}, ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red}, SK={foreground = Screen.colors.Blue}, PE={bold = true, foreground = Screen.colors.SeaGreen4} }) feed('(a(b)a)') screen:expect([[ ^ | {EOB:~ }| {EOB:~ }| {EOB:~ }| | ]], nil, nil, function() expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') end) end) end)