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

plugins update

This commit is contained in:
Geezus
2019-05-16 14:48:47 -05:00
parent 5bc3d0226c
commit 555992dd9b
162 changed files with 3534 additions and 1379 deletions

View File

@ -8,6 +8,7 @@ let g:ale_echo_msg_info_str = get(g:, 'ale_echo_msg_info_str', 'Info')
let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
" Ignoring linters, for disabling some, or ignoring LSP diagnostics.
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
let g:ale_disable_lsp = get(g:, 'ale_disable_lsp', 0)
let s:lint_timer = -1
let s:getcmdwintype_exists = exists('*getcmdwintype')
@ -42,6 +43,11 @@ function! ale#ShouldDoNothing(buffer) abort
return 1
endif
" Do nothing for diff buffers.
if getbufvar(a:buffer, '&diff')
return 1
endif
" Do nothing for blacklisted files.
if index(get(g:, 'ale_filetype_blacklist', []), l:filetype) >= 0
return 1
@ -90,8 +96,9 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:linters = !empty(l:ignore_config)
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
let l:linters = !empty(l:ignore_config) || l:disable_lsp
\ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config, l:disable_lsp)
\ : l:linters
" Tell other sources that they can start checking the buffer now.
@ -149,12 +156,19 @@ function! ale#Queue(delay, ...) abort
endif
endfunction
let g:ale_has_override = get(g:, 'ale_has_override', {})
let s:current_ale_version = [2, 4, 0]
" Call has(), but check a global Dictionary so we can force flags on or off
" for testing purposes.
" A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort
return get(g:ale_has_override, a:feature, has(a:feature))
let l:match = matchlist(a:feature, '\c\v^ale-(\d+)\.(\d+)(\.(\d+))?$')
if !empty(l:match)
let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0]
return ale#semver#GTE(s:current_ale_version, l:version)
endif
return 0
endfunction
" Given a buffer number and a variable name, look for that variable in the

View File

@ -1,7 +1,7 @@
let s:chain_results = []
let s:command_output = []
function! ale#assert#WithChainResults(...) abort
let s:chain_results = a:000
function! ale#assert#GivenCommandOutput(...) abort
let s:command_output = a:000
endfunction
function! s:GetLinter() abort
@ -19,6 +19,39 @@ function! s:GetLinter() abort
return l:filetype_linters[0]
endfunction
function! s:FormatExe(command, executable) abort
return substitute(a:command, '%e', '\=ale#Escape(a:executable)', 'g')
endfunction
function! s:ProcessDeferredCommands(initial_result) abort
let l:result = a:initial_result
let l:command_index = 0
let l:command = []
while ale#command#IsDeferred(l:result)
call add(l:command, s:FormatExe(l:result.command, l:result.executable))
if get(g:, 'ale_run_synchronously_emulate_commands')
" Don't run commands, but simulate the results.
let l:Callback = g:ale_run_synchronously_callbacks[0]
let l:output = get(s:command_output, l:command_index, [])
call l:Callback(0, l:output)
unlet g:ale_run_synchronously_callbacks
let l:command_index += 1
else
" Run the commands in the shell, synchronously.
call ale#test#FlushJobs()
endif
let l:result = l:result.value
endwhile
call add(l:command, l:result)
return l:command
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
@ -31,47 +64,20 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
let l:executable = l:executable.value
endwhile
if has_key(l:linter, 'command_chain')
let l:callbacks = map(copy(l:linter.command_chain), 'v:val.callback')
let l:command = s:ProcessDeferredCommands(
\ ale#linter#GetCommand(l:buffer, l:linter),
\)
" If the expected command is a string, just check the last one.
if type(a:expected_command) is v:t_string
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)
while ale#command#IsDeferred(l:command)
call ale#test#FlushJobs()
let l:command = l:command.value
endwhile
if type(a:expected_command) isnot v:t_list
let l:command = l:command[-1]
endif
if type(l:command) is v:t_string
" 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')
let l:command = s:FormatExe(l:command, l:executable)
elseif type(l:command) is v:t_list
call map(l:command, 'substitute(v:val, ''%e'', ''\=ale#Escape(l:executable)'', ''g'')')
call map(l:command, 's:FormatExe(v:val, l:executable)')
endif
AssertEqual
@ -79,6 +85,17 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
\ [l:executable, l:command]
endfunction
function! ale#assert#Fixer(expected_result) abort
let l:buffer = bufnr('')
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))
if type(a:expected_result) isnot v:t_list
let l:result = l:result[-1]
endif
AssertEqual a:expected_result, l:result
endfunction
function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
@ -128,7 +145,7 @@ function! ale#assert#LSPAddress(expected_address) abort
endfunction
function! ale#assert#SetUpLinterTestCommands() abort
command! -nargs=+ WithChainResults :call ale#assert#WithChainResults(<args>)
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<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>)
@ -138,6 +155,11 @@ function! ale#assert#SetUpLinterTestCommands() abort
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
endfunction
function! ale#assert#SetUpFixerTestCommands() abort
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
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.
@ -179,14 +201,21 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
endif
call ale#assert#SetUpLinterTestCommands()
let g:ale_run_synchronously = 1
let g:ale_run_synchronously_emulate_commands = 1
endfunction
function! ale#assert#TearDownLinterTest() abort
unlet! g:ale_create_dummy_temporary_file
let s:chain_results = []
unlet! g:ale_run_synchronously
unlet! g:ale_run_synchronously_callbacks
unlet! g:ale_run_synchronously_emulate_commands
unlet! g:ale_run_synchronously_command_results
let s:command_output = []
if exists(':WithChainResults')
delcommand WithChainResults
if exists(':GivenCommandOutput')
delcommand GivenCommandOutput
endif
if exists(':AssertLinter')
@ -229,3 +258,62 @@ function! ale#assert#TearDownLinterTest() abort
call ale#semver#ResetVersionCache()
endif
endfunction
function! ale#assert#SetUpFixerTest(filetype, name) abort
" Set up a marker so ALE doesn't create real random temporary filenames.
let g:ale_create_dummy_temporary_file = 1
let l:function_name = ale#fix#registry#GetFunc(a:name)
let s:FixerFunction = function(l:function_name)
let l:prefix = 'ale_' . a:filetype . '_' . a:name
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
for l:key in filter(keys(g:), b:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
for l:key in filter(keys(b:), b:filter_expr)
unlet b:[l:key]
endfor
execute 'runtime autoload/ale/fixers/' . a:name . '.vim'
if !exists('g:dir')
call ale#test#SetDirectory('/testplugin/test/fixers')
endif
call ale#assert#SetUpFixerTestCommands()
let g:ale_run_synchronously = 1
let g:ale_run_synchronously_emulate_commands = 1
endfunction
function! ale#assert#TearDownFixerTest() abort
unlet! g:ale_create_dummy_temporary_file
unlet! g:ale_run_synchronously
unlet! g:ale_run_synchronously_callbacks
unlet! g:ale_run_synchronously_emulate_commands
unlet! g:ale_run_synchronously_command_results
let s:command_output = []
unlet! s:FixerFunction
if exists('g:dir')
call ale#test#RestoreDirectory()
endif
Restore
if exists('*ale#semver#ResetVersionCache')
call ale#semver#ResetVersionCache()
endif
if exists(':GivenCommandOutput')
delcommand GivenCommandOutput
endif
if exists(':AssertFixer')
delcommand AssertFixer
endif
endfunction

View File

@ -219,9 +219,32 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
" Search for an exact file match first.
let l:basename = tolower(expand('#' . a:buffer . ':t'))
let l:file_list = get(a:file_lookup, l:basename, [])
" A source file matching the header filename.
let l:source_file = ''
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
for l:suffix in ['.c', '.cpp']
let l:key = fnamemodify(l:basename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, [])
if !empty(l:file_list)
let l:source_file = l:key
break
endif
endfor
endif
for l:item in l:file_list
if bufnr(l:item.file) is a:buffer && has_key(l:item, 'command')
" Load the flags for this file, or for a source file matching the
" header file.
if has_key(l:item, 'command')
\&& (
\ bufnr(l:item.file) is a:buffer
\ || (
\ !empty(l:source_file)
\ && l:item.file[-len(l:source_file):] is? l:source_file
\ )
\)
return ale#c#ParseCFlags(l:item.directory, l:item.command)
endif
endfor
@ -284,6 +307,20 @@ function! ale#c#GetMakeCommand(buffer) abort
return ''
endfunction
function! ale#c#RunMakeCommand(buffer, Callback) abort
let l:command = ale#c#GetMakeCommand(a:buffer)
if empty(l:command)
return a:Callback(a:buffer, [])
endif
return ale#command#Run(
\ a:buffer,
\ l:command,
\ {b, output -> a:Callback(a:buffer, output)},
\)
endfunction
" Given a buffer number, search for a project root, and output a List
" of directories to include based on some heuristics.
"

