Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coverage overlay integration (vim-go-coverlay) #786

Merged
merged 2 commits into from
Apr 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ IMPROVEMENTS:

BUG FIXES:

* Term mode: fix closing location list if result is succesfull after a failed attempt [gh-768]
* Term mode: fix closing location list if result is successful after a failed attempt [gh-768]
* Syntax: fix gotexttmpl identifier highlighting [gh-778]

13 changes: 13 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env rake

task :ci => [:dump, :test]

task :dump do
sh 'vim --version'
end

# Firstly, `bundle install; bundle install --deployment`
# Then, `rake test`
task :test do
sh 'bundle exec vim-flavor test'
end
1 change: 1 addition & 0 deletions VimFlavor
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flavor 'fatih/vim-go', '~> 1.5'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be removed since it means This test depends on external plugin vim-go

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Btw I've changed the source code a lot and renamed the internal functions too. They will not work and probably will be broken. But I'm going to work on tests soon.

41 changes: 0 additions & 41 deletions autoload/go/cmd.vim
Original file line number Diff line number Diff line change
Expand Up @@ -290,47 +290,6 @@ function! go#cmd#TestFunc(bang, ...)
call call('go#cmd#Test', args)
endfunction

let s:coverage_handler_id = ''
let s:coverage_handler_jobs = {}

function! s:coverage_handler(job, exit_status, data)
if !has_key(s:coverage_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_handler_jobs[a:job.id]
if a:exit_status == 0
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif
call delete(l:tmpname)
unlet s:coverage_handler_jobs[a:job.id]
endfunction

" Coverage creates a new cover profile with 'go test -coverprofile' and opens
" a new HTML coverage page from that profile.
function! go#cmd#Coverage(bang, ...)
let l:tmpname=tempname()
let args = [a:bang, 0, "-coverprofile", l:tmpname]

if a:0
call extend(args, a:000)
endif
let id = call('go#cmd#Test', args)
if has('nvim')
if s:coverage_handler_id == ''
let s:coverage_handler_id = go#jobcontrol#AddHandler(function('s:coverage_handler'))
endif
let s:coverage_handler_jobs[id] = l:tmpname
return
endif
if !v:shell_error
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif

call delete(l:tmpname)
endfunction

" Generate runs 'go generate' in similar fashion to go#cmd#Build()
function! go#cmd#Generate(bang, ...)
let default_makeprg = &makeprg
Expand Down
239 changes: 239 additions & 0 deletions autoload/go/coverage.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
let s:toggle = 0

" Buffer creates a new cover profile with 'go test -coverprofile' and changes
" teh current buffers highlighting to show covered and uncovered sections of
" the code. If run again it clears the annotation
function! go#coverage#Buffer(bang, ...)
if s:toggle
call go#coverage#Clear()
return
endif

let s:toggle = 1
let l:tmpname=tempname()
let args = [a:bang, 0, "-coverprofile", l:tmpname]

if a:0
call extend(args, a:000)
endif
"TODO: add -coverpkg options based on current buf list
let id = call('go#cmd#Test', args)
if has('nvim')
if s:coverage_handler_id == ''
let s:coverage_handler_id = go#jobcontrol#AddHandler(function('s:coverage_handler'))
endif
let s:coverage_handler_jobs[id] = l:tmpname
return
endif
if !v:shell_error
call go#coverage#overlay(l:tmpname)
endif
call delete(l:tmpname)
endfunction

" Clear clears and resets the buffer annotation matches
function! go#coverage#Clear()
if exists("g:syntax_on") | syntax enable | endif

if exists("s:toggle") | let s:toggle = 0 | endif

" remove the autocmd we defined
if exists("#BufWinLeave#<buffer>")
autocmd! BufWinLeave <buffer>
endif

call clearmatches()
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
function! go#coverage#Browser(bang, ...)
let l:tmpname=tempname()
let args = [a:bang, 0, "-coverprofile", l:tmpname]

if a:0
call extend(args, a:000)
endif
let id = call('go#cmd#Test', args)
if has('nvim')
if s:coverage_browser_handler_id == ''
let s:coverage_browser_handler_id = go#jobcontrol#AddHandler(function('s:coverage_browser_handler'))
endif
let s:coverage_browser_handler_jobs[id] = l:tmpname
return
endif
if !v:shell_error
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif

call delete(l:tmpname)
endfunction

" Parses a single line from the cover file generated via go test -coverprofile
" and returns a single coverage profile block.
function! go#coverage#parsegocoverline(line)
" 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
endfunction

" Generates matches to be added to matchaddpos for the given coverage profile
" block
function! go#coverage#genmatch(cov)
let color = 'covered'
if a:cov.cnt == 0
let color = 'uncover'
endif

let matches = []

" 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
call add(matches, {
\ 'group': color,
\ 'pos': [[a:cov.startline, a:cov.startcol, a:cov.endcol - a:cov.startcol]],
\ 'priority': 2,
\ })
return matches
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, {
\ 'group': color,
\ 'pos': [[a:cov.startline, a:cov.startcol, 200]],
\ '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, {
\ 'group': color,
\ 'pos': [[start_line]],
\ 'priority': 2,
\ })
endwhile

" finally end columns
call add(matches, {
\ 'group': color,
\ 'pos': [[a:cov.endline, a:cov.endcol-1]],
\ 'priority': 2,
\ })

