Skip to content

Commit b73598e

Browse files
committed
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().
1 parent e4a76ad commit b73598e

8 files changed

Lines changed: 161 additions & 20 deletions

File tree

runtime/doc/eval.txt

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 7.4. Last change: 2016 Aug 06
1+
*eval.txt* For Vim version 7.4. Last change: 2016 Aug 07
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1969,7 +1969,7 @@ assert_exception({error} [, {msg}]) none assert {error} is in v:exception
19691969
assert_fails({cmd} [, {error}]) none assert {cmd} fails
19701970
assert_false({actual} [, {msg}]) none assert {actual} is false
19711971
assert_inrange({lower}, {upper}, {actual} [, {msg}])
1972-
none assert {actual} is inside the range
1972+
none assert {actual} is inside the range
19731973
assert_match({pat}, {text} [, {msg}]) none assert {pat} matches {text}
19741974
assert_notequal({exp}, {act} [, {msg}]) none assert {exp} is not equal {act}
19751975
assert_notmatch({pat}, {text} [, {msg}]) none assert {pat} not matches {text}
@@ -2340,9 +2340,11 @@ test_null_partial() Funcref null value for testing
23402340
test_null_string() String null value for testing
23412341
test_settime({expr}) none set current time for testing
23422342
timer_info([{id}]) List information about timers
2343+
timer_pause({id}, {pause}) none pause or unpause a timer
23432344
timer_start({time}, {callback} [, {options}])
23442345
Number create a timer
23452346
timer_stop({timer}) none stop a timer
2347+
timer_stopall() none stop all timers
23462348
tolower({expr}) String the String {expr} switched to lowercase
23472349
toupper({expr}) String the String {expr} switched to uppercase
23482350
tr({src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr}
@@ -7555,8 +7557,26 @@ timer_info([{id}])
75557557
"time" time the timer was started with
75567558
"remaining" time until the timer fires
75577559
"repeat" number of times the timer will still fire;
7558-
-1 means forever
7560+
-1 means forever
75597561
"callback" the callback
7562+
"paused" 1 if the timer is paused, 0 otherwise
7563+
7564+
{only available when compiled with the |+timers| feature}
7565+
7566+
timer_pause({timer}, {paused}) *timer_pause()*
7567+
Pause or unpause a timer. A paused timer does not invoke its
7568+
callback, while the time it would is not changed. Unpausing a
7569+
timer may cause the callback to be invoked almost immediately
7570+
if enough time has passed.
7571+
7572+
Pausing a timer is useful to avoid the callback to be called
7573+
for a short time.
7574+
7575+
If {paused} evaluates to a non-zero Number or a non-empty
7576+
String, then the timer is paused, otherwise it is unpaused.
7577+
See |non-zero-arg|.
7578+
7579+
{only available when compiled with the |+timers| feature}
75607580

75617581
*timer_start()*
75627582
timer_start({time}, {callback} [, {options}])
@@ -7583,13 +7603,23 @@ timer_start({time}, {callback} [, {options}])
75837603
\ {'repeat': 3})
75847604
< This will invoke MyHandler() three times at 500 msec
75857605
intervals.
7606+
75867607
{only available when compiled with the |+timers| feature}
75877608

75887609
timer_stop({timer}) *timer_stop()*
75897610
Stop a timer. The timer callback will no longer be invoked.
75907611
{timer} is an ID returned by timer_start(), thus it must be a
75917612
Number. If {timer} does not exist there is no error.
75927613

7614+
{only available when compiled with the |+timers| feature}
7615+
7616+
timer_stopall() *timer_stopall()*
7617+
Stop all timers. The timer callbacks will no longer be
7618+
invoked. Useful if some timers is misbehaving. If there are
7619+
no timers there is no error.
7620+
7621+
{only available when compiled with the |+timers| feature}
7622+
75937623
tolower({expr}) *tolower()*
75947624
The result is a copy of the String given, with all uppercase
75957625
characters turned into lowercase (just like applying |gu| to

src/evalfunc.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,10 @@ static void f_tanh(typval_T *argvars, typval_T *rettv);
397397
#endif
398398
#ifdef FEAT_TIMERS
399399
static void f_timer_info(typval_T *argvars, typval_T *rettv);
400+
static void f_timer_pause(typval_T *argvars, typval_T *rettv);
400401
static void f_timer_start(typval_T *argvars, typval_T *rettv);
401402
static void f_timer_stop(typval_T *argvars, typval_T *rettv);
403+
static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
402404
#endif
403405
static void f_tolower(typval_T *argvars, typval_T *rettv);
404406
static void f_toupper(typval_T *argvars, typval_T *rettv);
@@ -817,8 +819,10 @@ static struct fst
817819
{"test_settime", 1, 1, f_test_settime},
818820
#ifdef FEAT_TIMERS
819821
{"timer_info", 0, 1, f_timer_info},
822+
{"timer_pause", 2, 2, f_timer_pause},
820823
{"timer_start", 2, 3, f_timer_start},
821824
{"timer_stop", 1, 1, f_timer_stop},
825+
{"timer_stopall", 0, 0, f_timer_stopall},
822826
#endif
823827
{"tolower", 1, 1, f_tolower},
824828
{"toupper", 1, 1, f_toupper},
@@ -11987,6 +11991,25 @@ f_timer_info(typval_T *argvars, typval_T *rettv)
1198711991
add_timer_info_all(rettv);
1198811992
}
1198911993

