1
0
mirror of https://github.com/amix/vimrc synced 2025-06-16 01:25:00 +08:00

Updated plugins

This commit is contained in:
Amir Salihefendic
2018-07-19 14:52:53 +02:00
parent 2f164fee9b
commit cc997dc3d0
99 changed files with 1572 additions and 1151 deletions

View File

@ -191,15 +191,12 @@ endfunction
"
" Every variable name will be prefixed with 'ale_'.
function! ale#Var(buffer, variable_name) abort
let l:nr = str2nr(a:buffer)
let l:full_name = 'ale_' . a:variable_name
let l:vars = getbufvar(str2nr(a:buffer), '', 0)
if bufexists(l:nr)
let l:vars = getbufvar(l:nr, '')
elseif has_key(g:, 'ale_fix_buffer_data')
let l:vars = get(g:ale_fix_buffer_data, l:nr, {'vars': {}}).vars
else
let l:vars = {}
if l:vars is 0
" Look for variables from deleted buffers, saved from :ALEFix
let l:vars = get(get(g:ale_fix_buffer_data, a:buffer, {}), 'vars', {})
endif
return get(l:vars, l:full_name, g:[l:full_name])
@ -210,10 +207,29 @@ endfunction
" Every variable name will be prefixed with 'ale_'.
function! ale#Set(variable_name, default) abort
let l:full_name = 'ale_' . a:variable_name
let l:value = get(g:, l:full_name, a:default)
let g:[l:full_name] = l:value
return l:value
if !has_key(g:, l:full_name)
let g:[l:full_name] = a:default
endif
endfunction
" Given a string for adding to a command, return the string padded with a
" space on the left if it is not empty. Otherwise return an empty string.
"
" This can be used for making command strings cleaner and easier to test.
function! ale#Pad(string) abort
return !empty(a:string) ? ' ' . a:string : ''
endfunction
" Given a environment variable name and a value, produce part of a command for
" setting an environment variable before running a command. The syntax will be
" valid for cmd on Windows, or most shells on Unix.
function! ale#Env(variable_name, value) abort
if has('win32')
return 'set ' . a:variable_name . '=' . ale#Escape(a:value) . ' && '
endif
return a:variable_name . '=' . ale#Escape(a:value) . ' '
endfunction
" Escape a string suitably for each platform.

View File

