diff --git a/autoload/go/job.vim b/autoload/go/job.vim index af139d3907..abcd6bdb70 100644 --- a/autoload/go/job.vim +++ b/autoload/go/job.vim @@ -14,8 +14,6 @@ endfunction " logic. " " args is a dictionary with the these keys: -" 'cmd': -" The value to pass to job_start(). " 'bang': " Set to 0 to jump to the first error in the error list. " Defaults to 0. @@ -32,9 +30,9 @@ endfunction " 'complete': " A function to call after the job exits and the channel is closed. The " function will be passed three arguments: the job, its exit code, and the -" list of messages received from the channel. The default value will -" process the messages and manage the error list after the job exits and -" the channel is closed. +" list of messages received from the channel. The default is a no-op. A +" custom value can modify the messages before they are processed by the +" returned exit_cb and close_cb callbacks. " The return value is a dictionary with these keys: " 'callback': @@ -47,7 +45,9 @@ endfunction " A function suitable to be passed as a job close_cb handler. See " job-close_cb. " 'cwd': -" The path to the directory which contains the current buffer. +" The path to the directory which contains the current buffer. The +" callbacks are configured to expect this directory is the working +" directory for the job; it should not be modified by callers. function! go#job#Options(args) let cbs = {} let state = { @@ -185,6 +185,10 @@ function! go#job#Options(args) function state.show_errors(job, exit_status, data) let l:winid = win_getid(winnr()) + " Always set the active window to the window that was active when the job + " was started. Among other things, this makes sure that the correct + " window's location list will be populated when the list type is + " 'location' and the user has moved windows since starting the job. call win_gotoid(self.winid) let l:listtype = go#list#Type(self.for) @@ -229,17 +233,20 @@ function! go#job#Options(args) endif endfunction - if has('nvim') - return s:neooptions(cbs) - endif - return cbs endfunction +" go#job#Start runs a job. The options are expected to be the options +" suitable for Vim8 jobs. When called from Neovim, Vim8 options will be +" transformed to their Neovim equivalents. function! go#job#Start(cmd, options) let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' let l:options = copy(a:options) + if has('nvim') + let l:options = s:neooptions(l:options) + endif + if !has_key(l:options, 'cwd') " pre start let dir = getcwd() @@ -249,10 +256,11 @@ function! go#job#Start(cmd, options) if has_key(l:options, '_start') call l:options._start() " remove _start to play nicely with vim (when vim encounters an unexpected - " job option it reports an "E475: invalid argument" error. + " job option it reports an "E475: invalid argument" error). unlet l:options._start endif + if has('nvim') let l:input = [] if has_key(l:options, 'in_io') && l:options.in_io ==# 'file' && !empty(l:options.in_name) @@ -286,6 +294,11 @@ function! s:neooptions(options) let l:options['stderr_buf'] = '' for key in keys(a:options) + if key == 'cwd' + let l:options['cwd'] = a:options['cwd'] + continue + endif + if key == 'callback' let l:options['callback'] = a:options['callback'] @@ -402,5 +415,4 @@ function! s:neooptions(options) return l:options endfunction - " vim: sw=2 ts=2 et diff --git a/autoload/go/lint.vim b/autoload/go/lint.vim index ee15905006..7714b07636 100644 --- a/autoload/go/lint.vim +++ b/autoload/go/lint.vim @@ -41,7 +41,11 @@ function! go#lint#Gometa(autosave, ...) abort redraw " Include only messages for the active buffer for autosave. - let cmd += [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))] + let include = [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))] + if go#util#has_job() || has('nvim') + let include = [printf('--include=^%s:.*$', expand('%:p:t'))] + endif + let cmd += include endif " Call gometalinter asynchronously. @@ -52,7 +56,7 @@ function! go#lint#Gometa(autosave, ...) abort let cmd += goargs - if go#util#has_job() && has('lambda') + if go#util#has_job() || has('nvim') call s:lint_job({'cmd': cmd}, a:autosave) return endif @@ -193,113 +197,46 @@ function! go#lint#ToggleMetaLinterAutoSave() abort endfunction function! s:lint_job(args, autosave) - let state = { - \ 'status_dir': expand('%:p:h'), - \ 'started_at': reltime(), - \ 'messages': [], - \ 'exited': 0, - \ 'closed': 0, - \ 'exit_status': 0, - \ 'winid': win_getid(winnr()), - \ 'autosave': a:autosave - \ } - - call go#statusline#Update(state.status_dir, { - \ 'desc': "current status", - \ 'type': "gometalinter", - \ 'state': "analysing", - \}) - - " autowrite is not enabled for jobs - call go#cmd#autowrite() + let l:opts = { + \ 'statustype': "gometalinter", + \ 'errorformat': '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m', + \ 'for': "GoMetaLinter", + \ } if a:autosave - let state.listtype = go#list#Type("GoMetaLinterAutoSave") - else - let state.listtype = go#list#Type("GoMetaLinter") + let l:opts.for = "GoMetaLinterAutoSave" endif - function! s:callback(chan, msg) dict closure - call add(self.messages, a:msg) - endfunction - - function! s:exit_cb(job, exitval) dict - let self.exited = 1 - let self.exit_status = a:exitval - - let status = { - \ 'desc': 'last status', - \ 'type': "gometaliner", - \ 'state': "finished", - \ } - - if a:exitval - let status.state = "failed" - endif - - let elapsed_time = reltimestr(reltime(self.started_at)) - " strip whitespace - let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') - let status.state .= printf(" (%ss)", elapsed_time) - - call go#statusline#Update(self.status_dir, status) - - if self.closed - call self.show_errors() - endif - endfunction - - function! s:close_cb(ch) dict - let self.closed = 1 - - if self.exited - call self.show_errors() - endif - endfunction - - function state.show_errors() - let l:winid = win_getid(winnr()) - - " make sure the current window is the window from which gometalinter was - " run when the listtype is locationlist so that the location list for the - " correct window will be populated. - if self.listtype == 'locationlist' - call win_gotoid(self.winid) - endif - - let l:errorformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m' - call go#list#ParseFormat(self.listtype, l:errorformat, self.messages, 'GoMetaLinter') - - let errors = go#list#Get(self.listtype) - call go#list#Window(self.listtype, len(errors)) + let l:cbs = go#job#Options(l:opts) + if a:autosave " move to the window that was active before processing the errors, because " the user may have moved around within the window or even moved to a " different window since saving. Moving back to current window as of the " start of this function avoids the perception that the quickfix window " steals focus when linting takes a while. - if self.autosave - call win_gotoid(self.winid) - endif - if go#config#EchoCommandInfo() - call go#util#EchoSuccess("linting finished") - endif - endfunction - - " explicitly bind the callbacks to state so that self within them always - " refers to state. See :help Partial for more information. - let start_options = { - \ 'callback': funcref("s:callback", [], state), - \ 'exit_cb': funcref("s:exit_cb", [], state), - \ 'close_cb': funcref("s:close_cb", [], state), - \ } + function! s:exit_cb(next, job, exitval) + let l:winid = win_getid(winnr()) + call call(a:next, [a:job, a:exitval]) + call win_gotoid(l:winid) + endfunction + " wrap l:cbs.exit_cb in s:exit_cb. + let l:cbs.exit_cb = funcref('s:exit_cb', [l:cbs.exit_cb]) - call job_start(a:args.cmd, start_options) - - if go#config#EchoCommandInfo() - call go#util#EchoProgress("linting started ...") + function! s:close_cb(next, ch) + let l:winid = win_getid(winnr()) + call call(a:next, [a:ch]) + call win_gotoid(l:winid) + endfunction + " wrap l:cbs.close_cb in s:close_cb. + let l:cbs.close_cb = funcref('s:close_cb', [l:cbs.close_cb]) endif + + " autowrite is not enabled for jobs + call go#cmd#autowrite() + + call go#job#Start(a:args.cmd, l:cbs) endfunction " vim: sw=2 ts=2 et diff --git a/autoload/go/lint_test.vim b/autoload/go/lint_test.vim index 7432e748bd..61a14fd5ab 100644 --- a/autoload/go/lint_test.vim +++ b/autoload/go/lint_test.vim @@ -9,13 +9,6 @@ func! Test_Gometa() abort " clear the quickfix lists call setqflist([], 'r') - " call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will - " be autoloaded and the default for g:go_metalinter_enabled will be set so - " we can capture it to restore it after the test is run. - silent call go#lint#ToggleMetaLinterAutoSave() - " And restore it back to its previous value - silent call go#lint#ToggleMetaLinterAutoSave() - let g:go_metalinter_enabled = ['golint'] call go#lint#Gometa(0, $GOPATH . '/src/foo') @@ -42,13 +35,6 @@ func! Test_GometaWithDisabled() abort " clear the quickfix lists call setqflist([], 'r') - " call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will - " be autoloaded and the default for g:go_metalinter_disabled will be set so - " we can capture it to restore it after the test is run. - silent call go#lint#ToggleMetaLinterAutoSave() - " And restore it back to its previous value - silent call go#lint#ToggleMetaLinterAutoSave() - let g:go_metalinter_disabled = ['vet'] call go#lint#Gometa(0, $GOPATH . '/src/foo') @@ -77,13 +63,6 @@ func! Test_GometaAutoSave() abort " clear the location lists call setloclist(l:winnr, [], 'r') - " call go#lint#ToggleMetaLinterAutoSave from lint.vim so that the file will - " be autoloaded and the default for g:go_metalinter_autosave_enabled will be - " set so we can capture it to restore it after the test is run. - silent call go#lint#ToggleMetaLinterAutoSave() - " And restore it back to its previous value - silent call go#lint#ToggleMetaLinterAutoSave() - let g:go_metalinter_autosave_enabled = ['golint'] call go#lint#Gometa(1) diff --git a/autoload/go/util.vim b/autoload/go/util.vim index dbe390493b..49eeb87a17 100644 --- a/autoload/go/util.vim +++ b/autoload/go/util.vim @@ -61,7 +61,7 @@ endfunction " Check if Vim jobs API is supported. " -" The (optional) first paramter can be added to indicate the 'cwd' or 'env' +" The (optional) first parameter can be added to indicate the 'cwd' or 'env' " parameters will be used, which wasn't added until a later version. function! go#util#has_job(...) abort " cwd and env parameters to job_start was added in this version.