cmdline_spec.lua (10443B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local clear = n.clear 6 local command = n.command 7 local eq = t.eq 8 local expect = n.expect 9 local eval = n.eval 10 local next_msg = n.next_msg 11 local feed = n.feed 12 local api = n.api 13 14 describe('cmdline autocommands', function() 15 local channel 16 before_each(function() 17 clear() 18 channel = api.nvim_get_chan_info(0).id 19 api.nvim_set_var('channel', channel) 20 command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)") 21 command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)") 22 command("autocmd CmdwinEnter * call rpcnotify(g:channel, 'CmdwinEnter', v:event)") 23 command("autocmd CmdwinLeave * call rpcnotify(g:channel, 'CmdwinLeave', v:event)") 24 end) 25 26 it('works', function() 27 feed(':') 28 eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg()) 29 feed('redraw<cr>') 30 eq( 31 { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } }, 32 next_msg() 33 ) 34 35 feed(':') 36 eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg()) 37 38 -- note: feed('bork<c-c>') might not consume 'bork' 39 -- due to out-of-band interrupt handling 40 feed('bork<esc>') 41 eq( 42 { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = true } } }, 43 next_msg() 44 ) 45 end) 46 47 it('can abort cmdline', function() 48 command('autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15') 49 feed(":put! ='ok'<cr>") 50 expect([[ 51 ok 52 ]]) 53 54 feed(":put! ='blah blah'<cr>") 55 expect([[ 56 ok 57 ]]) 58 end) 59 60 it('handles errors correctly', function() 61 clear() 62 local screen = Screen.new(72, 8) 63 command("autocmd CmdlineEnter * echoerr 'FAIL'") 64 command("autocmd CmdlineLeave * echoerr 'very error'") 65 66 feed(':') 67 screen:expect([[ 68 | 69 {1:~ }|*3 70 {3: }| 71 : | 72 {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | 73 :^ | 74 ]]) 75 76 feed("put ='lorem ipsum'<cr>") 77 screen:expect([[ 78 | 79 {3: }| 80 : | 81 {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | 82 :put ='lorem ipsum' | 83 {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | 84 | 85 {6:Press ENTER or type command to continue}^ | 86 ]]) 87 88 -- cmdline was still executed 89 feed('<cr>') 90 screen:expect([[ 91 | 92 ^lorem ipsum | 93 {1:~ }|*5 94 | 95 ]]) 96 97 command("autocmd CmdlineChanged * echoerr 'change erreor'") 98 99 -- history recall still works 100 feed(':<c-p>') 101 screen:expect([[ 102 | 103 lorem ipsum | 104 {3: }| 105 : | 106 {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | 107 :put ='lorem ipsum' | 108 {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | 109 :put ='lorem ipsum'^ | 110 ]]) 111 112 feed('<left>') 113 screen:expect([[ 114 | 115 lorem ipsum | 116 {3: }| 117 : | 118 {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | 119 :put ='lorem ipsum' | 120 {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | 121 :put ='lorem ipsum^' | 122 ]]) 123 124 -- edit still works 125 feed('.') 126 screen:expect([[ 127 {3: }| 128 : | 129 {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} | 130 :put ='lorem ipsum' | 131 {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | 132 :put ='lorem ipsum.' | 133 {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | 134 :put ='lorem ipsum.^' | 135 ]]) 136 137 feed('<cr>') 138 screen:expect([[ 139 :put ='lorem ipsum' | 140 {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | 141 :put ='lorem ipsum.' | 142 {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} | 143 :put ='lorem ipsum.' | 144 {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} | 145 | 146 {6:Press ENTER or type command to continue}^ | 147 ]]) 148 149 -- cmdline was still executed 150 feed('<cr>') 151 screen:expect([[ 152 | 153 lorem ipsum | 154 ^lorem ipsum. | 155 {1:~ }|*4 156 | 157 ]]) 158 end) 159 160 it('works with nested cmdline', function() 161 feed(':') 162 eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg()) 163 feed('<c-r>=') 164 eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg()) 165 feed('<c-f>') 166 eq({ 'notification', 'CmdwinEnter', { {} } }, next_msg()) 167 feed(':') 168 eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 3 } } }, next_msg()) 169 feed('<c-c>') 170 eq( 171 { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 3, abort = true } } }, 172 next_msg() 173 ) 174 feed('<c-c>') 175 eq({ 'notification', 'CmdwinLeave', { {} } }, next_msg()) 176 feed('1+2<cr>') 177 eq( 178 { 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } }, 179 next_msg() 180 ) 181 end) 182 183 it('no crash with recursive use of v:event #19484', function() 184 command('autocmd CmdlineEnter * normal :') 185 feed(':') 186 eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg()) 187 feed('<CR>') 188 eq( 189 { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } }, 190 next_msg() 191 ) 192 end) 193 194 it('supports CmdlineChanged', function() 195 command( 196 "autocmd CmdlineChanged * call rpcnotify(g:channel, 'CmdlineChanged', v:event, getcmdline())" 197 ) 198 feed(':') 199 eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg()) 200 feed('l') 201 eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'l' } }, next_msg()) 202 feed('e') 203 eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'le' } }, next_msg()) 204 feed('t') 205 eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let' } }, next_msg()) 206 feed('<space>') 207 eq( 208 { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let ' } }, 209 next_msg() 210 ) 211 feed('x') 212 eq( 213 { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x' } }, 214 next_msg() 215 ) 216 feed('<space>') 217 eq( 218 { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x ' } }, 219 next_msg() 220 ) 221 feed('=') 222 eq( 223 { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x =' } }, 224 next_msg() 225 ) 226 feed('<space>') 227 eq( 228 { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x = ' } }, 229 next_msg() 230 ) 231 feed('<c-r>=') 232 eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg()) 233 feed('1') 234 eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1' } }, next_msg()) 235 feed('+') 236 eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1+' } }, next_msg()) 237 feed('1') 238 eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1+1' } }, next_msg()) 239 feed('<cr>') 240 eq( 241 { 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } }, 242 next_msg() 243 ) 244 eq( 245 { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x = 2' } }, 246 next_msg() 247 ) 248 feed('<cr>') 249 eq( 250 { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } }, 251 next_msg() 252 ) 253 eq(2, eval('x')) 254 end) 255 end)