Patch 7.4.2180
Problem:    There is no easy way to stop all timers.  There is no way to
            temporary pause a timer.
Solution:   Add timer_stopall() and timer_pause().
Files:      src/evalfunc.c, src/ex_cmds2.c, src/proto/ex_cmds2.pro,
            src/structs.h, src/testdir/test_timers.vim,
            src/testdir/shared.vim, runtime/doc/eval.txt


*** ../vim-7.4.2179/src/evalfunc.c      2016-08-06 22:04:44.274311280 +0200
--- src/evalfunc.c      2016-08-07 18:15:25.349625170 +0200
***************
*** 397,404 ****
--- 397,406 ----
  #endif
  #ifdef FEAT_TIMERS
  static void f_timer_info(typval_T *argvars, typval_T *rettv);
+ static void f_timer_pause(typval_T *argvars, typval_T *rettv);
  static void f_timer_start(typval_T *argvars, typval_T *rettv);
  static void f_timer_stop(typval_T *argvars, typval_T *rettv);
+ static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
  #endif
  static void f_tolower(typval_T *argvars, typval_T *rettv);
  static void f_toupper(typval_T *argvars, typval_T *rettv);
***************
*** 817,824 ****
--- 819,828 ----
      {"test_settime",  1, 1, f_test_settime},
  #ifdef FEAT_TIMERS
      {"timer_info",    0, 1, f_timer_info},
+     {"timer_pause",   2, 2, f_timer_pause},
      {"timer_start",   2, 3, f_timer_start},
      {"timer_stop",    1, 1, f_timer_stop},
+     {"timer_stopall", 0, 0, f_timer_stopall},
  #endif
      {"tolower",               1, 1, f_tolower},
      {"toupper",               1, 1, f_toupper},
***************
*** 11988,11993 ****
--- 11992,12016 ----
  }
  
  /*
+  * "timer_pause(timer, paused)" function
+  */
+     static void
+ f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+     timer_T   *timer = NULL;
+     int               paused = (int)get_tv_number(&argvars[1]);
+ 
+     if (argvars[0].v_type != VAR_NUMBER)
+       EMSG(_(e_number_exp));
+     else
+     {
+       timer = find_timer((int)get_tv_number(&argvars[0]));
+       if (timer != NULL)
+           timer->tr_paused = paused;
+     }
+ }
+ 
+ /*
   * "timer_start(time, callback [, options])" function
   */
      static void
***************
*** 12048,12053 ****
--- 12071,12085 ----
      if (timer != NULL)
        stop_timer(timer);
  }
+ 
+ /*
+  * "timer_stopall()" function
+  */
+     static void
+ f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+ {
+     stop_all_timers();
+ }
  #endif
  
  /*
*** ../vim-7.4.2179/src/ex_cmds2.c      2016-08-06 22:27:24.799508423 +0200
--- src/ex_cmds2.c      2016-08-07 17:49:39.726424958 +0200
***************
*** 1189,1194 ****
--- 1189,1196 ----
        next_due = -1;
        for (timer = first_timer; timer != NULL; timer = timer->tr_next)
        {
+           if (timer->tr_paused)
+               continue;
  # ifdef WIN3264
            this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
                                               / (double)fr.QuadPart) * 1000);
***************
*** 1252,1257 ****
--- 1254,1268 ----
  }
  
      void
+ stop_all_timers(void)
+ {
+     timer_T *timer;
+ 
+     while (first_timer != NULL)
+       stop_timer(first_timer);
+ }
+ 
+     void
  add_timer_info(typval_T *rettv, timer_T *timer)
  {
      list_T    *list = rettv->vval.v_list;
***************
*** 1283,1288 ****
--- 1294,1300 ----
  
      dict_add_nr_str(dict, "repeat",
               (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
+     dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
  
      di = dictitem_alloc((char_u *)"callback");
      if (di != NULL)
*** ../vim-7.4.2179/src/proto/ex_cmds2.pro      2016-08-06 22:04:44.278311247 
+0200
--- src/proto/ex_cmds2.pro      2016-08-07 17:18:46.937920379 +0200
***************
*** 22,27 ****
--- 22,28 ----
  long check_due_timer(void);
  timer_T *find_timer(int id);
  void stop_timer(timer_T *timer);
+ void stop_all_timers(void);
  void add_timer_info(typval_T *rettv, timer_T *timer);
  void add_timer_info_all(typval_T *rettv);
  int set_ref_in_timer(int copyID);
*** ../vim-7.4.2179/src/structs.h       2016-08-07 15:19:22.204295369 +0200
--- src/structs.h       2016-08-07 17:45:30.456510980 +0200
***************
*** 3159,3164 ****
--- 3159,3165 ----
      timer_T   *tr_next;
      timer_T   *tr_prev;
      proftime_T        tr_due;             /* when the callback is to be 
invoked */
+     int               tr_paused;          /* when TRUE callback is not 
invoked */
      int               tr_repeat;          /* number of times to repeat, -1 
forever */
      long      tr_interval;        /* msec */
      char_u    *tr_callback;       /* allocated */
