Move all functions for fixing things to autoload/ale/fixers, and only accept the lines of input where needed.

This commit is contained in:
w0rp 2017-06-07 14:02:29 +01:00
parent edddb1910b
commit 7517fd8226
15 changed files with 132 additions and 98 deletions

View File

@ -232,11 +232,11 @@ function! s:RunFixer(options) abort
let l:index = a:options.callback_index
while len(a:options.callback_list) > l:index
let l:Function = ale#util#GetFunction(a:options.callback_list[l:index])
let l:Function = a:options.callback_list[l:index]
let l:result = ale#util#FunctionArgCount(l:Function) == 1
\ ? l:Function(l:buffer)
\ : l:Function(l:buffer, copy(l:input))
\ ? call(l:Function, [l:buffer])
\ : call(l:Function, [l:buffer, copy(l:input)])
if type(l:result) == type(0) && l:result == 0
" When `0` is returned, skip this item.

View File

@ -3,42 +3,42 @@
let s:default_registry = {
\ 'add_blank_lines_for_python_control_statements': {
\ 'function': 'ale#handlers#python#AddLinesBeforeControlStatements',
\ 'function': 'ale#fixers#generic_python#AddLinesBeforeControlStatements',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Add blank lines before control statements.',
\ },
\ 'autopep8': {
\ 'function': 'ale#handlers#python#AutoPEP8',
\ 'function': 'ale#fixers#autopep8#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix PEP8 issues with autopep8.',
\ },
\ 'eslint': {
\ 'function': 'ale#handlers#eslint#Fix',
\ 'function': 'ale#fixers#eslint#Fix',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Apply eslint --fix to a file.',
\ },
\ 'isort': {
\ 'function': 'ale#handlers#python#ISort',
\ 'function': 'ale#fixers#isort#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Sort Python imports with isort.',
\ },
\ 'prettier': {
\ 'function': 'ale#handlers#prettier#Fix',
\ 'function': 'ale#fixers#prettier#Fix',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Apply prettier to a file.',
\ },
\ 'prettier_eslint': {
\ 'function': 'ale#handlers#prettier_eslint#Fix',
\ 'function': 'ale#fixers#prettier_eslint#Fix',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Apply prettier-eslint to a file.',
\ },
\ 'remove_trailing_lines': {
\ 'function': 'ale#fix#generic#RemoveTrailingBlankLines',
\ 'function': 'ale#fixers#generic#RemoveTrailingBlankLines',
\ 'suggested_filetypes': [],
\ 'description': 'Remove all blank lines at the end of a file.',
\ },
\ 'yapf': {
\ 'function': 'ale#handlers#python#YAPF',
\ 'function': 'ale#fixers#yapf#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix Python files with yapf.',
\ },

View File

@ -0,0 +1,8 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Fixing files with autopep8.
function! ale#fixers#autopep8#Fix(buffer) abort
return {
\ 'command': 'autopep8 -'
\}
endfunction

View File

@ -0,0 +1,36 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Fixing files with eslint.
function! s:FindConfig(buffer) abort
for l:filename in [
\ '.eslintrc.js',
\ '.eslintrc.yaml',
\ '.eslintrc.yml',
\ '.eslintrc.json',
\ '.eslintrc',
\]
let l:config = ale#path#FindNearestFile(a:buffer, l:filename)
if !empty(l:config)
return l:config
endif
endfor
return ''
endfunction
function! ale#fixers#eslint#Fix(buffer) abort
let l:executable = ale#handlers#eslint#GetExecutable(a:buffer)
let l:config = s:FindConfig(a:buffer)
if empty(l:config)
return 0
endif
return {
\ 'command': ale#Escape(l:executable)
\ . ' --config ' . ale#Escape(l:config)
\ . ' --fix %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -0,0 +1,22 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Generic fixer functions for Python.
" Add blank lines before control statements.
function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, lines) abort
let l:new_lines = []
let l:last_indent_size = 0
for l:line in a:lines
let l:indent_size = len(matchstr(l:line, '^ *'))
if l:indent_size <= l:last_indent_size
\&& match(l:line, '\v^ *(return|if|for|while|break|continue)') >= 0
call add(l:new_lines, '')
endif
call add(l:new_lines, l:line)
let l:last_indent_size = l:indent_size
endfor
return l:new_lines
endfunction

View File

@ -0,0 +1,13 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Fixing Python imports with isort.
function! ale#fixers#isort#Fix(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.isort.cfg')
let l:config_options = !empty(l:config)
\ ? ' --settings-path ' . ale#Escape(l:config)
\ : ''
return {
\ 'command': 'isort' . l:config_options . ' -',
\}
endfunction

View File

@ -0,0 +1,13 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Fixing Python files with yapf.
function! ale#fixers#yapf#Fix(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.style.yapf')
let l:config_options = !empty(l:config)
\ ? ' --style ' . ale#Escape(l:config)
\ : ''
return {
\ 'command': 'yapf --no-local-style' . l:config_options,
\}
endfunction

View File

@ -1,5 +1,5 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: eslint functions for handling and fixing errors.
" Description: Functions for working with eslint, for checking or fixing files.
call ale#Set('javascript_eslint_executable', 'eslint')
call ale#Set('javascript_eslint_use_global', 0)
@ -11,36 +11,3 @@ function! ale#handlers#eslint#GetExecutable(buffer) abort
\ 'node_modules/.bin/eslint',
\])
endfunction
function! s:FindConfig(buffer) abort
for l:filename in [
\ '.eslintrc.js',
\ '.eslintrc.yaml',
\ '.eslintrc.yml',
\ '.eslintrc.json',
\ '.eslintrc',
\]
let l:config = ale#path#FindNearestFile(a:buffer, l:filename)
if !empty(l:config)
return l:config
endif
endfor
return ''
endfunction
function! ale#handlers#eslint#Fix(buffer, lines) abort
let l:config = s:FindConfig(a:buffer)
if empty(l:config)
return 0
endif
return {
\ 'command': ale#Escape(ale#handlers#eslint#GetExecutable(a:buffer))
\ . ' --config ' . ale#Escape(l:config)
\ . ' --fix %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -45,51 +45,3 @@ function! ale#handlers#python#HandlePEP8Format(buffer, lines) abort
return l:output
endfunction
" Add blank lines before control statements.
function! ale#handlers#python#AddLinesBeforeControlStatements(buffer, lines) abort
let l:new_lines = []
let l:last_indent_size = 0
for l:line in a:lines
let l:indent_size = len(matchstr(l:line, '^ *'))
if l:indent_size <= l:last_indent_size
\&& match(l:line, '\v^ *(return|if|for|while|break|continue)') >= 0
call add(l:new_lines, '')
endif
call add(l:new_lines, l:line)
let l:last_indent_size = l:indent_size
endfor
return l:new_lines
endfunction
function! ale#handlers#python#AutoPEP8(buffer, lines) abort
return {
\ 'command': 'autopep8 -'
\}
endfunction
function! ale#handlers#python#ISort(buffer, lines) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.isort.cfg')
let l:config_options = !empty(l:config)
\ ? ' --settings-path ' . ale#Escape(l:config)
\ : ''
return {
\ 'command': 'isort' . l:config_options . ' -',
\}
endfunction
function! ale#handlers#python#YAPF(buffer, lines) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.style.yapf')
let l:config_options = !empty(l:config)
\ ? ' --style ' . ale#Escape(l:config)
\ : ''
return {
\ 'command': 'yapf --no-local-style' . l:config_options,
\}
endfunction

View File

@ -124,10 +124,8 @@ function! ale#util#GetMatches(lines, patterns) abort
return l:matches
endfunction
" Given the name of a function, a Funcref, or a lambda, return the number
" of named arguments for a function.
function! ale#util#FunctionArgCount(function) abort
let l:Function = ale#util#GetFunction(a:function)
function! s:LoadArgCount(function) abort
let l:Function = a:function
redir => l:output
silent! function Function
@ -142,3 +140,24 @@ function! ale#util#FunctionArgCount(function) abort
return len(l:arg_list)
endfunction
" Given the name of a function, a Funcref, or a lambda, return the number
" of named arguments for a function.
function! ale#util#FunctionArgCount(function) abort
let l:Function = ale#util#GetFunction(a:function)
let l:count = s:LoadArgCount(l:Function)
" If we failed to get the count, forcibly load the autoload file, if the
" function is an autoload function. autoload functions aren't normally
" defined until they are called.
if l:count == 0
let l:function_name = matchlist(string(l:Function), 'function([''"]\(.\+\)[''"])')[1]
if l:function_name =~# '#'
execute 'runtime autoload/' . join(split(l:function_name, '#')[:-2], '/') . '.vim'
let l:count = s:LoadArgCount(l:Function)
endif
endif
return l:count
endfunction

View File

@ -39,7 +39,7 @@ Given python(Some Python without blank lines):
pass
Execute(Blank lines should be added appropriately):
let g:ale_fixers = {'python': ['ale#handlers#python#AddLinesBeforeControlStatements']}
let g:ale_fixers = {'python': ['add_blank_lines_for_python_control_statements']}
ALEFix
Expect python(Newlines should be added):

View File

@ -39,3 +39,7 @@ Execute(We should be able to compute the argument count for lambdas):
AssertEqual 3, ale#util#FunctionArgCount({x,y,z->1})
AssertEqual 3, ale#util#FunctionArgCount({x,y,z,...->1})
endif
Execute(We should be able to compute the argument count autoload functions not yet loaded):
AssertEqual 1, ale#util#FunctionArgCount(function('ale#fixers#yapf#Fix'))
AssertEqual 1, ale#util#FunctionArgCount('ale#fixers#yapf#Fix')