View File

@ -329,30 +329,46 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
"
" The `_deferred_job_id` is used for both checking the type of object, and
" for checking the job ID and status.
let l:result = {'_deferred_job_id': l:job_id}
"
" The original command here is used in tests.
let l:result = {
\ '_deferred_job_id': l:job_id,
\ 'executable': get(l:options, 'executable', ''),
\ 'command': a:command,
\}
if get(g:, 'ale_run_synchronously') == 1 && l:job_id
" Run a command synchronously if this test option is set.
call extend(l:line_list, systemlist(
\ type(l:command) is v:t_list
\ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2])
\ : l:command
\))
" Don't capture output when the callbacks aren't set.
if !has_key(l:job_options, 'out_cb')
\&& !has_key(l:job_options, 'err_cb')
let l:line_list = []
endif
if !exists('g:ale_run_synchronously_callbacks')
let g:ale_run_synchronously_callbacks = []
endif
call add(
\ g:ale_run_synchronously_callbacks,
\ {-> l:job_options.exit_cb(l:job_id, v:shell_error)}
\)
if get(g:, 'ale_run_synchronously_emulate_commands', 0)
call add(
\ g:ale_run_synchronously_callbacks,
\ {exit_code, output -> [
\ extend(l:line_list, output),
\ l:job_options.exit_cb(l:job_id, exit_code),
\ ]}
\)
else
" Run a command synchronously if this test option is set.
call extend(l:line_list, systemlist(
\ type(l:command) is v:t_list
\ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2])
\ : l:command
\))
" Don't capture output when the callbacks aren't set.
if !has_key(l:job_options, 'out_cb')
\&& !has_key(l:job_options, 'err_cb')
let l:line_list = []
endif
call add(
\ g:ale_run_synchronously_callbacks,
\ {-> l:job_options.exit_cb(l:job_id, v:shell_error)}
\)
endif
endif
return l:result

View File