11994+
/*
11995+
* "timer_pause(timer, paused)" function
11996+
*/
11997+
static void
11998+
f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
11999+
{
12000+
timer_T *timer = NULL;
12001+
int paused = (int)get_tv_number(&argvars[1]);
12002+
12003+
if (argvars[0].v_type != VAR_NUMBER)
12004+
EMSG(_(e_number_exp));
12005+
else
12006+
{
12007+
timer = find_timer((int)get_tv_number(&argvars[0]));
12008+
if (timer != NULL)
12009+
timer->tr_paused = paused;
12010+
}
12011+
}
12012+
1199012013
/*
1199112014
* "timer_start(time, callback [, options])" function
1199212015
*/
@@ -12048,6 +12071,15 @@ f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
1204812071
if (timer != NULL)
1204912072
stop_timer(timer);
1205012073
}
12074+
12075+
/*
12076+
* "timer_stopall()" function
12077+
*/
12078+
static void
12079+
f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12080+
{
12081+
stop_all_timers();
12082+
}
1205112083
#endif
1205212084

1205312085
/*

src/ex_cmds2.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,8 @@ check_due_timer(void)
11891189
next_due = -1;
11901190
for (timer = first_timer; timer != NULL; timer = timer->tr_next)
11911191
{
1192+
if (timer->tr_paused)
1193+
continue;
11921194
# ifdef WIN3264
11931195
this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
11941196
/ (double)fr.QuadPart) * 1000);
@@ -1251,6 +1253,15 @@ stop_timer(timer_T *timer)
12511253
free_timer(timer);
12521254
}
12531255

1256+
void
1257+
stop_all_timers(void)
1258+
{
1259+
timer_T *timer;
1260+
1261+
while (first_timer != NULL)
1262+
stop_timer(first_timer);
1263+
}
1264+
12541265
void
12551266
add_timer_info(typval_T *rettv, timer_T *timer)
12561267
{
@@ -1283,6 +1294,7 @@ add_timer_info(typval_T *rettv, timer_T *timer)
12831294

12841295
dict_add_nr_str(dict, "repeat",
12851296
(long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
1297+
dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
12861298

12871299
di = dictitem_alloc((char_u *)"callback");
12881300
if (di != NULL)

src/proto/ex_cmds2.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ timer_T *create_timer(long msec, int repeat);
2222
long check_due_timer(void);
2323
timer_T *find_timer(int id);
2424
void stop_timer(timer_T *timer);
25+
void stop_all_timers(void);
2526
void add_timer_info(typval_T *rettv, timer_T *timer);
2627
void add_timer_info_all(typval_T *rettv);
2728
int set_ref_in_timer(int copyID);

src/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,6 +3159,7 @@ struct timer_S
31593159
timer_T *tr_next;
31603160
timer_T *tr_prev;
31613161
proftime_T tr_due; /* when the callback is to be invoked */
3162+
int tr_paused; /* when TRUE callback is not invoked */
31623163
int tr_repeat; /* number of times to repeat, -1 forever */
31633164
long tr_interval; /* msec */
31643165
char_u *tr_callback; /* allocated */

src/testdir/shared.vim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,17 @@ func s:kill_server(cmd)
109109
endfunc
110110

111111
" Wait for up to a second for "expr" to become true.
112+
" Return time slept in milliseconds.
112113
func WaitFor(expr)
114+
let slept = 0
113115
for i in range(100)
114116
try
115117
if eval(a:expr)
116-
return
118+
return slept
117119
endif
118120
catch
119121
endtry
122+
let slept += 10
120123
sleep 10m
121124
endfor
122125
endfunc

src/testdir/test_timers.vim

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,115 @@
11
" Test for timers
22

