mirror of
https://github.com/vim/vim.git
synced 2025-10-05 05:34:07 -04:00
patch 8.0.1817: a timer may change v:count unexpectedly
Problem: A timer may change v:count unexpectedly. Solution: Save and restore v:count and similar variables when a timer callback is invoked. (closes #2897)
This commit is contained in:
23
src/eval.c
23
src/eval.c
@@ -6461,6 +6461,29 @@ set_vcount(
|
|||||||
vimvars[VV_COUNT1].vv_nr = count1;
|
vimvars[VV_COUNT1].vv_nr = count1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save variables that might be changed as a side effect. Used when executing
|
||||||
|
* a timer callback.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
save_vimvars(vimvars_save_T *vvsave)
|
||||||
|
{
|
||||||
|
vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
|
||||||
|
vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
|
||||||
|
vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore variables saved by save_vimvars().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
restore_vimvars(vimvars_save_T *vvsave)
|
||||||
|
{
|
||||||
|
vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
|
||||||
|
vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
|
||||||
|
vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set string v: variable to a copy of "val".
|
* Set string v: variable to a copy of "val".
|
||||||
*/
|
*/
|
||||||
|
@@ -1336,6 +1336,8 @@ check_due_timer(void)
|
|||||||
this_due = proftime_time_left(&timer->tr_due, &now);
|
this_due = proftime_time_left(&timer->tr_due, &now);
|
||||||
if (this_due <= 1)
|
if (this_due <= 1)
|
||||||
{
|
{
|
||||||
|
/* Save and restore a lot of flags, because the timer fires while
|
||||||
|
* waiting for a character, which might be halfway a command. */
|
||||||
int save_timer_busy = timer_busy;
|
int save_timer_busy = timer_busy;
|
||||||
int save_vgetc_busy = vgetc_busy;
|
int save_vgetc_busy = vgetc_busy;
|
||||||
int save_did_emsg = did_emsg;
|
int save_did_emsg = did_emsg;
|
||||||
@@ -1345,6 +1347,7 @@ check_due_timer(void)
|
|||||||
int save_did_throw = did_throw;
|
int save_did_throw = did_throw;
|
||||||
int save_ex_pressedreturn = get_pressedreturn();
|
int save_ex_pressedreturn = get_pressedreturn();
|
||||||
except_T *save_current_exception = current_exception;
|
except_T *save_current_exception = current_exception;
|
||||||
|
vimvars_save_T vvsave;
|
||||||
|
|
||||||
/* Create a scope for running the timer callback, ignoring most of
|
/* Create a scope for running the timer callback, ignoring most of
|
||||||
* the current scope, such as being inside a try/catch. */
|
* the current scope, such as being inside a try/catch. */
|
||||||
@@ -1357,6 +1360,7 @@ check_due_timer(void)
|
|||||||
trylevel = 0;
|
trylevel = 0;
|
||||||
did_throw = FALSE;
|
did_throw = FALSE;
|
||||||
current_exception = NULL;
|
current_exception = NULL;
|
||||||
|
save_vimvars(&vvsave);
|
||||||
|
|
||||||
timer->tr_firing = TRUE;
|
timer->tr_firing = TRUE;
|
||||||
timer_callback(timer);
|
timer_callback(timer);
|
||||||
@@ -1373,6 +1377,7 @@ check_due_timer(void)
|
|||||||
trylevel = save_trylevel;
|
trylevel = save_trylevel;
|
||||||
did_throw = save_did_throw;
|
did_throw = save_did_throw;
|
||||||
current_exception = save_current_exception;
|
current_exception = save_current_exception;
|
||||||
|
restore_vimvars(&vvsave);
|
||||||
if (must_redraw != 0)
|
if (must_redraw != 0)
|
||||||
need_update_screen = TRUE;
|
need_update_screen = TRUE;
|
||||||
must_redraw = must_redraw > save_must_redraw
|
must_redraw = must_redraw > save_must_redraw
|
||||||
|
@@ -67,6 +67,8 @@ list_T *get_vim_var_list(int idx);
|
|||||||
dict_T *get_vim_var_dict(int idx);
|
dict_T *get_vim_var_dict(int idx);
|
||||||
void set_vim_var_char(int c);
|
void set_vim_var_char(int c);
|
||||||
void set_vcount(long count, long count1, int set_prevcount);
|
void set_vcount(long count, long count1, int set_prevcount);
|
||||||
|
void save_vimvars(vimvars_save_T *vvsave);
|
||||||
|
void restore_vimvars(vimvars_save_T *vvsave);
|
||||||
void set_vim_var_string(int idx, char_u *val, int len);
|
void set_vim_var_string(int idx, char_u *val, int len);
|
||||||
void set_vim_var_list(int idx, list_T *val);
|
void set_vim_var_list(int idx, list_T *val);
|
||||||
void set_vim_var_dict(int idx, dict_T *val);
|
void set_vim_var_dict(int idx, dict_T *val);
|
||||||
|
@@ -3423,3 +3423,9 @@ typedef struct {
|
|||||||
int save_opcount;
|
int save_opcount;
|
||||||
tasave_T tabuf;
|
tasave_T tabuf;
|
||||||
} save_state_T;
|
} save_state_T;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
varnumber_T vv_prevcount;
|
||||||
|
varnumber_T vv_count;
|
||||||
|
varnumber_T vv_count1;
|
||||||
|
} vimvars_save_T;
|
||||||
|
@@ -5,6 +5,7 @@ if !has('timers')
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
source shared.vim
|
source shared.vim
|
||||||
|
source screendump.vim
|
||||||
|
|
||||||
func MyHandler(timer)
|
func MyHandler(timer)
|
||||||
let g:val += 1
|
let g:val += 1
|
||||||
@@ -260,4 +261,35 @@ func Test_ex_mode()
|
|||||||
call timer_stop(timer)
|
call timer_stop(timer)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_restore_count()
|
||||||
|
if !CanRunVimInTerminal()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
" Check that v:count is saved and restored, not changed by a timer.
|
||||||
|
call writefile([
|
||||||
|
\ 'nnoremap <expr><silent> L v:count ? v:count . "l" : "l"',
|
||||||
|
\ 'func Doit(id)',
|
||||||
|
\ ' normal 3j',
|
||||||
|
\ 'endfunc',
|
||||||
|
\ 'call timer_start(100, "Doit")',
|
||||||
|
\ ], 'Xtrcscript')
|
||||||
|
call writefile([
|
||||||
|
\ '1-1234',
|
||||||
|
\ '2-1234',
|
||||||
|
\ '3-1234',
|
||||||
|
\ ], 'Xtrctext')
|
||||||
|
let buf = RunVimInTerminal('-S Xtrcscript Xtrctext', {})
|
||||||
|
|
||||||
|
" Wait for the timer to move the cursor to the third line.
|
||||||
|
call WaitForAssert({-> assert_equal(3, term_getcursor(buf)[0])})
|
||||||
|
call assert_equal(1, term_getcursor(buf)[1])
|
||||||
|
" Now check that v:count has not been set to 3
|
||||||
|
call term_sendkeys(buf, 'L')
|
||||||
|
call WaitForAssert({-> assert_equal(2, term_getcursor(buf)[1])})
|
||||||
|
|
||||||
|
call StopVimInTerminal(buf)
|
||||||
|
call delete('Xtrcscript')
|
||||||
|
call delete('Xtrctext')
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -761,6 +761,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1817,
|
||||||
/**/
|
/**/
|
||||||
1816,
|
1816,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user