@ -0,0 +1,159 @@
let s:chain_results = []
function! ale#assert#WithChainResults(...) abort
let s:chain_results = a:000
endfunction
function! s:GetLinter() abort
let l:linters = ale#linter#GetLintersLoaded()
let l:filetype_linters = get(values(l:linters), 0, [])
if len(l:linters) is 0 || len(l:filetype_linters) is 0
throw 'No linters were loaded'
endif
if len(l:linters) > 1 || len(l:filetype_linters) > 1
throw 'More than one linter was loaded'
endif
return l:filetype_linters[0]
endfunction
" Load the currently loaded linter for a test case, and check that the command
" matches the given string.
function! ale#assert#Linter(expected_executable, expected_command) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
if has_key(l:linter, 'command_chain')
let l:callbacks = map(copy(l:linter.command_chain), 'v:val.callback')
" If the expected command is a string, just check the last one.
if type(a:expected_command) is type('')
if len(l:callbacks) is 1
let l:command = call(l:callbacks[0], [l:buffer])
else
let l:input = get(s:chain_results, len(l:callbacks) - 2, [])
let l:command = call(l:callbacks[-1], [l:buffer, l:input])
endif
else
let l:command = []
let l:chain_index = 0
for l:Callback in l:callbacks
if l:chain_index is 0
call add(l:command, call(l:Callback, [l:buffer]))
else
let l:input = get(s:chain_results, l:chain_index - 1, [])
call add(l:command, call(l:Callback, [l:buffer, l:input]))
endif
let l:chain_index += 1
endfor
endif
else
let l:command = ale#linter#GetCommand(l:buffer, l:linter)
" Replace %e with the escaped executable, so tests keep passing after
" linters are changed to use %e.
let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g')
endif
AssertEqual
\ [a:expected_executable, a:expected_command],
\ [l:executable, l:command]
endfunction
function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
Assert empty(l:executable), "The linter will be executed when it shouldn't be"
endfunction
function! ale#assert#LSPOptions(expected_options) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:initialization_options = ale#lsp_linter#GetOptions(l:buffer, l:linter)
AssertEqual a:expected_options, l:initialization_options
endfunction
function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:language = ale#util#GetFunction(l:linter.language_callback)(l:buffer)
AssertEqual a:expected_language, l:language
endfunction
function! ale#assert#LSPProject(expected_root) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:root = ale#util#GetFunction(l:linter.project_root_callback)(l:buffer)
AssertEqual a:expected_root, l:root
endfunction
" A dummy function for making sure this module is loaded.
function! ale#assert#SetUpLinterTest(filetype, name) abort
" Set up a marker so ALE doesn't create real random temporary filenames.
let g:ale_create_dummy_temporary_file = 1
" Remove current linters.
call ale#linter#Reset()
call ale#linter#PreventLoading(a:filetype)
let l:prefix = 'ale_' . a:filetype . '_' . a:name
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
Save g:ale_c_build_dir
unlet! g:ale_c_build_dir
" Save and clear linter variables.
" We'll load the runtime file to reset them to defaults.
for l:key in filter(keys(g:), b:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
unlet! b:ale_c_build_dir
for l:key in filter(keys(b:), b:filter_expr)
unlet b:[l:key]
endfor
execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim'
call ale#test#SetDirectory('/testplugin/test/command_callback')
command! -nargs=+ WithChainResults :call ale#assert#WithChainResults(<args>)
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
endfunction
function! ale#assert#TearDownLinterTest() abort
unlet! g:ale_create_dummy_temporary_file
let s:chain_results = []
delcommand WithChainResults
delcommand AssertLinter
delcommand AssertLinterNotExecuted
delcommand AssertLSPOptions
delcommand AssertLSPLanguage
delcommand AssertLSPProject
call ale#test#RestoreDirectory()
Restore
call ale#linter#Reset()
if exists('*ale#semver#ResetVersionCache')
call ale#semver#ResetVersionCache()
endif
endfunction

View File

@ -13,14 +13,14 @@ function! s:TemporaryFilename(buffer) abort
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
return tempname() . (has('win32') ? '\' : '/') . l:filename
return ale#util#Tempname() . (has('win32') ? '\' : '/') . l:filename
endfunction
" Given a command string, replace every...
" %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory
" %% -> with a literal %
function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort
function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed) abort
let l:temporary_file = ''
let l:command = a:command
@ -28,6 +28,11 @@ function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort
" with an ugly string.
let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g')
" Replace %e with the escaped executable, if available.
if !empty(a:executable) && l:command =~# '%e'
let l:command = substitute(l:command, '%e', '\=ale#Escape(a:executable)', 'g')
endif
" Replace all %s occurrences in the string with the name of the current
" file.
if l:command =~# '%s'

View File

@ -1,6 +1,17 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Completion support for LSP linters
" The omnicompletion menu is shown through a special Plug mapping which is
" only valid in Insert mode. This way, feedkeys() won't send these keys if you
" quit Insert mode quickly enough.
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o>
" If we hit the key sequence in normal mode, then we won't show the menu, so
" we should restore the old settings right away.
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR>
cnoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
vnoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
onoremap <silent> <Plug>(ale_show_completion_menu) <Nop>
let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100)
let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', [])
let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50)
@ -129,7 +140,16 @@ function! ale#completion#Filter(buffer, suggestions, prefix) abort
return l:filtered_suggestions
endfunction
function! s:ReplaceCompleteopt() abort
function! s:ReplaceCompletionOptions() abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
endif
let &l:omnifunc = 'ale#completion#OmniFunc'
if !exists('b:ale_old_completopt')
let b:ale_old_completopt = &l:completeopt
endif
@ -141,6 +161,22 @@ function! s:ReplaceCompleteopt() abort
endif
endfunction
function! ale#completion#RestoreCompletionOptions() abort
" Reset settings when completion is done.
if exists('b:ale_old_omnifunc')
if b:ale_old_omnifunc isnot# 'pythoncomplete#Complete'
let &l:omnifunc = b:ale_old_omnifunc
endif
unlet b:ale_old_omnifunc
endif
if exists('b:ale_old_completopt')
let &l:completeopt = b:ale_old_completopt
unlet b:ale_old_completopt
endif
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:line = b:ale_completion_info.line
@ -163,33 +199,30 @@ function! ale#completion#OmniFunc(findstart, base) abort
let b:ale_completion_result = function(l:parser)(l:response)
endif
call s:ReplaceCompleteopt()
call s:ReplaceCompletionOptions()
return get(b:, 'ale_completion_result', [])
endif
endfunction
function! ale#completion#Show(response, completion_parser) abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
if ale#util#Mode() isnot# 'i'
return
endif
" Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion.
let b:ale_completion_response = a:response
let b:ale_completion_parser = a:completion_parser
let &l:omnifunc = 'ale#completion#OmniFunc'
call s:ReplaceCompleteopt()
call ale#util#FeedKeys("\<C-x>\<C-o>", 'n')
call s:ReplaceCompletionOptions()
call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")
endfunction
function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getcurpos()[1:2]
return has_key(b:, 'ale_completion_info')
return ale#util#Mode() is# 'i'
\&& has_key(b:, 'ale_completion_info')
\&& b:ale_completion_info.request_id == a:request_id
\&& b:ale_completion_info.line == l:line
\&& b:ale_completion_info.column == l:column
@ -477,7 +510,7 @@ function! s:TimerHandler(...) abort
" When running the timer callback, we have to be sure that the cursor
" hasn't moved from where it was when we requested completions by typing.
if s:timer_pos == [l:line, l:column]
if s:timer_pos == [l:line, l:column] && ale#util#Mode() is# 'i'
call ale#completion#GetCompletions()
endif
endfunction
@ -518,19 +551,7 @@ endfunction
function! ale#completion#Done() abort
silent! pclose
" Reset settings when completion is done.
if exists('b:ale_old_omnifunc')
if b:ale_old_omnifunc isnot# 'pythoncomplete#Complete'
let &l:omnifunc = b:ale_old_omnifunc
endif
unlet b:ale_old_omnifunc
endif
if exists('b:ale_old_completopt')
let &l:completeopt = b:ale_old_completopt
unlet b:ale_old_completopt
endif
call ale#completion#RestoreCompletionOptions()
let s:last_done_pos = getcurpos()[1:2]
endfunction