@ -159,18 +159,20 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
endfunction
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
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
" 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'
endif
let &l:omnifunc = 'ale#completion#OmniFunc'
let l:info = get(b:, 'ale_completion_info', {})
if !get(l:info, 'manual')
if l:source is# 'ale-automatic'
if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt
endif
@ -199,31 +201,49 @@ function! ale#completion#RestoreCompletionOptions() abort
endif
endfunction
function! ale#completion#GetCompletionPosition() abort
if !exists('b:ale_completion_info')
return 0
endif
let l:line = b:ale_completion_info.line
let l:column = b:ale_completion_info.column
let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype)
let l:up_to_column = getline(l:line)[: l:column - 2]
let l:match = matchstr(l:up_to_column, l:regex)
return l:column - len(l:match) - 1
endfunction
function! ale#completion#GetCompletionResult() abort
" Parse a new response if there is one.
if exists('b:ale_completion_response')
\&& exists('b:ale_completion_parser')
let l:response = b:ale_completion_response
let l:parser = b:ale_completion_parser
unlet b:ale_completion_response
unlet b:ale_completion_parser
let b:ale_completion_result = function(l:parser)(l:response)
endif
if exists('b:ale_completion_result')
return b:ale_completion_result
endif
return v:null
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:line = b:ale_completion_info.line
let l:column = b:ale_completion_info.column
let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype)
let l:up_to_column = getline(l:line)[: l:column - 2]
let l:match = matchstr(l:up_to_column, l:regex)
return l:column - len(l:match) - 1
return ale#completion#GetCompletionPosition()
else
" Parse a new response if there is one.
if exists('b:ale_completion_response')
\&& exists('b:ale_completion_parser')
let l:response = b:ale_completion_response
let l:parser = b:ale_completion_parser
unlet b:ale_completion_response
unlet b:ale_completion_parser
let b:ale_completion_result = function(l:parser)(l:response)
endif
let l:result = ale#completion#GetCompletionResult()
call s:ReplaceCompletionOptions()
return get(b:, 'ale_completion_result', [])
return l:result isnot v:null ? l:result : []
endif
endfunction
@ -239,7 +259,14 @@ function! ale#completion#Show(response, completion_parser) abort
" Replace completion options shortly before opening the menu.
call s:ReplaceCompletionOptions()
call timer_start(0, {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")})
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call timer_start(
\ 0,
\ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")}
\)
endif
endfunction
function! s:CompletionStillValid(request_id) abort
@ -249,7 +276,10 @@ function! s:CompletionStillValid(request_id) abort
\&& 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
\&& (
\ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'deoplete'
\)
endfunction
function! ale#completion#ParseTSServerCompletions(response) abort
@ -356,6 +386,8 @@ function! ale#completion#ParseLSPCompletions(response) abort
if get(l:item, 'insertTextFormat') is s:LSP_INSERT_TEXT_FORMAT_PLAIN
\&& type(get(l:item, 'textEdit')) is v:t_dict
let l:text = l:item.textEdit.newText
elseif type(get(l:item, 'insertText')) is v:t_string
let l:text = l:item.insertText
else
let l:text = l:item.label
endif
@ -517,14 +549,27 @@ function! s:OnReady(linter, lsp_details) abort
endif
endfunction
" This function can be called to check if ALE can provide completion data for
" the current buffer. 1 will be returned if there's a potential source of
" completion data ALE can use, and 0 will be returned otherwise.
function! ale#completion#CanProvideCompletions() abort
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
return 1
endif
endfor
return 0
endfunction
" This function can be used to manually trigger autocomplete, even when
" g:ale_completion_enabled is set to false
function! ale#completion#GetCompletions(manual) abort
function! ale#completion#GetCompletions(source) abort
let [l:line, l:column] = getpos('.')[1:2]
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if !a:manual && empty(l:prefix)
if a:source is# 'ale-automatic' && empty(l:prefix)
return
endif
@ -537,8 +582,9 @@ function! ale#completion#GetCompletions(manual) abort
\ 'prefix': l:prefix,
\ 'conn_id': 0,
\ 'request_id': 0,
\ 'manual': a:manual,
\ 'source': a:source,
\}
unlet! b:ale_completion_result
let l:buffer = bufnr('')
let l:Callback = function('s:OnReady')
@ -551,7 +597,7 @@ function! ale#completion#GetCompletions(manual) abort
endfunction
function! s:TimerHandler(...) abort
if !g:ale_completion_enabled
if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled)
return
endif
@ -562,7 +608,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] && ale#util#Mode() is# 'i'
call ale#completion#GetCompletions(0)
call ale#completion#GetCompletions('ale-automatic')
endif
endfunction
@ -576,7 +622,7 @@ function! ale#completion#StopTimer() abort
endfunction
function! ale#completion#Queue() abort
if !g:ale_completion_enabled
if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled)
return
endif

View File

@ -25,7 +25,7 @@ function! ale#cursor#TruncatedEcho(original_message) abort
let l:cursor_position = getpos('.')
" The message is truncated and saved to the history.
setlocal shortmess+=T
silent! setlocal shortmess+=T
try
exec "norm! :echomsg l:message\n"

View File

@ -3,6 +3,9 @@
let s:go_to_definition_map = {}
" Enable automatic updates of the tagstack
let g:ale_update_tagstack = get(g:, 'ale_update_tagstack', 1)
" Used to get the definition map in tests.
function! ale#definition#GetMap() abort
return deepcopy(s:go_to_definition_map)
@ -17,6 +20,20 @@ function! ale#definition#ClearLSPData() abort
let s:go_to_definition_map = {}
endfunction
function! ale#definition#UpdateTagStack() abort
let l:should_update_tagstack = exists('*gettagstack') && exists('*settagstack') && g:ale_update_tagstack
if l:should_update_tagstack
" Grab the old location (to jump back to) and the word under the
" cursor (as a label for the tagstack)
let l:old_location = [bufnr('%'), line('.'), col('.'), 0]
let l:tagname = expand('<cword>')
let l:winid = win_getid()
call settagstack(l:winid, {'items': [{'from': l:old_location, 'tagname': l:tagname}]}, 'a')
call settagstack(l:winid, {'curidx': len(gettagstack(l:winid)['items']) + 1})
endif
endfunction
function! ale#definition#HandleTSServerResponse(conn_id, response) abort
if get(a:response, 'command', '') is# 'definition'
\&& has_key(s:go_to_definition_map, a:response.request_seq)
@ -27,6 +44,7 @@ function! ale#definition#HandleTSServerResponse(conn_id, response) abort
let l:line = a:response.body[0].start.line
let l:column = a:response.body[0].start.offset
call ale#definition#UpdateTagStack()
call ale#util#Open(l:filename, l:line, l:column, l:options)
endif
endif
@ -51,6 +69,7 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
let l:line = l:item.range.start.line + 1
let l:column = l:item.range.start.character + 1
call ale#definition#UpdateTagStack()
call ale#util#Open(l:filename, l:line, l:column, l:options)
break
endfor

View File

