]> granicus.if.org Git - vim/commitdiff
patch 7.4.2180 v7.4.2180
authorBram Moolenaar <Bram@vim.org>
Sun, 7 Aug 2016 16:22:53 +0000 (18:22 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 7 Aug 2016 16:22:53 +0000 (18:22 +0200)
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().

runtime/doc/eval.txt
src/evalfunc.c
src/ex_cmds2.c
src/proto/ex_cmds2.pro
src/structs.h
src/testdir/shared.vim
src/testdir/test_timers.vim
src/version.c

index d6269d5a3d80e763625bfa739c827b0156af11d6..39765d59e670b15ebc0652d7ce1fb917edaf9bc7 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 7.4.  Last change: 2016 Aug 06
+*eval.txt*     For Vim version 7.4.  Last change: 2016 Aug 07
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -1969,7 +1969,7 @@ assert_exception({error} [, {msg}])      none  assert {error} is in v:exception
 assert_fails({cmd} [, {error}])          none  assert {cmd} fails
 assert_false({actual} [, {msg}])         none  assert {actual} is false
 assert_inrange({lower}, {upper}, {actual} [, {msg}])
-                               none    assert {actual} is inside the range
+                               none    assert {actual} is inside the range
 assert_match({pat}, {text} [, {msg}])    none  assert {pat} matches {text}
 assert_notequal({exp}, {act} [, {msg}])  none  assert {exp} is not equal {act}
 assert_notmatch({pat}, {text} [, {msg}]) none  assert {pat} not matches {text}
@@ -2340,9 +2340,11 @@ test_null_partial()              Funcref null value for testing
 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}
@@ -7555,8 +7557,26 @@ timer_info([{id}])
                    "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
+                                   -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}])
@@ -7583,6 +7603,7 @@ timer_start({time}, {callback} [, {options}])
                                \ {'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()*
@@ -7590,6 +7611,15 @@ timer_stop({timer})                                      *timer_stop()*
                {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
index 50fa3bf7200dbcaf28462202a321e9782e94bb04..8b5ad22fedd4426962b733e538ef9d2198e7ca28 100644 (file)
@@ -397,8 +397,10 @@ static void f_tanh(typval_T *argvars, typval_T *rettv);
 #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,8 +819,10 @@ static struct fst
     {"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},
@@ -11987,6 +11991,25 @@ f_timer_info(typval_T *argvars, typval_T *rettv)
        add_timer_info_all(rettv);
 }
 
+/*
+ * "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
  */
@@ -12048,6 +12071,15 @@ f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
     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
 
 /*
index 6cf26e9931ce447ccfb4c6aba7cfe9d53ed6c35d..73b3a522fd680faeaddacaaac156a4e825b79098 100644 (file)
@@ -1189,6 +1189,8 @@ check_due_timer(void)
        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);
@@ -1251,6 +1253,15 @@ stop_timer(timer_T *timer)
     free_timer(timer);
 }
 
+    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)
 {
@@ -1283,6 +1294,7 @@ add_timer_info(typval_T *rettv, timer_T *timer)
 
     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)
index 977f5c0de183577e4f6d30e4b866f731cc9f613a..f241d377e8d4f4867e4749c4c0128ac1e144be96 100644 (file)
@@ -22,6 +22,7 @@ timer_T *create_timer(long msec, int repeat);
 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);
index 6cfbb3c25dbb11b86a247297103a9d945bb114e8..b56282fc2999736a82a66fc313018935b55ccb8f 100644 (file)
@@ -3159,6 +3159,7 @@ struct timer_S
     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 */
index ad8afe1ff2af702f3b64e5fa43e63ba42cfd75f0..aba428a46d3e216583cfc88f21eeb8774b880383 100644 (file)
@@ -109,14 +109,17 @@ func s:kill_server(cmd)
 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
+       return slept
       endif
     catch
     endtry
+    let slept += 10
     sleep 10m
   endfor
 endfunc
index 0969377c87b97524bde24e1cdb0cf218cad0bef2..fb35f61fff68c6a3b36f2b17d997f0babef5e288 100644 (file)
@@ -1,11 +1,13 @@
 " Test for timers
 
+source shared.vim
+
 if !has('timers')
   finish
 endif
 
 func MyHandler(timer)
-  let s:val += 1
+  let g:val += 1
 endfunc
 
 func MyHandlerWithLists(lists, timer)
@@ -13,43 +15,101 @@ func MyHandlerWithLists(lists, timer)
 endfunc
 
 func Test_oneshot()
-  let s:val = 0
+  let g:val = 0
   let timer = timer_start(50, 'MyHandler')
-  sleep 200m
-  call assert_equal(1, s:val)
+  let slept = WaitFor('g:val == 1')
+  call assert_equal(1, g:val)
+  call assert_inrange(30, 100, slept)
 endfunc
 
 func Test_repeat_three()
-  let s:val = 0
+  let g:val = 0
   let timer = timer_start(50, 'MyHandler', {'repeat': 3})
-  sleep 500m
-  call assert_equal(3, s:val)
+  let slept = WaitFor('g:val == 3')
+  call assert_equal(3, g:val)
+  call assert_inrange(100, 250, slept)
 endfunc
 
 func Test_repeat_many()
-  let s:val = 0
+  let g: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)
+  call assert_inrange(2, 4, g:val)
 endfunc
 
 func Test_with_partial_callback()
-  let s:val = 0
+  let g:val = 0
   let s:meow = {}
   function s:meow.bite(...)
-    let s:val += 1
+    let g:val += 1
   endfunction
 
   call timer_start(50, s:meow.bite)
-  sleep 200m
-  call assert_equal(1, s:val)
+  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(100, function('MyHandlerWithLists', [['a']]))
+  call timer_start(50, function('MyHandlerWithLists', [['a']]))
   call test_garbagecollect_now()
-  sleep 200m
+  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
index c9197f44a32215dc0592c92b386ad490cbfbd3b0..044546b3d103379df4935a8f7a6e9ca954cb2797 100644 (file)
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2180,
 /**/
     2179,
 /**/