mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
vim-patch:9.1.1571: CmdlineChanged triggered to often
Problem: The CmdlineChanged event was firing unnecessarily, even when
the command line's content hadn't actually changed.
Solution: I've added a check to compare the command-line buffer's state
before and after key processing. The `CmdlineChanged` event
now only triggers if the buffer's contents are genuinely
different (Girish Palya).
closes: vim/vim#17803
239c4e4abe
Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
@@ -134,6 +134,7 @@ typedef struct {
|
|||||||
int save_msg_scroll;
|
int save_msg_scroll;
|
||||||
int save_State; // remember State when called
|
int save_State; // remember State when called
|
||||||
int prev_cmdpos;
|
int prev_cmdpos;
|
||||||
|
char *prev_cmdbuff;
|
||||||
char *save_p_icm;
|
char *save_p_icm;
|
||||||
bool some_key_typed; // one of the keys was typed
|
bool some_key_typed; // one of the keys was typed
|
||||||
// mouse drag and release events are ignored, unless they are
|
// mouse drag and release events are ignored, unless they are
|
||||||
@@ -1013,12 +1014,14 @@ theend:
|
|||||||
ccline.cmdbuff = NULL;
|
ccline.cmdbuff = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xfree(s->prev_cmdbuff);
|
||||||
return (uint8_t *)p;
|
return (uint8_t *)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int command_line_check(VimState *state)
|
static int command_line_check(VimState *state)
|
||||||
{
|
{
|
||||||
CommandLineState *s = (CommandLineState *)state;
|
CommandLineState *s = (CommandLineState *)state;
|
||||||
|
s->prev_cmdpos = ccline.cmdpos;
|
||||||
|
|
||||||
redir_off = true; // Don't redirect the typed command.
|
redir_off = true; // Don't redirect the typed command.
|
||||||
// Repeated, because a ":redir" inside
|
// Repeated, because a ":redir" inside
|
||||||
@@ -1029,6 +1032,10 @@ static int command_line_check(VimState *state)
|
|||||||
// that occurs while typing a command should
|
// that occurs while typing a command should
|
||||||
// cause the command not to be executed.
|
// cause the command not to be executed.
|
||||||
|
|
||||||
|
if (ccline.cmdbuff != NULL) {
|
||||||
|
s->prev_cmdbuff = xmemdupz(ccline.cmdbuff, (size_t)ccline.cmdpos);
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger SafeState if nothing is pending.
|
// Trigger SafeState if nothing is pending.
|
||||||
may_trigger_safestate(s->xpc.xp_numfiles <= 0);
|
may_trigger_safestate(s->xpc.xp_numfiles <= 0);
|
||||||
|
|
||||||
@@ -2288,7 +2295,6 @@ static void may_trigger_cursormovedc(CommandLineState *s)
|
|||||||
{
|
{
|
||||||
if (ccline.cmdpos != s->prev_cmdpos) {
|
if (ccline.cmdpos != s->prev_cmdpos) {
|
||||||
trigger_cmd_autocmd(s->cmdline_type, EVENT_CURSORMOVEDC);
|
trigger_cmd_autocmd(s->cmdline_type, EVENT_CURSORMOVEDC);
|
||||||
s->prev_cmdpos = ccline.cmdpos;
|
|
||||||
ccline.redraw_state = MAX(ccline.redraw_state, kCmdRedrawPos);
|
ccline.redraw_state = MAX(ccline.redraw_state, kCmdRedrawPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2296,12 +2302,14 @@ static void may_trigger_cursormovedc(CommandLineState *s)
|
|||||||
static int command_line_not_changed(CommandLineState *s)
|
static int command_line_not_changed(CommandLineState *s)
|
||||||
{
|
{
|
||||||
may_trigger_cursormovedc(s);
|
may_trigger_cursormovedc(s);
|
||||||
|
s->prev_cmdpos = ccline.cmdpos;
|
||||||
// Incremental searches for "/" and "?":
|
// Incremental searches for "/" and "?":
|
||||||
// Enter command_line_not_changed() when a character has been read but the
|
// Enter command_line_not_changed() when a character has been read but the
|
||||||
// command line did not change. Then we only search and redraw if something
|
// command line did not change. Then we only search and redraw if something
|
||||||
// changed in the past.
|
// changed in the past.
|
||||||
// Enter command_line_changed() when the command line did change.
|
// Enter command_line_changed() when the command line did change.
|
||||||
if (!s->is_state.incsearch_postponed) {
|
if (!s->is_state.incsearch_postponed) {
|
||||||
|
XFREE_CLEAR(s->prev_cmdbuff);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return command_line_changed(s);
|
return command_line_changed(s);
|
||||||
@@ -2772,8 +2780,14 @@ static void do_autocmd_cmdlinechanged(int firstc)
|
|||||||
|
|
||||||
static int command_line_changed(CommandLineState *s)
|
static int command_line_changed(CommandLineState *s)
|
||||||
{
|
{
|
||||||
|
if (ccline.cmdpos != s->prev_cmdpos
|
||||||
|
|| (s->prev_cmdbuff != NULL
|
||||||
|
&& strncmp(s->prev_cmdbuff, ccline.cmdbuff, (size_t)s->prev_cmdpos) != 0)) {
|
||||||
// Trigger CmdlineChanged autocommands.
|
// Trigger CmdlineChanged autocommands.
|
||||||
do_autocmd_cmdlinechanged(s->firstc > 0 ? s->firstc : '-');
|
do_autocmd_cmdlinechanged(s->firstc > 0 ? s->firstc : '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
XFREE_CLEAR(s->prev_cmdbuff);
|
||||||
|
|
||||||
may_trigger_cursormovedc(s);
|
may_trigger_cursormovedc(s);
|
||||||
|
|
||||||
|
@@ -4719,4 +4719,53 @@ func Test_pum_scroll_noselect()
|
|||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" CmdlineChanged shouldn't trigger if command-line text is unchanged
|
||||||
|
func Test_cmdline_changed()
|
||||||
|
let g:cmdchg_count = 0
|
||||||
|
let g:cmdprefix = ''
|
||||||
|
augroup test_CmdlineAugrp | autocmd!
|
||||||
|
autocmd CmdlineChanged * if getcmdline() =~ g:cmdprefix | let g:cmdchg_count += 1 | endif
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
new
|
||||||
|
set wildmenu
|
||||||
|
set wildmode=full
|
||||||
|
|
||||||
|
let g:cmdprefix = 'echomsg'
|
||||||
|
let g:cmdchg_count = 0
|
||||||
|
call feedkeys(":echomsg\<Tab>", "tx")
|
||||||
|
call assert_equal(1, g:cmdchg_count) " once only for 'g', not again for <Tab>
|
||||||
|
|
||||||
|
let g:cmdchg_count = 0
|
||||||
|
let g:cmdprefix = 'echo'
|
||||||
|
call feedkeys(":ech\<Tab>", "tx")
|
||||||
|
call assert_equal(1, g:cmdchg_count) " (once for 'h' and) once for 'o'
|
||||||
|
|
||||||
|
set wildmode=noselect,full
|
||||||
|
let g:cmdchg_count = 0
|
||||||
|
let g:cmdprefix = 'ech'
|
||||||
|
call feedkeys(":ech\<Tab>", "tx")
|
||||||
|
call assert_equal(1, g:cmdchg_count) " once for 'h', not again for <tab>
|
||||||
|
|
||||||
|
command! -nargs=+ -complete=custom,TestComplete Test echo
|
||||||
|
|
||||||
|
func TestComplete(arglead, cmdline, cursorpos)
|
||||||
|
return "AbC"
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
set wildoptions=fuzzy wildmode=full
|
||||||
|
let g:cmdchg_count = 0
|
||||||
|
let g:cmdprefix = 'Test \(AbC\|abc\)'
|
||||||
|
call feedkeys(":Test abc\<Tab>", "tx")
|
||||||
|
call assert_equal(2, g:cmdchg_count) " once for 'c', again for 'AbC'
|
||||||
|
|
||||||
|
bw!
|
||||||
|
set wildmode& wildmenu& wildoptions&
|
||||||
|
augroup test_CmdlineAugrp | autocmd! | augroup END
|
||||||
|
unlet g:cmdchg_count
|
||||||
|
unlet g:cmdprefix
|
||||||
|
delfunc TestComplete
|
||||||
|
delcommand Test
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Reference in New Issue
Block a user