To: vim_dev@googlegroups.com Subject: Patch 7.4.2180 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- 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 ///