2

I just started to use Vim 8 and I'm trying to figure out how to use the async mechanism: timer_start.

As my understanding, timer_start allows us to run a job asynchronously and repeatly.

I have two questions on it:

  1. Need I care about the resource issue?

    Saying that I want to start a job, which needs to be executed only once. So I may code like this:

    timer_start(10, 'MyCustomFunc')
    

    Which means that after 10 milliseconds, MyCustomFunc will be called only once.

In this case, need I explicitly call the function timer_stop to stop this job? If not, will it cause some resource issue? For example, some resource may not be released because of non-calling timer_stop?

  1. I just read this link: https://laravel-news.com/vim-8-0-is-released and I got this example:

    let tempTimer = timer_start(4000, function('CheckTemp', ['out']))
    

    This link said: This will call CheckTemp(‘out’) four seconds later.

    OK, it seems that everything is fine.

    But in the doc of Vim, I got this:

timer_start({time}, {callback} [, {options}])

Create a timer and return the timer ID.

{time} is the waiting time in milliseconds. This is the minimum time before invoking the callback. When the system is busy or Vim is not waiting for input the time will be longer.

{callback} is the function to call. It can be the name of a function or a |Funcref|. It is called with one argument, which is the timer ID. The callback is only invoked when Vim is waiting for input.

As my understanding, {callback} is a function, which takes one argument, which is the timer ID.

Now I'm confused. In the example above, if I'm right, function('CheckTemp', ['out']) is a functor/lambda, which will invoke the function CheckTemp('out'). It doesn't seem that there is a function, which takes one argument which is the timer ID.

So what did I misunderstand here?

About the second question

With the help of Jake Grossman, I just did a test as below:

function! MyTest(...) abort
    echo a:000
endfunction

function! CustomGrep(...) abort
    call timer_start(0, function('MyTest', ['xxx']))
endfunction
    
command! -nargs=? Grep :call CustomGrep(<f-args>)

When I execute :Grep in my Vim, I can see the output: ['xxx', 18]. So the job ID 18 is passed to the function MyTest as the second parameter.

I can understand that now.

But how about labmda? if I change the function CustomGrep as below:

function! CustomGrep(...) abort
    call timer_start(0, {-> call(function('MyTest'), ['xxx'])})
endfunction

and now if I execute :Grep in my Vim, the output becomes ['xxx']. So where is the job ID in this case?

1 Answer 1

2

Tested on Vim Version: 8.2.1537

Response:

  1. A timer's resources will be freed on one of three conditions:

    • the timer_stop() function in Vim is called, invoking it's counterpart stop_timer() in the C source.1
    • after invoking the callback function, there are no repetitions left for the timer, upon which free_timer() is invoked.2
    • the timer has encountered an error three times in a row (this is done to prevent Vim from becoming unresponsive/unusable due to error messages).3
  2. function() calls can be nested, so even though the the Funcref itself is called with a single parameter (the timer ID), it may be a Partial created by another function() call, binding an arglist or a dictionary to it as well.

See:

:h timer_stop()
:h Funcref
:h Partial
:h function()
9
  • 1
    For the second question, I don't quite understand what you meant. Let's use the example above: timer_start(4000, function('CheckTemp', ['out'])). In this example, IMHO, it will just call the function CheckTemp('out'), am I right? I don't konw where the job ID is. In a word, I thought the function must be like this: CheckoutTemp(jobID), which is not at all.
    – Yves
    Commented Aug 29, 2020 at 7:28
  • 1
    Great. I just re-edited my post. That proved that you were right. But I got another question: if I use lambda, instead of function(), where is the job ID?
    – Yves
    Commented Aug 29, 2020 at 8:18
  • 1
    It sounded fishy to me that Vim would keep timer entries around and burden the programmer with the need to free them so I took a look. free_timer() is also called from check_due_timer() after a timer is fired if it doesn't have any repeats remaining.
    – B Layer
    Commented Aug 29, 2020 at 19:56
  • 1
    Also, if it had been required they didn't document it which would have been an egregious mistake. It's hard to imagine they'd make it (especially this long after release)
    – B Layer
    Commented Aug 29, 2020 at 20:08
  • 1
    Great, I can freely use lambda now.
    – Yves
    Commented Aug 30, 2020 at 14:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.