@ -39,8 +39,8 @@ function! ale#engine#MarkLinterActive(info, linter) abort
endif
endfunction
function! ale#engine#MarkLinterInactive(info, linter) abort
call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter.name')
function! ale#engine#MarkLinterInactive(info, linter_name) abort
call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter_name')
endfunction
function! ale#engine#ResetExecutableCache() abort
@ -107,24 +107,36 @@ endfunction
" Register a temporary file to be managed with the ALE engine for
" a current job run.
function! ale#engine#ManageFile(buffer, filename) abort
" TODO: Emit deprecation warning here later.
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#ManageFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
call ale#command#ManageFile(a:buffer, a:filename)
endfunction
" Same as the above, but manage an entire directory.
function! ale#engine#ManageDirectory(buffer, directory) abort
" TODO: Emit deprecation warning here later.
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#ManageDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
call ale#command#ManageDirectory(a:buffer, a:directory)
endfunction
function! ale#engine#CreateFile(buffer) abort
" TODO: Emit deprecation warning here later.
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#CreateFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
return ale#command#CreateFile(a:buffer)
endfunction
" Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort
" TODO: Emit deprecation warning here later.
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#CreateDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
return ale#command#CreateDirectory(a:buffer)
endfunction
@ -183,7 +195,7 @@ function! s:HandleExit(job_info, buffer, output, data) abort
let l:next_chain_index = a:job_info.next_chain_index
" Remove this job from the list.
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter)
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name)
" Stop here if we land in the handle for a job completing if we're in
" a sandbox.
@ -698,6 +710,10 @@ function! ale#engine#Cleanup(buffer) abort
return
endif
if exists('*ale#lsp#CloseDocument')
call ale#lsp#CloseDocument(a:buffer)
endif
if !has_key(g:ale_buffer_info, a:buffer)
return
endif

View File

@ -22,7 +22,7 @@ function! ale#engine#ignore#GetList(filetype, config) abort
endfunction
" Given a List of linter descriptions, exclude the linters to be ignored.
function! ale#engine#ignore#Exclude(filetype, all_linters, config) abort
function! ale#engine#ignore#Exclude(filetype, all_linters, config, disable_lsp) abort
let l:names_to_remove = ale#engine#ignore#GetList(a:filetype, a:config)
let l:filtered_linters = []
@ -37,6 +37,10 @@ function! ale#engine#ignore#Exclude(filetype, all_linters, config) abort
endif
endfor
if a:disable_lsp && has_key(l:linter, 'lsp') && l:linter.lsp isnot# ''
let l:should_include = 0
endif
if l:should_include
call add(l:filtered_linters, l:linter)
endif

View File

@ -1,3 +1,5 @@
call ale#Set('fix_on_save_ignore', {})
" Apply fixes queued up for buffers which may be hidden.
" Vim doesn't let you modify hidden buffers.
function! ale#fix#ApplyQueuedFixes() abort
@ -40,6 +42,7 @@ function! ale#fix#ApplyQueuedFixes() abort
if l:data.should_save
let l:should_lint = g:ale_fix_on_save
\ && ale#Var(l:buffer, 'lint_on_save')
else
let l:should_lint = l:data.changes_made
endif
@ -117,6 +120,10 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
let l:input = a:job_info.input
endif
if l:ChainCallback isnot v:null && !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''chain_with is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
let l:next_index = l:ChainCallback is v:null
\ ? a:job_info.callback_index + 1
\ : a:job_info.callback_index
@ -261,7 +268,21 @@ function! s:AddSubCallbacks(full_list, callbacks) abort
return 1
endfunction
function! s:GetCallbacks(buffer, fixers) abort
function! s:IgnoreFixers(callback_list, filetype, config) abort
if type(a:config) is v:t_list
let l:ignore_list = a:config
else
let l:ignore_list = []
for l:part in split(a:filetype , '\.')
call extend(l:ignore_list, get(a:config, l:part, []))
endfor
endif
call filter(a:callback_list, 'index(l:ignore_list, v:val) < 0')
endfunction
function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
if len(a:fixers)
let l:callback_list = a:fixers
elseif type(get(b:, 'ale_fixers')) is v:t_list
@ -286,8 +307,12 @@ function! s:GetCallbacks(buffer, fixers) abort
endif
endif
if empty(l:callback_list)
return []
if a:fixing_flag is# 'save_file'
let l:config = ale#Var(a:buffer, 'fix_on_save_ignore')
if !empty(l:config)
call s:IgnoreFixers(l:callback_list, &filetype, l:config)
endif
endif
let l:corrected_list = []
@ -335,7 +360,7 @@ function! ale#fix#Fix(buffer, fixing_flag, ...) abort
endif
try
let l:callback_list = s:GetCallbacks(a:buffer, a:000)
let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000)
catch /E700\|BADNAME/
let l:function_name = join(split(split(v:exception, ':')[3]))
let l:echo_message = printf(

View File

@ -27,6 +27,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix PEP8 issues with black.',
\ },
\ 'fecs': {
\ 'function': 'ale#fixers#fecs#Fix',
\ 'suggested_filetypes': ['javascript', 'css', 'html'],
\ 'description': 'Apply fecs format to a file.',
\ },
\ 'tidy': {
\ 'function': 'ale#fixers#tidy#Fix',
\ 'suggested_filetypes': ['html'],
@ -185,6 +190,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['hack'],
\ 'description': 'Fix Hack files with hackfmt.',
\ },
\ 'floskell': {
\ 'function': 'ale#fixers#floskell#Fix',
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with floskell.',
\ },
\ 'hfmt': {
\ 'function': 'ale#fixers#hfmt#Fix',
\ 'suggested_filetypes': ['haskell'],
@ -210,6 +220,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['ocaml'],
\ 'description': 'Fix OCaml files with ocamlformat.',
\ },
\ 'ocp-indent': {
\ 'function': 'ale#fixers#ocp_indent#Fix',
\ 'suggested_filetypes': ['ocaml'],
\ 'description': 'Fix OCaml files with ocp-indent.',
\ },
\ 'refmt': {
\ 'function': 'ale#fixers#refmt#Fix',
\ 'suggested_filetypes': ['reason'],
@ -247,8 +262,8 @@ let s:default_registry = {
\ },
\ 'xo': {
\ 'function': 'ale#fixers#xo#Fix',
\ 'suggested_filetypes': ['javascript'],
\ 'description': 'Fix JavaScript files using xo --fix.',
\ 'suggested_filetypes': ['javascript', 'typescript'],
\ 'description': 'Fix JavaScript/TypeScript files using xo --fix.',
\ },
\ 'qmlfmt': {
\ 'function': 'ale#fixers#qmlfmt#Fix',
@ -280,6 +295,16 @@ let s:default_registry = {
\ 'suggested_filetypes': ['kt'],
\ 'description': 'Fix Kotlin files with ktlint.',
\ },
\ 'styler': {
\ 'function': 'ale#fixers#styler#Fix',
\ 'suggested_filetypes': ['r'],
\ 'description': 'Fix R files with styler.',
\ },
\ 'latexindent': {
\ 'function': 'ale#fixers#latexindent#Fix',
\ 'suggested_filetypes': ['tex'],
\ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.',
\ },
\}
" Reset the function registry to the default entries.

View File

@ -3,15 +3,15 @@
function! ale#fixers#eslint#Fix(buffer) abort
let l:executable = ale#handlers#eslint#GetExecutable(a:buffer)
let l:command = ale#node#Executable(a:buffer, l:executable)
\ . ' --version'
let l:command = ale#semver#HasVersion(l:executable)
\ ? ''
\ : ale#node#Executable(a:buffer, l:executable) . ' --version'
return {
\ 'command': l:command,
\ 'chain_with': 'ale#fixers#eslint#ApplyFixForVersion',
\}
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ l:executable,
\ l:command,
\ function('ale#fixers#eslint#ApplyFixForVersion'),
\)
endfunction
function! ale#fixers#eslint#ProcessFixDryRunOutput(buffer, output) abort
@ -33,10 +33,8 @@ function! ale#fixers#eslint#ProcessEslintDOutput(buffer, output) abort
return a:output
endfunction
function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort
function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#handlers#eslint#GetExecutable(a:buffer)
let l:version = ale#semver#GetVersion(l:executable, a:version_output)
let l:config = ale#handlers#eslint#FindConfig(a:buffer)
if empty(l:config)
@ -44,7 +42,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort
endif
" Use --fix-to-stdout with eslint_d
if l:executable =~# 'eslint_d$' && ale#semver#GTE(l:version, [3, 19, 0])
if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0])
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ' --stdin-filename %s --stdin --fix-to-stdout',
@ -53,7 +51,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort
endif
" 4.9.0 is the first version with --fix-dry-run
if ale#semver#GTE(l:version, [4, 9, 0])
if ale#semver#GTE(a:version, [4, 9, 0])
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ' --stdin-filename %s --stdin --fix-dry-run --format=json',

View File

@ -0,0 +1,17 @@
" Author: harttle <yangjvn@126.com>
" Description: Apply fecs format to a file.
function! ale#fixers#fecs#Fix(buffer) abort
let l:executable = ale#handlers#fecs#GetExecutable(a:buffer)
if !executable(l:executable)
return 0
endif
let l:config_options = ' format --replace=true %t'
return {
\ 'command': ale#Escape(l:executable) . l:config_options,
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -0,0 +1,20 @@
" Author: robertjlooby <robertjlooby@gmail.com>
" Description: Integration of floskell with ALE.
call ale#Set('haskell_floskell_executable', 'floskell')
function! ale#fixers#floskell#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'haskell_floskell_executable')
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'floskell')
endfunction
function! ale#fixers#floskell#Fix(buffer) abort
let l:executable = ale#fixers#floskell#GetExecutable(a:buffer)
return {
\ 'command': l:executable
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -0,0 +1,18 @@
" Author: riley-martine <riley.martine@protonmail.com>
" Description: Integration of latexindent with ALE.
call ale#Set('tex_latexindent_executable', 'latexindent')
call ale#Set('tex_latexindent_options', '')
function! ale#fixers#latexindent#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'tex_latexindent_executable')
let l:options = ale#Var(a:buffer, 'tex_latexindent_options')
return {
\ 'command': ale#Escape(l:executable)
\ . ' -l -w'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -0,0 +1,18 @@
" Author: Kanenobu Mitsuru
" Description: Integration of ocp-indent with ALE.
call ale#Set('ocaml_ocp_indent_executable', 'ocp-indent')
call ale#Set('ocaml_ocp_indent_options', '')
call ale#Set('ocaml_ocp_indent_config', '')
function! ale#fixers#ocp_indent#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'ocaml_ocp_indent_executable')
let l:config = ale#Var(a:buffer, 'ocaml_ocp_indent_config')
let l:options = ale#Var(a:buffer, 'ocaml_ocp_indent_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:config) ? '' : ' --config=' . ale#Escape(l:config))
\ . (empty(l:options) ? '': ' ' . l:options)
\}
endfunction

View File

@ -15,16 +15,12 @@ function! ale#fixers#prettier#GetExecutable(buffer) abort
endfunction
function! ale#fixers#prettier#Fix(buffer) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:command = ale#semver#HasVersion(l:executable)
\ ? ''
\ : ale#Escape(l:executable) . ' --version'
return {
\ 'command': l:command,
\ 'chain_with': 'ale#fixers#prettier#ApplyFixForVersion',
\}
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ ale#fixers#prettier#GetExecutable(a:buffer),
\ '%e --version',
\ function('ale#fixers#prettier#ApplyFixForVersion'),
\)
endfunction
function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
@ -38,10 +34,9 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output
endfunction
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
let l:version = ale#semver#GetVersion(l:executable, a:version_output)
let l:parser = ''
" Append the --parser flag depending on the current filetype (unless it's
@ -50,7 +45,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
" Mimic Prettier's defaults. In cases without a file extension or
" filetype (scratch buffer), Prettier needs `parser` set to know how
" to process the buffer.
if ale#semver#GTE(l:version, [1, 16, 0])
if ale#semver#GTE(a:version, [1, 16, 0])
let l:parser = 'babel'
else
let l:parser = 'babylon'
@ -94,7 +89,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
endif
" 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(l:version, [1, 4, 0])
if ale#semver#GTE(a:version, [1, 4, 0])
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable)

View File

@ -2,13 +2,9 @@
" w0rp <devw0rp@gmail.com>, morhetz (Pavel Pertsev) <morhetz@gmail.com>
" Description: Integration between Prettier and ESLint.
function! ale#fixers#prettier_eslint#SetOptionDefaults() abort
call ale#Set('javascript_prettier_eslint_executable', 'prettier-eslint')
call ale#Set('javascript_prettier_eslint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('javascript_prettier_eslint_options', '')
endfunction
call ale#fixers#prettier_eslint#SetOptionDefaults()
call ale#Set('javascript_prettier_eslint_executable', 'prettier-eslint')
call ale#Set('javascript_prettier_eslint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('javascript_prettier_eslint_options', '')
function! ale#fixers#prettier_eslint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_prettier_eslint', [
@ -18,26 +14,20 @@ function! ale#fixers#prettier_eslint#GetExecutable(buffer) abort
endfunction
function! ale#fixers#prettier_eslint#Fix(buffer) abort
let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer)
let l:command = ale#semver#HasVersion(l:executable)
\ ? ''
\ : ale#Escape(l:executable) . ' --version'
return {
\ 'command': l:command,
\ 'chain_with': 'ale#fixers#prettier_eslint#ApplyFixForVersion',
\}
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ ale#fixers#prettier_eslint#GetExecutable(a:buffer),
\ '%e --version',
\ function('ale#fixers#prettier_eslint#ApplyFixForVersion'),
\)
endfunction
function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version_output) abort
function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort
let l:options = ale#Var(a:buffer, 'javascript_prettier_eslint_options')
let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer)
let l:version = ale#semver#GetVersion(l:executable, a:version_output)
" 4.2.0 is the first version with --eslint-config-path
let l:config = ale#semver#GTE(l:version, [4, 2, 0])
let l:config = ale#semver#GTE(a:version, [4, 2, 0])
\ ? ale#handlers#eslint#FindConfig(a:buffer)
\ : ''
let l:eslint_config_option = !empty(l:config)
@ -45,7 +35,7 @@ function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version_output)
\ : ''
" 4.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(l:version, [4, 4, 0])
if ale#semver#GTE(a:version, [4, 4, 0])
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable)

View File

@ -0,0 +1,16 @@
" Author: tvatter <thibault.vatter@gmail.com>
" Description: Fixing R files with styler.
call ale#Set('r_styler_executable', 'Rscript')
call ale#Set('r_styler_options', 'tidyverse_style')
function! ale#fixers#styler#Fix(buffer) abort
return {
\ 'command': 'Rscript --vanilla -e '
\ . '"suppressPackageStartupMessages(library(styler));'
\ . 'style_file(commandArgs(TRUE), style = '
\ . ale#Var(a:buffer, 'r_styler_options') . ')"'
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -143,6 +143,11 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort
" The code can be something like 'Error/foo/bar', or just 'Error'
if !empty(get(l:split_code, 1))
let l:obj.code = join(l:split_code[1:], '/')
if l:obj.code is# 'no-trailing-spaces'
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
continue
endif
endif
for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns)

View File

@ -0,0 +1,52 @@
" Author: harttle <yangjvn@126.com>
" Description: fecs http://fecs.baidu.com/
call ale#Set('javascript_fecs_executable', 'fecs')
call ale#Set('javascript_fecs_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#handlers#fecs#GetCommand(buffer) abort
return '%e check --colors=false --rule=true %t'
endfunction
function! ale#handlers#fecs#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_fecs', [
\ 'node_modules/.bin/fecs',
\ 'node_modules/fecs/bin/fecs',
\])
endfunction
function! ale#handlers#fecs#Handle(buffer, lines) abort
" Matches patterns looking like the following
"
" fecs WARN → line 20, col 25: Unexpected console statement. (no-console)
" fecs ERROR → line 24, col 36: Missing radix parameter. (radix)
"
let l:pattern = '\v^.*(WARN|ERROR)\s+→\s+line (\d+),\s+col\s+(\d+):\s+(.*)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:obj = {
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[4]
\}
let l:code_match = matchlist(l:match[4], '\v^(.{-})\s*\((.+)\)$')
if !empty(l:code_match)
let l:obj.code = l:code_match[2]
let l:obj.text = l:code_match[1]
endif
if l:match[1] is# 'WARN'
let l:obj.type = 'W'
elseif l:match[1] is# 'ERROR'
let l:obj.type = 'E'
endif
call add(l:output, l:obj)
endfor
return l:output
endfunction

View File

@ -4,10 +4,10 @@
function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort
" Only one file was passed to redpen. So response array has only one
" element.
let l:res = json_decode(join(a:lines))[0]
let l:res = get(ale#util#FuzzyJSONDecode(a:lines, []), 0, {})
let l:output = []
for l:err in l:res.errors
for l:err in get(l:res, 'errors', [])
let l:item = {
\ 'text': l:err.message,
\ 'type': 'W',

View File

@ -49,6 +49,7 @@ endfunction
" Given a loclist for current items to highlight, remove all highlights
" except these which have matching loclist item entries.
function! ale#highlight#RemoveHighlights() abort
for l:match in getmatches()
if l:match.group =~# '^ALE'
@ -57,6 +58,24 @@ function! ale#highlight#RemoveHighlights() abort
endfor
endfunction
function! s:highlight_line(bufnr, lnum, group) abort
call matchaddpos(a:group, [a:lnum])
endfunction
function! s:highlight_range(bufnr, range, group) abort
" Set all of the positions, which are chunked into Lists which
" are as large as will be accepted by matchaddpos.
call map(
\ ale#highlight#CreatePositions(
\ a:range.lnum,
\ a:range.col,
\ a:range.end_lnum,
\ a:range.end_col
\ ),
\ 'matchaddpos(a:group, v:val)'
\)
endfunction
function! ale#highlight#UpdateHighlights() abort
let l:item_list = get(b:, 'ale_enabled', 1) && g:ale_enabled
\ ? get(b:, 'ale_highlight_items', [])
@ -79,17 +98,14 @@ function! ale#highlight#UpdateHighlights() abort
let l:group = 'ALEError'
endif
let l:line = l:item.lnum
let l:col = l:item.col
let l:end_line = get(l:item, 'end_lnum', l:line)
let l:end_col = get(l:item, 'end_col', l:col)
let l:range = {
\ 'lnum': l:item.lnum,
\ 'col': l:item.col,
\ 'end_lnum': get(l:item, 'end_lnum', l:item.lnum),
\ 'end_col': get(l:item, 'end_col', l:item.col)
\}
" Set all of the positions, which are chunked into Lists which
" are as large as will be accepted by matchaddpos.
call map(
\ ale#highlight#CreatePositions(l:line, l:col, l:end_line, l:end_col),
\ 'matchaddpos(l:group, v:val)'
\)
call s:highlight_range(l:item.bufnr, l:range, l:group)
endfor
" If highlights are enabled and signs are not enabled, we should still
@ -111,7 +127,7 @@ function! ale#highlight#UpdateHighlights() abort
endif
if l:available_groups[l:group]
call matchaddpos(l:group, [l:item.lnum])
call s:highlight_line(l:item.bufnr, l:item.lnum, l:group)
endif
endfor
endif

View File

@ -32,7 +32,7 @@ let s:default_ale_linter_aliases = {
" NOTE: Update the g:ale_linters documentation when modifying this.
let s:default_ale_linters = {
\ 'csh': ['shell'],
\ 'elixir': ['credo', 'dialyxir', 'dogma', 'elixir-ls'],
\ 'elixir': ['credo', 'dialyxir', 'dogma'],
\ 'go': ['gofmt', 'golint', 'go vet'],
\ 'hack': ['hack'],
\ 'help': [],
@ -340,7 +340,13 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`aliases` must be a List of String values'
endif
" TODO: Emit deprecation warnings for deprecated options later.
for l:key in filter(keys(a:linter), 'v:val[-9:] is# ''_callback'' || v:val is# ''command_chain''')
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom l:key . '' is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
break
endfor
return l:obj
endfunction

View File

@ -115,7 +115,7 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort
let l:open_type = ''
if ale#Var(a:buffer, 'list_vertical') == 1
let l:open_type = 'vert '
let l:open_type = 'vert rightbelow '
endif
if g:ale_set_quickfix

View File

@ -484,6 +484,35 @@ function! ale#lsp#OpenDocument(conn_id, buffer, language_id) abort
return l:opened
endfunction
" Notify LSP servers or tsserver that a document is closed, if opened before.
" If a document is closed, 1 will be returned, otherwise 0 will be returned.
"
" Only the buffer number is required here. A message will be sent to every
" language server that was notified previously of the document being opened.
function! ale#lsp#CloseDocument(buffer) abort
let l:closed = 0
" The connection keys are sorted so the messages are easier to test, and
" so messages are sent in a consistent order.
for l:conn_id in sort(keys(s:connections))
let l:conn = s:connections[l:conn_id]
if l:conn.initialized && has_key(l:conn.open_documents, a:buffer)
if l:conn.is_tsserver
let l:message = ale#lsp#tsserver_message#Close(a:buffer)
else
let l:message = ale#lsp#message#DidClose(a:buffer)
endif
call ale#lsp#Send(l:conn_id, l:message)
call remove(l:conn.open_documents, a:buffer)
let l:closed = 1
endif
endfor
return l:closed
endfunction
" Notify LSP servers or tsserver that a document has changed, if needed.
" If a notification is sent, 1 will be returned, otherwise 0 will be returned.
function! ale#lsp#NotifyForChanges(conn_id, buffer) abort

View File

@ -159,7 +159,7 @@ function! ale#lsp#message#Hover(buffer, line, column) abort
endfunction
function! ale#lsp#message#DidChangeConfiguration(buffer, config) abort
return [0, 'workspace/didChangeConfiguration', {
return [1, 'workspace/didChangeConfiguration', {
\ 'settings': a:config,
\}]
endfunction

View File

@ -28,7 +28,7 @@ function! ale#lsp#response#ReadDiagnostics(response) abort
for l:diagnostic in a:response.params.diagnostics
let l:severity = get(l:diagnostic, 'severity', 0)
let l:loclist_item = {
\ 'text': l:diagnostic.message,
\ 'text': substitute(l:diagnostic.message, '\(\r\n\|\n\|\r\)', ' ', 'g'),
\ 'type': 'E',
\ 'lnum': l:diagnostic.range.start.line + 1,
\ 'col': l:diagnostic.range.start.character + 1,

View File

@ -10,6 +10,11 @@ endif
" Check if diagnostics for a particular linter should be ignored.
function! s:ShouldIgnore(buffer, linter_name) abort
" Ignore all diagnostics if LSP integration is disabled.
if ale#Var(a:buffer, 'disable_lsp')
return 1
endif
let l:config = ale#Var(a:buffer, 'linters_ignore')
" Don't load code for ignoring diagnostics if there's nothing to ignore.
@ -27,12 +32,13 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr(l:filename)
let l:info = get(g:ale_buffer_info, l:buffer, {})
if s:ShouldIgnore(l:buffer, l:linter_name)
if empty(l:info)
return
endif
if l:buffer <= 0
if s:ShouldIgnore(l:buffer, l:linter_name)
return
endif
@ -50,6 +56,8 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
return
endif
call ale#engine#MarkLinterInactive(l:info, l:linter_name)
if s:ShouldIgnore(l:buffer, l:linter_name)
return
endif
@ -376,6 +384,10 @@ function! s:CheckWithLSP(linter, details) abort
if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Geterr(l:buffer)
let l:notified = ale#lsp#Send(l:id, l:message) != 0
if l:notified
call ale#engine#MarkLinterActive(l:info, a:linter)
endif
else
let l:notified = ale#lsp#NotifyForChanges(l:id, l:buffer)
endif
@ -386,10 +398,6 @@ function! s:CheckWithLSP(linter, details) abort
let l:save_message = ale#lsp#message#DidSave(l:buffer)
let l:notified = ale#lsp#Send(l:id, l:save_message) != 0
endif
if l:notified
call ale#engine#MarkLinterActive(l:info, a:linter)
endif
endfunction
function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort

View File

@ -32,7 +32,7 @@ endfunction
"
" The executable is only prefixed for Windows machines
function! ale#node#Executable(buffer, executable) abort
if ale#Has('win32') && a:executable =~? '\.js$'
if has('win32') && a:executable =~? '\.js$'
let l:node = ale#Var(a:buffer, 'windows_node_executable_path')
return ale#Escape(l:node) . ' ' . ale#Escape(a:executable)

View File

@ -0,0 +1,32 @@
" Author: zigford <zigford@gmail.com>
" Description: Functions for integrating with Powershell linters.
" Write a powershell script to a temp file for execution
" return the command used to execute it
function! s:TemporaryPSScript(buffer, input) abort
let l:filename = 'script.ps1'
" Create a temp dir to house our temp .ps1 script
" a temp dir is needed as powershell needs the .ps1
" extension
let l:tempdir = ale#util#Tempname() . (has('win32') ? '\' : '/')
let l:tempscript = l:tempdir . l:filename
" Create the temporary directory for the file, unreadable by 'other'
" users.
call mkdir(l:tempdir, '', 0750)
" Automatically delete the directory later.
call ale#command#ManageDirectory(a:buffer, l:tempdir)
" Write the script input out to a file.
call ale#util#Writefile(a:buffer, a:input, l:tempscript)
return l:tempscript
endfunction
function! ale#powershell#RunPowerShell(buffer, base_var_name, command) abort
let l:executable = ale#Var(a:buffer, a:base_var_name . '_executable')
let l:tempscript = s:TemporaryPSScript(a:buffer, a:command)
return ale#Escape(l:executable)
\ . ' -Exe Bypass -NoProfile -File '
\ . ale#Escape(l:tempscript)
\ . ' %t'
endfunction

View File

@ -49,13 +49,15 @@ function! ale#references#HandleLSPResponse(conn_id, response) abort
let l:result = get(a:response, 'result', [])
let l:item_list = []
for l:response_item in l:result
call add(l:item_list, {
\ 'filename': ale#path#FromURI(l:response_item.uri),
\ 'line': l:response_item.range.start.line + 1,
\ 'column': l:response_item.range.start.character + 1,
\})
endfor
if type(l:result) is v:t_list
for l:response_item in l:result
call add(l:item_list, {
\ 'filename': ale#path#FromURI(l:response_item.uri),
\ 'line': l:response_item.range.start.line + 1,
\ 'column': l:response_item.range.start.character + 1,
\})
endfor
endif
if empty(l:item_list)
call ale#util#Execute('echom ''No references found.''')

View File

@ -1,7 +1,7 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: Functions for integrating with Ruby tools
" Find the nearest dir contining "app", "db", and "config", and assume it is
" Find the nearest dir containing "app", "db", and "config", and assume it is
" the root of a Rails app.
function! ale#ruby#FindRailsRoot(buffer) abort
for l:name in ['app', 'config', 'db']

View File

@ -5,31 +5,52 @@ function! ale#semver#ResetVersionCache() abort
let s:version_cache = {}
endfunction
function! ale#semver#ParseVersion(version_lines) abort
for l:line in a:version_lines
let l:match = matchlist(l:line, '\v(\d+)\.(\d+)(\.(\d+))?')
if !empty(l:match)
return [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0]
endif
endfor
return []
endfunction
" Given an executable name and some lines of output, which can be empty,
" parse the version from the lines of output, or return the cached version
" triple [major, minor, patch]
"
" If the version cannot be found, an empty List will be returned instead.
function! ale#semver#GetVersion(executable, version_lines) abort
function! s:GetVersion(executable, version_lines) abort
let l:version = get(s:version_cache, a:executable, [])
let l:parsed_version = ale#semver#ParseVersion(a:version_lines)
for l:line in a:version_lines
let l:match = matchlist(l:line, '\v(\d+)\.(\d+)(\.(\d+))?')
if !empty(l:match)
let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0]
let s:version_cache[a:executable] = l:version
break
endif
endfor
if !empty(l:parsed_version)
let l:version = l:parsed_version
let s:version_cache[a:executable] = l:version
endif
return l:version
endfunction
" Return 1 if the semver version has been cached for a given executable.
function! ale#semver#HasVersion(executable) abort
return has_key(s:version_cache, a:executable)
function! ale#semver#RunWithVersionCheck(buffer, executable, command, Callback) abort
if empty(a:executable)
return ''
endif
let l:cache = s:version_cache
if has_key(s:version_cache, a:executable)
return a:Callback(a:buffer, s:version_cache[a:executable])
endif
return ale#command#Run(
\ a:buffer,
\ a:command,
\ {_, output -> a:Callback(a:buffer, s:GetVersion(a:executable, output))},
\ {'output_stream': 'both', 'executable': a:executable}
\)
endfunction
" Given two triples of integers [major, minor, patch], compare the triples

View File

@ -66,7 +66,7 @@ endif
" Spaces and backslashes need to be escaped for signs.
function! s:EscapeSignText(sign_text) abort
return substitute(a:sign_text, '\\\| ', '\\\0', 'g')
return substitute(substitute(a:sign_text, ' *$', '', ''), '\\\| ', '\\\0', 'g')
endfunction
" Signs show up on the left for error markers.

View File

@ -0,0 +1,13 @@
" Author: Dan Loman <https://github.com/namolnad>
" Description: Functions for integrating with Swift tools
" Find the nearest dir containing a Package.swift file and assume it is the root of the Swift project.
function! ale#swift#FindProjectRoot(buffer) abort
let l:swift_config = ale#path#FindNearestFile(a:buffer, 'Package.swift')
if !empty(l:swift_config)
return fnamemodify(l:swift_config, ':h')
endif
return ''
endfunction

View File

@ -422,7 +422,7 @@ function! ale#util#Writefile(buffer, lines, filename) abort
\ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : a:lines
call writefile(l:corrected_lines, a:filename) " no-custom-checks
call writefile(l:corrected_lines, a:filename, 'S') " no-custom-checks
endfunction
if !exists('s:patial_timers')

View File

@ -81,7 +81,7 @@ function! ale#virtualtext#ShowCursorWarning(...) abort
call ale#virtualtext#Clear()
if !empty(l:loc)
let l:msg = get(l:loc, 'detail', l:loc.text)
let l:msg = l:loc.text
let l:hl_group = 'ALEVirtualTextInfo'
let l:type = get(l:loc, 'type', 'E')