Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
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 )
Loading branch information
Showing
6 changed files
with
70 additions
and
0 deletions .
+23
−0
src/eval.c
+5
−0
src/ex_cmds2.c
+2
−0
src/proto/eval.pro
+6
−0
src/structs.h
+32
−0
src/testdir/test_timers.vim
+2
−0
src/version.c
@@ -6461,6 +6461,29 @@ set_vcount(
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".
*/
@@ -1336,6 +1336,8 @@ check_due_timer(void)
this_due = proftime_time_left (&timer->tr_due , &now);
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_vgetc_busy = vgetc_busy;
int save_did_emsg = did_emsg;
@@ -1345,6 +1347,7 @@ check_due_timer(void)
int save_did_throw = did_throw;
int save_ex_pressedreturn = get_pressedreturn ();
except_T *save_current_exception = current_exception;
vimvars_save_T vvsave;
/* Create a scope for running the timer callback, ignoring most of
* the current scope, such as being inside a try/catch. */
@@ -1357,6 +1360,7 @@ check_due_timer(void)
trylevel = 0 ;
did_throw = FALSE ;
current_exception = NULL ;
save_vimvars (&vvsave);
timer->tr_firing = TRUE ;
timer_callback (timer);
@@ -1373,6 +1377,7 @@ check_due_timer(void)
trylevel = save_trylevel;
did_throw = save_did_throw;
current_exception = save_current_exception;
restore_vimvars (&vvsave);
if (must_redraw != 0 )
need_update_screen = TRUE ;
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);
void set_vim_var_char (int c);
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_list (int idx, list_T *val);
void set_vim_var_dict (int idx, dict_T *val);
@@ -3423,3 +3423,9 @@ typedef struct {
int save_opcount;
tasave_T tabuf;
} 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
source shared.vim
source screendump.vim
func MyHandler (timer)
let g: val += 1
@@ -260,4 +261,35 @@ func Test_ex_mode()
call timer_stop (timer)
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
@@ -761,6 +761,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/* */
1817 ,
/* */
1816 ,
/* */
Toggle all file notes
Toggle all file annotations