]> 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:

[WIP] Adds error message feature
[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#ShowErrorMessage()
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
110
111 endfunction  " }}}
112
113 "" do flake8
114
115 function! s:Flake8()  " {{{
116     " read config
117     call s:Setup()
118
119     let l:executable = split(s:flake8_cmd)[0]
120
121     if !executable(l:executable)
122         echoerr "File " . l:executable . " not found. Please install it first."
123         return
124     endif
125
126     " clear old
127     call s:UnplaceMarkers()
128     let s:matchids = []
129     let s:signids  = []
130
131     " store old grep settings (to restore later)
132     let l:old_gfm=&grepformat
133     let l:old_gp=&grepprg
134     let l:old_shellpipe=&shellpipe
135     let l:old_t_ti=&t_ti
136     let l:old_t_te=&t_te
137
138     " write any changes before continuing
139     if &readonly == 0
140         update
141     endif
142
143     set lazyredraw   " delay redrawing
144
145     " prevent terminal from blinking
146     set shellpipe=>
147     set t_ti=
148     set t_te=
149
150     " perform the grep itself
151     let &grepformat="%f:%l:%c: %m\,%f:%l: %m"
152     let &grepprg=s:flake8_cmd
153     silent! grep! "%"
154     " close any existing cwindows,
155     " placed after 'grep' in case quickfix is open on autocmd QuickFixCmdPost
156     cclose
157
158     " restore grep settings
159     let &grepformat=l:old_gfm
160     let &grepprg=l:old_gp
161     let &shellpipe=l:old_shellpipe
162     let &t_ti=l:old_t_ti
163     let &t_te=l:old_t_te
164     " store mapping of line number to error string
165
166     " process results
167     let s:resultDict = {} 
168
169     let l:results=getqflist()
170     let l:has_results=results != []
171     if l:has_results
172         " save line number of each error message        
173         for result in a:results:
174             s:resultDict[result.lnum] = result.text
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 "" markers
202 function! s:PlaceMarkers(results)  " {{{
203     " in gutter?
204     if !s:flake8_show_in_gutter == 0
205         " define signs
206         for val in values(s:markerdata)
207             if val.marker != ''
208                 execute "sign define ".val.name." text=".val.marker." texthl=".val.name
209             endif
210         endfor
211     endif
212
213     " place
214     let l:index0 = 100
215     let l:index  = l:index0
216     for result in a:results
217         if l:index >= (s:flake8_max_markers+l:index0)
218             break
219         endif
220         let l:type = strpart(result.text, 0, 1)
221         if has_key(s:markerdata, l:type) && s:markerdata[l:type].marker != ''
222             " file markers
223             if !s:flake8_show_in_file == 0
224                 if !has_key(s:markerdata[l:type], 'matchstr')
225                     let s:markerdata[l:type].matchstr = '\%('
226                 else
227                     let s:markerdata[l:type].matchstr .= '\|'
228                 endif
229                 let s:markerdata[l:type].matchstr .= '\%'.result.lnum.'l\%'.result.col.'c'
230             endif
231             " gutter markers
232             if !s:flake8_show_in_gutter == 0
233                 execute ":sign place ".index." name=".s:markerdata[l:type].name
234                             \ . " line=".result.lnum." file=".expand("%:p")
235                 let s:signids += [l:index]
236             endif
237             let l:index += 1
238         endif
239     endfor
240
241     " in file?
242     if !s:flake8_show_in_file == 0
243         for l:val in values(s:markerdata)
244             if l:val.marker != '' && has_key(l:val, 'matchstr')
245                 let l:val.matchid = matchadd(l:val.name, l:val.matchstr.'\)')
246             endif
247         endfor
248     endif
249 endfunction  " }}}
250
251 function! s:UnplaceMarkers()  " {{{
252     " gutter markers
253     if exists('s:signids')
254         for i in s:signids
255             execute ":sign unplace ".i
256         endfor
257         unlet s:signids
258     endif
259     " file markers
260     for l:val in values(s:markerdata)
261         if has_key(l:val, 'matchid')
262             call matchdelete(l:val.matchid)
263             unlet l:val.matchid
264             unlet l:val.matchstr
265         endif
266     endfor
267 endfunction  " }}}
268
269 function! s:ShowErrorMessage()  " {{{
270     let l:cursorPos = getpos(".")
271     if !exists('s:resultDict')
272         return
273     endif
274
275     " if there is a message on the current line,
276     " then echo it 
277     if has_key(s:matchDict, s:cursorPos[1])
278         let l:errorText = get(s:matchDict, l:cursorPos[1]) 
279         echo strpart(l:errorText, 0, &columns-1)
280         let b:showing_message = 1
281     endif
282
283     " if a message is already being shown,
284     " then clear it
285     if !b:showing_message == 0
286         echo
287         let b:showing_message = 0
288     endif
289
290 endfunction  " }}}
291
292 "" }}}
293
294 let &cpo = s:save_cpo
295 unlet s:save_cpo
296