2015-12-08 08:20:04 -05:00
|
|
|
function! go#lint#Gometa(autosave, ...) abort
|
2016-06-26 07:12:36 -04:00
|
|
|
if a:0 == 0
|
2018-02-04 06:35:08 -05:00
|
|
|
let goargs = [expand('%:p:h')]
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
2018-02-04 06:35:08 -05:00
|
|
|
let goargs = a:000
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
|
|
|
|
2016-12-27 09:46:49 -05:00
|
|
|
let bin_path = go#path#CheckBinPath("gometalinter")
|
|
|
|
if empty(bin_path)
|
|
|
|
return
|
|
|
|
endif
|
2015-12-08 08:20:04 -05:00
|
|
|
|
2016-12-27 09:46:49 -05:00
|
|
|
let cmd = [bin_path]
|
|
|
|
let cmd += ["--disable-all"]
|
2015-12-08 08:20:04 -05:00
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
if a:autosave || empty(go#config#MetalinterCommand())
|
2016-06-26 07:12:36 -04:00
|
|
|
" linters
|
2018-06-14 06:31:12 -04:00
|
|
|
let linters = a:autosave ? go#config#MetalinterAutosaveEnabled() : go#config#MetalinterEnabled()
|
2016-06-26 07:12:36 -04:00
|
|
|
for linter in linters
|
2016-12-27 09:46:49 -05:00
|
|
|
let cmd += ["--enable=".linter]
|
2016-06-26 07:12:36 -04:00
|
|
|
endfor
|
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
for linter in go#config#MetalinterDisabled()
|
2018-02-04 06:35:08 -05:00
|
|
|
let cmd += ["--disable=".linter]
|
2017-05-02 08:42:08 -04:00
|
|
|
endfor
|
|
|
|
|
2017-11-24 08:54:40 -05:00
|
|
|
" gometalinter has a --tests flag to tell its linters whether to run
|
|
|
|
" against tests. While not all of its linters respect this flag, for those
|
|
|
|
" that do, it means if we don't pass --tests, the linter won't run against
|
|
|
|
" test files. One example of a linter that will not run against tests if
|
|
|
|
" we do not specify this flag is errcheck.
|
|
|
|
let cmd += ["--tests"]
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
|
|
|
" the user wants something else, let us use it.
|
2018-06-14 06:31:12 -04:00
|
|
|
let cmd += split(go#config#MetalinterCommand(), " ")
|
2016-12-27 09:46:49 -05:00
|
|
|
endif
|
|
|
|
|
2018-02-04 06:35:08 -05:00
|
|
|
if a:autosave
|
|
|
|
" redraw so that any messages that were displayed while writing the file
|
|
|
|
" will be cleared
|
|
|
|
redraw
|
|
|
|
|
|
|
|
" Include only messages for the active buffer for autosave.
|
2018-08-25 12:13:42 -04:00
|
|
|
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
|
2018-02-04 06:35:08 -05:00
|
|
|
endif
|
|
|
|
|
2017-02-11 08:01:38 -05:00
|
|
|
" Call gometalinter asynchronously.
|
2018-06-14 06:31:12 -04:00
|
|
|
let deadline = go#config#MetalinterDeadline()
|
|
|
|
if deadline != ''
|
|
|
|
let cmd += ["--deadline=" . deadline]
|
|
|
|
endif
|
2017-02-11 08:01:38 -05:00
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
let cmd += goargs
|
2018-02-04 06:35:08 -05:00
|
|
|
|
2018-08-25 12:13:42 -04:00
|
|
|
if go#util#has_job() || has('nvim')
|
2018-02-04 06:35:08 -05:00
|
|
|
call s:lint_job({'cmd': cmd}, a:autosave)
|
2016-12-27 09:46:49 -05:00
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2018-02-04 06:35:08 -05:00
|
|
|
let [l:out, l:err] = go#util#Exec(cmd)
|
2016-12-27 09:46:49 -05:00
|
|
|
|
2018-02-04 06:35:08 -05:00
|
|
|
if a:autosave
|
|
|
|
let l:listtype = go#list#Type("GoMetaLinterAutoSave")
|
|
|
|
else
|
|
|
|
let l:listtype = go#list#Type("GoMetaLinter")
|
|
|
|
endif
|
2016-06-26 07:12:36 -04:00
|
|
|
|
2018-02-04 06:35:08 -05:00
|
|
|
if l:err == 0
|
2016-06-26 07:12:36 -04:00
|
|
|
call go#list#Clean(l:listtype)
|
|
|
|
echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None
|
|
|
|
else
|
|
|
|
" GoMetaLinter can output one of the two, so we look for both:
|
|
|
|
" <file>:<line>:[<column>]: <message> (<linter>)
|
|
|
|
" <file>:<line>:: <message> (<linter>)
|
|
|
|
" This can be defined by the following errorformat:
|
|
|
|
let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m"
|
|
|
|
|
|
|
|
" Parse and populate our location list
|
2016-12-27 09:46:49 -05:00
|
|
|
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter')
|
2016-06-26 07:12:36 -04:00
|
|
|
|
|
|
|
let errors = go#list#Get(l:listtype)
|
|
|
|
call go#list#Window(l:listtype, len(errors))
|
|
|
|
|
|
|
|
if !a:autosave
|
|
|
|
call go#list#JumpToFirst(l:listtype)
|
2015-12-08 08:20:04 -05:00
|
|
|
endif
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
2015-12-08 08:20:04 -05:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Golint calls 'golint' on the current directory. Any warnings are populated in
|
|
|
|
" the location list
|
|
|
|
function! go#lint#Golint(...) abort
|
2016-06-26 07:12:36 -04:00
|
|
|
if a:0 == 0
|
2018-06-14 06:31:12 -04:00
|
|
|
let [l:out, l:err] = go#util#Exec([go#config#GolintBin(), go#package#ImportPath()])
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
2018-06-14 06:31:12 -04:00
|
|
|
let [l:out, l:err] = go#util#Exec([go#config#GolintBin()] + a:000)
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
if empty(l:out)
|
|
|
|
call go#util#EchoSuccess('[lint] PASS')
|
2016-06-26 07:12:36 -04:00
|
|
|
return
|
|
|
|
endif
|
|
|
|
|
2017-11-24 08:54:40 -05:00
|
|
|
let l:listtype = go#list#Type("GoLint")
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#list#Parse(l:listtype, l:out, "GoLint")
|
|
|
|
let l:errors = go#list#Get(l:listtype)
|
|
|
|
call go#list#Window(l:listtype, len(l:errors))
|
2016-06-26 07:12:36 -04:00
|
|
|
call go#list#JumpToFirst(l:listtype)
|
2015-12-08 08:20:04 -05:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
" Vet calls 'go vet' on the current directory. Any warnings are populated in
|
|
|
|
" the location list
|
2016-12-27 09:46:49 -05:00
|
|
|
function! go#lint#Vet(bang, ...) abort
|
2016-06-26 07:12:36 -04:00
|
|
|
call go#cmd#autowrite()
|
2018-06-14 06:31:12 -04:00
|
|
|
|
|
|
|
call go#util#EchoProgress('calling vet...')
|
|
|
|
|
2016-06-26 07:12:36 -04:00
|
|
|
if a:0 == 0
|
2018-06-14 06:31:12 -04:00
|
|
|
let [l:out, l:err] = go#util#Exec(['go', 'vet', go#package#ImportPath()])
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
2018-06-14 06:31:12 -04:00
|
|
|
let [l:out, l:err] = go#util#Exec(['go', 'tool', 'vet'] + a:000)
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
|
|
|
|
2017-11-24 08:54:40 -05:00
|
|
|
let l:listtype = go#list#Type("GoVet")
|
2018-06-14 06:31:12 -04:00
|
|
|
if l:err != 0
|
|
|
|
let errorformat = "%-Gexit status %\\d%\\+," . &errorformat
|
2018-03-31 10:56:26 -04:00
|
|
|
call go#list#ParseFormat(l:listtype, l:errorformat, out, "GoVet")
|
|
|
|
let errors = go#list#Get(l:listtype)
|
2016-06-26 07:12:36 -04:00
|
|
|
call go#list#Window(l:listtype, len(errors))
|
|
|
|
if !empty(errors) && !a:bang
|
|
|
|
call go#list#JumpToFirst(l:listtype)
|
2015-12-08 08:20:04 -05:00
|
|
|
endif
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#util#EchoError('[vet] FAIL')
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
|
|
|
call go#list#Clean(l:listtype)
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#util#EchoSuccess('[vet] PASS')
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
2014-10-31 17:30:24 -04:00
|
|
|
endfunction
|
|
|
|
|
2015-12-08 08:20:04 -05:00
|
|
|
" ErrCheck calls 'errcheck' for the given packages. Any warnings are populated in
|
|
|
|
" the location list
|
|
|
|
function! go#lint#Errcheck(...) abort
|
2016-06-26 07:12:36 -04:00
|
|
|
if a:0 == 0
|
2018-06-14 06:31:12 -04:00
|
|
|
let l:import_path = go#package#ImportPath()
|
2017-07-06 08:57:35 -04:00
|
|
|
if import_path == -1
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#util#EchoError('package is not inside GOPATH src')
|
2016-06-26 07:12:36 -04:00
|
|
|
return
|
2015-12-08 08:20:04 -05:00
|
|
|
endif
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
2018-06-14 06:31:12 -04:00
|
|
|
let l:import_path = join(a:000, ' ')
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
2015-12-08 08:20:04 -05:00
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#util#EchoProgress('[errcheck] analysing ...')
|
2016-06-26 07:12:36 -04:00
|
|
|
redraw
|
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
let [l:out, l:err] = go#util#Exec([go#config#ErrcheckBin(), '-abspath', l:import_path])
|
2016-06-26 07:12:36 -04:00
|
|
|
|
2017-11-24 08:54:40 -05:00
|
|
|
let l:listtype = go#list#Type("GoErrCheck")
|
2018-06-14 06:31:12 -04:00
|
|
|
if l:err != 0
|
2016-06-26 07:12:36 -04:00
|
|
|
let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m"
|
|
|
|
|
|
|
|
" Parse and populate our location list
|
2016-12-27 09:46:49 -05:00
|
|
|
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'Errcheck')
|
2016-06-26 07:12:36 -04:00
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
let l:errors = go#list#Get(l:listtype)
|
|
|
|
if empty(l:errors)
|
|
|
|
call go#util#EchoError(l:out)
|
2016-06-26 07:12:36 -04:00
|
|
|
return
|
2015-12-08 08:20:04 -05:00
|
|
|
endif
|
|
|
|
|
2016-06-26 07:12:36 -04:00
|
|
|
if !empty(errors)
|
2016-12-27 09:46:49 -05:00
|
|
|
call go#list#Populate(l:listtype, errors, 'Errcheck')
|
2016-06-26 07:12:36 -04:00
|
|
|
call go#list#Window(l:listtype, len(errors))
|
|
|
|
if !empty(errors)
|
|
|
|
call go#list#JumpToFirst(l:listtype)
|
|
|
|
endif
|
2015-12-08 08:20:04 -05:00
|
|
|
endif
|
2016-06-26 07:12:36 -04:00
|
|
|
else
|
|
|
|
call go#list#Clean(l:listtype)
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#util#EchoSuccess('[errcheck] PASS')
|
2016-06-26 07:12:36 -04:00
|
|
|
endif
|
2015-12-08 08:20:04 -05:00
|
|
|
endfunction
|
2014-10-31 17:30:24 -04:00
|
|
|
|
2016-12-27 09:46:49 -05:00
|
|
|
function! go#lint#ToggleMetaLinterAutoSave() abort
|
2018-06-14 06:31:12 -04:00
|
|
|
if go#config#MetalinterAutosave()
|
|
|
|
call go#config#SetMetalinterAutosave(0)
|
2016-08-02 08:48:32 -04:00
|
|
|
call go#util#EchoProgress("auto metalinter disabled")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-06-14 06:31:12 -04:00
|
|
|
call go#config#SetMetalinterAutosave(1)
|
2016-08-02 08:48:32 -04:00
|
|
|
call go#util#EchoProgress("auto metalinter enabled")
|
|
|
|
endfunction
|
|
|
|
|
2018-02-04 06:35:08 -05:00
|
|
|
function! s:lint_job(args, autosave)
|
2018-08-25 12:13:42 -04:00
|
|
|
let l:opts = {
|
|
|
|
\ 'statustype': "gometalinter",
|
|
|
|
\ 'errorformat': '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m',
|
|
|
|
\ 'for': "GoMetaLinter",
|
|
|
|
\ }
|
2016-12-27 09:46:49 -05:00
|
|
|
|
2018-02-04 06:35:08 -05:00
|
|
|
if a:autosave
|
2018-08-25 12:13:42 -04:00
|
|
|
let l:opts.for = "GoMetaLinterAutoSave"
|
2018-02-04 06:35:08 -05:00
|
|
|
endif
|
2016-12-27 09:46:49 -05:00
|
|
|
|
2018-08-25 12:13:42 -04:00
|
|
|
let l:cbs = go#job#Options(l:opts)
|
2018-03-31 10:56:26 -04:00
|
|
|
|
2018-08-25 12:13:42 -04:00
|
|
|
if a:autosave
|
2018-03-31 10:56:26 -04:00
|
|
|
" 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.
|
2016-12-27 09:46:49 -05:00
|
|
|
|
2018-08-25 12:13:42 -04:00
|
|
|
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])
|
2016-12-27 09:46:49 -05:00
|
|
|
|
2018-08-25 12:13:42 -04:00
|
|
|
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])
|
2016-12-27 09:46:49 -05:00
|
|
|
endif
|
2018-08-25 12:13:42 -04:00
|
|
|
|
|
|
|
" autowrite is not enabled for jobs
|
|
|
|
call go#cmd#autowrite()
|
|
|
|
|
|
|
|
call go#job#Start(a:args.cmd, l:cbs)
|
2016-12-27 09:46:49 -05:00
|
|
|
endfunction
|
|
|
|
|
2016-06-26 07:12:36 -04:00
|
|
|
" vim: sw=2 ts=2 et
|