diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2018-12-12 21:40:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-12 21:40:10 +0100 |
commit | 2f3a18695e41ec6afa98194b22d064ec81154dbf (patch) | |
tree | 936600d127e522fef943cdf44090dd76581a8ab2 | |
parent | b9a441eb78349088d54eaa6e12c35aa06f0b1c6b (diff) | |
parent | 5f82889be78856ee189c254110bf087dba918b23 (diff) | |
download | rneovim-2f3a18695e41ec6afa98194b22d064ec81154dbf.tar.gz rneovim-2f3a18695e41ec6afa98194b22d064ec81154dbf.tar.bz2 rneovim-2f3a18695e41ec6afa98194b22d064ec81154dbf.zip |
Merge pull request #7946 from bfredl/vim-8.0.1445
implement CmdlineChanged: vim-patch:8.0.1445 + nvim specific v:event stuff
-rw-r--r-- | runtime/doc/autocmd.txt | 9 | ||||
-rw-r--r-- | src/nvim/auevents.lua | 1 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 31 | ||||
-rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 12 | ||||
-rw-r--r-- | test/functional/autocmd/cmdline_spec.lua | 106 |
5 files changed, 155 insertions, 4 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index c34dbaaf60..d7b74f99c2 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -521,10 +521,11 @@ CmdUndefined When a user command is used but it isn't command is defined. An alternative is to always define the user command and have it invoke an autoloaded function. See |autoload|. - *CmdlineChanged* -CmdlineChanged After a change was made to the text in the - command line. Be careful not to mess up - the command line, it may cause Vim to lock up. + *CmdlineChanged* +CmdlineChanged After a change was made to the text inside + command line. Be careful not to mess up the + command line, it may cause Vim to lock up. + <afile> is set to the |cmdline-char|. *CmdlineEnter* CmdlineEnter After entering the command-line (including non-interactive use of ":" in a mapping: use diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index ab92e84799..3cffd66dee 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -21,6 +21,7 @@ return { 'BufWritePre', -- before writing a buffer 'ChanInfo', -- info was received about channel 'ChanOpen', -- channel was opened + 'CmdLineChanged', -- command line was modified 'CmdLineEnter', -- after entering cmdline mode 'CmdLineLeave', -- before leaving cmdline mode 'CmdUndefined', -- command undefined diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 19a52c913a..bfc32887ca 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1804,6 +1804,37 @@ static int empty_pattern(char_u *p) 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. if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) { pos_T end_pos; diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 9e8d2081c8..5deb789f48 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -818,6 +818,18 @@ func Test_QuitPre() endfunc 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! CmdlineLeave : let g:left = expand('<afile>') let g:entered = 0 diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua index 3f0504d02f..51b7b819e9 100644 --- a/test/functional/autocmd/cmdline_spec.lua +++ b/test/functional/autocmd/cmdline_spec.lua @@ -5,6 +5,7 @@ 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 @@ -63,6 +64,7 @@ describe('cmdline autocommands', function() }) command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineLeave * echoerr 'very error'") + feed(':') screen:expect([[ | @@ -74,6 +76,7 @@ describe('cmdline autocommands', function() {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} | :^ | ]]) + feed("put ='lorem ipsum'<cr>") screen:expect([[ | @@ -86,6 +89,7 @@ describe('cmdline autocommands', function() {3:Press ENTER or type command to continue}^ | ]]) + -- cmdline was still executed feed('<cr>') screen:expect([[ | @@ -97,6 +101,71 @@ describe('cmdline autocommands', function() {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) it('works with nested cmdline', function() @@ -115,4 +184,41 @@ describe('cmdline autocommands', function() feed('1+2<cr>') eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, 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('<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) |