From 17c03852f35d594e3fe7f23073fae91cc775886d Mon Sep 17 00:00:00 2001 From: guns Date: Mon, 11 Sep 2017 14:19:24 -0500 Subject: [PATCH] Parse messages from guru on close_cb, not exit_cb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a race condition in `async_guru` in which not all messages from a `guru` call are displayed: 1. An async `guru` call is started. 2. Lines streamed from `guru` are appended to a message list in `callback()`. 3. The `guru` process ends, `exit_cb()` is called, and the list of messages is processed for display. 4. The rest of the lines from `guru` are appended to the message list. Note that `callback` may still be called after `exit_cb`, as noted in `:help exit_cb`: "exit_cb": handler … Note that data can be buffered, callbacks may still be called after the process ends. This race was recently exposed by [Vim v8.0.1073][vim], which avoids a redraw after statusline evaluation changes a highlight. Since vim-go modifies the goStatusLineColor highlight definition on async calls, the corresponding redraw acted as a delay, masking this data race. The solution to this problem is to process `guru` output in `close_cb`, which is called after all `callback` calls are complete. [vim]: https://github.com/vim/vim/commit/ba2929b6afd2fc20479912a8dec789be26a38244 --- autoload/go/guru.vim | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/autoload/go/guru.vim b/autoload/go/guru.vim index fbd36110de..d64cd8fa1f 100644 --- a/autoload/go/guru.vim +++ b/autoload/go/guru.vim @@ -159,9 +159,10 @@ function! s:async_guru(args) abort call add(messages, a:msg) endfunction - function! s:exit_cb(job, exitval) closure - let out = join(messages, "\n") + let status = {} + let exitval = 0 + function! s:exit_cb(job, exitval) closure let status = { \ 'desc': 'last status', \ 'type': statusline_type, @@ -169,21 +170,27 @@ function! s:async_guru(args) abort \ } if a:exitval + let exitval = a:exitval let status.state = "failed" endif call go#statusline#Update(status_dir, status) + endfunction + + function! s:close_cb(ch) closure + let out = join(messages, "\n") if has_key(a:args, 'custom_parse') - call a:args.custom_parse(a:exitval, out) + call a:args.custom_parse(exitval, out) else - call s:parse_guru_output(a:exitval, out, a:args.mode) + call s:parse_guru_output(exitval, out, a:args.mode) endif endfunction let start_options = { \ 'callback': funcref("s:callback"), \ 'exit_cb': funcref("s:exit_cb"), + \ 'close_cb': funcref("s:close_cb"), \ } if has_key(result, 'stdin_content')