3+
source shared.vim
4+
35
if !has('timers')
46
finish
57
endif
68

79
func MyHandler(timer)
8-
let s:val += 1
10+
let g:val += 1
911
endfunc
1012

1113
func MyHandlerWithLists(lists, timer)
1214
let x = string(a:lists)
1315
endfunc
1416

1517
func Test_oneshot()
16-
let s:val = 0
18+
let g:val = 0
1719
let timer = timer_start(50, 'MyHandler')
18-
sleep 200m
19-
call assert_equal(1, s:val)
20+
let slept = WaitFor('g:val == 1')
21+
call assert_equal(1, g:val)
22+
call assert_inrange(30, 100, slept)
2023
endfunc
2124

2225
func Test_repeat_three()
23-
let s:val = 0
26+
let g:val = 0
2427
let timer = timer_start(50, 'MyHandler', {'repeat': 3})
25-
sleep 500m
26-
call assert_equal(3, s:val)
28+
let slept = WaitFor('g:val == 3')
29+
call assert_equal(3, g:val)
30+
call assert_inrange(100, 250, slept)
2731
endfunc
2832

2933
func Test_repeat_many()
30-
let s:val = 0
34+
let g:val = 0
3135
let timer = timer_start(50, 'MyHandler', {'repeat': -1})
3236
sleep 200m
3337
call timer_stop(timer)
34-
call assert_true(s:val > 1)
35-
call assert_true(s:val < 5)
38+
call assert_inrange(2, 4, g:val)
3639
endfunc
3740

3841
func Test_with_partial_callback()
39-
let s:val = 0
42+
let g:val = 0
4043
let s:meow = {}
4144
function s:meow.bite(...)
42-
let s:val += 1
45+
let g:val += 1
4346
endfunction
4447

4548
call timer_start(50, s:meow.bite)
46-
sleep 200m
47-
call assert_equal(1, s:val)
49+
let slept = WaitFor('g:val == 1')
50+
call assert_equal(1, g:val)
51+
call assert_inrange(30, 100, slept)
4852
endfunc
4953

5054
func Test_retain_partial()
51-
call timer_start(100, function('MyHandlerWithLists', [['a']]))
55+
call timer_start(50, function('MyHandlerWithLists', [['a']]))
5256
call test_garbagecollect_now()
53-
sleep 200m
57+
sleep 100m
58+
endfunc
59+
60+
func Test_info()
61+
let id = timer_start(1000, 'MyHandler')
62+
let info = timer_info(id)
63+
call assert_equal(id, info[0]['id'])
64+
call assert_equal(1000, info[0]['time'])
65+
call assert_true(info[0]['remaining'] > 500)
66+
call assert_true(info[0]['remaining'] <= 1000)
67+
call assert_equal(1, info[0]['repeat'])
68+
call assert_equal("function('MyHandler')", string(info[0]['callback']))
69+
70+
let found = 0
71+
for info in timer_info()
72+
if info['id'] == id
73+
let found += 1
74+
endif
75+
endfor
76+
call assert_equal(1, found)
77+
78+
call timer_stop(id)
79+
call assert_equal([], timer_info(id))
80+
endfunc
81+
82+
func Test_stopall()
83+
let id1 = timer_start(1000, 'MyHandler')
84+
let id2 = timer_start(2000, 'MyHandler')
85+
let info = timer_info()
86+
call assert_equal(2, len(info))
87+
88+
call timer_stopall()
89+
let info = timer_info()
90+
call assert_equal(0, len(info))
5491
endfunc
92+
93+
func Test_paused()
94+
let g:val = 0
95+
96+
let id = timer_start(50, 'MyHandler')
97+
let info = timer_info(id)
98+
call assert_equal(0, info[0]['paused'])
99+
100+
call timer_pause(id, 1)
101+
let info = timer_info(id)
102+
call assert_equal(1, info[0]['paused'])
103+
sleep 100m
104+
call assert_equal(0, g:val)
105+
106+
call timer_pause(id, 0)
107+
let info = timer_info(id)
108+
call assert_equal(0, info[0]['paused'])
109+
110+
let slept = WaitFor('g:val == 1')
111+
call assert_equal(1, g:val)
112+
call assert_inrange(0, 10, slept)
113+
endfunc
114+
55115
" vim: ts=2 sw=0 et

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,8 @@ static char *(features[]) =
763763

764764
static int included_patches[] =
765765
{ /* Add new patch number below this line */
766+
/**/
767+
2180,
766768
/**/
767769
2179,
768770
/**/

0 commit comments

Comments
 (0)