I have a job I want to run in the background of vim, and update my status line with the periodic results of that job.

I'm able to setup the timer, call the external job and get my response back. I'm able to echom the response and see it in :messages.

I am unable to get my global variable to take hold of the new value though.

Here is the vimscript:

let g:please_vim_why = 'an echo example'
let g:why_vim_why = -1
function! TimerRun(timer)
  call jobstart('date', {'on_stdout': 'TimerCallback'})
function! TimerCallback(j, d, e)
  echom a:d[0]
  let g:why_vim_why = a:d[0]
let timer = timer_start(2000, 'TimerRun', {'repeat': -1})

Run via nvim -u godwhyvimwhydoyouhateme.vim to load it as your vimrc.

Now if you go :echo g:please_vim_why, you'll see the response, 'an echo example'.

If you run :messages, you'll see a repeated output of the date.

If you run :echo g:why_vim_why you will see no output.

I thought maybe it might be a:d is scoped and gets garbage collected after the function, but let g:why_vim_why = 'not a good joke' . a:d[0], sets the variable to 'not a good joke' but doesn't concatenate anything.

Why VIM? Why?

  • Nice detailed question with a minimum working example. +1 I observe the same behaviour in neovim 0.3.4 when I test your example, but don't know either why this is happening. – swalladge Feb 10 at 4:48
  • So you think it's not the code at fault? I can't figure why it wouldn't work, perhaps I should create an issue on GH? Vimscript is awkward to use though so I'm first leaning towards me not understanding it. – purplelulu Feb 10 at 5:07
  • 2
    This seems to be neovim only. In Vim the example works as expected (slightly different syntax, like job_start instead of jobstart). – Ralf Feb 10 at 8:37
  • BTW: You should not crosspost. See FAQ – Ralf Feb 10 at 9:25
  • 1
    @purplelulu it would probably be worth it to raise an issue on the neovim github, seeing as it appears to be a neovim only issue as Ralf pointed out. – swalladge Feb 10 at 11:18

The on_stdout callback will be called twice for each execution of date in this example.

First it will be called with the result from date as an array with two elements ['the-date', ''] where '' is an artifact of the newline output by date. (If you run a job such as echo -n "no new line", you'd only receive ['no new line'].

Second it will be called with [''] to signal EOF on stdout.

The second call is clobbering the first, which makes it appear as if the result is going missing somehow.

You can either check the length of the argument (i.e. if len(a:d[0])...) or pass the option 'stdout_buffered': 1 to jobstart to only receive output when all output from the command is collected.

All this is explained in :h on_stdout.

  • 1
    Glad to see you were able to fix your problem! I’ve edited the last sentence a bit to be less snarky for future readers, in the hope that it will make things feel more welcoming. Great answer! – D. Ben Knoble Feb 10 at 16:15
  • Great job troubleshooting this one! – filbranden Feb 10 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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