]> git.madduck.net Git - etc/vim.git/blob - autoload/flake8.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

ignore --count lines
[etc/vim.git] / autoload / flake8.vim
1 "
2 " Python filetype plugin for running flake8
3 " Language:     Python (ft=python)
4 " Maintainer:   Vincent Driessen <vincent@3rdcloud.com>
5 " Version:      Vim 7 (may work with lower Vim versions, but not tested)
6 " URL:          http://github.com/nvie/vim-flake8
7
8 let s:save_cpo = &cpo
9 set cpo&vim
10
11 "" ** external ** {{{
12
13 function! flake8#Flake8()
14     call s:Flake8()
15     call s:Warnings()
16 endfunction
17
18 function! flake8#Flake8UnplaceMarkers()
19     call s:UnplaceMarkers()
20     call s:Warnings()
21 endfunction
22
23 function! flake8#Flake8ShowError()
24     call s:ShowErrorMessage()
25 endfunction
26
27 "" }}}
28
29 "" ** internal ** {{{
30
31 "" warnings 
32
33 let s:displayed_warnings = 0
34 function s:Warnings()
35   if !s:displayed_warnings
36     let l:show_website_url = 0
37
38     let l:msg = "has been deprecated in favour of flake8 config files"
39     for setting_name in ['g:flake8_ignore', 'g:flake8_builtins', 'g:flake8_max_line_length', 'g:flake8_max_complexity']
40       if exists(setting_name)
41         echohl WarningMsg | echom setting_name l:msg | echohl None
42         let l:show_website_url = 1
43       endif
44     endfor
45
46     if l:show_website_url
47       let l:url = "http://flake8.readthedocs.org/en/latest/config.html"
48       echohl WarningMsg | echom l:url | echohl None
49     endif
50     let s:displayed_warnings = 1
51   endif
52 endfunction
53
54 "" config
55
56 function! s:DeclareOption(name, globalPrefix, default)  " {{{
57     if !exists('g:'.a:name)
58         if a:default != ''
59             execute 'let s:'.a:name.'='.a:default
60         else
61             execute 'let s:'.a:name.'=""'
62         endif
63     else
64         execute 'let l:global="g:".a:name'
65         if l:global != ''
66             execute 'let s:'.a:name.'="'.a:globalPrefix.'".g:'.a:name
67         else
68             execute 'let s:'.a:name.'=""'
69         endif
70     endif
71 endfunction  " }}}
72
73 function! s:Setup()  " {{{
74     "" read options
75
76     " flake8 command
77     call s:DeclareOption('flake8_cmd', '', '"flake8"')
78     " quickfix
79     call s:DeclareOption('flake8_quickfix_location', '', '"belowright"')
80     call s:DeclareOption('flake8_quickfix_height', '', 5)
81     call s:DeclareOption('flake8_show_quickfix', '', 1)
82     " markers to show
83     call s:DeclareOption('flake8_show_in_gutter', '',   0)
84     call s:DeclareOption('flake8_show_in_file', '',   0)
85     call s:DeclareOption('flake8_max_markers', '', 500)
86     " marker signs
87     call s:DeclareOption('flake8_error_marker', '', '"E>"')
88     call s:DeclareOption('flake8_warning_marker', '', '"W>"')
89     call s:DeclareOption('flake8_pyflake_marker', '', '"F>"')
90     call s:DeclareOption('flake8_complexity_marker', '', '"C>"')
91     call s:DeclareOption('flake8_naming_marker', '', '"N>"')
92
93     "" setup markerdata
94
95     if !exists('s:markerdata')
96         let s:markerdata = {}
97         let s:markerdata['E'] = {'name': 'Flake8_Error'}
98         let s:markerdata['W'] = {'name': 'Flake8_Warning'}
99         let s:markerdata['F'] = {'name': 'Flake8_PyFlake'}
100         let s:markerdata['C'] = {'name': 'Flake8_Complexity'}
101         let s:markerdata['N'] = {'name': 'Flake8_Nameing'}
102     endif
103     let s:markerdata['E'].marker = s:flake8_error_marker
104     let s:markerdata['W'].marker = s:flake8_warning_marker
105     let s:markerdata['F'].marker = s:flake8_pyflake_marker
106     let s:markerdata['C'].marker = s:flake8_complexity_marker
107     let s:markerdata['N'].marker = s:flake8_naming_marker
108
109 endfunction  " }}}
110
111 "" do flake8
112
113 function! s:Flake8()  " {{{
114     " read config
115     call s:Setup()
116
117     let l:executable = split(s:flake8_cmd)[0]
118
119     if !executable(l:executable)
120         echoerr "File " . l:executable . " not found. Please install it first."
121         return
122     endif
123
124     " clear old
125     call s:UnplaceMarkers()
126     let s:matchids = []
127     let s:signids  = []
128
129     " store old grep settings (to restore later)
130     let l:old_gfm=&grepformat
131     let l:old_gp=&grepprg
132     let l:old_shellpipe=&shellpipe
133     let l:old_t_ti=&t_ti
134     let l:old_t_te=&t_te
135
136     " write any changes before continuing
137     if &readonly == 0
138         update
139     endif
140
141     set lazyredraw   " delay redrawing
142
143     " prevent terminal from blinking
144     set shellpipe=>
145     set t_ti=
146     set t_te=
147
148     " perform the grep itself
149     let &grepformat="%f:%l:%c: %m\,%f:%l: %m,%-G%\\d"
150     let &grepprg=s:flake8_cmd
151     silent! grep! "%"
152     " close any existing cwindows,
153     " placed after 'grep' in case quickfix is open on autocmd QuickFixCmdPost
154     cclose
155
156     " restore grep settings
157     let &grepformat=l:old_gfm
158     let &grepprg=l:old_gp
159     let &shellpipe=l:old_shellpipe
160     let &t_ti=l:old_t_ti
161     let &t_te=l:old_t_te
162     " store mapping of line number to error string
163
164     " process results
165     let s:resultDict = {} 
166
167     let l:results=getqflist()
168     let l:has_results=results != []
169     if l:has_results
170         " save line number of each error message        
171         for result in l:results
172             let linenum = result.lnum
173             let s:resultDict[linenum] = result.text
174         endfor
175
176         " markers
177         if !s:flake8_show_in_gutter == 0 || !s:flake8_show_in_file == 0
178             call s:PlaceMarkers(l:results)
179         endif
180         " quickfix
181         if !s:flake8_show_quickfix == 0
182             " open cwindow
183             execute s:flake8_quickfix_location." copen".s:flake8_quickfix_height
184             setlocal wrap
185             nnoremap <buffer> <silent> c :cclose<CR>
186             nnoremap <buffer> <silent> q :cclose<CR>
187         endif
188     endif
189
190     set nolazyredraw
191     redraw!
192
193     " Show status
194     if l:has_results == 0
195         echon "Flake8 check OK"
196     else
197         echon "Flake8 found issues"
198     endif
199 endfunction  " }}}
200
201
202
203 "" markers
204 function! s:PlaceMarkers(results)  " {{{
205     " in gutter?
206     if !s:flake8_show_in_gutter == 0
207         " define signs
208         for val in values(s:markerdata)
209             if val.marker != ''
210                 execute "sign define ".val.name." text=".val.marker." texthl=".val.name
211             endif
212         endfor
213     endif
214
215     " place
216     let l:index0 = 100
217     let l:index  = l:index0
218     for result in a:results
219         if l:index >= (s:flake8_max_markers+l:index0)
220             break
221         endif
222         let l:type = strpart(result.text, 0, 1)
223         if has_key(s:markerdata, l:type) && s:markerdata[l:type].marker != ''
224             " file markers
225             if !s:flake8_show_in_file == 0
226                 if !has_key(s:markerdata[l:type], 'matchstr')
227                     let s:markerdata[l:type].matchstr = '\%('
228                 else
229                     let s:markerdata[l:type].matchstr .= '\|'
230                 endif
231                 let s:markerdata[l:type].matchstr .= '\%'.result.lnum.'l\%'.result.col.'c'
232             endif
233             " gutter markers
234             if !s:flake8_show_in_gutter == 0
235                 execute ":sign place ".index." name=".s:markerdata[l:type].name
236                             \ . " line=".result.lnum." file=".expand("%:p")
237                 let s:signids += [l:index]
238             endif
239             let l:index += 1
240         endif
241     endfor
242
243     " in file?
244     if !s:flake8_show_in_file == 0
245         for l:val in values(s:markerdata)
246             if l:val.marker != '' && has_key(l:val, 'matchstr')
247                 let l:val.matchid = matchadd(l:val.name, l:val.matchstr.'\)')
248             endif
249         endfor
250     endif
251 endfunction  " }}}
252
253 function! s:UnplaceMarkers()  " {{{
254     " gutter markers
255     if exists('s:signids')
256         for i in s:signids
257             execute ":sign unplace ".i
258         endfor
259         unlet s:signids
260     endif
261     " file markers
262     for l:val in values(s:markerdata)
263         if has_key(l:val, 'matchid')
264             call matchdelete(l:val.matchid)
265             unlet l:val.matchid
266             unlet l:val.matchstr
267         endif
268     endfor
269 endfunction  " }}}
270
271 function! s:ShowErrorMessage()  " {{{
272     let l:cursorPos = getpos(".")
273     if !exists('s:resultDict')
274         return
275     endif
276     if !exists('b:showing_message')
277         " ensure showing msg is always defined
278         let b:showing_message = ' '
279     endif
280
281     " if there is a message on the current line,
282     " then echo it 
283     if has_key(s:resultDict, l:cursorPos[1])
284         let l:errorText = get(s:resultDict, l:cursorPos[1]) 
285         echo strpart(l:errorText, 0, &columns-1)
286         let b:showing_message = 1
287     endif
288
289     " if a message is already being shown,
290     " then clear it
291     if !b:showing_message == 0
292         echo
293         let b:showing_message = 0
294     endif
295
296 endfunction  " }}}
297
298 "" }}}
299
300 let &cpo = s:save_cpo
301 unlet s:save_cpo