Skip to content

Commit 0eff026

Browse files
committed
coverage: improvements and integration into vim-go
1 parent f92fac2 commit 0eff026

File tree

11 files changed

+269
-265
lines changed

11 files changed

+269
-265
lines changed

Gemfile

-3
This file was deleted.

README.md

-9
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ People have asked for this for a long time, now you can be a fully supporter by
5757

5858
[https://www.patreon.com/fatih](https://www.patreon.com/fatih)
5959

60-
![ss-vim-go-coverlay](https://cloud.githubusercontent.com/assets/3804806/5319001/81a3b89a-7ce8-11e4-9fbd-2f0fd00ce1c7.gif)
61-
6260
## Install
6361

6462
Vim-go follows the standard runtime path structure, so I highly recommend to
@@ -219,15 +217,8 @@ By default when `:GoInstallBinaries` is called, the binaries are installed to
219217
`$GOBIN` or `$GOPATH/bin`. To change it:
220218

221219
```vim
222-
<<<<<<< HEAD
223220
let g:go_bin_path = expand("~/.gotools")
224221
let g:go_bin_path = "/home/fatih/.mypath" "or give absolute path
225-
=======
226-
au FileType go nmap <leader>c <Plug>(go-coverlay) "test coverage then overlay covered lines
227-
au FileType go nmap <leader>C <Plug>(go-clearlay) "clear overlay
228-
229-
au BufWritePost *.go call go#coverlay#Coverlay() "run test and cover on file save
230-
>>>>>>> 70c8cf8... code cleanup
231222
```
232223

233224
### Using with Neovim (beta)

autoload/go/cmd.vim

-41
Original file line numberDiff line numberDiff line change
@@ -290,47 +290,6 @@ function! go#cmd#TestFunc(bang, ...)
290290
call call('go#cmd#Test', args)
291291
endfunction
292292

293-
let s:coverage_handler_id = ''
294-
let s:coverage_handler_jobs = {}
295-
296-
function! s:coverage_handler(job, exit_status, data)
297-
if !has_key(s:coverage_handler_jobs, a:job.id)
298-
return
299-
endif
300-
let l:tmpname = s:coverage_handler_jobs[a:job.id]
301-
if a:exit_status == 0
302-
let openHTML = 'go tool cover -html='.l:tmpname
303-
call go#tool#ExecuteInDir(openHTML)
304-
endif
305-
call delete(l:tmpname)
306-
unlet s:coverage_handler_jobs[a:job.id]
307-
endfunction
308-
309-
" Coverage creates a new cover profile with 'go test -coverprofile' and opens
310-
" a new HTML coverage page from that profile.
311-
function! go#cmd#Coverage(bang, ...)
312-
let l:tmpname=tempname()
313-
let args = [a:bang, 0, "-coverprofile", l:tmpname]
314-
315-
if a:0
316-
call extend(args, a:000)
317-
endif
318-
let id = call('go#cmd#Test', args)
319-
if has('nvim')
320-
if s:coverage_handler_id == ''
321-
let s:coverage_handler_id = go#jobcontrol#AddHandler(function('s:coverage_handler'))
322-
endif
323-
let s:coverage_handler_jobs[id] = l:tmpname
324-
return
325-
endif
326-
if !v:shell_error
327-
let openHTML = 'go tool cover -html='.l:tmpname
328-
call go#tool#ExecuteInDir(openHTML)
329-
endif
330-
331-
call delete(l:tmpname)
332-
endfunction
333-
334293
" Generate runs 'go generate' in similar fashion to go#cmd#Build()
335294
function! go#cmd#Generate(bang, ...)
336295
let default_makeprg = &makeprg

autoload/go/coverage.vim

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
let s:toggle = 0
2+
3+
" Buffer creates a new cover profile with 'go test -coverprofile' and changes
4+
" teh current buffers highlighting to show covered and uncovered sections of
5+
" the code. If run again it clears the annotation
6+
function! go#coverage#Buffer(bang, ...)
7+
if s:toggle
8+
call go#coverage#Clear()
9+
return
10+
endif
11+
12+
let s:toggle = 1
13+
let l:tmpname=tempname()
14+
let args = [a:bang, 0, "-coverprofile", l:tmpname]
15+
16+
if a:0
17+
call extend(args, a:000)
18+
endif
19+
"TODO: add -coverpkg options based on current buf list
20+
let id = call('go#cmd#Test', args)
21+
if has('nvim')
22+
if s:coverage_handler_id == ''
23+
let s:coverage_handler_id = go#jobcontrol#AddHandler(function('s:coverage_handler'))
24+
endif
25+
let s:coverage_handler_jobs[id] = l:tmpname
26+
return
27+
endif
28+
if !v:shell_error
29+
call go#coverage#overlay(l:tmpname)
30+
endif
31+
call delete(l:tmpname)
32+
endfunction
33+
34+
" Clear clears and resets the buffer annotation matches
35+
function! go#coverage#Clear()
36+
if exists("g:syntax_on") | syntax enable | endif
37+
38+
if exists("s:toggle") | let s:toggle = 0 | endif
39+
40+
" remove the autocmd we defined
41+
if exists("#BufWinLeave#<buffer>")
42+
autocmd! BufWinLeave <buffer>
43+
endif
44+
45+
call clearmatches()
46+
endfunction
47+
48+
" Browser creates a new cover profile with 'go test -coverprofile' and opens
49+
" a new HTML coverage page from that profile in a new browser
50+
function! go#coverage#Browser(bang, ...)
51+
let l:tmpname=tempname()
52+
let args = [a:bang, 0, "-coverprofile", l:tmpname]
53+
54+
if a:0
55+
call extend(args, a:000)
56+
endif
57+
let id = call('go#cmd#Test', args)
58+
if has('nvim')
59+
if s:coverage_browser_handler_id == ''
60+
let s:coverage_browser_handler_id = go#jobcontrol#AddHandler(function('s:coverage_browser_handler'))
61+
endif
62+
let s:coverage_browser_handler_jobs[id] = l:tmpname
63+
return
64+
endif
65+
if !v:shell_error
66+
let openHTML = 'go tool cover -html='.l:tmpname
67+
call go#tool#ExecuteInDir(openHTML)
68+
endif
69+
70+
call delete(l:tmpname)
71+
endfunction
72+
73+
" Parses a single line from the cover file generated via go test -coverprofile
74+
" and returns a single coverage profile block.
75+
function! go#coverage#parsegocoverline(line)
76+
" file:startline.col,endline.col numstmt count
77+
let mx = '\([^:]\+\):\(\d\+\)\.\(\d\+\),\(\d\+\)\.\(\d\+\)\s\(\d\+\)\s\(\d\+\)'
78+
let tokens = matchlist(a:line, mx)
79+
let ret = {}
80+
let ret.file = tokens[1]
81+
let ret.startline = str2nr(tokens[2])
82+
let ret.startcol = str2nr(tokens[3])
83+
let ret.endline = str2nr(tokens[4])
84+
let ret.endcol = str2nr(tokens[5])
85+
let ret.numstmt = tokens[6]
86+
let ret.cnt = tokens[7]
87+
return ret
88+
endfunction
89+
90+
" Generates matches to be added to matchaddpos for the given coverage profile
91+
" block
92+
function! go#coverage#genmatch(cov)
93+
let color = 'covered'
94+
if a:cov.cnt == 0
95+
let color = 'uncover'
96+
endif
97+
98+
let matches = []
99+
100+
" if start and end are the same, also specify the byte length
101+
" example: foo.go:92.2,92.65 1 0
102+
if a:cov.startline == a:cov.endline
103+
call add(matches, {
104+
\ 'group': color,
105+
\ 'pos': [[a:cov.startline, a:cov.startcol, a:cov.endcol - a:cov.startcol]],
106+
\ 'priority': 2,
107+
\ })
108+
return matches
109+
endif
110+
111+
" add start columns. Because we don't know the length of the of
112+
" the line, we assume it is at maximum 200 bytes. I know this is hacky,
113+
" but that's only way of fixing the issue
114+
call add(matches, {
115+
\ 'group': color,
116+
\ 'pos': [[a:cov.startline, a:cov.startcol, 200]],
117+
\ 'priority': 2,
118+
\ })
119+
120+
" and then the remaining lines
121+
let start_line = a:cov.startline
122+
while start_line < a:cov.endline
123+
let start_line += 1
124+
call add(matches, {
125+
\ 'group': color,
126+
\ 'pos': [[start_line]],
127+
\ 'priority': 2,
128+
\ })
129+
endwhile
130+
131+
" finally end columns
132+
call add(matches, {
133+
\ 'group': color,
134+
\ 'pos': [[a:cov.endline, a:cov.endcol-1]],
135+
\ 'priority': 2,
136+
\ })
137+
138+
return matches
139+
endfunction
140+
141+
" Reads the given coverprofile file and annotates the current buffer
142+
function! go#coverage#overlay(file)
143+
if !filereadable(a:file)
144+
return
145+
endif
146+
let lines = readfile(a:file)
147+
148+
" cover mode, by default it's 'set'. Just here for debugging purposes
149+
let mode = lines[0]
150+
151+
" contains matches for matchaddpos()
152+
let matches = []
153+
154+
" first mark all lines as normaltext. We use a custom group to not
155+
" interfere with other buffers highlightings. Because the priority is
156+
" lower than the cover and uncover matches, it'll be overriden.
157+
let cnt = 1
158+
while cnt <= line('$')
159+
call add(matches, {'group': 'normaltext', 'pos': [cnt], 'priority': 1})
160+
let cnt += 1
161+
endwhile
162+
163+
let fname = expand('%:t')
164+
165+
" when called for a _test.go file, run the coverage for the actuall file
166+
" file
167+
if fname =~# '^\f\+_test\.go$'
168+
let l:root = split(fname, '_test.go$')[0]
169+
let fname = l:root . ".go"
170+
171+
" open the alternate file to show the coverage
172+
exe ":edit ". fname
173+
endif
174+
175+
for line in lines[1:]
176+
let cov = go#coverage#parsegocoverline(line)
177+
178+
" TODO(arslan): for now only include the coverage for the current
179+
" buffer
180+
if fname != fnamemodify(cov.file, ':t')
181+
continue
182+
endif
183+
184+
call extend(matches, go#coverage#genmatch(cov))
185+
endfor
186+
187+
syntax manual
188+
highlight normaltext term=bold ctermfg=59 guifg=#75715E
189+
highlight covered term=bold ctermfg=118 guifg=#A6E22E
190+
highlight uncover term=bold ctermfg=197 guifg=#F92672
191+
192+
" clear the matches if we leave the buffer
193+
autocmd BufWinLeave <buffer> call go#coverage#Clear()
194+
195+
for m in matches
196+
call matchaddpos(m.group, m.pos)
197+
endfor
198+
endfunction
199+
200+
201+
" -----------------------
202+
" | Neovim job handlers |
203+
" -----------------------
204+
205+
let s:coverage_handler_id = ''
206+
let s:coverage_handler_jobs = {}
207+
208+
function! s:coverage_handler(job, exit_status, data)
209+
if !has_key(s:coverage_handler_jobs, a:job.id)
210+
return
211+
endif
212+
let l:tmpname = s:coverage_handler_jobs[a:job.id]
213+
if a:exit_status == 0
214+
call go#coverage#overlay(l:tmpname)
215+
endif
216+
217+
call delete(l:tmpname)
218+
unlet s:coverage_handler_jobs[a:job.id]
219+
endfunction
220+
221+
222+
let s:coverage_browser_handler_id = ''
223+
let s:coverage_browser_handler_jobs = {}
224+
225+
function! s:coverage_browser_handler(job, exit_status, data)
226+
if !has_key(s:coverage_browser_handler_jobs, a:job.id)
227+
return
228+
endif
229+
let l:tmpname = s:coverage_browser_handler_jobs[a:job.id]
230+
if a:exit_status == 0
231+
let openHTML = 'go tool cover -html='.l:tmpname
232+
call go#tool#ExecuteInDir(openHTML)
233+
endif
234+
call delete(l:tmpname)
235+
unlet s:coverage_browser_handler_jobs[a:job.id]
236+
endfunction
237+
238+
239+
" vim:ts=4:sw=4:et

0 commit comments

Comments
 (0)