vimrc/sources_non_forked/vim-go/autoload/go/coverage.vim

298 lines
8 KiB
VimL
Raw Normal View History

2018-12-17 11:28:27 +00:00
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim
2016-04-12 08:31:09 +00:00
let s:toggle = 0
" Buffer creates a new cover profile with 'go test -coverprofile' and changes
2016-05-14 11:57:54 +00:00
" the current buffers highlighting to show covered and uncovered sections of
" the code. If run again it clears the annotation.
2016-12-27 14:46:49 +00:00
function! go#coverage#BufferToggle(bang, ...) abort
2016-06-26 11:12:36 +00:00
if s:toggle
call go#coverage#Clear()
return
endif
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
if a:0 == 0
return call(function('go#coverage#Buffer'), [a:bang])
endif
2016-05-14 11:57:54 +00:00
2016-06-26 11:12:36 +00:00
return call(function('go#coverage#Buffer'), [a:bang] + a:000)
2016-05-14 11:57:54 +00:00
endfunction
" Buffer creates a new cover profile with 'go test -coverprofile' and changes
2017-07-06 12:57:35 +00:00
" the current buffers highlighting to show covered and uncovered sections of
2016-05-14 11:57:54 +00:00
" the code. Calling it again reruns the tests and shows the last updated
" coverage.
2016-12-27 14:46:49 +00:00
function! go#coverage#Buffer(bang, ...) abort
2016-06-26 11:12:36 +00:00
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
if !exists("*matchaddpos")
call go#util#EchoError("GoCoverage is supported with Vim version 7.4-330 or later")
return -1
endif
" check if there is any test file, if not we just return
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
try
execute cd . fnameescape(expand("%:p:h"))
if empty(glob("*_test.go"))
2017-03-07 17:04:28 +00:00
call go#util#EchoError("no test files available")
2016-06-26 11:12:36 +00:00
return
2016-05-14 11:57:54 +00:00
endif
2016-06-26 11:12:36 +00:00
finally
execute cd . fnameescape(dir)
endtry
2016-05-14 11:57:54 +00:00
2016-06-26 11:12:36 +00:00
let s:toggle = 1
let l:tmpname = tempname()
2016-04-12 08:31:09 +00:00
2018-09-25 00:40:17 +00:00
if go#util#has_job()
2016-12-27 14:46:49 +00:00
call s:coverage_job({
2018-06-14 10:31:12 +00:00
\ 'cmd': ['go', 'test', '-tags', go#config#BuildTags(), '-coverprofile', l:tmpname] + a:000,
2018-02-04 11:35:08 +00:00
\ 'complete': function('s:coverage_callback', [l:tmpname]),
2016-12-27 14:46:49 +00:00
\ 'bang': a:bang,
\ 'for': 'GoTest',
2018-07-19 12:52:53 +00:00
\ 'statustype': 'coverage',
2016-12-27 14:46:49 +00:00
\ })
return
endif
2018-09-25 00:40:17 +00:00
if go#config#EchoCommandInfo()
call go#util#EchoProgress("testing...")
endif
2016-12-27 14:46:49 +00:00
let args = [a:bang, 0, "-coverprofile", l:tmpname]
2016-06-26 11:12:36 +00:00
if a:0
call extend(args, a:000)
endif
2016-04-12 08:31:09 +00:00
2017-07-06 12:57:35 +00:00
let id = call('go#test#Test', args)
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
if go#util#ShellError() == 0
call go#coverage#overlay(l:tmpname)
endif
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
call delete(l:tmpname)
2016-04-12 08:31:09 +00:00
endfunction
" Clear clears and resets the buffer annotation matches
2016-12-27 14:46:49 +00:00
function! go#coverage#Clear() abort
call clearmatches()
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
if exists("s:toggle") | let s:toggle = 0 | endif
2016-04-12 08:31:09 +00:00
2017-03-07 17:04:28 +00:00
" remove the autocmd we defined
augroup vim-go-coverage
autocmd!
augroup end
2016-04-12 08:31:09 +00:00
endfunction
" Browser creates a new cover profile with 'go test -coverprofile' and opens
" a new HTML coverage page from that profile in a new browser
2016-12-27 14:46:49 +00:00
function! go#coverage#Browser(bang, ...) abort
2016-06-26 11:12:36 +00:00
let l:tmpname = tempname()
2018-09-25 00:40:17 +00:00
if go#util#has_job()
2016-12-27 14:46:49 +00:00
call s:coverage_job({
2018-06-14 10:31:12 +00:00
\ 'cmd': ['go', 'test', '-tags', go#config#BuildTags(), '-coverprofile', l:tmpname],
2018-02-04 11:35:08 +00:00
\ 'complete': function('s:coverage_browser_callback', [l:tmpname]),
2016-12-27 14:46:49 +00:00
\ 'bang': a:bang,
\ 'for': 'GoTest',
2018-09-25 00:40:17 +00:00
\ 'statustype': 'coverage',
2016-12-27 14:46:49 +00:00
\ })
return
endif
2016-06-26 11:12:36 +00:00
2016-12-27 14:46:49 +00:00
let args = [a:bang, 0, "-coverprofile", l:tmpname]
2016-06-26 11:12:36 +00:00
if a:0
call extend(args, a:000)
endif
2016-12-27 14:46:49 +00:00
2017-07-06 12:57:35 +00:00
let id = call('go#test#Test', args)
2016-12-27 14:46:49 +00:00
2016-06-26 11:12:36 +00:00
if go#util#ShellError() == 0
2018-06-14 10:31:12 +00:00
call go#tool#ExecuteInDir(['go', 'tool', 'cover', '-html=' . l:tmpname])
2016-06-26 11:12:36 +00:00
endif
call delete(l:tmpname)
2016-04-12 08:31:09 +00:00
endfunction
" Parses a single line from the cover file generated via go test -coverprofile
" and returns a single coverage profile block.
2016-12-27 14:46:49 +00:00
function! go#coverage#parsegocoverline(line) abort
2016-06-26 11:12:36 +00:00
" file:startline.col,endline.col numstmt count
let mx = '\([^:]\+\):\(\d\+\)\.\(\d\+\),\(\d\+\)\.\(\d\+\)\s\(\d\+\)\s\(\d\+\)'
let tokens = matchlist(a:line, mx)
let ret = {}
let ret.file = tokens[1]
let ret.startline = str2nr(tokens[2])
let ret.startcol = str2nr(tokens[3])
let ret.endline = str2nr(tokens[4])
let ret.endcol = str2nr(tokens[5])
let ret.numstmt = tokens[6]
let ret.cnt = tokens[7]
return ret
2016-04-12 08:31:09 +00:00
endfunction
" Generates matches to be added to matchaddpos for the given coverage profile
" block
2016-12-27 14:46:49 +00:00
function! go#coverage#genmatch(cov) abort
2016-08-02 12:48:32 +00:00
let color = 'goCoverageCovered'
2016-06-26 11:12:36 +00:00
if a:cov.cnt == 0
2016-08-02 12:48:32 +00:00
let color = 'goCoverageUncover'
2016-06-26 11:12:36 +00:00
endif
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
let matches = []
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
" if start and end are the same, also specify the byte length
" example: foo.go:92.2,92.65 1 0
if a:cov.startline == a:cov.endline
2016-04-12 08:31:09 +00:00
call add(matches, {
2017-03-07 17:04:28 +00:00
\ 'group': color,
\ 'pos': [[a:cov.startline, a:cov.startcol, a:cov.endcol - a:cov.startcol]],
2016-06-26 11:12:36 +00:00
\ 'priority': 2,
\ })
2016-04-12 08:31:09 +00:00
return matches
2016-06-26 11:12:36 +00:00
endif
" add start columns. Because we don't know the length of the of
" the line, we assume it is at maximum 200 bytes. I know this is hacky,
" but that's only way of fixing the issue
call add(matches, {
2017-03-07 17:04:28 +00:00
\ 'group': color,
\ 'pos': [[a:cov.startline, a:cov.startcol, 200]],
2016-06-26 11:12:36 +00:00
\ 'priority': 2,
\ })
" and then the remaining lines
let start_line = a:cov.startline
while start_line < a:cov.endline
let start_line += 1
call add(matches, {
2017-03-07 17:04:28 +00:00
\ 'group': color,
\ 'pos': [[start_line]],
2016-06-26 11:12:36 +00:00
\ 'priority': 2,
\ })
endwhile
" finally end columns
call add(matches, {
2017-03-07 17:04:28 +00:00
\ 'group': color,
\ 'pos': [[a:cov.endline, a:cov.endcol-1]],
2016-06-26 11:12:36 +00:00
\ 'priority': 2,
\ })
return matches
2016-04-12 08:31:09 +00:00
endfunction
" Reads the given coverprofile file and annotates the current buffer
2016-12-27 14:46:49 +00:00
function! go#coverage#overlay(file) abort
2016-06-26 11:12:36 +00:00
if !filereadable(a:file)
return
endif
let lines = readfile(a:file)
" cover mode, by default it's 'set'. Just here for debugging purposes
let mode = lines[0]
" contains matches for matchaddpos()
let matches = []
2016-08-02 12:48:32 +00:00
" first mark all lines as goCoverageNormalText. We use a custom group to not
2016-06-26 11:12:36 +00:00
" interfere with other buffers highlightings. Because the priority is
2017-07-06 12:57:35 +00:00
" lower than the cover and uncover matches, it'll be overridden.
2016-06-26 11:12:36 +00:00
let cnt = 1
while cnt <= line('$')
2016-08-02 12:48:32 +00:00
call add(matches, {'group': 'goCoverageNormalText', 'pos': [cnt], 'priority': 1})
2016-06-26 11:12:36 +00:00
let cnt += 1
endwhile
2016-12-27 14:46:49 +00:00
let fname = expand('%')
2016-06-26 11:12:36 +00:00
" when called for a _test.go file, run the coverage for the actuall file
" file
if fname =~# '^\f\+_test\.go$'
let l:root = split(fname, '_test.go$')[0]
let fname = l:root . ".go"
if !filereadable(fname)
call go#util#EchoError("couldn't find ".fname)
return
2016-04-12 08:31:09 +00:00
endif
2016-06-26 11:12:36 +00:00
" open the alternate file to show the coverage
exe ":edit ". fnamemodify(fname, ":p")
endif
2016-12-27 14:46:49 +00:00
" cov.file includes only the filename itself, without full path
let fname = fnamemodify(fname, ":t")
2016-06-26 11:12:36 +00:00
for line in lines[1:]
let cov = go#coverage#parsegocoverline(line)
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
" TODO(arslan): for now only include the coverage for the current
" buffer
if fname != fnamemodify(cov.file, ':t')
continue
endif
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
call extend(matches, go#coverage#genmatch(cov))
endfor
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
" clear the matches if we leave the buffer
augroup vim-go-coverage
autocmd!
autocmd BufWinLeave <buffer> call go#coverage#Clear()
augroup end
2016-04-12 08:31:09 +00:00
2016-06-26 11:12:36 +00:00
for m in matches
call matchaddpos(m.group, m.pos)
endfor
2016-04-12 08:31:09 +00:00
endfunction
2016-12-27 14:46:49 +00:00
" ---------------------
" | Vim job callbacks |
" ---------------------
"
function s:coverage_job(args)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
2018-07-19 12:52:53 +00:00
let disabled_term = 0
if go#config#TermEnabled()
let disabled_term = 1
call go#config#SetTermEnabled(0)
endif
2016-12-27 14:46:49 +00:00
2018-07-19 12:52:53 +00:00
call go#job#Spawn(a:args.cmd, a:args)
2016-12-27 14:46:49 +00:00
2018-07-19 12:52:53 +00:00
if disabled_term
call go#config#SetTermEnabled(1)
endif
2016-12-27 14:46:49 +00:00
endfunction
" coverage_callback is called when the coverage execution is finished
function! s:coverage_callback(coverfile, job, exit_status, data)
if a:exit_status == 0
call go#coverage#overlay(a:coverfile)
endif
call delete(a:coverfile)
endfunction
function! s:coverage_browser_callback(coverfile, job, exit_status, data)
if a:exit_status == 0
2018-06-14 10:31:12 +00:00
call go#tool#ExecuteInDir(['go', 'tool', 'cover', '-html=' . a:coverfile])
2016-12-27 14:46:49 +00:00
endif
call delete(a:coverfile)
endfunction
2018-12-17 11:28:27 +00:00
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
2016-06-26 11:12:36 +00:00
" vim: sw=2 ts=2 et