Permalink
Browse files

Add vim report using signs to display coverage.

From a discussion with Tatsuhiko Miyagawa about what we could steal from Ruby.
  • Loading branch information...
1 parent 8575819 commit bde4b059e8c2be3e69b0a66704f32b98b9a6ff3e @pjcj committed Mar 31, 2012
Showing with 393 additions and 0 deletions.
  1. +102 −0 devel-cover.vim
  2. +291 −0 lib/Devel/Cover/Report/Vim.pm
View
@@ -0,0 +1,102 @@
+" This file was generated by Devel::Cover Version $VERSION
+" Devel::Cover is copyright 2001-2011, Paul Johnson (pjcj@cpan.org)
+" Devel::Cover is free. It is licensed under the same terms as Perl itself.
+" The latest version of Devel::Cover should be available from my homepage:
+" http://www.pjcj.net
+
+
+" Run: tests/module1
+" Perl version: 118.53.46.49.52.46.50
+" OS: linux
+" Start: Wed Nov 16 18:15:30 42249368
+" Finish: Wed Nov 16 18:24:00 42249368
+
+
+
+"hi HitLine ctermbg=Cyan guibg=Cyan
+"hi MissLine ctermbg=Magenta guibg=Magenta
+hi HitSign ctermfg=Green cterm=bold gui=bold guifg=Green
+hi MissSign ctermfg=Red cterm=bold gui=bold guifg=Red
+
+sign define hit linehl=HitLine texthl=HitSign text=>>
+sign define miss linehl=MissLine texthl=MissSign text=:(
+
+" let s:coverage = {<%
+ " results.each_pair do |file, coverage|
+ " %>'<%= file %>': [<%= coverage[:hits].inspect %>,<%= coverage[:misses].inspect%>], <%
+ " end%> }
+let s:coverage = { 'tests/Module1.pm': [ [ 33, 34 ], [ 28, 17, 15, 22, 16, 23 ] ], 'tests/module1': [ [ 27, 17, 12, 15, 24, 23, 19, 13, 29, 31 ], [ 35 ] ] }
+
+let s:generatedTime = 1333199390
+
+function! BestCoverage(coverageForName)
+ let matchBadness = strlen(a:coverageForName)
+ for filename in keys(s:coverage)
+ let matchQuality = match(a:coverageForName, filename . "$")
+ if (matchQuality >= 0 && matchQuality < matchBadness)
+ let found = filename
+ endif
+ endfor
+
+ if exists("found")
+ return s:coverage[found]
+ else
+ echom "No coverage recorded for " . a:coverageForName
+ return [[],[]]
+ endif
+endfunction
+
+let s:signs = {}
+let s:signIndex = 1
+
+function! s:CoverageSigns(filename)
+ let [hits,misses] = BestCoverage(a:filename)
+
+ if (getftime(a:filename) > s:generatedTime)
+ echom "File is newer than coverage report which was generated at " . strftime("%c", s:generatedTime)
+ endif
+
+ if (! exists("s:signs['".a:filename."']"))
+ let s:signs[a:filename] = []
+ endif
+
+ for hit in hits
+ let id = s:signIndex
+ let s:signIndex += 1
+ let s:signs[a:filename] += [id]
+ exe ":sign place ". id ." line=".hit." name=hit file=" . a:filename
+ endfor
+
+ for miss in misses
+ let id = s:signIndex
+ let s:signIndex += 1
+ let s:signs[a:filename] += [id]
+ exe ":sign place ".id." line=".miss." name=miss file=" . a:filename
+ endfor
+endfunction
+
+function! s:ClearCoverageSigns(filename)
+ if(exists("s:signs['". a:filename."']"))
+ for signId in s:signs[a:filename]
+ exe ":sign unplace ".signId
+ endfor
+ let s:signs[a:filename] = []
+ endif
+endfunction
+
+let s:filename = expand("<sfile>")
+function! s:AutocommandUncov(sourced)
+ if(a:sourced == s:filename)
+ call s:ClearCoverageSigns(expand("%:p"))
+ endif
+endfunction
+
+command! -nargs=0 Cov call s:CoverageSigns(expand("%:p"))
+command! -nargs=0 Uncov call s:ClearCoverageSigns(expand("%:p"))
+
+augroup SimpleCov
+ au!
+ exe "au SourcePre ".expand("<sfile>:t")." call s:AutocommandUncov(expand('<afile>:p'))"
+augroup end
+
+Cov
@@ -0,0 +1,291 @@
+# Copyright 2012, Paul Johnson (pjcj@cpan.org)
+
+# This software is free. It is licensed under the same terms as Perl itself.
+
+# The latest version of this software should be available from my homepage:
+# http://www.pjcj.net
+
+package Devel::Cover::Report::Vim;
+
+use strict;
+use warnings;
+
+# VERSION
+
+use Devel::Cover::DB;
+
+use Getopt::Long;
+use Template 2.00;
+
+sub get_options
+{
+ my ($self, $opt) = @_;
+ $opt->{outputfile} = "coverage.vim";
+ die "Invalid command line options" unless
+ GetOptions($opt,
+ qw(
+ outputfile=s
+ ));
+ use Data::Dumper; print Dumper $opt;
+}
+
+sub coverage
+{
+ my ($db, $file, $options) = @_;
+
+ my $statements = $db->cover->file($file)->statement or return ([], []);
+
+ my ($cov, $err) = ([], []);
+
+ for my $location ($statements->items)
+ {
+ my $l = $statements->location($location);
+ my ($c, $e);
+ for my $statement (@$l)
+ {
+ $c ||= $statement->covered;
+ $e ||= $statement->error;
+ }
+ push @$cov, $location if $c;
+ push @$err, $location if $e;
+ }
+
+ ($cov, $err)
+}
+
+sub report
+{
+ my ($pkg, $db, $options) = @_;
+
+ my $template = Template->new
+ ({
+ LOAD_TEMPLATES =>
+ [
+ Devel::Cover::Report::Vim::Template::Provider->new({}),
+ ],
+ });
+
+ my $vars =
+ {
+ runs =>
+ [
+ map
+ {
+ run => $_->{run},
+ perl => $_->{perl},
+ OS => $_->{OS},
+ start => scalar gmtime $_->{start},
+ finish => scalar gmtime $_->{finish},
+ },
+ sort {$a->{start} <=> $b->{start}}
+ $db->runs
+ ],
+ now => time,
+ coverage => join ", ", map {
+ my ($cov, $err) = coverage($db, $_);
+ local $" = ", ";
+ "'$_': [ [ @$cov ], [ @$err ] ]"
+ } @{$options->{file}},
+ };
+
+ $template->process("vim", $vars,
+ "$options->{outputdir}/$options->{outputfile}")
+ or die $template->error();
+}
+
+1;
+
+package Devel::Cover::Report::Vim::Template::Provider;
+
+use strict;
+use warnings;
+
+# VERSION
+
+use base "Template::Provider";
+
+my %Templates;
+
+sub fetch
+{
+ my $self = shift;
+ my ($name) = @_;
+ # print "Looking for <$name>\n";
+ $self->SUPER::fetch(exists $Templates{$name} ? \$Templates{$name} : $name)
+}
+
+$Templates{vim} = <<'EOT';
+" This file was generated by Devel::Cover Version $VERSION
+" Devel::Cover is copyright 2001-2011, Paul Johnson (pjcj@cpan.org)
+" Devel::Cover is free. It is licensed under the same terms as Perl itself.
+" The latest version of Devel::Cover should be available from my homepage:
+" http://www.pjcj.net
+
+[% FOREACH r = runs %]
+" Run: [% r.run %]
+" Perl version: [% r.perl %]
+" OS: [% r.OS %]
+" Start: [% r.start %]
+" Finish: [% r.finish %]
+
+[% END %]
+
+"hi HitLine ctermbg=Cyan guibg=Cyan
+"hi MissLine ctermbg=Magenta guibg=Magenta
+hi HitSign ctermfg=Green cterm=bold gui=bold guifg=Green
+hi MissSign ctermfg=Red cterm=bold gui=bold guifg=Red
+
+sign define hit linehl=HitLine texthl=HitSign text=>>
+sign define miss linehl=MissLine texthl=MissSign text=:(
+
+let s:coverage = { [% coverage %] }
+
+let s:generatedTime = [% now %]
+
+function! BestCoverage(coverageForName)
+ let matchBadness = strlen(a:coverageForName)
+ for filename in keys(s:coverage)
+ let matchQuality = match(a:coverageForName, filename . "$")
+ if (matchQuality >= 0 && matchQuality < matchBadness)
+ let found = filename
+ endif
+ endfor
+
+ if exists("found")
+ return s:coverage[found]
+ else
+ echom "No coverage recorded for " . a:coverageForName
+ return [[],[]]
+ endif
+endfunction
+
+let s:signs = {}
+let s:signIndex = 1
+
+function! s:CoverageSigns(filename)
+ let [hits,misses] = BestCoverage(a:filename)
+
+ if (getftime(a:filename) > s:generatedTime)
+ echom "File is newer than coverage report which was generated at " . strftime("%c", s:generatedTime)
+ endif
+
+ if (! exists("s:signs['".a:filename."']"))
+ let s:signs[a:filename] = []
+ endif
+
+ for hit in hits
+ let id = s:signIndex
+ let s:signIndex += 1
+ let s:signs[a:filename] += [id]
+ exe ":sign place ". id ." line=".hit." name=hit file=" . a:filename
+ endfor
+
+ for miss in misses
+ let id = s:signIndex
+ let s:signIndex += 1
+ let s:signs[a:filename] += [id]
+ exe ":sign place ".id." line=".miss." name=miss file=" . a:filename
+ endfor
+endfunction
+
+function! s:ClearCoverageSigns(filename)
+ if(exists("s:signs['". a:filename."']"))
+ for signId in s:signs[a:filename]
+ exe ":sign unplace ".signId
+ endfor
+ let s:signs[a:filename] = []
+ endif
+endfunction
+
+let s:filename = expand("<sfile>")
+function! s:AutocommandUncov(sourced)
+ if(a:sourced == s:filename)
+ call s:ClearCoverageSigns(expand("%:p"))
+ endif
+endfunction
+
+command! -nargs=0 Cov call s:CoverageSigns(expand("%:p"))
+command! -nargs=0 Uncov call s:ClearCoverageSigns(expand("%:p"))
+
+augroup SimpleCov
+ au!
+ exe "au SourcePre ".expand("<sfile>:t")." call s:AutocommandUncov(expand('<afile>:p'))"
+augroup end
+
+Cov
+EOT
+
+1
+
+__END__
+
+=head1 NAME
+
+Devel::Cover::Report::Vim - Backend for displaying coverage data in Vim
+
+=head1 SYNOPSIS
+
+ cover -report vim
+
+=head1 DESCRIPTION
+
+This module provides a reporting mechanism for displaying coverage data in
+Vim. It is designed to be called from the C<cover> program.
+
+By default, the output of this report is a file named C<coverage.vim> in the directory of the coverage database. To use it, run
+
+ :so cover_db/coverage.vim
+
+and you should see signs in the left column indicating the coverage status of
+that line.
+
+coverage.vim adds two user commands: :Cov and :Uncov which can be used to
+toggle the state of coverage signs.
+
+The idea and the vim template is shamelessly stolen from Simplecov-Vim. See
+https://github.com/nyarly/Simplecov-Vim
+
+=head1 SEE ALSO
+
+ Devel::Cover
+
+=head1 BUGS
+
+Huh?
+
+=head1 LICENCE
+
+Copyright 2012, Paul Johnson (pjcj@cpan.org)
+
+This software is free. It is licensed under the same terms as Perl itself.
+
+The latest version of this software should be available from my homepage:
+http://www.pjcj.net
+
+The template is copied from Simplecov-Vim
+(https://github.com/nyarly/Simplecov-Vim) and is under the MIT Licence.
+
+
+The MIT License
+
+Copyright (c) 2011 Judson Lester
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+=cut

0 comments on commit bde4b05

Please sign in to comment.