Skip to content

Commit b095c56

Browse files
committed
lint: make gopls diagnostics visible
Add a new command, `:GoDiagnostics`, to display the LSP diagnostics for packages. Teach :GoMetaLinter to display LSP diagnostics when g:go_metalinter_command == 'gopls'. Closes #2538
1 parent 9262f08 commit b095c56

File tree

8 files changed

+328
-77
lines changed

8 files changed

+328
-77
lines changed

autoload/go/lint.vim

+81-19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ function! go#lint#Gometa(bang, autosave, ...) abort
1111

1212
let l:metalinter = go#config#MetalinterCommand()
1313

14+
let cmd = []
1415
if l:metalinter == 'golangci-lint'
1516
let cmd = s:metalintercmd(l:metalinter)
1617
if empty(cmd)
@@ -22,7 +23,7 @@ function! go#lint#Gometa(bang, autosave, ...) abort
2223
for linter in linters
2324
let cmd += ["--enable=".linter]
2425
endfor
25-
else
26+
elseif l:metalinter != 'gopls'
2627
" the user wants something else, let us use it.
2728
let cmd = split(go#config#MetalinterCommand(), " ")
2829
endif
@@ -45,17 +46,35 @@ function! go#lint#Gometa(bang, autosave, ...) abort
4546

4647
let cmd += goargs
4748

48-
" Golangci-lint can output the following:
49-
" <file>:<line>:<column>: <message> (<linter>)
50-
" This can be defined by the following errorformat:
51-
let errformat = "%f:%l:%c:\ %m"
49+
let errformat = s:errorformat(l:metalinter)
5250

53-
if go#util#has_job()
54-
call s:lint_job({'cmd': cmd, 'statustype': l:metalinter, 'errformat': errformat}, a:bang, a:autosave)
55-
return
56-
endif
51+
if l:metalinter == 'gopls'
52+
if a:autosave
53+
let l:messages = go#lsp#AnalyzeFile(expand('%:p'))
54+
else
55+
let l:import_paths = l:goargs
56+
if len(l:import_paths) == 0
57+
let l:pkg = go#package#ImportPath()
58+
if l:pkg == -1
59+
call go#util#EchoError('could not determine package name')
60+
return
61+
endif
62+
63+
let l:import_paths = [l:pkg]
64+
endif
65+
let l:messages = call('go#lsp#Diagnostics', l:import_paths)
66+
endif
67+
68+
let l:err = len(l:messages)
69+
else
70+
if go#util#has_job()
71+
call s:lint_job({'cmd': cmd, 'statustype': l:metalinter, 'errformat': errformat}, a:bang, a:autosave)
72+
return
73+
endif
5774

58-
let [l:out, l:err] = go#util#Exec(cmd)
75+
let [l:out, l:err] = go#util#Exec(cmd)
76+
let l:messages = split(out, "\n")
77+
endif
5978

6079
if a:autosave
6180
let l:listtype = go#list#Type("GoMetaLinterAutoSave")
@@ -70,9 +89,7 @@ function! go#lint#Gometa(bang, autosave, ...) abort
7089
let l:winid = win_getid(winnr())
7190
" Parse and populate our location list
7291

73-
let l:messages = split(out, "\n")
74-
75-
if a:autosave
92+
if a:autosave && l:metalinter != 'gopls'
7693
call s:metalinterautosavecomplete(fnamemodify(expand('%:p'), ":."), 0, 1, l:messages)
7794
endif
7895
call go#list#ParseFormat(l:listtype, errformat, l:messages, 'GoMetaLinter')
@@ -88,6 +105,44 @@ function! go#lint#Gometa(bang, autosave, ...) abort
88105
endif
89106
endfunction
90107

108+
function! go#lint#Diagnostics(bang, ...) abort
109+
if a:0 == 0
110+
let l:pkg = go#package#ImportPath()
111+
if l:pkg == -1
112+
call go#util#EchoError('could not determine package name')
113+
return
114+
endif
115+
116+
let l:import_paths = [l:pkg]
117+
else
118+
let l:import_paths = a:000
119+
endif
120+
121+
let errformat = s:errorformat('gopls')
122+
123+
let l:messages = call('go#lsp#Diagnostics', l:import_paths)
124+
125+
let l:listtype = go#list#Type("GoDiagnostics")
126+
127+
if len(l:messages) == 0
128+
call go#list#Clean(l:listtype)
129+
call go#util#EchoSuccess('[diagnostics] PASS')
130+
else
131+
" Parse and populate the quickfix list
132+
let l:winid = win_getid(winnr())
133+
call go#list#ParseFormat(l:listtype, errformat, l:messages, 'GoDiagnostics')
134+
135+
let errors = go#list#Get(l:listtype)
136+
call go#list#Window(l:listtype, len(errors))
137+
138+
if a:bang
139+
call win_gotoid(l:winid)
140+
return
141+
endif
142+
call go#list#JumpToFirst(l:listtype)
143+
endif
144+
endfunction
145+
91146
" Golint calls 'golint' on the current directory. Any warnings are populated in
92147
" the location list
93148
function! go#lint#Golint(bang, ...) abort
@@ -275,18 +330,25 @@ function! s:metalinterautosavecomplete(filepath, job, exit_code, messages)
275330

276331
let l:idx = len(a:messages) - 1
277332
while l:idx >= 0
278-
" Go 1.13 changed how go vet output is formatted by prepending a leading
279-
" 'vet :', so account for that, too. This function isn't really needed for
280-
" gometalinter at all, so the check for Go 1.13's go vet output shouldn't
281-
" be neeeded, but s:lint_job hooks this up even when the
282-
" g:go_metalinter_command is golangci-lint.
283-
if a:messages[l:idx] !~# '^' . a:filepath . ':' && a:messages[l:idx] !~# '^vet: \.[\\/]' . a:filepath . ':'
333+
if a:messages[l:idx] !~# '^' . a:filepath . ':'
284334
call remove(a:messages, l:idx)
285335
endif
286336
let l:idx -= 1
287337
endwhile
288338
endfunction
289339

340+
function! s:errorformat(metalinter) abort
341+
if a:metalinter == 'golangci-lint'
342+
" Golangci-lint can output the following:
343+
" <file>:<line>:<column>: <message> (<linter>)
344+
" This can be defined by the following errorformat:
345+
return '%f:%l:%c:\ %m'
346+
elseif a:metalinter == 'gopls'
347+
return '%f:%l:%c:%t:\ %m,%f:%l:%c::\ %m'
348+
endif
349+
350+
endfunction
351+
290352
" restore Vi compatibility settings
291353
let &cpo = s:cpo_save
292354
unlet s:cpo_save

autoload/go/list.vim

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ endfunction
135135
" in g:go_list_type_commands.
136136
let s:default_list_type_commands = {
137137
\ "GoBuild": "quickfix",
138+
\ "GoDiagnostics": "quickfix",
138139
\ "GoDebug": "quickfix",
139140
\ "GoErrCheck": "quickfix",
140141
\ "GoFmt": "locationlist",

0 commit comments

Comments
 (0)