*** ../vim-7.4.2179/src/testdir/test_timers.vim 2016-05-31 21:12:59.734705409 
+0200
--- src/testdir/test_timers.vim 2016-08-07 18:13:19.222665327 +0200
***************
*** 1,11 ****
  " Test for timers
  
  if !has('timers')
    finish
  endif
  
  func MyHandler(timer)
!   let s:val += 1
  endfunc
  
  func MyHandlerWithLists(lists, timer)
--- 1,13 ----
  " Test for timers
  
+ source shared.vim
+ 
  if !has('timers')
    finish
  endif
  
  func MyHandler(timer)
!   let g:val += 1
  endfunc
  
  func MyHandlerWithLists(lists, timer)
***************
*** 13,55 ****
  endfunc
  
  func Test_oneshot()
!   let s:val = 0
    let timer = timer_start(50, 'MyHandler')
!   sleep 200m
!   call assert_equal(1, s:val)
  endfunc
  
  func Test_repeat_three()
!   let s:val = 0
    let timer = timer_start(50, 'MyHandler', {'repeat': 3})
!   sleep 500m
!   call assert_equal(3, s:val)
  endfunc
  
  func Test_repeat_many()
!   let s:val = 0
    let timer = timer_start(50, 'MyHandler', {'repeat': -1})
    sleep 200m
    call timer_stop(timer)
!   call assert_true(s:val > 1)
!   call assert_true(s:val < 5)
  endfunc
  
  func Test_with_partial_callback()
!   let s:val = 0
    let s:meow = {}
    function s:meow.bite(...)
!     let s:val += 1
    endfunction
  
    call timer_start(50, s:meow.bite)
!   sleep 200m
!   call assert_equal(1, s:val)
  endfunc
  
  func Test_retain_partial()
!   call timer_start(100, function('MyHandlerWithLists', [['a']]))
    call test_garbagecollect_now()
!   sleep 200m
  endfunc
  " vim: ts=2 sw=0 et
--- 15,115 ----
  endfunc
  
  func Test_oneshot()
!   let g:val = 0
    let timer = timer_start(50, 'MyHandler')
!   let slept = WaitFor('g:val == 1')
!   call assert_equal(1, g:val)
!   call assert_inrange(30, 100, slept)
  endfunc
  
  func Test_repeat_three()
!   let g:val = 0
    let timer = timer_start(50, 'MyHandler', {'repeat': 3})
!   let slept = WaitFor('g:val == 3')
!   call assert_equal(3, g:val)
!   call assert_inrange(100, 250, slept)
  endfunc
  
  func Test_repeat_many()
!   let g:val = 0
    let timer = timer_start(50, 'MyHandler', {'repeat': -1})
    sleep 200m
    call timer_stop(timer)
!   call assert_inrange(2, 4, g:val)
  endfunc
  
  func Test_with_partial_callback()
!   let g:val = 0
    let s:meow = {}
    function s:meow.bite(...)
!     let g:val += 1
    endfunction
  
    call timer_start(50, s:meow.bite)
!   let slept = WaitFor('g:val == 1')
!   call assert_equal(1, g:val)
!   call assert_inrange(30, 100, slept)
  endfunc
  
  func Test_retain_partial()
!   call timer_start(50, function('MyHandlerWithLists', [['a']]))
    call test_garbagecollect_now()
!   sleep 100m
  endfunc
+ 
+ func Test_info()
+   let id = timer_start(1000, 'MyHandler')
+   let info = timer_info(id)
+   call assert_equal(id, info[0]['id'])
+   call assert_equal(1000, info[0]['time'])
+   call assert_true(info[0]['remaining'] > 500)
+   call assert_true(info[0]['remaining'] <= 1000)
+   call assert_equal(1, info[0]['repeat'])
+   call assert_equal("function('MyHandler')", string(info[0]['callback']))
+ 
+   let found = 0
+   for info in timer_info()
+     if info['id'] == id
+       let found += 1
+     endif
+   endfor
+   call assert_equal(1, found)
+ 
+   call timer_stop(id)
+   call assert_equal([], timer_info(id))
+ endfunc
+ 
+ func Test_stopall()
+   let id1 = timer_start(1000, 'MyHandler')
+   let id2 = timer_start(2000, 'MyHandler')
+   let info = timer_info()
+   call assert_equal(2, len(info))
+ 
+   call timer_stopall()
+   let info = timer_info()
+   call assert_equal(0, len(info))
+ endfunc
+ 
+ func Test_paused()
+   let g:val = 0
+ 
+   let id = timer_start(50, 'MyHandler')
+   let info = timer_info(id)
+   call assert_equal(0, info[0]['paused'])
+ 
+   call timer_pause(id, 1)
+   let info = timer_info(id)
+   call assert_equal(1, info[0]['paused'])
+   sleep 100m
+   call assert_equal(0, g:val)
+ 
+   call timer_pause(id, 0)
+   let info = timer_info(id)
+   call assert_equal(0, info[0]['paused'])
+ 
+   let slept = WaitFor('g:val == 1')
+   call assert_equal(1, g:val)
+   call assert_inrange(0, 10, slept)
+ endfunc
+ 
  " vim: ts=2 sw=0 et
