]> git.madduck.net Git - etc/vim.git/blob - .vim/bundle/ale/ale_linters/python/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:

Merge commit 'a39f715c13be3352193ffd9c5b7536b8786eff64' as '.vim/bundle/vim-lsp'
[etc/vim.git] / .vim / bundle / ale / ale_linters / python / flake8.vim
1 " Author: w0rp <devw0rp@gmail.com>
2 " Description: flake8 for python files
3
4 call ale#Set('python_flake8_executable', 'flake8')
5 call ale#Set('python_flake8_options', '')
6 call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
7 call ale#Set('python_flake8_change_directory', 'project')
8 call ale#Set('python_flake8_auto_pipenv', 0)
9 call ale#Set('python_flake8_auto_poetry', 0)
10 call ale#Set('python_flake8_auto_uv', 0)
11
12 function! s:UsingModule(buffer) abort
13     return ale#Var(a:buffer, 'python_flake8_options') =~# ' *-m flake8'
14 endfunction
15
16 function! ale_linters#python#flake8#GetExecutable(buffer) abort
17     if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_flake8_auto_pipenv'))
18     \ && ale#python#PipenvPresent(a:buffer)
19         return 'pipenv'
20     endif
21
22     if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_flake8_auto_poetry'))
23     \ && ale#python#PoetryPresent(a:buffer)
24         return 'poetry'
25     endif
26
27     if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_flake8_auto_uv'))
28     \ && ale#python#UvPresent(a:buffer)
29         return 'uv'
30     endif
31
32     if !s:UsingModule(a:buffer)
33         return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8'])
34     endif
35
36     return ale#Var(a:buffer, 'python_flake8_executable')
37 endfunction
38
39 function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
40     let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
41
42     let l:module_string = s:UsingModule(a:buffer) ? ' -m flake8' : ''
43     let l:command = ale#Escape(l:executable) . l:module_string . ' --version'
44
45     return ale#semver#RunWithVersionCheck(
46     \   a:buffer,
47     \   l:executable,
48     \   l:command,
49     \   function('ale_linters#python#flake8#GetCommand'),
50     \)
51 endfunction
52
53 function! ale_linters#python#flake8#GetCwd(buffer) abort
54     let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory')
55     let l:cwd = ''
56
57     if l:change_directory is# 'project'
58         let l:project_root = ale#python#FindProjectRootIni(a:buffer)
59
60         if !empty(l:project_root)
61             let l:cwd = l:project_root
62         endif
63     endif
64
65     if (l:change_directory is# 'project' && empty(l:cwd))
66     \|| l:change_directory
67     \|| l:change_directory is# 'file'
68         let l:cwd = '%s:h'
69     endif
70
71     return l:cwd
72 endfunction
73
74 function! ale_linters#python#flake8#GetCommand(buffer, version) abort
75     let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
76
77     let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$'
78     \   ? ' run flake8'
79     \   : ''
80
81     " Only include the --stdin-display-name argument if we can parse the
82     " flake8 version, and it is recent enough to support it.
83     let l:display_name_args = ale#semver#GTE(a:version, [3, 0, 0])
84     \   ? ' --stdin-display-name %s'
85     \   : ''
86
87     let l:options = ale#Var(a:buffer, 'python_flake8_options')
88
89     return ale#Escape(l:executable) . l:exec_args
90     \   . (!empty(l:options) ? ' ' . l:options : '')
91     \   . ' --format=default'
92     \   . l:display_name_args . ' -'
93 endfunction
94
95 let s:end_col_pattern_map = {
96 \   'F405': '\(.\+\) may be undefined',
97 \   'F821': 'undefined name ''\([^'']\+\)''',
98 \   'F999': '^''\([^'']\+\)''',
99 \   'F841': 'local variable ''\([^'']\+\)''',
100 \}
101
102 function! ale_linters#python#flake8#Handle(buffer, lines) abort
103     let l:output = ale#python#HandleTraceback(a:lines, 10)
104
105     if !empty(l:output)
106         return l:output
107     endif
108
109     " Matches patterns line the following:
110     "
111     " Matches patterns line the following:
112     "
113     " stdin:6:6: E111 indentation is not a multiple of four
114     let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: ([[:alnum:]]+):? (.*)$'
115
116     for l:match in ale#util#GetMatches(a:lines, l:pattern)
117         let l:code = l:match[3]
118
119         if (l:code is# 'W291' || l:code is# 'W293')
120         \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
121             " Skip warnings for trailing whitespace if the option is off.
122             continue
123         endif
124
125         if l:code is# 'W391'
126         \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines')
127             " Skip warnings for trailing blank lines if the option is off
128             continue
129         endif
130
131         let l:item = {
132         \   'lnum': l:match[1] + 0,
133         \   'col': l:match[2] + 0,
134         \   'vcol': 1,
135         \   'text': l:match[4],
136         \   'code': l:code,
137         \   'type': 'W',
138         \}
139
140         if l:code[:0] is# 'F'
141             if l:code isnot# 'F401'
142                 let l:item.type = 'E'
143             endif
144         elseif l:code[:0] is# 'E'
145             let l:item.type = 'E'
146
147             if l:code isnot# 'E999' && l:code isnot# 'E112'
148                 let l:item.sub_type = 'style'
149             endif
150         elseif l:code[:0] is# 'W'
151             let l:item.sub_type = 'style'
152         endif
153
154         let l:end_col_pattern = get(s:end_col_pattern_map, l:code, '')
155
156         if !empty(l:end_col_pattern)
157             let l:end_col_match = matchlist(l:match[4], l:end_col_pattern)
158
159             if !empty(l:end_col_match)
160                 let l:item.end_col = l:item.col + len(l:end_col_match[1]) - 1
161             endif
162         endif
163
164         call add(l:output, l:item)
165     endfor
166
167     return l:output
168 endfunction
169
170 call ale#linter#Define('python', {
171 \   'name': 'flake8',
172 \   'executable': function('ale_linters#python#flake8#GetExecutable'),
173 \   'cwd': function('ale_linters#python#flake8#GetCwd'),
174 \   'command': function('ale_linters#python#flake8#RunWithVersionCheck'),
175 \   'callback': 'ale_linters#python#flake8#Handle',
176 \})