return matches
endfunction

" Reads the given coverprofile file and annotates the current buffer
function! go#coverage#overlay(file)
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 = []

" first mark all lines as normaltext. We use a custom group to not
" interfere with other buffers highlightings. Because the priority is
" lower than the cover and uncover matches, it'll be overriden.
let cnt = 1
while cnt <= line('$')
call add(matches, {'group': 'normaltext', 'pos': [cnt], 'priority': 1})
let cnt += 1
endwhile

let fname = expand('%:t')

" 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"

" open the alternate file to show the coverage
exe ":edit ". fname
endif

for line in lines[1:]
let cov = go#coverage#parsegocoverline(line)

" TODO(arslan): for now only include the coverage for the current
" buffer
if fname != fnamemodify(cov.file, ':t')
continue
endif

call extend(matches, go#coverage#genmatch(cov))
endfor

syntax manual
highlight normaltext term=bold ctermfg=59 guifg=#75715E
highlight covered term=bold ctermfg=118 guifg=#A6E22E
highlight uncover term=bold ctermfg=197 guifg=#F92672

" clear the matches if we leave the buffer
autocmd BufWinLeave <buffer> call go#coverage#Clear()

for m in matches
call matchaddpos(m.group, m.pos)
endfor
endfunction


" -----------------------
" | Neovim job handlers |
" -----------------------

let s:coverage_handler_id = ''
let s:coverage_handler_jobs = {}

function! s:coverage_handler(job, exit_status, data)
if !has_key(s:coverage_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_handler_jobs[a:job.id]
if a:exit_status == 0
call go#coverage#overlay(l:tmpname)
endif

call delete(l:tmpname)
unlet s:coverage_handler_jobs[a:job.id]
endfunction


let s:coverage_browser_handler_id = ''
let s:coverage_browser_handler_jobs = {}

function! s:coverage_browser_handler(job, exit_status, data)
if !has_key(s:coverage_browser_handler_jobs, a:job.id)
return
endif
let l:tmpname = s:coverage_browser_handler_jobs[a:job.id]
if a:exit_status == 0
let openHTML = 'go tool cover -html='.l:tmpname
call go#tool#ExecuteInDir(openHTML)
endif
call delete(l:tmpname)
unlet s:coverage_browser_handler_jobs[a:job.id]
endfunction


" vim:ts=4:sw=4:et
15 changes: 12 additions & 3 deletions doc/vim-go.txt
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,22 @@ COMMANDS *go-commands*

If [!] is not given the first error is jumped to.

If using neovim `:GoTestCompile` will run in a new terminal or run asynchronously
in the background according to |g:go_term_enabled|. You can set the mode of
the new terminal with |g:go_term_mode|.
If using neovim `:GoTestCompile` will run in a new terminal or run
asynchronously in the background according to |g:go_term_enabled|. You can
set the mode of the new terminal with |g:go_term_mode|.

*:GoCoverage*
:GoCoverage[!] [options]

Create a coverage profile and annotates the current file's source code. If
called again clears the annotation (works as a toggle)

If [!] is not given the first error is jumped to.


*:GoCoverageBrowser*
:GoCoverageBrowser[!] [options]

Create a coverage profile and open a browser to display the annotated
source code of the current package.

Expand Down
5 changes: 4 additions & 1 deletion ftplugin/go/commands.vim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ command! -nargs=* -bang GoInstall call go#cmd#Install(<bang>0, <f-args>)
command! -nargs=* -bang GoTest call go#cmd#Test(<bang>0, 0, <f-args>)
command! -nargs=* -bang GoTestFunc call go#cmd#TestFunc(<bang>0, <f-args>)
command! -nargs=* -bang GoTestCompile call go#cmd#Test(<bang>0, 1, <f-args>)
command! -nargs=* -bang GoCoverage call go#cmd#Coverage(<bang>0, <f-args>)

" -- cover
command! -nargs=* -bang GoCoverage call go#coverage#Buffer(<bang>0, <f-args>)
command! -nargs=* -bang GoCoverageBrowser call go#coverage#Browser(<bang>0, <f-args>)

" -- play
command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>)
Expand Down
4 changes: 3 additions & 1 deletion ftplugin/go/mappings.vim
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ nnoremap <silent> <Plug>(go-install) :<C-u>call go#cmd#Install(!g:go_jump_to_err
nnoremap <silent> <Plug>(go-test) :<C-u>call go#cmd#Test(!g:go_jump_to_error, 0)<CR>
nnoremap <silent> <Plug>(go-test-func) :<C-u>call go#cmd#TestFunc(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-test-compile) :<C-u>call go#cmd#Test(!g:go_jump_to_error, 1)<CR>
nnoremap <silent> <Plug>(go-coverage) :<C-u>call go#cmd#Coverage(!g:go_jump_to_error)<CR>

nnoremap <silent> <Plug>(go-coverage) :<C-u>call go#coverage#Buffer(!g:go_jump_to_error)<CR>
nnoremap <silent> <Plug>(go-coverage-browser) :<C-u>call go#coverage#Browser(!g:go_jump_to_error)<CR>

nnoremap <silent> <Plug>(go-files) :<C-u>call go#tool#Files()<CR>
nnoremap <silent> <Plug>(go-deps) :<C-u>call go#tool#Deps()<CR>
Expand Down
Loading