*** ../vim-7.4.2179/src/testdir/shared.vim      2016-08-07 16:36:26.718630005 
+0200
--- src/testdir/shared.vim      2016-08-07 17:24:09.703254829 +0200
***************
*** 109,122 ****
  endfunc
  
  " Wait for up to a second for "expr" to become true.
  func WaitFor(expr)
    for i in range(100)
      try
        if eval(a:expr)
!       return
        endif
      catch
      endtry
      sleep 10m
    endfor
  endfunc
--- 109,125 ----
  endfunc
  
  " Wait for up to a second for "expr" to become true.
+ " Return time slept in milliseconds.
  func WaitFor(expr)
+   let slept = 0
    for i in range(100)
      try
        if eval(a:expr)
!       return slept
        endif
      catch
      endtry
+     let slept += 10
      sleep 10m
    endfor
  endfunc
*** ../vim-7.4.2179/runtime/doc/eval.txt        2016-08-06 22:04:44.286311184 
+0200
--- runtime/doc/eval.txt        2016-08-07 17:44:49.332855441 +0200
***************
*** 2318,2326 ****
--- 2340,2350 ----
  test_null_string()            String  null value for testing
  test_settime({expr})          none    set current time for testing
  timer_info([{id}])            List    information about timers
+ timer_pause({id}, {pause})    none    pause or unpause a timer
  timer_start({time}, {callback} [, {options}])
                                Number  create a timer
  timer_stop({timer})           none    stop a timer
+ timer_stopall()                       none    stop all timers
  tolower({expr})                       String  the String {expr} switched to 
lowercase
  toupper({expr})                       String  the String {expr} switched to 
uppercase
  tr({src}, {fromstr}, {tostr}) String  translate chars of {src} in {fromstr}
***************
*** 7450,7457 ****
                    "time"          time the timer was started with
                    "remaining"     time until the timer fires
                    "repeat"        number of times the timer will still fire;
!                                   -1 means forever
                    "callback"      the callback
  
                                                        *timer_start()*
  timer_start({time}, {callback} [, {options}])
--- 7557,7582 ----
                    "time"          time the timer was started with
                    "remaining"     time until the timer fires
                    "repeat"        number of times the timer will still fire;
!                                   -1 means forever
                    "callback"      the callback
+                   "paused"        1 if the timer is paused, 0 otherwise
+ 
+               {only available when compiled with the |+timers| feature}
+ 
+ timer_pause({timer}, {paused})                                *timer_pause()*
+               Pause or unpause a timer.  A paused timer does not invoke its
+               callback, while the time it would is not changed.  Unpausing a
+               timer may cause the callback to be invoked almost immediately
+               if enough time has passed.
+ 
+               Pausing a timer is useful to avoid the callback to be called
+               for a short time.
+ 
+               If {paused} evaluates to a non-zero Number or a non-empty
+               String, then the timer is paused, otherwise it is unpaused.
+               See |non-zero-arg|.
+ 
+               {only available when compiled with the |+timers| feature}
  
                                                        *timer_start()*
  timer_start({time}, {callback} [, {options}])
***************
*** 7478,7483 ****
--- 7603,7609 ----
                                \ {'repeat': 3})
  <             This will invoke MyHandler() three times at 500 msec
                intervals.
+ 
                {only available when compiled with the |+timers| feature}
  
  timer_stop({timer})                                   *timer_stop()*
***************
*** 7485,7490 ****
--- 7611,7625 ----
                {timer} is an ID returned by timer_start(), thus it must be a
                Number.  If {timer} does not exist there is no error.
  
+               {only available when compiled with the |+timers| feature}
+ 
+ timer_stopall()                                               
*timer_stopall()*
+               Stop all timers.  The timer callbacks will no longer be
+               invoked.  Useful if some timers is misbehaving.  If there are
+               no timers there is no error.
+ 
+               {only available when compiled with the |+timers| feature}
+ 
  tolower({expr})                                               *tolower()*
                The result is a copy of the String given, with all uppercase
                characters turned into lowercase (just like applying |gu| to
*** ../vim-7.4.2179/src/version.c       2016-08-07 16:50:07.751926334 +0200
--- src/version.c       2016-08-07 17:17:03.190762909 +0200
***************
*** 765,766 ****
--- 765,768 ----
  {   /* Add new patch number below this line */
+ /**/
+     2180,
  /**/

-- 
"You're fired." (1980)
"You're laid off." (1985)
"You're downsized." (1990)
"You're rightsized." (1992)
                                (Scott Adams - The Dilbert principle)

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui