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 <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-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 -- b...@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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui