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 local wild_items = nil local wild_selected = nil before_each(function() clear() cmdline, block = {}, nil screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {reverse = true}, [3] = {bold = true, reverse = 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 elseif name == "wildmenu_show" then wild_items = data[1] elseif name == "wildmenu_select" then wild_selected = data[1] elseif name == "wildmenu_hide" then wild_items, wild_selected = nil, 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([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq(1, last_level) eq({{ content = { { {}, "" } }, firstc = ":", indent = 0, pos = 0, prompt = "" }}, cmdline) end) feed('sign') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign" } }, firstc = ":", indent = 0, pos = 3, prompt = "" }}, cmdline) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sin" } }, firstc = ":", indent = 0, pos = 2, prompt = "" }}, cmdline) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({}, cmdline) end) end) it("works with input()", function() feed(':call input("input", "default")') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "default" } }, firstc = "", indent = 0, pos = 7, prompt = "input" }}, cmdline) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({}, cmdline) end) end) it("works with special chars and nested cmdline", function() feed(':xx') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "xx" } }, firstc = ":", indent = 0, pos = 2, prompt = "", special = {'"', true}, }}, cmdline) end) feed('=') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], 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([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], 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([[ | {1:~ }| {1:~ }| {1:~ }| ^ | ]], nil, nil, function() eq(expectation, cmdline) end) feed('') screen:expect([[ | {1:~ }| {1:~ }| {1:~ }| ^ | ]], nil, nil, function() eq({{ content = { { {}, "xx3" } }, firstc = ":", indent = 0, pos = 3, prompt = "", }}, cmdline) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({}, cmdline) end) end) it("works with function definitions", function() feed(':function Foo()') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "" } }, firstc = ":", indent = 2, pos = 0, prompt = "", }}, cmdline) eq({ { { {}, 'function Foo()'} } }, block) end) feed('line1') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({ { { {}, 'function Foo()'} }, { { {}, ' line1'} } }, block) end) block = {} command("redraw!") screen:expect([[ | {1:~ }| {1:~ }| {1:~ }| ^ | ]], nil, nil, function() eq({ { { {}, 'function Foo()'} }, { { {}, ' line1'} } }, block) end) feed('endfunction') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq(nil, block) end) end) it("works with cmdline window", function() feed(':make') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "make" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) feed('') screen:expect([[ | {2:[No Name] }| {1::}make^ | {3:[Command Line] }| | ]], nil, nil, function() eq({}, cmdline) end) -- nested cmdline feed(':yank') screen:expect([[ | {2:[No Name] }| {1::}make^ | {3:[Command Line] }| | ]], nil, nil, function() eq({nil, { content = { { {}, "yank" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) cmdline = {} command("redraw!") screen:expect([[ | {2:[No Name] }| {1::}make | {3:[Command Line] }| ^ | ]], nil, nil, function() eq({nil, { content = { { {}, "yank" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) feed("") screen:expect([[ | {2:[No Name] }| {1::}make^ | {3:[Command Line] }| | ]], nil, nil, function() eq({}, cmdline) end) feed("") screen:expect([[ | {2:[No Name] }| {1::}make^ | {3:[Command Line] }| | ]], nil, nil, function() eq({{ content = { { {}, "make" } }, firstc = ":", indent = 0, pos = 4, prompt = "" }}, cmdline) end) cmdline = {} command("redraw!") screen:expect([[ | {1:~ }| {1:~ }| {1:~ }| ^ | ]], 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([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], 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) it('works together with ext_wildmenu', function() local expected = { 'define', 'jump', 'list', 'place', 'undefine', 'unplace', } command('set wildmode=full') command('set wildmenu') screen:set_option('ext_wildmenu', true) feed(':sign ') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign define"} }, firstc = ":", indent = 0, pos = 11, prompt = "" }}, cmdline) eq(expected, wild_items) eq(0, wild_selected) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign jump"} }, firstc = ":", indent = 0, pos = 9, prompt = "" }}, cmdline) eq(expected, wild_items) eq(1, wild_selected) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign "} }, firstc = ":", indent = 0, pos = 5, prompt = "" }}, cmdline) eq(expected, wild_items) eq(-1, wild_selected) end) feed('') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign define"} }, firstc = ":", indent = 0, pos = 11, prompt = "" }}, cmdline) eq(expected, wild_items) eq(0, wild_selected) end) feed('a') screen:expect([[ ^ | {1:~ }| {1:~ }| {1:~ }| | ]], nil, nil, function() eq({{ content = { { {}, "sign definea"} }, firstc = ":", indent = 0, pos = 12, prompt = "" }}, cmdline) eq(nil, wild_items) eq(nil, wild_selected) end) end) end)