View File

@ -96,9 +96,26 @@ function! ale#engine#ManageDirectory(buffer, directory) abort
call add(g:ale_buffer_info[a:buffer].temporary_directory_list, a:directory)
endfunction
function! ale#engine#CreateFile(buffer) abort
" This variable can be set to 1 in tests to stub this out.
if get(g:, 'ale_create_dummy_temporary_file')
return 'TEMP'
endif
let l:temporary_file = ale#util#Tempname()
call ale#engine#ManageFile(a:buffer, l:temporary_file)
return l:temporary_file
endfunction
" Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort
let l:temporary_directory = tempname()
" This variable can be set to 1 in tests to stub this out.
if get(g:, 'ale_create_dummy_temporary_file')
return 'TEMP_DIR'
endif
let l:temporary_directory = ale#util#Tempname()
" Create the temporary directory for the file, unreadable by 'other'
" users.
call mkdir(l:temporary_directory, '', 0750)
@ -189,6 +206,7 @@ function! s:HandleExit(job_id, exit_code) abort
let l:linter = l:job_info.linter
let l:output = l:job_info.output
let l:buffer = l:job_info.buffer
let l:executable = l:job_info.executable
let l:next_chain_index = l:job_info.next_chain_index
if g:ale_history_enabled
@ -212,7 +230,7 @@ function! s:HandleExit(job_id, exit_code) abort
endif
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output)
call s:InvokeChain(l:buffer, l:executable, l:linter, l:next_chain_index, l:output)
return
endif
@ -221,7 +239,12 @@ function! s:HandleExit(job_id, exit_code) abort
call ale#history#RememberOutput(l:buffer, a:job_id, l:output[:])
endif
let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
try
let l:loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output)
" Handle the function being unknown, or being deleted.
catch /E700/
let l:loclist = []
endtry
call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
endfunction
@ -440,6 +463,12 @@ endfunction
" Returns 1 when the job was started successfully.
function! s:RunJob(options) abort
let l:command = a:options.command
if empty(l:command)
return 0
endif
let l:executable = a:options.executable
let l:buffer = a:options.buffer
let l:linter = a:options.linter
let l:output_stream = a:options.output_stream
@ -447,11 +476,12 @@ function! s:RunJob(options) abort
let l:read_buffer = a:options.read_buffer
let l:info = g:ale_buffer_info[l:buffer]
if empty(l:command)
return 0
endif
let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer)
let [l:temporary_file, l:command] = ale#command#FormatCommand(
\ l:buffer,
\ l:executable,
\ l:command,
\ l:read_buffer,
\)
if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file)
" If a temporary filename has been formatted in to the command, then
@ -512,6 +542,7 @@ function! s:RunJob(options) abort
let s:job_info_map[l:job_id] = {
\ 'linter': l:linter,
\ 'buffer': l:buffer,
\ 'executable': l:executable,
\ 'output': [],
\ 'next_chain_index': l:next_chain_index,
\}
@ -604,8 +635,9 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
\}
endfunction
function! s:InvokeChain(buffer, linter, chain_index, input) abort
function! s:InvokeChain(buffer, executable, linter, chain_index, input) abort
let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input)
let l:options.executable = a:executable
return s:RunJob(l:options)
endfunction
@ -699,7 +731,7 @@ function! s:RunLinter(buffer, linter) abort
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if ale#engine#IsExecutable(a:buffer, l:executable)
return s:InvokeChain(a:buffer, a:linter, 0, [])
return s:InvokeChain(a:buffer, l:executable, a:linter, 0, [])
endif
endif

