Commits

Peter Sagerson  committed d62107f

Initial checkin.

  • Participants

Comments (0)

Files changed (3)

+^doc/tags$

File doc/py-coverage.txt

+*py-coverage.txt*       For Vim version 7.3       Last change: 2012 October 25
+
+py-coverage
+
+==============================================================================
+1. About                                                         *py-coverage*
+
+This plugin integrates with Ned Batchelder's code coverage tool for Python
+(http://nedbatchelder.com/code/coverage/). After coverage data has been
+gathered, this plugin can be used to retrieve the results and present them in
+the relevant buffers.
+
+Source lines lacking coverage ("missing") may be indicated by directly
+highlighting the lines or by populating the quickfix or location lists. The
+function that retrieves the line numbers is also provided for low-level
+access.
+
+
+==============================================================================
+2. Commands
+
+These commands all operate on the current buffer. Excepting
+|:PyCoverageClear|, they will all call |PyCoverageMissedLines| for the current
+buffer and process the line numbers as appropriate.
+
+:PyCoverageHighlight                                    *:PyCoverageHighlight*
+    Uses |matchadd()| to highlight each line in the current buffer that lacks
+    coverage. This uses the PyCoverageMissed highlight group, which is aliased
+    to Error by default.
+
+
+==============================================================================
+3. Functions
+
+PyCoverageMissedLines({buffer})                        *PyCoverageMissedLines*
+    Returns the |List| of line numbers that lack coverage in the given buffer.
+    {buffer} should be a valid argument to |bufname()|; it will usually be ""
+    or "%" for the current buffer.
+
+
+==============================================================================
+4. Configuration
+
+All configuration options have sensible defaults.
+
+g:py_coverage_bin                                          *g:py_coverage_bin*
+    This can be set to the coverage executable. Defaults to "coverage", which
+    we expect to find in your path.
+>
+    let g:py_coverage_bin = '/usr/local/bin/coverage'
+<
+g:py_coverage_dir                                          *g:py_coverage_dir*
+    Set this to the directory that contains the .coverage file with coverage
+    data. If this is unset, we'll search for it up the directory tree from the
+    target file.
+>
+    let g:py_coverage_dir = expand('~/')
+<
+
+ vim:tw=78:ts=4:ft=help:norl:

File ftplugin/python/py-coverage.vim

+"
+" Python filetype plugin for marking code coverage.
+" Language:     Vim (ft=python)
+" Maintainer:   Peter Sagerson <psagers@ignorare.net>
+" Version:      Vim 7 (may work with lower Vim versions, but not tested)
+" URL:
+"
+
+if exists("b:loaded_py_coverage_ftplugin")
+    finish
+endif
+let b:loaded_py_coverage_ftplugin=1
+
+
+let g:py_coverage_bin = ! exists('g:py_coverage_bin') ? 'coverage' : g:py_coverage_bin
+
+
+highlight default link PyCoverageMissed Error
+
+
+"
+" Populate the quickfix list with the missed line numbers.
+"
+function! s:PyCoverageSetQuickfix()
+    let newlist = []
+
+    for line in PyCoverageMissedLines('')
+        call add(newlist, {'bufnr': bufnr(''), 'lnum': line, 'text': 'Line not covered'})
+    endfor
+
+    call setqflist(newlist)
+endfunction
+
+command! PyCoverageSetQuickfix  :call s:PyCoverageSetQuickfix()
+
+
+"
+" Populate the current window's location list with the missed line numbers.
+"
+function! s:PyCoverageSetLoclist()
+    let newlist = []
+
+    for line in PyCoverageMissedLines('')
+        call add(newlist, {'bufnr': bufnr(''), 'lnum': line, 'text': 'Line not covered'})
+    endfor
+
+    call setloclist(winnr(), newlist)
+endfunction
+
+command! PyCoverageSetLoclist  :call s:PyCoverageSetLoclist()
+
+
+"
+" Highlight the missed line numbers.
+"
+function! s:PyCoverageHighlight()
+    call s:PyCoverageClear()
+
+    for line in PyCoverageMissedLines('')
+        call matchadd('PyCoverageMissed', '\%'.line.'l')
+    endfor
+endfunction
+
+command! PyCoverageHighlight  :call s:PyCoverageHighlight()
+
+
+"
+" Clear highlighting.
+"
+function! s:PyCoverageClear()
+    for m in getmatches()
+        if m.group == 'PyCoverageMissed'
+            call matchdelete(m.id)
+        endif
+    endfor
+endfunction
+
+command! PyCoverageClear  :call s:PyCoverageClear()
+
+
+" Returns an array of line numbers representing all of the lines missed by the
+" last coverage run in a given source file.
+function! PyCoverageMissedLines(buffer)
+    let linenos = []
+
+    let sourcefile = fnamemodify(bufname(a:buffer), ':p')
+    let report = s:CoverageReport(sourcefile)
+    let lines = split(report, '[\r\n]\+')
+
+    if len(lines) == 3
+        let headers = lines[0]
+        let fields = lines[2]
+    else
+        return []
+    endif
+
+    let offset = match(headers, 'Missing$')
+
+    if offset >= 0
+        let missing = fields[offset :]
+    else
+        return []
+    endif
+
+    for range in split(missing, ', ')
+        let bounds = map(split(range, '-'), 'str2nr(v:val)')
+
+        if len(bounds) == 1
+            call extend(linenos, bounds)
+        elseif len(bounds) == 2
+            let lineno = bounds[0]
+            while lineno <= bounds[1]
+                call add(linenos, lineno)
+                let lineno += 1
+            endwhile
+        endif
+    endfor
+
+    return linenos
+endfunction
+
+
+" Find the nearest .coverage file and generate a report for the given target
+" source file. The report looks like:
+"
+" Name                 Stmts   Miss  Cover   Missing
+" --------------------------------------------------
+" python/module/path     169     30    82%   26-28, 64, 73-74, ...
+function! s:CoverageReport(sourcefile)
+    let coverage_dir = ''
+    let report = ''
+
+    if exists('g:py_coverage_dir')
+        let coverage_dir = g:py_coverage_dir
+    elseif filereadable(a:sourcefile)
+        let suffixesadd_save = &suffixesadd
+        let &suffixesadd = ''
+        let coverage_db = findfile('.coverage', fnamemodify(a:sourcefile, ':h') . ';')
+        let &suffixesadd = suffixesadd_save
+
+        let coverage_dir = fnamemodify(coverage_db, ':h')
+    endif
+
+    if coverage_dir != ''
+        exec printf('cd! %s', fnameescape(coverage_dir))
+
+        let report = system(printf('%s report -m --include=%s', shellescape(g:py_coverage_bin), shellescape(a:sourcefile)))
+
+        if v:shell_error != 0
+            echo report
+            let report = ''
+        endif
+
+        cd! -
+    endif
+
+    return report
+endfunction