To: vim_dev@googlegroups.com Subject: Patch 8.0.1817 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1817 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) Files: src/eval.c, src/proto/eval.pro, src/ex_cmds2.c, src/structs.h, src/testdir/test_timers.vim *** ../vim-8.0.1816/src/eval.c 2018-04-28 16:56:20.788322741 +0200 --- src/eval.c 2018-05-12 14:55:23.568928017 +0200 *************** *** 6462,6467 **** --- 6462,6490 ---- } /* + * 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". */ void *** ../vim-8.0.1816/src/proto/eval.pro 2018-04-28 16:56:20.788322741 +0200 --- src/proto/eval.pro 2018-05-12 14:56:45.804401726 +0200 *************** *** 67,72 **** --- 67,74 ---- 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); *** ../vim-8.0.1816/src/ex_cmds2.c 2018-05-10 18:05:52.545048437 +0200 --- src/ex_cmds2.c 2018-05-12 15:36:03.067514977 +0200 *************** *** 1336,1341 **** --- 1336,1343 ---- 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,1350 **** --- 1347,1353 ---- 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,1362 **** --- 1360,1366 ---- trylevel = 0; did_throw = FALSE; current_exception = NULL; + save_vimvars(&vvsave); timer->tr_firing = TRUE; timer_callback(timer); *************** *** 1373,1378 **** --- 1377,1383 ---- 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 *** ../vim-8.0.1816/src/structs.h 2018-04-21 22:30:04.708058436 +0200 --- src/structs.h 2018-05-12 14:54:52.697125458 +0200 *************** *** 3423,3425 **** --- 3423,3431 ---- 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; *** ../vim-8.0.1816/src/testdir/test_timers.vim 2018-04-30 14:28:20.448618066 +0200 --- src/testdir/test_timers.vim 2018-05-12 15:38:17.314743971 +0200 *************** *** 5,10 **** --- 5,11 ---- endif source shared.vim + source screendump.vim func MyHandler(timer) let g:val += 1 *************** *** 260,263 **** --- 261,295 ---- 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 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-8.0.1816/src/version.c 2018-05-12 13:18:42.292000343 +0200 --- src/version.c 2018-05-12 15:36:18.443426926 +0200 *************** *** 763,764 **** --- 763,766 ---- { /* Add new patch number below this line */ + /**/ + 1817, /**/ -- ARTHUR: Go on, Bors, chop its head off. BORS: Right. Silly little bleeder. One rabbit stew coming up. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///