View File

@ -39,35 +39,48 @@ function! ale#events#SaveEvent(buffer) abort
endif
endfunction
function! s:LintOnEnter(buffer) abort
if ale#Var(a:buffer, 'enabled')
\&& g:ale_lint_on_enter
\&& has_key(b:, 'ale_file_changed')
call remove(b:, 'ale_file_changed')
function! ale#events#LintOnEnter(buffer) abort
" Unmark a file as being changed outside of Vim after we try to check it.
call setbufvar(a:buffer, 'ale_file_changed', 0)
if ale#Var(a:buffer, 'enabled') && g:ale_lint_on_enter
call ale#Queue(0, 'lint_file', a:buffer)
endif
endfunction
function! ale#events#EnterEvent(buffer) abort
function! ale#events#ReadOrEnterEvent(buffer) abort
" Apply pattern options if the variable is set.
if get(g:, 'ale_pattern_options_enabled', 1)
\&& !empty(get(g:, 'ale_pattern_options'))
call ale#pattern_options#SetOptions(a:buffer)
endif
" When entering a buffer, we are no longer quitting it.
call setbufvar(a:buffer, 'ale_quitting', 0)
let l:filetype = getbufvar(a:buffer, '&filetype')
call setbufvar(a:buffer, 'ale_original_filetype', l:filetype)
call s:LintOnEnter(a:buffer)
" If the file changed outside of Vim, check it on BufEnter,BufRead
if getbufvar(a:buffer, 'ale_file_changed')
call ale#events#LintOnEnter(a:buffer)
endif
endfunction
function! ale#events#FileTypeEvent(buffer, new_filetype) abort
let l:filetype = getbufvar(a:buffer, 'ale_original_filetype', '')
" The old filetype will be set to an empty string by the BuFEnter event,
" and not linting when the old filetype hasn't been set yet prevents
" buffers being checked when you enter them when linting on enter is off.
let l:old_filetype = getbufvar(a:buffer, 'ale_original_filetype', v:null)
" If we're setting the filetype for the first time after it was blank,
" and the option for linting on enter is off, then we should set this
" filetype as the original filetype. Otherwise ALE will still appear to
" lint files because of the BufEnter event, etc.
if empty(l:filetype) && !ale#Var(a:buffer, 'lint_on_enter')
if l:old_filetype isnot v:null
\&& !empty(a:new_filetype)
\&& a:new_filetype isnot# l:old_filetype
" Remember what the new filetype is.
call setbufvar(a:buffer, 'ale_original_filetype', a:new_filetype)
elseif a:new_filetype isnot# l:filetype
call ale#Queue(300, 'lint_file', a:buffer)
if g:ale_lint_on_filetype_changed
call ale#Queue(300, 'lint_file', a:buffer)
endif
endif
endfunction
@ -75,7 +88,7 @@ function! ale#events#FileChangedEvent(buffer) abort
call setbufvar(a:buffer, 'ale_file_changed', 1)
if bufnr('') == a:buffer
call s:LintOnEnter(a:buffer)
call ale#events#LintOnEnter(a:buffer)
endif
endfunction
@ -87,7 +100,7 @@ function! ale#events#Init() abort
autocmd!
" These events always need to be set up.
autocmd BufEnter,BufRead * call ale#pattern_options#SetOptions(str2nr(expand('<abuf>')))
autocmd BufEnter,BufRead * call ale#events#ReadOrEnterEvent(str2nr(expand('<abuf>')))
autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
if g:ale_enabled
@ -99,11 +112,8 @@ function! ale#events#Init() abort
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
endif
" Handle everything that needs to happen when buffers are entered.
autocmd BufEnter * call ale#events#EnterEvent(str2nr(expand('<abuf>')))
if g:ale_lint_on_enter
autocmd BufWinEnter,BufRead * call ale#Queue(0, 'lint_file', str2nr(expand('<abuf>')))
autocmd BufWinEnter * call ale#events#LintOnEnter(str2nr(expand('<abuf>')))
" Track when the file is changed outside of Vim.
autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
endif

