local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command local eq = helpers.eq local expect = helpers.expect local eval = helpers.eval local next_msg = helpers.next_msg local feed = helpers.feed local meths = helpers.meths describe('cmdline autocommands', function() local channel before_each(function() clear() channel = meths.get_api_info()[1] meths.set_var("channel",channel) command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)") command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)") command("autocmd CmdWinEnter * call rpcnotify(g:channel, 'CmdWinEnter', v:event)") command("autocmd CmdWinLeave * call rpcnotify(g:channel, 'CmdWinLeave', v:event)") end) it('works', function() feed(':') eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) feed('redraw') eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) feed(':') eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) -- note: feed('bork') might not consume 'bork' -- due to out-of-band interrupt handling feed('bork') eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=true}}}, next_msg()) end) it('can abort cmdline', function() command("autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15") feed(":put! ='ok'") expect([[ ok ]]) feed(":put! ='blah blah'") expect([[ ok ]]) end) it('handles errors correctly', function() clear() local screen = Screen.new(72, 8) screen:attach() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, [4] = {bold = true, reverse = true}, }) command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineLeave * echoerr 'very error'") feed(':') screen:expect([[ | {1:~ }| {1:~ }| {1:~ }| {4: }| : | {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :^ | ]]) feed("put ='lorem ipsum'") screen:expect([[ | {4: }| : | {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | | {3:Press ENTER or type command to continue}^ | ]]) -- cmdline was still executed feed('') screen:expect([[ | ^lorem ipsum | {1:~ }| {1:~ }| {1:~ }| {1:~ }| {1:~ }| | ]]) command("autocmd CmdlineChanged * echoerr 'change erreor'") -- history recall still works feed(":") screen:expect([[ | lorem ipsum | {4: }| : | {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum'^ | ]]) feed("") screen:expect([[ | lorem ipsum | {4: }| : | {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum^' | ]]) -- edit still works feed(".") screen:expect([[ {4: }| : | {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | :put ='lorem ipsum' | {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.^' | ]]) feed('') screen:expect([[ :put ='lorem ipsum' | {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | :put ='lorem ipsum.' | {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | | {3:Press ENTER or type command to continue}^ | ]]) -- cmdline was still executed feed('') screen:expect([[ | lorem ipsum | ^lorem ipsum. | {1:~ }| {1:~ }| {1:~ }| {1:~ }| | ]]) end) it('works with nested cmdline', function() feed(':') eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) feed('=') eq({'notification', 'CmdlineEnter', {{cmdtype='=', cmdlevel=2}}}, next_msg()) feed('') eq({'notification', 'CmdWinEnter', {{}}}, next_msg()) feed(':') eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=3}}}, next_msg()) feed('') eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=3, abort=true}}}, next_msg()) feed('') eq({'notification', 'CmdWinLeave', {{}}}, next_msg()) feed('1+2') eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg()) end) it('no crash with recursive use of v:event #19484', function() command('autocmd CmdlineEnter * normal :') feed(':') eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) feed('') eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) end) it('supports CmdlineChanged' ,function() command("autocmd CmdlineChanged * call rpcnotify(g:channel, 'CmdlineChanged', v:event, getcmdline())") feed(':') eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg()) feed('l') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "l"}}, next_msg()) feed('e') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "le"}}, next_msg()) feed('t') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let"}}, next_msg()) feed('') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let "}}, next_msg()) feed('x') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x"}}, next_msg()) feed('') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x "}}, next_msg()) feed('=') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x ="}}, next_msg()) feed('') eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = "}}, next_msg()) feed('=') eq({'notification', 'CmdlineEnter', {{cmdtype='=', cmdlevel=2}}}, next_msg()) feed('1') eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1"}}, next_msg()) feed('+') eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1+"}}, next_msg()) feed('1') eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1+1"}}, next_msg()) feed('') eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg()) eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = 2"}}, next_msg()) feed('') eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg()) eq(2, eval('x')) end) end)