Merge pull request #7946 from bfredl/vim-8.0.1445

implement CmdlineChanged: vim-patch:8.0.1445 + nvim specific v:event stuff
This commit is contained in:
Björn Linse 2018-12-12 21:40:10 +01:00 committed by GitHub
commit 2f3a18695e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 155 additions and 4 deletions

View File

@ -521,10 +521,11 @@ CmdUndefined When a user command is used but it isn't
command is defined. An alternative is to command is defined. An alternative is to
always define the user command and have it always define the user command and have it
invoke an autoloaded function. See |autoload|. invoke an autoloaded function. See |autoload|.
*CmdlineChanged* *CmdlineChanged*
CmdlineChanged After a change was made to the text in the CmdlineChanged After a change was made to the text inside
command line. Be careful not to mess up command line. Be careful not to mess up the
the command line, it may cause Vim to lock up. command line, it may cause Vim to lock up.
<afile> is set to the |cmdline-char|.
*CmdlineEnter* *CmdlineEnter*
CmdlineEnter After entering the command-line (including CmdlineEnter After entering the command-line (including
non-interactive use of ":" in a mapping: use non-interactive use of ":" in a mapping: use

View File

@ -21,6 +21,7 @@ return {
'BufWritePre', -- before writing a buffer 'BufWritePre', -- before writing a buffer
'ChanInfo', -- info was received about channel 'ChanInfo', -- info was received about channel
'ChanOpen', -- channel was opened 'ChanOpen', -- channel was opened
'CmdLineChanged', -- command line was modified
'CmdLineEnter', -- after entering cmdline mode 'CmdLineEnter', -- after entering cmdline mode
'CmdLineLeave', -- before leaving cmdline mode 'CmdLineLeave', -- before leaving cmdline mode
'CmdUndefined', -- command undefined 'CmdUndefined', -- command undefined

View File

@ -1804,6 +1804,37 @@ static int empty_pattern(char_u *p)
static int command_line_changed(CommandLineState *s) static int command_line_changed(CommandLineState *s)
{ {
// Trigger CmdlineChanged autocommands.
if (has_event(EVENT_CMDLINECHANGED)) {
TryState tstate;
Error err = ERROR_INIT;
bool tl_ret = true;
dict_T *dict = get_vim_var_dict(VV_EVENT);
char firstcbuf[2];
firstcbuf[0] = s->firstc > 0 ? s->firstc : '-';
firstcbuf[1] = 0;
// set v:event to a dictionary with information about the commandline
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
tv_dict_set_keys_readonly(dict);
try_enter(&tstate);
apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf,
(char_u *)firstcbuf, false, curbuf);
tv_dict_clear(dict);
tl_ret = try_leave(&tstate, &err);
if (!tl_ret && ERROR_SET(&err)) {
msg_putchar('\n');
msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg);
api_clear_error(&err);
redrawcmd();
}
tl_ret = true;
}
// 'incsearch' highlighting. // 'incsearch' highlighting.
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) { if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
pos_T end_pos; pos_T end_pos;

View File

@ -818,6 +818,18 @@ func Test_QuitPre()
endfunc endfunc
func Test_Cmdline() func Test_Cmdline()
au! CmdlineChanged : let g:text = getcmdline()
let g:text = 0
call feedkeys(":echom 'hello'\<CR>", 'xt')
call assert_equal("echom 'hello'", g:text)
au! CmdlineChanged
au! CmdlineChanged : let g:entered = expand('<afile>')
let g:entered = 0
call feedkeys(":echom 'hello'\<CR>", 'xt')
call assert_equal(':', g:entered)
au! CmdlineChanged
au! CmdlineEnter : let g:entered = expand('<afile>') au! CmdlineEnter : let g:entered = expand('<afile>')
au! CmdlineLeave : let g:left = expand('<afile>') au! CmdlineLeave : let g:left = expand('<afile>')
let g:entered = 0 let g:entered = 0

View File

@ -5,6 +5,7 @@ local clear = helpers.clear
local command = helpers.command local command = helpers.command
local eq = helpers.eq local eq = helpers.eq
local expect = helpers.expect local expect = helpers.expect
local eval = helpers.eval
local next_msg = helpers.next_msg local next_msg = helpers.next_msg
local feed = helpers.feed local feed = helpers.feed
local meths = helpers.meths local meths = helpers.meths
@ -63,6 +64,7 @@ describe('cmdline autocommands', function()
}) })
command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineEnter * echoerr 'FAIL'")
command("autocmd CmdlineLeave * echoerr 'very error'") command("autocmd CmdlineLeave * echoerr 'very error'")
feed(':') feed(':')
screen:expect([[ screen:expect([[
| |
@ -74,6 +76,7 @@ describe('cmdline autocommands', function()
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} | {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
:^ | :^ |
]]) ]])
feed("put ='lorem ipsum'<cr>") feed("put ='lorem ipsum'<cr>")
screen:expect([[ screen:expect([[
| |
@ -86,6 +89,7 @@ describe('cmdline autocommands', function()
{3:Press ENTER or type command to continue}^ | {3:Press ENTER or type command to continue}^ |
]]) ]])
-- cmdline was still executed
feed('<cr>') feed('<cr>')
screen:expect([[ screen:expect([[
| |
@ -97,6 +101,71 @@ describe('cmdline autocommands', function()
{1:~ }| {1:~ }|
| |
]]) ]])
command("autocmd CmdlineChanged * echoerr 'change erreor'")
-- history recall still works
feed(":<c-p>")
screen:expect([[
|
lorem ipsum |
{4: }|
: |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
:put ='lorem ipsum'^ |
]])
feed("<left>")
screen:expect([[
|
lorem ipsum |
{4: }|
: |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
:put ='lorem ipsum^' |
]])
-- edit still works
feed(".")
screen:expect([[
{4: }|
: |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
:put ='lorem ipsum.^' |
]])
feed('<cr>')
screen:expect([[
:put ='lorem ipsum' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):very error} |
|
{3:Press ENTER or type command to continue}^ |
]])
-- cmdline was still executed
feed('<cr>')
screen:expect([[
|
lorem ipsum |
^lorem ipsum. |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]])
end) end)
it('works with nested cmdline', function() it('works with nested cmdline', function()
@ -115,4 +184,41 @@ describe('cmdline autocommands', function()
feed('1+2<cr>') feed('1+2<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg()) eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg())
end) 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('<space>')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let "}}, next_msg())
feed('x')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x"}}, next_msg())
feed('<space>')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x "}}, next_msg())
feed('=')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x ="}}, next_msg())
feed('<space>')
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = "}}, next_msg())
feed('<c-r>=')
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('<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg())
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = "}}, next_msg())
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = 2"}}, next_msg())
feed('<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg())
eq(2, eval('x'))
end)
end) end)