View File

@ -1,10 +1,3 @@
" This global Dictionary tracks the ALE fix data for jobs, etc.
" This Dictionary should not be accessed outside of the plugin. It is only
" global so it can be modified in Vader tests.
if !has_key(g:, 'ale_fix_buffer_data')
let g:ale_fix_buffer_data = {}
endif
if !has_key(s:, 'job_info_map')
let s:job_info_map = {}
endif
@ -219,6 +212,7 @@ function! s:RunJob(options) abort
let [l:temporary_file, l:command] = ale#command#FormatCommand(
\ l:buffer,
\ '',
\ l:command,
\ l:read_buffer,
\)

View File

@ -242,6 +242,9 @@ endfunction
" Add a function for fixing problems to the registry.
" (name, func, filetypes, desc, aliases)
function! ale#fix#registry#Add(name, func, filetypes, desc, ...) abort
" This command will throw from the sandbox.
let &equalprg=&equalprg
if type(a:name) != type('')
throw '''name'' must be a String'
endif

View File

@ -2,9 +2,12 @@
" Description: Fixing Python imports with isort.
call ale#Set('python_isort_executable', 'isort')
call ale#Set('python_isort_options', '')
call ale#Set('python_isort_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#fixers#isort#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'python_isort_options')
let l:executable = ale#python#FindExecutable(
\ a:buffer,
\ 'python_isort',
@ -17,6 +20,6 @@ function! ale#fixers#isort#Fix(buffer) abort
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) . ' -',
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\}
endfunction

View File

@ -2,7 +2,7 @@
" Description: Fixing files with tslint.
function! ale#fixers#tslint#Fix(buffer) abort
let l:executable = ale_linters#typescript#tslint#GetExecutable(a:buffer)
let l:executable = ale#handlers#tslint#GetExecutable(a:buffer)
let l:tslint_config_path = ale#path#ResolveLocalPath(
\ a:buffer,

View File

@ -2,7 +2,7 @@
" Description: Error handling for the format GHC outputs.
" Remember the directory used for temporary files for Vim.
let s:temp_dir = fnamemodify(tempname(), ':h')
let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h')
" Build part of a regular expression for matching ALE temporary filenames.
let s:temp_regex_prefix =
\ '\M'

View File

@ -1,6 +0,0 @@
call ale#Set('ruby_rails_best_practices_options', '')
call ale#Set('ruby_rails_best_practices_executable', 'rails_best_practices')
function! ale#handlers#rails_best_practices#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
endfunction

View File

@ -0,0 +1,13 @@
function! ale#handlers#tslint#InitVariables() abort
call ale#Set('typescript_tslint_executable', 'tslint')
call ale#Set('typescript_tslint_config_path', '')
call ale#Set('typescript_tslint_rules_dir', '')
call ale#Set('typescript_tslint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('typescript_tslint_ignore_empty_files', 0)
endfunction
function! ale#handlers#tslint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'typescript_tslint', [
\ 'node_modules/.bin/tslint',
\])
endfunction

View File

@ -1,4 +1,3 @@
call ale#Set('wrap_command_as_one_argument', 0)
" Author: w0rp <devw0rp@gmail.com>
" Description: Linter registration and lazy-loading
" Retrieves linters as requested by the engine, loading them if needed.
@ -47,6 +46,16 @@ function! ale#linter#Reset() abort
let s:linters = {}
endfunction
" Return a reference to the linters loaded.
" This is only for tests.
" Do not call this function.
function! ale#linter#GetLintersLoaded() abort
" This command will throw from the sandbox.
let &equalprg=&equalprg
return s:linters
endfunction
function! s:IsCallback(value) abort
return type(a:value) == type('') || type(a:value) == type(function('type'))
endfunction
@ -59,7 +68,7 @@ function! s:LanguageGetter(buffer) dict abort
return l:self.language
endfunction
function! ale#linter#PreProcess(linter) abort
function! ale#linter#PreProcess(filetype, linter) abort
if type(a:linter) != type({})
throw 'The linter object must be a Dictionary'
endif
@ -193,13 +202,20 @@ function! ale#linter#PreProcess(linter) abort
endif
if l:needs_lsp_details
if has_key(a:linter, 'language')
if has_key(a:linter, 'language_callback')
if has_key(a:linter, 'language_callback')
if has_key(a:linter, 'language')
throw 'Only one of `language` or `language_callback` '
\ . 'should be set'
endif
let l:obj.language = get(a:linter, 'language')
let l:obj.language_callback = get(a:linter, 'language_callback')
if !s:IsCallback(l:obj.language_callback)
throw '`language_callback` must be a callback for LSP linters'
endif
else
" Default to using the filetype as the language.
let l:obj.language = get(a:linter, 'language', a:filetype)
if type(l:obj.language) != type('')
throw '`language` must be a string'
@ -207,12 +223,6 @@ function! ale#linter#PreProcess(linter) abort
" Make 'language_callback' return the 'language' value.
let l:obj.language_callback = function('s:LanguageGetter')
else
let l:obj.language_callback = get(a:linter, 'language_callback')
if !s:IsCallback(l:obj.language_callback)
throw '`language_callback` must be a callback for LSP linters'
endif
endif
let l:obj.project_root_callback = get(a:linter, 'project_root_callback')
@ -282,11 +292,14 @@ function! ale#linter#PreProcess(linter) abort
endfunction
function! ale#linter#Define(filetype, linter) abort
" This command will throw from the sandbox.
let &equalprg=&equalprg
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
endif
let l:new_linter = ale#linter#PreProcess(a:linter)
let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter)
call add(s:linters[a:filetype], l:new_linter)
endfunction
@ -297,6 +310,12 @@ function! ale#linter#PreventLoading(filetype) abort
endfunction
function! ale#linter#GetAll(filetypes) abort
" Don't return linters in the sandbox.
" Otherwise a sandboxed script could modify them.
if ale#util#InSandbox()
return []
endif
let l:combined_linters = []
for l:filetype in a:filetypes

View File

@ -105,11 +105,17 @@ function! ale#lsp#response#GetErrorMessage(response) abort
return ''
endif
" Include the traceback as details, if it's there.
let l:traceback = get(get(a:response.error, 'data', {}), 'traceback', [])
" Include the traceback or error data as details, if present.
let l:error_data = get(a:response.error, 'data', {})
if type(l:traceback) is type([]) && !empty(l:traceback)
let l:message .= "\n" . join(l:traceback, "\n")
if type(l:error_data) is type('')
let l:message .= "\n" . l:error_data
else
let l:traceback = get(l:error_data, 'traceback', [])
if type(l:traceback) is type([]) && !empty(l:traceback)
let l:message .= "\n" . join(l:traceback, "\n")
endif
endif
return l:message

View File

@ -114,6 +114,18 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
endif
endfunction
function! ale#lsp_linter#GetOptions(buffer, linter) abort
let l:initialization_options = {}
if has_key(a:linter, 'initialization_options_callback')
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
elseif has_key(a:linter, 'initialization_options')
let l:initialization_options = a:linter.initialization_options
endif
return l:initialization_options
endfunction
" Given a buffer, an LSP linter, and a callback to register for handling
" messages, start up an LSP linter and get ready to receive errors or
" completions.
@ -128,13 +140,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
return {}
endif
let l:initialization_options = {}
if has_key(a:linter, 'initialization_options_callback')
let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
elseif has_key(a:linter, 'initialization_options')
let l:initialization_options = a:linter.initialization_options
endif
let l:initialization_options = ale#lsp_linter#GetOptions(a:buffer, a:linter)
if a:linter.lsp is# 'socket'
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
@ -147,14 +153,14 @@ function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
if !executable(l:executable)
if empty(l:executable) || !executable(l:executable)
return {}
endif
let l:command = ale#job#PrepareCommand(
\ a:buffer,
\ ale#linter#GetCommand(a:buffer, a:linter),
\)
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
" Format the command, so %e can be formatted into it.
let l:command = ale#command#FormatCommand(a:buffer, l:executable, l:command, 0)[1]
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:conn_id = ale#lsp#StartProgram(
\ l:executable,
\ l:command,

View File

@ -84,7 +84,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction
let s:temp_dir = ale#path#Simplify(fnamemodify(tempname(), ':h'))
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h'))
" Given a filename, return 1 if the file represents some temporary file
" created by Vim.

View File

@ -1,11 +1,6 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Set options in files based on regex patterns.
" A dictionary mapping regular expression patterns to arbitrary buffer
" variables to be set. Useful for configuring ALE based on filename patterns.
let g:ale_pattern_options = get(g:, 'ale_pattern_options', {})
let g:ale_pattern_options_enabled = get(g:, 'ale_pattern_options_enabled', !empty(g:ale_pattern_options))
" These variables are used to cache the sorting of patterns below.
let s:last_pattern_options = {}
let s:sorted_items = []
@ -23,17 +18,19 @@ function! s:CmpPatterns(left_item, right_item) abort
endfunction
function! ale#pattern_options#SetOptions(buffer) abort
if !get(g:, 'ale_pattern_options_enabled', 0)
\|| empty(get(g:, 'ale_pattern_options', 0))
let l:pattern_options = get(g:, 'ale_pattern_options', {})
if empty(l:pattern_options)
" Stop if no options are set.
return
endif
" The items will only be sorted whenever the patterns change.
if g:ale_pattern_options != s:last_pattern_options
let s:last_pattern_options = deepcopy(g:ale_pattern_options)
if l:pattern_options != s:last_pattern_options
let s:last_pattern_options = deepcopy(l:pattern_options)
" The patterns are sorted, so they are applied consistently.
let s:sorted_items = sort(
\ items(g:ale_pattern_options),
\ items(l:pattern_options),
\ function('s:CmpPatterns')
\)
endif

View File

@ -6,6 +6,7 @@ let s:sep = has('win32') ? '\' : '/'
let s:bin_dir = has('unix') ? 'bin' : 'Scripts'
let g:ale_virtualenv_dir_names = get(g:, 'ale_virtualenv_dir_names', [
\ '.env',
\ '.venv',
\ 'env',
\ 've-py3',
\ 've',
@ -23,6 +24,8 @@ function! ale#python#FindProjectRootIni(buffer) abort
\|| filereadable(l:path . '/mypy.ini')
\|| filereadable(l:path . '/pycodestyle.cfg')
\|| filereadable(l:path . '/flake8.cfg')
\|| filereadable(l:path . '/Pipfile')
\|| filereadable(l:path . '/Pipfile.lock')
return l:path
endif
endfor

View File

@ -45,25 +45,23 @@ if !hlexists('ALESignColumnWithErrors')
highlight link ALESignColumnWithErrors error
endif
function! ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() abort
redir => l:output
0verbose silent highlight SignColumn
redir end
let l:highlight_syntax = join(split(l:output)[2:])
let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$')
if !empty(l:match)
execute 'highlight link ALESignColumnWithoutErrors ' . l:match[1]
elseif l:highlight_syntax isnot# 'cleared'
execute 'highlight ALESignColumnWithoutErrors ' . l:highlight_syntax
endif
endfunction
if !hlexists('ALESignColumnWithoutErrors')
function! s:SetSignColumnWithoutErrorsHighlight() abort
redir => l:output
silent highlight SignColumn
redir end
let l:highlight_syntax = join(split(l:output)[2:])
let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$')
if !empty(l:match)
execute 'highlight link ALESignColumnWithoutErrors ' . l:match[1]
elseif l:highlight_syntax isnot# 'cleared'
execute 'highlight ALESignColumnWithoutErrors ' . l:highlight_syntax
endif
endfunction
call s:SetSignColumnWithoutErrorsHighlight()
delfunction s:SetSignColumnWithoutErrorsHighlight
call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight()
endif
" Signs show up on the left for error markers.

View File

@ -268,9 +268,8 @@ endfunction
" See :help sandbox
function! ale#util#InSandbox() abort
try
function! s:SandboxCheck() abort
endfunction
catch /^Vim\%((\a\+)\)\=:E48/
let &equalprg=&equalprg
catch /E48/
" E48 is the sandbox error.
return 1
endtry
@ -278,6 +277,25 @@ function! ale#util#InSandbox() abort
return 0
endfunction
function! ale#util#Tempname() abort
let l:clear_tempdir = 0
if exists('$TMPDIR') && empty($TMPDIR)
let l:clear_tempdir = 1
let $TMPDIR = '/tmp'
endif
try
let l:name = tempname() " no-custom-checks
finally
if l:clear_tempdir
let $TMPDIR = ''
endif
endtry
return l:name
endfunction
" Given a single line, or a List of lines, and a single pattern, or a List
" of patterns, return all of the matches for the lines(s) from the given
" patterns, using matchlist().