]> git.madduck.net Git - etc/vim.git/blob - .vim/bundle/ale/ale_linters/python/flakehell.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 '76265755a1add77121c8f9dabb3e9bb70fe9a972' as '.vim/bundle/ale'
[etc/vim.git] / .vim / bundle / ale / ale_linters / python / flakehell.vim
1 " Author: w0rp <devw0rp@gmail.com>
2 " Description: flakehell for python files
3
4 call ale#Set('python_flakehell_executable', 'flakehell')
5 call ale#Set('python_flakehell_options', '')
6 call ale#Set('python_flakehell_use_global', get(g:, 'ale_use_global_executables', 0))
7 call ale#Set('python_flakehell_change_directory', 'project')
8 call ale#Set('python_flakehell_auto_pipenv', 0)
9 call ale#Set('python_flakehell_auto_poetry', 0)
10 call ale#Set('python_flakehell_auto_uv', 0)
11
12 function! s:UsingModule(buffer) abort
13     return ale#Var(a:buffer, 'python_flakehell_executable') is? 'python'
14 endfunction
15
16 function! ale_linters#python#flakehell#GetExecutable(buffer) abort
17     if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_flakehell_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_flakehell_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_flakehell_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_flakehell', ['flakehell'])
34     endif
35
36     return ale#Var(a:buffer, 'python_flakehell_executable')
37 endfunction
38
39 function! ale_linters#python#flakehell#RunWithVersionCheck(buffer) abort
40     let l:executable = ale_linters#python#flakehell#GetExecutable(a:buffer)
41
42     let l:module_string = s:UsingModule(a:buffer) ? ' -m flakehell' : ''
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#flakehell#GetCommand'),
50     \)
51 endfunction
52
53 function! ale_linters#python#flakehell#GetCwd(buffer) abort
54     let l:change_directory = ale#Var(a:buffer, 'python_flakehell_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#flakehell#GetCommand(buffer, version) abort
75     let l:executable = ale_linters#python#flakehell#GetExecutable(a:buffer)
76
77     if (l:executable =~? '\(pipenv\|poetry\|uv\)$')
78         let l:exec_args = ' run flakehell'
79     elseif (l:executable is? 'python')
80         let l:exec_args = ' -m flakehell'
81     else
82         let l:exec_args = ''
83     endif
84
85     " Only include the --stdin-display-name argument if we can parse the
86     " flakehell version, and it is recent enough to support it.
87     let l:display_name_args = ale#semver#GTE(a:version, [0, 8, 0])
88     \   ? ' --stdin-display-name %s'
89     \   : ''
90
91     let l:options = ale#Var(a:buffer, 'python_flakehell_options')
92
93     return ale#Escape(l:executable)
94     \   . l:exec_args
95     \   . (!empty(l:options) ? ' lint ' . l:options : ' lint')
96     \   . ' --format=default'
97     \   . l:display_name_args . ' -'
98 endfunction
99
100 let s:end_col_pattern_map = {
101 \   'F405': '\(.\+\) may be undefined',
102 \   'F821': 'undefined name ''\([^'']\+\)''',
103 \   'F999': '^''\([^'']\+\)''',
104 \   'F841': 'local variable ''\([^'']\+\)''',
105 \}
106
107 function! ale_linters#python#flakehell#Handle(buffer, lines) abort
108     let l:output = ale#python#HandleTraceback(a:lines, 10)
109
110     if !empty(l:output)
111         return l:output
112     endif
113
114     " Matches patterns line the following:
115     "
116     " Matches patterns line the following:
117     "
118     " stdin:6:6: E111 indentation is not a multiple of four
119     let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: ([[:alnum:]]+):? (.*)$'
120
121     for l:match in ale#util#GetMatches(a:lines, l:pattern)
122         let l:code = l:match[3]
123
124         if (l:code is# 'W291' || l:code is# 'W293')
125         \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
126             " Skip warnings for trailing whitespace if the option is off.
127             continue
128         endif
129
130         if l:code is# 'W391'
131         \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines')
132             " Skip warnings for trailing blank lines if the option is off
133             continue
134         endif
135
136         let l:item = {
137         \   'lnum': l:match[1] + 0,
138         \   'col': l:match[2] + 0,
139         \   'vcol': 1,
140         \   'text': l:match[4],
141         \   'code': l:code,
142         \   'type': 'W',
143         \}
144
145         if l:code[:0] is# 'F'
146             if l:code isnot# 'F401'
147                 let l:item.type = 'E'
148             endif
149         elseif l:code[:0] is# 'E'
150             let l:item.type = 'E'
151
152             if l:code isnot# 'E999' && l:code isnot# 'E112'
153                 let l:item.sub_type = 'style'
154             endif
155         elseif l:code[:0] is# 'W'
156             let l:item.sub_type = 'style'
157         endif
158
159         let l:end_col_pattern = get(s:end_col_pattern_map, l:code, '')
160
161         if !empty(l:end_col_pattern)
162             let l:end_col_match = matchlist(l:match[4], l:end_col_pattern)
163
164             if !empty(l:end_col_match)
165                 let l:item.end_col = l:item.col + len(l:end_col_match[1]) - 1
166             endif
167         endif
168
169         call add(l:output, l:item)
170     endfor
171
172     return l:output
173 endfunction
174
175 call ale#linter#Define('python', {
176 \   'name': 'flakehell',
177 \   'executable': function('ale_linters#python#flakehell#GetExecutable'),
178 \   'cwd': function('ale_linters#python#flakehell#GetCwd'),
179 \   'command': function('ale_linters#python#flakehell#RunWithVersionCheck'),
180 \   'callback': 'ale_linters#python#flakehell#Handle',
181 \})