323 lines
8.7 KiB
VimL
323 lines
8.7 KiB
VimL
|
" Vim compiler file for Python
|
||
|
" Compiler: Style checking tool for Python
|
||
|
" Maintainer: Cong Ma <cma@pmo.ac.cn>
|
||
|
" Last Change: 2014 April 15
|
||
|
" Version: 0.8dev
|
||
|
" Contributors:
|
||
|
" Oleksandr Tymoshenko
|
||
|
" Artur Wroblewski
|
||
|
" Menno
|
||
|
" Jose Blanca
|
||
|
" Bogdan Frankovskyi
|
||
|
" Oren Held
|
||
|
" Cong Ma
|
||
|
"
|
||
|
" Installation:
|
||
|
" Drop pylint.vim in ~/.vim/compiler directory. Ensure that your PATH
|
||
|
" environment variable includes the path to 'pylint' executable.
|
||
|
"
|
||
|
" Add the following line to the autocmd section of .vimrc
|
||
|
"
|
||
|
" autocmd FileType python compiler pylint
|
||
|
"
|
||
|
" Usage:
|
||
|
" Pylint is called after a buffer with Python code is saved. QuickFix
|
||
|
" window is opened to show errors, warnings and hints provided by Pylint.
|
||
|
" Code rate calculated by Pylint is displayed at the bottom of the
|
||
|
" window.
|
||
|
"
|
||
|
" Above is realized with :Pylint command. To disable calling Pylint every
|
||
|
" time a buffer is saved put into .vimrc file
|
||
|
"
|
||
|
" let g:pylint_onwrite = 0
|
||
|
"
|
||
|
" Displaying code rate calculated by Pylint can be avoided by setting
|
||
|
"
|
||
|
" let g:pylint_show_rate = 0
|
||
|
"
|
||
|
" Openning of QuickFix window can be disabled with
|
||
|
"
|
||
|
" let g:pylint_cwindow = 0
|
||
|
"
|
||
|
" Setting signs for the lines with errors can be enabled with
|
||
|
"
|
||
|
" let g:pylint_signs = 1
|
||
|
"
|
||
|
" Of course, standard :make command can be used as in case of every
|
||
|
" other compiler.
|
||
|
"
|
||
|
" Setting highlights for the lines can be disabled with
|
||
|
"
|
||
|
" let g:pylint_inline_highlight = 0
|
||
|
"
|
||
|
" Coding style warning highlight can be disabled with
|
||
|
"
|
||
|
" let g:pylint_conventions = 0
|
||
|
"
|
||
|
" Warning highlight can be disabled with
|
||
|
"
|
||
|
" let g:pylint_warning = 0
|
||
|
"
|
||
|
|
||
|
if exists('current_compiler')
|
||
|
finish
|
||
|
endif
|
||
|
let current_compiler = 'pylint'
|
||
|
|
||
|
if !exists('g:pylint_onwrite')
|
||
|
let g:pylint_onwrite = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_onfly')
|
||
|
let g:pylint_onfly = 0
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_show_rate')
|
||
|
let g:pylint_show_rate = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_cwindow')
|
||
|
let g:pylint_cwindow = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_signs')
|
||
|
let g:pylint_signs = 0
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_inline_highlight')
|
||
|
let g:pylint_inline_highlight = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_warning')
|
||
|
let g:pylint_warning = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:pylint_conventions')
|
||
|
let g:pylint_conventions = 1
|
||
|
endif
|
||
|
|
||
|
if exists(':Pylint') != 2
|
||
|
command Pylint :call Pylint(0)
|
||
|
endif
|
||
|
|
||
|
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
|
||
|
command -nargs=* CompilerSet setlocal <args>
|
||
|
endif
|
||
|
|
||
|
au CursorHold <buffer> call s:GetPylintMessage()
|
||
|
au CursorMoved <buffer> call s:GetPylintMessage()
|
||
|
|
||
|
|
||
|
" We should echo filename because pylint truncates .py
|
||
|
" If someone know better way - let me know :)
|
||
|
CompilerSet makeprg=(echo\ '[%]';pylint\ --msg-template=\"{msg_id}:{line},{column}:\ {msg}\"\ '%'\\\|grep\ -E\ -e\ \'^\([WECR][0-9]\\\|Your\ code\)\'\\\|sed\ -e\ \'s/^E/1\ E\ /\'\ -e\ \'s/^W/2\ W\ /\'\ -e\ \'s/^C/3\ C\ /\'\ -e\ \'s/^R/4\ R\ /\'\ \\\|sort)
|
||
|
|
||
|
" We could omit end of file-entry, there is only one file
|
||
|
" %+I... - include code rating information
|
||
|
" %-G... - remove all remaining report lines from quickfix buffer
|
||
|
CompilerSet efm=%-P[%f],%*\\d\ %t\ %n:%l\\,%c:%m,%Z,%+IYour\ code%m,%Z,%-G%.%#
|
||
|
|
||
|
""sings
|
||
|
"signs definition
|
||
|
sign define W text=WW texthl=pylint
|
||
|
sign define C text=CC texthl=pylint
|
||
|
sign define R text=RR texthl=pylint
|
||
|
sign define E text=EE texthl=pylint_error
|
||
|
|
||
|
if g:pylint_onwrite
|
||
|
augroup python
|
||
|
au!
|
||
|
au BufWritePost * call Pylint(1)
|
||
|
augroup end
|
||
|
endif
|
||
|
|
||
|
if g:pylint_onfly
|
||
|
augroup python
|
||
|
au!
|
||
|
au BufRead * call Pylint(1)
|
||
|
augroup end
|
||
|
endif
|
||
|
|
||
|
if !exists("*s:Pylint")
|
||
|
function! Pylint(writing)
|
||
|
if has('win32') || has('win16') || has('win95') || has('win64')
|
||
|
setlocal sp=>%s
|
||
|
else
|
||
|
setlocal sp=>%s\ 2>&1
|
||
|
endif
|
||
|
|
||
|
" If check is executed by buffer write - do not jump to first error
|
||
|
if !a:writing
|
||
|
silent make
|
||
|
else
|
||
|
silent make!
|
||
|
endif
|
||
|
|
||
|
if g:pylint_cwindow
|
||
|
cwindow
|
||
|
endif
|
||
|
|
||
|
call PylintEvaluation()
|
||
|
|
||
|
if g:pylint_show_rate
|
||
|
echon 'code rate: ' b:pylint_rate ', prev: ' b:pylint_prev_rate
|
||
|
endif
|
||
|
|
||
|
if g:pylint_signs
|
||
|
call PlacePylintSigns()
|
||
|
endif
|
||
|
|
||
|
if g:pylint_inline_highlight
|
||
|
call PylintHighlight()
|
||
|
endif
|
||
|
|
||
|
redraw!
|
||
|
|
||
|
endfunction
|
||
|
endif
|
||
|
|
||
|
function! PylintEvaluation()
|
||
|
let l:list = getqflist()
|
||
|
let b:pylint_rate = '0.00'
|
||
|
let b:pylint_prev_rate = '0.00'
|
||
|
for l:item in l:list
|
||
|
if l:item.type == 'I' && l:item.text =~ 'Your code has been rated'
|
||
|
let l:re_rate = '\(-\?[0-9]\{1,2\}\.[0-9]\{2\}\)/'
|
||
|
let b:pylint_rate = substitute(l:item.text, '.*rated at '.l:re_rate.'.*', '\1', 'g')
|
||
|
" Only if there is information about previous run
|
||
|
if l:item.text =~ 'previous run: '
|
||
|
let b:pylint_prev_rate = substitute(l:item.text, '.*previous run: '.l:re_rate.'.*', '\1', 'g')
|
||
|
endif
|
||
|
endif
|
||
|
endfor
|
||
|
endfunction
|
||
|
|
||
|
function! PlacePylintSigns()
|
||
|
"in which buffer are we?
|
||
|
"in theory let l:buffr=bufname(l:item.bufnr)
|
||
|
"should work inside the next loop, but i haven't manage to do it
|
||
|
let l:buffr = bufname('%')
|
||
|
"the previous lines are suppose to work, but sometimes it doesn't
|
||
|
if empty(l:buffr)
|
||
|
let l:buffr=bufname(1)
|
||
|
endif
|
||
|
|
||
|
"first remove all sings
|
||
|
exec('sign unplace *')
|
||
|
"now we place one sign for every quickfix line
|
||
|
let l:list = getqflist()
|
||
|
let l:id = 1
|
||
|
for l:item in l:list
|
||
|
"the line signs
|
||
|
let l:lnum=item.lnum
|
||
|
let l:type=item.type
|
||
|
"sign place 1 line=l:lnum name=pylint file=l:buffr
|
||
|
if l:type != 'I'
|
||
|
let l:exec = printf('sign place %d name=%s line=%d file=%s',
|
||
|
\ l:id, l:type, l:lnum, l:buffr)
|
||
|
let l:id = l:id + 1
|
||
|
execute l:exec
|
||
|
endif
|
||
|
endfor
|
||
|
call PylintHighlight()
|
||
|
endfunction
|
||
|
|
||
|
if !exists("*s:PylintHighlight")
|
||
|
function! PylintHighlight()
|
||
|
highlight link PyError SpellBad
|
||
|
highlight link PyWarning SpellRare
|
||
|
highlight link PyConventions SpellCap
|
||
|
|
||
|
"clear all already highlighted
|
||
|
if exists("b:cleared")
|
||
|
if b:cleared == 0
|
||
|
silent call s:ClearHighlight()
|
||
|
let b:cleared = 1
|
||
|
endif
|
||
|
else
|
||
|
let b:cleared = 1
|
||
|
endif
|
||
|
|
||
|
let b:matchedlines = {}
|
||
|
|
||
|
" get all messages from qicklist
|
||
|
let l:list = getqflist()
|
||
|
for l:item in l:list
|
||
|
" highlight lines with errors (only word characters) without end
|
||
|
" of line
|
||
|
let l:matchDict = {}
|
||
|
let l:matchDict['linenum'] = l:item.lnum
|
||
|
let l:matchDict['message'] = l:item.text
|
||
|
if l:item.type == 'E'
|
||
|
if !has_key(b:matchedlines, l:item.lnum)
|
||
|
let b:matchedlines[l:item.lnum] = l:matchDict
|
||
|
call matchadd("PyError", '\w\%' . l:item.lnum . 'l\n\@!')
|
||
|
endif
|
||
|
elseif item.type == 'W' && g:pylint_warning
|
||
|
if !has_key(b:matchedlines, l:item.lnum)
|
||
|
let b:matchedlines[l:item.lnum] = l:matchDict
|
||
|
call matchadd("PyWarning", '\w\%' . l:item.lnum . 'l\n\@!')
|
||
|
endif
|
||
|
elseif item.type == 'C' && g:pylint_conventions
|
||
|
if !has_key(b:matchedlines, l:item.lnum)
|
||
|
let b:matchedlines[item.lnum] = l:matchDict
|
||
|
call matchadd("PyConventions", '\w\%' . l:item.lnum . 'l\n\@!')
|
||
|
endif
|
||
|
endif
|
||
|
endfor
|
||
|
let b:cleared = 0
|
||
|
endfunction
|
||
|
endif
|
||
|
|
||
|
" keep track of whether or not we are showing a message
|
||
|
let b:showing_message = 0
|
||
|
|
||
|
" WideMsg() prints [long] message up to (&columns-1) length
|
||
|
" guaranteed without "Press Enter" prompt.
|
||
|
if !exists("*s:WideMsg")
|
||
|
function s:WideMsg(msg)
|
||
|
let x=&ruler | let y=&showcmd
|
||
|
set noruler noshowcmd
|
||
|
redraw
|
||
|
echo a:msg
|
||
|
let &ruler=x | let &showcmd=y
|
||
|
endfun
|
||
|
endif
|
||
|
|
||
|
if !exists('*s:GetPylintMessage')
|
||
|
function s:GetPylintMessage()
|
||
|
let l:cursorPos = getpos(".")
|
||
|
|
||
|
" Bail if Pylint hasn't been called yet.
|
||
|
if !exists('b:matchedlines')
|
||
|
return
|
||
|
endif
|
||
|
" if there's a message for the line the cursor is currently on, echo
|
||
|
" it to the console
|
||
|
if has_key(b:matchedlines, l:cursorPos[1])
|
||
|
let l:pylintMatch = get(b:matchedlines, l:cursorPos[1])
|
||
|
call s:WideMsg(l:pylintMatch['message'])
|
||
|
let b:showing_message = 1
|
||
|
return
|
||
|
endif
|
||
|
" otherwise, if we're showing a message, clear it
|
||
|
if b:showing_message == 1
|
||
|
echo
|
||
|
let b:showing_message = 0
|
||
|
endif
|
||
|
endfunction
|
||
|
endif
|
||
|
|
||
|
if !exists('*s:ClearHighlight')
|
||
|
function s:ClearHighlight()
|
||
|
let l:matches = getmatches()
|
||
|
for l:matchId in l:matches
|
||
|
if l:matchId['group'] == 'PyError' || l:matchId['group'] == 'PyWarning' || l:matchId['group'] == 'PyConventions'
|
||
|
call matchdelete(l:matchId['id'])
|
||
|
endif
|
||
|
endfor
|
||
|
let b:matchedlines = {}
|
||
|
let b:cleared = 1
|
||
|
endfunction
|
||
|
endif
|