1
0
forked from aniani/vim

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().
This commit is contained in:
Bram Moolenaar
2016-08-07 18:22:53 +02:00
parent e4a76ad0e7
commit b73598e2f0
8 changed files with 161 additions and 20 deletions

View 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 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_fails({cmd} [, {error}]) none assert {cmd} fails
assert_false({actual} [, {msg}]) none assert {actual} is false assert_false({actual} [, {msg}]) none assert {actual} is false
assert_inrange({lower}, {upper}, {actual} [, {msg}]) 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_match({pat}, {text} [, {msg}]) none assert {pat} matches {text}
assert_notequal({exp}, {act} [, {msg}]) none assert {exp} is not equal {act} assert_notequal({exp}, {act} [, {msg}]) none assert {exp} is not equal {act}
assert_notmatch({pat}, {text} [, {msg}]) none assert {pat} not matches {text} 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_null_string() String null value for testing
test_settime({expr}) none set current time for testing test_settime({expr}) none set current time for testing
timer_info([{id}]) List information about timers timer_info([{id}]) List information about timers
timer_pause({id}, {pause}) none pause or unpause a timer
timer_start({time}, {callback} [, {options}]) timer_start({time}, {callback} [, {options}])
Number create a timer Number create a timer
timer_stop({timer}) none stop a timer timer_stop({timer}) none stop a timer
timer_stopall() none stop all timers
tolower({expr}) String the String {expr} switched to lowercase tolower({expr}) String the String {expr} switched to lowercase
toupper({expr}) String the String {expr} switched to uppercase toupper({expr}) String the String {expr} switched to uppercase
tr({src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr} 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 "time" time the timer was started with
"remaining" time until the timer fires "remaining" time until the timer fires
"repeat" number of times the timer will still fire; "repeat" number of times the timer will still fire;
-1 means forever -1 means forever
"callback" the callback "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()*
timer_start({time}, {callback} [, {options}]) timer_start({time}, {callback} [, {options}])
@@ -7583,6 +7603,7 @@ timer_start({time}, {callback} [, {options}])
\ {'repeat': 3}) \ {'repeat': 3})
< This will invoke MyHandler() three times at 500 msec < This will invoke MyHandler() three times at 500 msec
intervals. intervals.
{only available when compiled with the |+timers| feature} {only available when compiled with the |+timers| feature}
timer_stop({timer}) *timer_stop()* 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 {timer} is an ID returned by timer_start(), thus it must be a
Number. If {timer} does not exist there is no error. 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()* tolower({expr}) *tolower()*
The result is a copy of the String given, with all uppercase The result is a copy of the String given, with all uppercase
characters turned into lowercase (just like applying |gu| to characters turned into lowercase (just like applying |gu| to

View File

@@ -397,8 +397,10 @@ static void f_tanh(typval_T *argvars, typval_T *rettv);
#endif #endif
#ifdef FEAT_TIMERS #ifdef FEAT_TIMERS
static void f_timer_info(typval_T *argvars, typval_T *rettv); 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_start(typval_T *argvars, typval_T *rettv);
static void f_timer_stop(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 #endif
static void f_tolower(typval_T *argvars, typval_T *rettv); static void f_tolower(typval_T *argvars, typval_T *rettv);
static void f_toupper(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}, {"test_settime", 1, 1, f_test_settime},
#ifdef FEAT_TIMERS #ifdef FEAT_TIMERS
{"timer_info", 0, 1, f_timer_info}, {"timer_info", 0, 1, f_timer_info},
{"timer_pause", 2, 2, f_timer_pause},
{"timer_start", 2, 3, f_timer_start}, {"timer_start", 2, 3, f_timer_start},
{"timer_stop", 1, 1, f_timer_stop}, {"timer_stop", 1, 1, f_timer_stop},
{"timer_stopall", 0, 0, f_timer_stopall},
#endif #endif
{"tolower", 1, 1, f_tolower}, {"tolower", 1, 1, f_tolower},
{"toupper", 1, 1, f_toupper}, {"toupper", 1, 1, f_toupper},
@@ -11987,6 +11991,25 @@ f_timer_info(typval_T *argvars, typval_T *rettv)
add_timer_info_all(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 * "timer_start(time, callback [, options])" function
*/ */
@@ -12048,6 +12071,15 @@ f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
if (timer != NULL) if (timer != NULL)
stop_timer(timer); stop_timer(timer);
} }
/*
* "timer_stopall()" function
*/
static void
f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
{
stop_all_timers();
}
#endif #endif
/* /*

View File

@@ -1189,6 +1189,8 @@ check_due_timer(void)
next_due = -1; next_due = -1;
for (timer = first_timer; timer != NULL; timer = timer->tr_next) for (timer = first_timer; timer != NULL; timer = timer->tr_next)
{ {
if (timer->tr_paused)
continue;
# ifdef WIN3264 # ifdef WIN3264
this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart) this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
/ (double)fr.QuadPart) * 1000); / (double)fr.QuadPart) * 1000);
@@ -1251,6 +1253,15 @@ stop_timer(timer_T *timer)
free_timer(timer); free_timer(timer);
} }
void
stop_all_timers(void)
{
timer_T *timer;
while (first_timer != NULL)
stop_timer(first_timer);
}
void void
add_timer_info(typval_T *rettv, timer_T *timer) 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", dict_add_nr_str(dict, "repeat",
(long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL); (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"); di = dictitem_alloc((char_u *)"callback");
if (di != NULL) if (di != NULL)

View File

@@ -22,6 +22,7 @@ timer_T *create_timer(long msec, int repeat);
long check_due_timer(void); long check_due_timer(void);
timer_T *find_timer(int id); timer_T *find_timer(int id);
void stop_timer(timer_T *timer); 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(typval_T *rettv, timer_T *timer);
void add_timer_info_all(typval_T *rettv); void add_timer_info_all(typval_T *rettv);
int set_ref_in_timer(int copyID); int set_ref_in_timer(int copyID);

View File

@@ -3159,6 +3159,7 @@ struct timer_S
timer_T *tr_next; timer_T *tr_next;
timer_T *tr_prev; timer_T *tr_prev;
proftime_T tr_due; /* when the callback is to be invoked */ 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 */ int tr_repeat; /* number of times to repeat, -1 forever */
long tr_interval; /* msec */ long tr_interval; /* msec */
char_u *tr_callback; /* allocated */ char_u *tr_callback; /* allocated */

View File

@@ -109,14 +109,17 @@ func s:kill_server(cmd)
endfunc endfunc
" Wait for up to a second for "expr" to become true. " Wait for up to a second for "expr" to become true.
" Return time slept in milliseconds.
func WaitFor(expr) func WaitFor(expr)
let slept = 0
for i in range(100) for i in range(100)
try try
if eval(a:expr) if eval(a:expr)
return return slept
endif endif
catch catch
endtry endtry
let slept += 10
sleep 10m sleep 10m
endfor endfor
endfunc endfunc

View File

@@ -1,11 +1,13 @@
" Test for timers " Test for timers
source shared.vim
if !has('timers') if !has('timers')
finish finish
endif endif
func MyHandler(timer) func MyHandler(timer)
let s:val += 1 let g:val += 1
endfunc endfunc
func MyHandlerWithLists(lists, timer) func MyHandlerWithLists(lists, timer)
@@ -13,43 +15,101 @@ func MyHandlerWithLists(lists, timer)
endfunc endfunc
func Test_oneshot() func Test_oneshot()
let s:val = 0 let g:val = 0
let timer = timer_start(50, 'MyHandler') let timer = timer_start(50, 'MyHandler')
sleep 200m let slept = WaitFor('g:val == 1')
call assert_equal(1, s:val) call assert_equal(1, g:val)
call assert_inrange(30, 100, slept)
endfunc endfunc
func Test_repeat_three() func Test_repeat_three()
let s:val = 0 let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': 3}) let timer = timer_start(50, 'MyHandler', {'repeat': 3})
sleep 500m let slept = WaitFor('g:val == 3')
call assert_equal(3, s:val) call assert_equal(3, g:val)
call assert_inrange(100, 250, slept)
endfunc endfunc
func Test_repeat_many() func Test_repeat_many()
let s:val = 0 let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': -1}) let timer = timer_start(50, 'MyHandler', {'repeat': -1})
sleep 200m sleep 200m
call timer_stop(timer) call timer_stop(timer)
call assert_true(s:val > 1) call assert_inrange(2, 4, g:val)
call assert_true(s:val < 5)
endfunc endfunc
func Test_with_partial_callback() func Test_with_partial_callback()
let s:val = 0 let g:val = 0
let s:meow = {} let s:meow = {}
function s:meow.bite(...) function s:meow.bite(...)
let s:val += 1 let g:val += 1
endfunction endfunction
call timer_start(50, s:meow.bite) call timer_start(50, s:meow.bite)
sleep 200m let slept = WaitFor('g:val == 1')
call assert_equal(1, s:val) call assert_equal(1, g:val)
call assert_inrange(30, 100, slept)
endfunc endfunc
func Test_retain_partial() func Test_retain_partial()
call timer_start(100, function('MyHandlerWithLists', [['a']])) call timer_start(50, function('MyHandlerWithLists', [['a']]))
call test_garbagecollect_now() call test_garbagecollect_now()
sleep 200m sleep 100m
endfunc 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: ts=2 sw=0 et

View File

@@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2180,
/**/ /**/
2179, 2179,
/**/ /**/