Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bartek thindil Jasicki 2020-11-27 13:38:24 +01:00
commit 09b8cc97de
58 changed files with 1406 additions and 283 deletions

View File

@ -341,12 +341,14 @@ git clone https://github.com/dense-analysis/ale.git
### 3.iii. Installation with Vundle
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim)
by using the path on GitHub for this repository.
by adding the GitHub path for this repository to your `~/.vimrc`:
```vim
Plugin 'dense-analysis/ale'
```
Then run the command `:PluginInstall` in Vim.
See the Vundle documentation for more information.
<a name="installation-with-vim-plug"></a>
@ -354,13 +356,16 @@ See the Vundle documentation for more information.
### 3.iiii. Installation with Vim-Plug
You can install this plugin using [Vim-Plug](https://github.com/junegunn/vim-plug)
by adding the GitHub path for this repository to your `~/.vimrc`
and running `:PlugInstall`.
by adding the GitHub path for this repository to your `~/.vimrc`:
```vim
Plug 'dense-analysis/ale'
```
Then run the command `:PlugInstall` in Vim.
See the Vim-Plug documentation for more information.
<a name="contributing"></a>
## 4. Contributing

View File

@ -0,0 +1,39 @@
" Author: Dmitri Vereshchagin <dmitri.vereshchagin@gmail.com>
" Description: Elvis linter for Erlang files
call ale#Set('erlang_elvis_executable', 'elvis')
function! ale_linters#erlang#elvis#Handle(buffer, lines) abort
let l:pattern = '\v:(\d+):[^:]+:(.+)'
let l:loclist = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:loclist, {
\ 'lnum': str2nr(l:match[1]),
\ 'text': s:AbbreviateMessage(l:match[2]),
\ 'type': 'W',
\})
endfor
return l:loclist
endfunction
function! s:AbbreviateMessage(text) abort
let l:pattern = '\v\c^(line \d+ is too long):.*$'
return substitute(a:text, l:pattern, '\1.', '')
endfunction
function! s:GetCommand(buffer) abort
let l:file = ale#Escape(expand('#' . a:buffer . ':.'))
return '%e rock --output-format=parsable ' . l:file
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'elvis',
\ 'callback': 'ale_linters#erlang#elvis#Handle',
\ 'executable': {b -> ale#Var(b, 'erlang_elvis_executable')},
\ 'command': function('s:GetCommand'),
\ 'lint_file': 1,
\})

View File

@ -0,0 +1,32 @@
" Author: Eric Stern <eric@ericstern.com>,
" Arnold Chand <creativenull@outlook.com>
" Description: Intelephense language server integration for ALE
call ale#Set('php_intelephense_executable', 'intelephense')
call ale#Set('php_intelephense_use_global', 1)
call ale#Set('php_intelephense_config', {})
function! ale_linters#php#intelephense#GetProjectRoot(buffer) abort
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json')
if (!empty(l:composer_path))
return fnamemodify(l:composer_path, ':h')
endif
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction
function! ale_linters#php#intelephense#GetInitializationOptions() abort
return ale#Get('php_intelephense_config')
endfunction
call ale#linter#Define('php', {
\ 'name': 'intelephense',
\ 'lsp': 'stdio',
\ 'initialization_options': function('ale_linters#php#intelephense#GetInitializationOptions'),
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_intelephense', [])},
\ 'command': '%e --stdio',
\ 'project_root': function('ale_linters#php#intelephense#GetProjectRoot'),
\})

View File

@ -23,7 +23,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
" Matches against lines like the following:
"
" /path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) - \(.\+\) (\(.\+\))$'
let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) - \(.\+\) (\(.\+\)).*$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)

80
ale_linters/php/tlint.vim Normal file
View File

@ -0,0 +1,80 @@
" Author: Jose Soto <jose@tighten.co>
"
" Description: Tighten Opinionated PHP Linting
" Website: https://github.com/tightenco/tlint
call ale#Set('php_tlint_executable', 'tlint')
call ale#Set('php_tlint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('php_tlint_options', '')
function! ale_linters#php#tlint#GetProjectRoot(buffer) abort
let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json')
if !empty(l:composer_path)
return fnamemodify(l:composer_path, ':h')
endif
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction
function! ale_linters#php#tlint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'php_tlint', [
\ 'vendor/bin/tlint',
\ 'tlint',
\])
endfunction
function! ale_linters#php#tlint#GetCommand(buffer) abort
let l:executable = ale_linters#php#tlint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'php_tlint_options')
return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' lint %s'
endfunction
function! ale_linters#php#tlint#Handle(buffer, lines) abort
" Matches against lines like the following:
"
" ! There should be 1 space around `.` concatenations, and additional lines should always start with a `.`
" 22 : ` $something = 'a'.'name';`
"
let l:loop_count = 0
let l:messages_pattern = '^\! \(.*\)'
let l:output = []
let l:pattern = '^\(\d\+\) \:'
let l:temp_messages = []
for l:message in ale#util#GetMatches(a:lines, l:messages_pattern)
call add(l:temp_messages, l:message)
endfor
let l:loop_count = 0
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:num = l:match[1]
let l:text = l:temp_messages[l:loop_count]
call add(l:output, {
\ 'lnum': l:num,
\ 'col': 0,
\ 'text': l:text,
\ 'type': 'W',
\ 'sub_type': 'style',
\})
let l:loop_count += 1
endfor
return l:output
endfunction
call ale#linter#Define('php', {
\ 'name': 'tlint',
\ 'executable': function('ale_linters#php#tlint#GetExecutable'),
\ 'command': function('ale_linters#php#tlint#GetCommand'),
\ 'callback': 'ale_linters#php#tlint#Handle',
\ 'project_root': function('ale_linters#php#tlint#GetProjectRoot'),
\})

View File

@ -0,0 +1,26 @@
" Author: Eric Zhao <21zhaoe@protonmail.com>
" Description: Implementation of the Language Server Protocol for R.
call ale#Set('r_languageserver_cmd', 'languageserver::run()')
call ale#Set('r_languageserver_config', {})
function! ale_linters#r#languageserver#GetCommand(buffer) abort
let l:cmd_string = ale#Var(a:buffer, 'r_languageserver_cmd')
return 'Rscript --vanilla -e ' . ale#Escape(l:cmd_string)
endfunction
function! ale_linters#r#languageserver#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, '.Rprofile')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : fnamemodify(a:buffer, ':h')
endfunction
call ale#linter#Define('r', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
\ 'lsp_config': {b -> ale#Var(b, 'r_languageserver_config')},
\ 'executable': 'Rscript',
\ 'command': function('ale_linters#r#languageserver#GetCommand'),
\ 'project_root': function('ale_linters#r#languageserver#GetProjectRoot')
\})

View File

@ -9,6 +9,7 @@ call ale#linter#Define('typescript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
\ 'executable': {b -> ale#node#FindExecutable(b, 'typescript_tsserver', [
\ '.yarn/sdks/typescript/bin/tsserver',
\ 'node_modules/.bin/tsserver',
\ ])},
\ 'command': '%e',

View File

@ -2,23 +2,39 @@
" Description: balloonexpr support for ALE.
function! ale#balloon#MessageForPos(bufnr, lnum, col) abort
let l:set_balloons = ale#Var(a:bufnr, 'set_balloons')
let l:show_problems = 0
let l:show_hover = 0
if l:set_balloons is 1
let l:show_problems = 1
let l:show_hover = 1
elseif l:set_balloons is# 'hover'
let l:show_hover = 1
endif
" Don't show balloons if they are disabled, or linting is disabled.
if !ale#Var(a:bufnr, 'set_balloons')
if !(l:show_problems || l:show_hover)
\|| !g:ale_enabled
\|| !getbufvar(a:bufnr, 'ale_enabled', 1)
return ''
endif
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col)
if l:show_problems
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col)
endif
" Show the diagnostics message if found, 'Hover' output otherwise
if l:index >= 0
if l:show_problems && l:index >= 0
return l:loclist[l:index].text
elseif exists('*balloon_show') || getbufvar(
\ a:bufnr,
\ 'ale_set_balloons_legacy_echo',
\ get(g:, 'ale_set_balloons_legacy_echo', 0)
elseif l:show_hover && (
\ exists('*balloon_show')
\ || getbufvar(
\ a:bufnr,
\ 'ale_set_balloons_legacy_echo',
\ get(g:, 'ale_set_balloons_legacy_echo', 0)
\ )
\)
" Request LSP/tsserver hover information, but only if this version of
" Vim supports the balloon_show function, or if we turned a legacy

View File

@ -1,28 +1,24 @@
" Author: Jerko Steiner <jerko.steiner@gmail.com>
" Description: Code action support for LSP / tsserver
function! ale#code_action#ReloadBuffer() abort
let l:buffer = bufnr('')
execute 'augroup ALECodeActionReloadGroup' . l:buffer
autocmd!
augroup END
silent! execute 'augroup! ALECodeActionReloadGroup' . l:buffer
call ale#util#Execute(':e!')
endfunction
function! ale#code_action#HandleCodeAction(code_action, options) abort
let l:current_buffer = bufnr('')
let l:changes = a:code_action.changes
let l:should_save = get(a:options, 'should_save')
let l:force_save = get(a:options, 'force_save')
let l:safe_changes = []
for l:file_code_edit in l:changes
let l:buf = bufnr(l:file_code_edit.fileName)
if l:buf != -1 && l:buf != l:current_buffer && getbufvar(l:buf, '&mod')
if !l:force_save
call ale#util#Execute('echom ''Aborting action, file is unsaved''')
return
endif
else
call add(l:safe_changes, l:file_code_edit)
endif
endfor
for l:file_code_edit in l:safe_changes
call ale#code_action#ApplyChanges(
\ l:file_code_edit.fileName,
\ l:file_code_edit.textChanges,
@ -125,7 +121,12 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
endif
call extend(l:middle, l:insertions[1:])
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
if l:end_line <= len(l:lines)
" Only extend the last line if end_line is within the range of
" lines.
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
endif
let l:lines_before_change = len(l:lines)
let l:lines = l:start + l:middle + l:lines[l:end_line :]
@ -156,6 +157,20 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
call setpos('.', [0, l:pos[0], l:pos[1], 0])
endif
if a:should_save && l:buffer > 0 && !l:is_current_buffer
" Set up a one-time use event that will delete itself to reload the
" buffer next time it's entered to view the changes made to it.
execute 'augroup ALECodeActionReloadGroup' . l:buffer
autocmd!
execute printf(
\ 'autocmd BufEnter <buffer=%d>'
\ . ' call ale#code_action#ReloadBuffer()',
\ l:buffer
\)
augroup END
endif
endfunction
function! s:UpdateCursor(cursor, start, end, offset) abort
@ -263,3 +278,105 @@ function! ale#code_action#BuildChangesList(changes_map) abort
return l:changes
endfunction
function! s:EscapeMenuName(text) abort
return substitute(a:text, '\\\| \|\.\|&', '\\\0', 'g')
endfunction
function! s:UpdateMenu(data, menu_items) abort
silent! aunmenu PopUp.Refactor\.\.\.
if empty(a:data)
return
endif
for [l:type, l:item] in a:menu_items
let l:name = l:type is# 'tsserver' ? l:item.name : l:item.title
let l:func_name = l:type is# 'tsserver'
\ ? 'ale#codefix#ApplyTSServerCodeAction'
\ : 'ale#codefix#ApplyLSPCodeAction'
execute printf(
\ 'anoremenu <silent> PopUp.&Refactor\.\.\..%s'
\ . ' :call %s(%s, %s)<CR>',
\ s:EscapeMenuName(l:name),
\ l:func_name,
\ string(a:data),
\ string(l:item),
\)
endfor
if empty(a:menu_items)
silent! anoremenu PopUp.Refactor\.\.\..(None) :silent
endif
endfunction
function! s:GetCodeActions(linter, options) abort
let l:buffer = bufnr('')
let [l:line, l:column] = getpos('.')[1:2]
let l:column = min([l:column, len(getline(l:line))])
let l:location = {
\ 'buffer': l:buffer,
\ 'line': l:line,
\ 'column': l:column,
\ 'end_line': l:line,
\ 'end_column': l:column,
\}
let l:Callback = function('s:OnReady', [l:location, a:options])
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
endfunction
function! ale#code_action#GetCodeActions(options) abort
silent! aunmenu PopUp.Rename
silent! aunmenu PopUp.Refactor\.\.\.
" Only display the menu items if there's an LSP server.
let l:has_lsp = 0
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
let l:has_lsp = 1
break
endif
endfor
if l:has_lsp
if !empty(expand('<cword>'))
silent! anoremenu <silent> PopUp.Rename :ALERename<CR>
endif
silent! anoremenu <silent> PopUp.Refactor\.\.\..(None) :silent<CR>
call ale#codefix#Execute(
\ mode() is# 'v' || mode() is# "\<C-V>",
\ function('s:UpdateMenu')
\)
endif
endfunction
function! s:Setup(enabled) abort
augroup ALECodeActionsGroup
autocmd!
if a:enabled
autocmd MenuPopup * :call ale#code_action#GetCodeActions({})
endif
augroup END
if !a:enabled
silent! augroup! ALECodeActionsGroup
silent! aunmenu PopUp.Rename
silent! aunmenu PopUp.Refactor\.\.\.
endif
endfunction
function! ale#code_action#EnablePopUpMenu() abort
call s:Setup(1)
endfunction
function! ale#code_action#DisablePopUpMenu() abort
call s:Setup(0)
endfunction

View File

@ -1,5 +1,5 @@
" Author: Dalius Dobravolskas <dalius.dobravolskas@gmail.com>
" Description: Code Fix support for tsserver
" Description: Code Fix support for tsserver and LSP servers
let s:codefix_map = {}
@ -21,23 +21,65 @@ function! s:message(message) abort
call ale#util#Execute('echom ' . string(a:message))
endfunction
function! ale#codefix#ApplyTSServerCodeAction(data, item) abort
if has_key(a:item, 'changes')
let l:changes = a:item.changes
call ale#code_action#HandleCodeAction(
\ {
\ 'description': 'codefix',
\ 'changes': l:changes,
\ },
\ {},
\)
else
let l:message = ale#lsp#tsserver_message#GetEditsForRefactor(
\ a:data.buffer,
\ a:data.line,
\ a:data.column,
\ a:data.end_line,
\ a:data.end_column,
\ a:item.id[0],
\ a:item.id[1],
\)
let l:request_id = ale#lsp#Send(a:data.connection_id, l:message)
let s:codefix_map[l:request_id] = a:data
endif
endfunction
function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
if !has_key(a:response, 'request_seq')
\ || !has_key(s:codefix_map, a:response.request_seq)
return
endif
let l:location = remove(s:codefix_map, a:response.request_seq)
let l:data = remove(s:codefix_map, a:response.request_seq)
let l:MenuCallback = get(l:data, 'menu_callback', v:null)
if get(a:response, 'command', '') is# 'getCodeFixes'
if get(a:response, 'success', v:false) is v:false
\&& l:MenuCallback is v:null
let l:message = get(a:response, 'message', 'unknown')
call s:message('Error while getting code fixes. Reason: ' . l:message)
return
endif
if len(a:response.body) == 0
let l:result = get(a:response, 'body', [])
call filter(l:result, 'has_key(v:val, ''changes'')')
if l:MenuCallback isnot v:null
call l:MenuCallback(
\ l:data,
\ map(copy(l:result), '[''tsserver'', v:val]')
\)
return
endif
if len(l:result) == 0
call s:message('No code fixes available.')
return
@ -45,14 +87,15 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
let l:code_fix_to_apply = 0
if len(a:response.body) == 1
if len(l:result) == 1
let l:code_fix_to_apply = 1
else
let l:codefix_no = 1
let l:codefixstring = "Code Fixes:\n"
for l:codefix in a:response.body
let l:codefixstring .= l:codefix_no . ') ' . l:codefix.description . "\n"
for l:codefix in l:result
let l:codefixstring .= l:codefix_no . ') '
\ . l:codefix.description . "\n"
let l:codefix_no += 1
endfor
@ -66,21 +109,22 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
endif
endif
let l:changes = a:response.body[l:code_fix_to_apply - 1].changes
call ale#code_action#HandleCodeAction({
\ 'description': 'codefix',
\ 'changes': l:changes,
\}, {})
call ale#codefix#ApplyTSServerCodeAction(
\ l:data,
\ l:result[l:code_fix_to_apply - 1],
\)
elseif get(a:response, 'command', '') is# 'getApplicableRefactors'
if get(a:response, 'success', v:false) is v:false
\&& l:MenuCallback is v:null
let l:message = get(a:response, 'message', 'unknown')
call s:message('Error while getting applicable refactors. Reason: ' . l:message)
return
endif
if len(a:response.body) == 0
let l:result = get(a:response, 'body', [])
if len(l:result) == 0
call s:message('No applicable refactors available.')
return
@ -88,7 +132,7 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
let l:refactors = []
for l:item in a:response.body
for l:item in l:result
for l:action in l:item.actions
call add(l:refactors, {
\ 'name': l:action.description,
@ -97,11 +141,21 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
endfor
endfor
if l:MenuCallback isnot v:null
call l:MenuCallback(
\ l:data,
\ map(copy(l:refactors), '[''tsserver'', v:val]')
\)
return
endif
let l:refactor_no = 1
let l:refactorstring = "Applicable refactors:\n"
for l:refactor in l:refactors
let l:refactorstring .= l:refactor_no . ') ' . l:refactor.name . "\n"
let l:refactorstring .= l:refactor_no . ') '
\ . l:refactor.name . "\n"
let l:refactor_no += 1
endfor
@ -116,19 +170,10 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
let l:id = l:refactors[l:refactor_to_apply - 1].id
let l:message = ale#lsp#tsserver_message#GetEditsForRefactor(
\ l:location.buffer,
\ l:location.line,
\ l:location.column,
\ l:location.end_line,
\ l:location.end_column,
\ l:id[0],
\ l:id[1],
call ale#codefix#ApplyTSServerCodeAction(
\ l:data,
\ l:refactors[l:refactor_to_apply - 1],
\)
let l:request_id = ale#lsp#Send(l:location.connection_id, l:message)
let s:codefix_map[l:request_id] = l:location
elseif get(a:response, 'command', '') is# 'getEditsForRefactor'
if get(a:response, 'success', v:false) is v:false
let l:message = get(a:response, 'message', 'unknown')
@ -137,10 +182,48 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
return
endif
call ale#code_action#HandleCodeAction({
\ 'description': 'editsForRefactor',
\ 'changes': a:response.body.edits,
\}, {})
call ale#code_action#HandleCodeAction(
\ {
\ 'description': 'editsForRefactor',
\ 'changes': a:response.body.edits,
\ },
\ {},
\)
endif
endfunction
function! ale#codefix#ApplyLSPCodeAction(data, item) abort
if has_key(a:item, 'command')
\&& type(a:item.command) == v:t_dict
let l:command = a:item.command
let l:message = ale#lsp#message#ExecuteCommand(
\ l:command.command,
\ l:command.arguments,
\)
let l:request_id = ale#lsp#Send(a:data.connection_id, l:message)
elseif has_key(a:item, 'edit') || has_key(a:item, 'arguments')
if has_key(a:item, 'edit')
let l:topass = a:item.edit
else
let l:topass = a:item.arguments[0]
endif
let l:changes_map = ale#code_action#GetChanges(l:topass)
if empty(l:changes_map)
return
endif
let l:changes = ale#code_action#BuildChangesList(l:changes_map)
call ale#code_action#HandleCodeAction(
\ {
\ 'description': 'codeaction',
\ 'changes': l:changes,
\ },
\ {},
\)
endif
endfunction
@ -158,17 +241,32 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort
let l:changes = ale#code_action#BuildChangesList(l:changes_map)
call ale#code_action#HandleCodeAction({
\ 'description': 'applyEdit',
\ 'changes': l:changes,
\}, {})
call ale#code_action#HandleCodeAction(
\ {
\ 'description': 'applyEdit',
\ 'changes': l:changes,
\ },
\ {}
\)
elseif has_key(a:response, 'id')
\&& has_key(s:codefix_map, a:response.id)
let l:location = remove(s:codefix_map, a:response.id)
let l:data = remove(s:codefix_map, a:response.id)
let l:MenuCallback = get(l:data, 'menu_callback', v:null)
if !has_key(a:response, 'result')
\ || type(a:response.result) != v:t_list
\ || len(a:response.result) == 0
let l:result = get(a:response, 'result')
if type(l:result) != v:t_list
let l:result = []
endif
" Send the results to the menu callback, if set.
if l:MenuCallback isnot v:null
call l:MenuCallback(map(copy(l:result), '[''lsp'', v:val]'))
return
endif
if len(l:result) == 0
call s:message('No code actions received from server')
return
@ -177,8 +275,9 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort
let l:codeaction_no = 1
let l:codeactionstring = "Code Fixes:\n"
for l:codeaction in a:response.result
let l:codeactionstring .= l:codeaction_no . ') ' . l:codeaction.title . "\n"
for l:codeaction in l:result
let l:codeactionstring .= l:codeaction_no . ') '
\ . l:codeaction.title . "\n"
let l:codeaction_no += 1
endfor
@ -191,42 +290,44 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort
return
endif
let l:item = a:response.result[l:codeaction_to_apply - 1]
let l:item = l:result[l:codeaction_to_apply - 1]
if has_key(l:item, 'command')
\ && type(l:item.command) == v:t_dict
let l:command = l:item.command
let l:message = ale#lsp#message#ExecuteCommand(
\ l:command.command,
\ l:command.arguments,
\)
let l:request_id = ale#lsp#Send(l:location.connection_id, l:message)
elseif has_key(l:item, 'edit') || has_key(l:item, 'arguments')
if has_key(l:item, 'edit')
let l:topass = l:item.edit
else
let l:topass = l:item.arguments[0]
endif
let l:changes_map = ale#code_action#GetChanges(l:topass)
if empty(l:changes_map)
return
endif
let l:changes = ale#code_action#BuildChangesList(l:changes_map)
call ale#code_action#HandleCodeAction({
\ 'description': 'codeaction',
\ 'changes': l:changes,
\}, {})
endif
call ale#codefix#ApplyLSPCodeAction(l:data, l:item)
endif
endfunction
function! s:FindError(buffer, line, column, end_line, end_column) abort
let l:nearest_error = v:null
function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abort
if a:line == a:end_line
\&& a:column == a:end_column
\&& has_key(g:ale_buffer_info, a:buffer)
let l:nearest_error_diff = -1
for l:error in get(g:ale_buffer_info[a:buffer], 'loclist', [])
if has_key(l:error, 'code') && l:error.lnum == a:line
let l:diff = abs(l:error.col - a:column)
if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff
let l:nearest_error_diff = l:diff
let l:nearest_error = l:error
endif
endif
endfor
endif
return l:nearest_error
endfunction
function! s:OnReady(
\ line,
\ column,
\ end_line,
\ end_column,
\ MenuCallback,
\ linter,
\ lsp_details,
\) abort
let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, 'code_actions')
@ -236,32 +337,17 @@ function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abo
let l:buffer = a:lsp_details.buffer
if a:linter.lsp is# 'tsserver'
if a:line == a:end_line && a:column == a:end_column
if !has_key(g:ale_buffer_info, l:buffer)
return
endif
let l:nearest_error = v:null
let l:nearest_error_diff = -1
for l:error in get(g:ale_buffer_info[l:buffer], 'loclist', [])
if has_key(l:error, 'code') && l:error.lnum == a:line
let l:diff = abs(l:error.col - a:column)
if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff
let l:nearest_error_diff = l:diff
let l:nearest_error = l:error.code
endif
endif
endfor
let l:nearest_error =
\ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column)
if l:nearest_error isnot v:null
let l:message = ale#lsp#tsserver_message#GetCodeFixes(
\ l:buffer,
\ a:line,
\ a:column,
\ a:line,
\ a:column,
\ [l:nearest_error],
\ [l:nearest_error.code],
\)
else
let l:message = ale#lsp#tsserver_message#GetApplicableRefactors(
@ -277,56 +363,37 @@ function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abo
" completions won't know what text is nearby.
call ale#lsp#NotifyForChanges(l:id, l:buffer)
if a:line == a:end_line && a:column == a:end_column
if !has_key(g:ale_buffer_info, l:buffer)
return
endif
let l:diagnostics = []
let l:nearest_error =
\ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column)
let l:nearest_error = v:null
let l:nearest_error_diff = -1
for l:error in get(g:ale_buffer_info[l:buffer], 'loclist', [])
if has_key(l:error, 'code') && l:error.lnum == a:line
let l:diff = abs(l:error.col - a:column)
if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff
let l:nearest_error_diff = l:diff
let l:nearest_error = l:error
endif
endif
endfor
let l:diagnostics = []
if l:nearest_error isnot v:null
let l:diagnostics = [{
\ 'code': l:nearest_error.code,
\ 'message': l:nearest_error.text,
\ 'range': {
\ 'start': { 'line': l:nearest_error.lnum - 1, 'character': l:nearest_error.col - 1 },
\ 'end': { 'line': l:nearest_error.end_lnum - 1, 'character': l:nearest_error.end_col - 1 }
\}
\}]
endif
let l:message = ale#lsp#message#CodeAction(
\ l:buffer,
\ a:line,
\ a:column,
\ a:end_line,
\ a:end_column,
\ l:diagnostics,
\)
else
let l:message = ale#lsp#message#CodeAction(
\ l:buffer,
\ a:line,
\ a:column,
\ a:end_line,
\ a:end_column,
\ [],
\)
if l:nearest_error isnot v:null
let l:diagnostics = [
\ {
\ 'code': l:nearest_error.code,
\ 'message': l:nearest_error.text,
\ 'range': {
\ 'start': {
\ 'line': l:nearest_error.lnum - 1,
\ 'character': l:nearest_error.col - 1,
\ },
\ 'end': {
\ 'line': l:nearest_error.end_lnum - 1,
\ 'character': l:nearest_error.end_col,
\ },
\ },
\ },
\]
endif
let l:message = ale#lsp#message#CodeAction(
\ l:buffer,
\ a:line,
\ a:column,
\ a:end_line,
\ a:end_column,
\ l:diagnostics,
\)
endif
let l:Callback = a:linter.lsp is# 'tsserver'
@ -338,22 +405,40 @@ function! s:OnReady(line, column, end_line, end_column, linter, lsp_details) abo
let l:request_id = ale#lsp#Send(l:id, l:message)
let s:codefix_map[l:request_id] = {
\ 'connection_id': l:id,
\ 'buffer': l:buffer,
\ 'line': a:line,
\ 'column': a:column,
\ 'end_line': a:end_line,
\ 'end_column': a:end_column,
\ 'connection_id': l:id,
\ 'buffer': l:buffer,
\ 'line': a:line,
\ 'column': a:column,
\ 'end_line': a:end_line,
\ 'end_column': a:end_column,
\ 'menu_callback': a:MenuCallback,
\}
endfunction
function! s:ExecuteGetCodeFix(linter, range) abort
function! s:ExecuteGetCodeFix(linter, range, MenuCallback) abort
let l:buffer = bufnr('')
if a:range == 0
let [l:line, l:column] = getpos('.')[1:2]
let l:end_line = l:line
let l:end_column = l:column
" Expand the range to cover the current word, if there is one.
let l:cword = expand('<cword>')
if !empty(l:cword)
let l:search_pos = searchpos('\V' . l:cword, 'bn', l:line)
if l:search_pos != [0, 0]
let l:column = l:search_pos[1]
let l:end_column = l:column + len(l:cword) - 1
endif
endif
elseif mode() is# 'v' || mode() is# "\<C-V>"
" You need to get the start and end in a different way when you're in
" visual mode.
let [l:line, l:column] = getpos('v')[1:2]
let [l:end_line, l:end_column] = getpos('.')[1:2]
else
let [l:line, l:column] = getpos("'<")[1:2]
let [l:end_line, l:end_column] = getpos("'>")[1:2]
@ -363,11 +448,18 @@ function! s:ExecuteGetCodeFix(linter, range) abort
let l:end_column = min([l:end_column, len(getline(l:end_line))])
let l:Callback = function(
\ 's:OnReady', [l:line, l:column, l:end_line, l:end_column])
\ 's:OnReady', [l:line, l:column, l:end_line, l:end_column, a:MenuCallback]
\)
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
endfunction
function! ale#codefix#Execute(range) abort
function! ale#codefix#Execute(range, ...) abort
if a:0 > 1
throw 'Too many arguments'
endif
let l:MenuCallback = get(a:000, 0, v:null)
let l:lsp_linters = []
for l:linter in ale#linter#Get(&filetype)
@ -377,12 +469,16 @@ function! ale#codefix#Execute(range) abort
endfor
if empty(l:lsp_linters)
call s:message('No active LSPs')
if l:MenuCallback is v:null
call s:message('No active LSPs')
else
call l:MenuCallback({}, [])
endif
return
endif
for l:lsp_linter in l:lsp_linters
call s:ExecuteGetCodeFix(l:lsp_linter, a:range)
call s:ExecuteGetCodeFix(l:lsp_linter, a:range, l:MenuCallback)
endfor
endfunction

View File

@ -606,11 +606,14 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:doc = l:doc.value
endif
" Collapse whitespaces and line breaks into a single space.
let l:detail = substitute(get(l:item, 'detail', ''), '\_s\+', ' ', 'g')
let l:result = {
\ 'word': l:word,
\ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')),
\ 'icase': 1,
\ 'menu': get(l:item, 'detail', ''),
\ 'menu': l:detail,
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
\}
" This flag is used to tell if this completion came from ALE or not.

View File

@ -12,6 +12,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['help'],
\ 'description': 'Align help tags to the right margin',
\ },
\ 'autoimport': {
\ 'function': 'ale#fixers#autoimport#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix import issues with autoimport.',
\ },
\ 'autopep8': {
\ 'function': 'ale#fixers#autopep8#Fix',
\ 'suggested_filetypes': ['python'],
@ -105,6 +110,11 @@ let s:default_registry = {
\ 'suggested_filetypes': [],
\ 'description': 'Remove all trailing whitespace characters at the end of every line.',
\ },
\ 'yamlfix': {
\ 'function': 'ale#fixers#yamlfix#Fix',
\ 'suggested_filetypes': ['yaml'],
\ 'description': 'Fix yaml files with yamlfix.',
\ },
\ 'yapf': {
\ 'function': 'ale#fixers#yapf#Fix',
\ 'suggested_filetypes': ['python'],
@ -375,11 +385,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['html', 'htmldjango'],
\ 'description': 'Fix HTML files with html-beautify.',
\ },
\ 'luafmt': {
\ 'function': 'ale#fixers#luafmt#Fix',
\ 'suggested_filetypes': ['lua'],
\ 'description': 'Fix Lua files with luafmt.',
\ },
\ 'dhall': {
\ 'function': 'ale#fixers#dhall#Fix',
\ 'suggested_filetypes': ['dhall'],
\ 'description': 'Fix Dhall files with dhall-format.',
\ },
\ 'ormolu': {
\ 'function': 'ale#fixers#ormolu#Fix',
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'A formatter for Haskell source code.',
\ },
\}
" Reset the function registry to the default entries.

View File

@ -0,0 +1,25 @@
" Author: lyz-code
" Description: Fixing Python imports with autoimport.
call ale#Set('python_autoimport_executable', 'autoimport')
call ale#Set('python_autoimport_options', '')
call ale#Set('python_autoimport_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#fixers#autoimport#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'python_autoimport_options')
let l:executable = ale#python#FindExecutable(
\ a:buffer,
\ 'python_autoimport',
\ ['autoimport'],
\)
if !executable(l:executable)
return 0
endif
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\}
endfunction

View File

@ -0,0 +1,13 @@
call ale#Set('lua_luafmt_executable', 'luafmt')
call ale#Set('lua_luafmt_options', '')
function! ale#fixers#luafmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'lua_luafmt_executable')
let l:options = ale#Var(a:buffer, 'lua_luafmt_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' --stdin',
\}
endfunction

View File

@ -0,0 +1,12 @@
call ale#Set('haskell_ormolu_executable', 'ormolu')
call ale#Set('haskell_ormolu_options', '')
function! ale#fixers#ormolu#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'haskell_ormolu_executable')
let l:options = ale#Var(a:buffer, 'haskell_ormolu_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options),
\}
endfunction

View File

@ -2,6 +2,7 @@
" Description: Fixing files with phpcbf.
call ale#Set('php_phpcbf_standard', '')
call ale#Set('php_phpcbf_options', '')
call ale#Set('php_phpcbf_executable', 'phpcbf')
call ale#Set('php_phpcbf_use_global', get(g:, 'ale_use_global_executables', 0))
@ -20,6 +21,6 @@ function! ale#fixers#phpcbf#Fix(buffer) abort
\ : ''
return {
\ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ' -'
\ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ale#Pad(ale#Var(a:buffer, 'php_phpcbf_options')) . ' -'
\}
endfunction

View File

@ -0,0 +1,25 @@
" Author: lyz-code
" Description: Fixing yaml files with yamlfix.
call ale#Set('yaml_yamlfix_executable', 'yamlfix')
call ale#Set('yaml_yamlfix_options', '')
call ale#Set('yaml_yamlfix_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#fixers#yamlfix#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'yaml_yamlfix_options')
let l:executable = ale#python#FindExecutable(
\ a:buffer,
\ 'yaml_yamlfix',
\ ['yamlfix'],
\)
if !executable(l:executable)
return 0
endif
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\}
endfunction

View File

@ -5,6 +5,7 @@ let s:executables = [
\ 'node_modules/.bin/eslint_d',
\ 'node_modules/eslint/bin/eslint.js',
\ 'node_modules/.bin/eslint',
\ '.yarn/sdks/eslint/bin/eslint',
\]
let s:sep = has('win32') ? '\' : '/'

View File

@ -1,8 +1,32 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: This file adds support for using the shellcheck linter
" Shellcheck supports shell directives to define the shell dialect for scripts
" that do not have a shebang for some reason.
" https://github.com/koalaman/shellcheck/wiki/Directive#shell
function! ale#handlers#shellcheck#GetShellcheckDialectDirective(buffer) abort
let l:linenr = 0
let l:pattern = '\s\{-}#\s\{-}shellcheck\s\{-}shell=\(.*\)'
let l:possible_shell = ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh']
while l:linenr < min([50, line('$')])
let l:linenr += 1
let l:match = matchlist(getline(l:linenr), l:pattern)
if len(l:match) > 1 && index(l:possible_shell, l:match[1]) >= 0
return l:match[1]
endif
endwhile
return ''
endfunction
function! ale#handlers#shellcheck#GetDialectArgument(buffer) abort
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
let l:shell_type = ale#handlers#shellcheck#GetShellcheckDialectDirective(a:buffer)
if empty(l:shell_type)
let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
endif
if !empty(l:shell_type)
" Use the dash dialect for /bin/ash, etc.

View File

@ -24,6 +24,8 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
if get(a:response, 'success', v:false) is v:true
\&& get(a:response, 'body', v:null) isnot v:null
let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons')
" If we pass the show_documentation flag, we should show the full
" documentation, and always in the preview window.
if get(l:options, 'show_documentation', 0)
@ -40,7 +42,7 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
endif
elseif get(l:options, 'hover_from_balloonexpr', 0)
\&& exists('*balloon_show')
\&& ale#Var(l:options.buffer, 'set_balloons')
\&& (l:set_balloons is 1 || l:set_balloons is# 'hover')
call balloon_show(a:response.body.displayString)
elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(split(a:response.body.displayString, "\n")[0])
@ -216,9 +218,11 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents)
if !empty(l:lines)
let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons')
if get(l:options, 'hover_from_balloonexpr', 0)
\&& exists('*balloon_show')
\&& ale#Var(l:options.buffer, 'set_balloons')
\&& (l:set_balloons is 1 || l:set_balloons is# 'hover')
call balloon_show(join(l:lines, "\n"))
elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(l:lines[0])

View File

@ -85,7 +85,6 @@ function! ale#rename#HandleTSServerResponse(conn_id, response) abort
\ },
\ {
\ 'should_save': 1,
\ 'force_save': get(l:options, 'force_save'),
\ },
\)
endfunction
@ -118,7 +117,6 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
\ },
\ {
\ 'should_save': 1,
\ 'force_save': get(l:options, 'force_save'),
\ },
\)
endif
@ -177,7 +175,7 @@ function! s:ExecuteRename(linter, options) abort
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
endfunction
function! ale#rename#Execute(options) abort
function! ale#rename#Execute() abort
let l:lsp_linters = []
for l:linter in ale#linter#Get(&filetype)
@ -205,7 +203,6 @@ function! ale#rename#Execute(options) abort
call s:ExecuteRename(l:lsp_linter, {
\ 'old_name': l:old_name,
\ 'new_name': l:new_name,
\ 'force_save': get(a:options, 'force_save') is 1,
\})
endfor
endfunction

View File

@ -486,7 +486,7 @@ function! ale#util#Input(message, value) abort
endfunction
function! ale#util#HasBuflineApi() abort
return exists('*deletebufline') && exists('*setbufline')
return exists('*deletebufline') && exists('*appendbufline') && exists('*getpos') && exists('*setpos')
endfunction
" Sets buffer contents to lines
@ -507,8 +507,11 @@ function! ale#util#SetBufferContents(buffer, lines) abort
" Use a Vim API for setting lines in other buffers, if available.
if l:has_bufline_api
call setbufline(a:buffer, 1, l:new_lines)
call deletebufline(a:buffer, l:first_line_to_remove, '$')
let l:save_cursor = getpos('.')
call deletebufline(a:buffer, 1, '$')
call appendbufline(a:buffer, 1, l:new_lines)
call deletebufline(a:buffer, 1, 1)
call setpos('.', l:save_cursor)
" Fall back on setting lines the old way, for the current buffer.
else
let l:old_line_length = line('$')

View File

@ -31,6 +31,18 @@ g:ale_erlang_dialyzer_rebar3_profile *g:ale_erlang_dialyzer_rebar3_profile*
This variable can be changed to specify the profile that is used to
run dialyzer with rebar3.
-------------------------------------------------------------------------------
elvis *ale-erlang-elvis*
g:ale_erlang_elvis_executable *g:ale_erlang_elvis_executable*
*b:ale_erlang_elvis_executable*
Type: |String|
Default: `'elvis'`
This variable can be changed to specify the elvis executable.
-------------------------------------------------------------------------------
erlc *ale-erlang-erlc*

View File

@ -172,5 +172,25 @@ g:ale_haskell_hie_executable *g:ale_haskell_hie_executable*
ide engine. i.e. `'hie-wrapper'`
===============================================================================
ormolu *ale-haskell-ormolu*
g:ale_haskell_ormolu_executable *g:ale_haskell_ormolu_executable*
*b:ale_haskell_ormolu_executable*
Type: |String|
Default: `'ormolu'`
This variable can be changed to use a different executable for ormolu.
g:ale_haskell_ormolu_options *g:ale_haskell_ormolu_options*
*b:ale_haskell_ormolu_options*
Type: String
Default: ''
This variable can be used to pass extra options to the underlying ormolu
executable.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -30,5 +30,21 @@ g:ale_lua_luacheck_options *g:ale_lua_luacheck_options*
This variable can be set to pass additional options to luacheck.
===============================================================================
luafmt *ale-lua-luafmt*
g:ale_lua_luafmt_executable *g:ale_lua_luafmt_executable*
*b:ale_lua_luafmt_executable*
Type: |String|
Default: `'luafmt'`
This variable can be set to use a different executable for luafmt.
g:ale_lua_luafmt_options *g:ale_lua_luafmt_options*
*b:ale_lua_luafmt_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to the luafmt fixer.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -85,6 +85,14 @@ g:ale_php_phpcbf_use_global *g:ale_php_phpcbf_use_global*
See |ale-integrations-local-executables|
g:ale_php_phpcbf_options *g:ale_php_phpcbf_options*
*b:ale_php_phpcbf_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to php-cbf
===============================================================================
phpcs *ale-php-phpcs*
@ -243,5 +251,70 @@ g:ale_php_php_executable *g:ale_php_php_executable*
This variable sets the executable used for php.
===============================================================================
tlint *ale-php-tlint*
g:ale_php_tlint_executable *g:ale_php_tlint_executable*
*b:ale_php_tlint_executable*
Type: |String|
Default: `'tlint'`
See |ale-integrations-local-executables|
g:ale_php_tlint_use_global *g:ale_php_tlint_use_global*
*b:ale_php_tlint_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
g:ale_php_tlint_options *g:ale_php_tlint_options*
*b:ale_php_tlint_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to tlint
===============================================================================
intelephense *ale-php-intelephense*
g:ale_php_intelephense_executable *g:ale_php_intelephense_executable*
*b:ale_php_intelephense_executable*
Type: |String|
Default: `'intelephense'`
The variable can be set to configure the executable that will be used for
running the intelephense language server. `node_modules` directory
executable will be preferred instead of this setting if
|g:ale_php_intelephense_use_global| is `0`.
See: |ale-integrations-local-executables|
g:ale_php_intelephense_use_global *g:ale_php_intelephense_use_global*
*b:ale_php_intelephense_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
This variable can be set to `1` to force the language server to be run with
the executable set for |g:ale_php_intelephense_executable|.
See: |ale-integrations-local-executables|
g:ale_php_intelephense_config *g:ale_php_intelephense_config*
*b:ale_php_intelephense_config*
Type: |Dictionary|
Default: `{}`
The initialization options config specified by Intelephense. Refer to the
installation docs provided by intelephense (github.com/bmewburn/intelephense
-docs).
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -41,6 +41,32 @@ ALE will look for configuration files with the following filenames. >
The first directory containing any of the files named above will be used.
===============================================================================
autoimport *ale-python-autoimport*
g:ale_python_autoimport_executable *g:ale_python_autoimport_executable*
*b:ale_python_autoimport_executable*
Type: |String|
Default: `'autoimport'`
See |ale-integrations-local-executables|
g:ale_python_autoimport_options *g:ale_python_autoimport_options*
*b:ale_python_autoimport_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to autoimport.
g:ale_python_autoimport_use_global *g:ale_python_autoimport_use_global*
*b:ale_python_autoimport_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
autopep8 *ale-python-autopep8*
@ -687,7 +713,7 @@ g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv*
===============================================================================
pyright *ale-python-pyright*
The `pyrlight` linter requires a recent version of `pyright` which includes
The `pyright` linter requires a recent version of `pyright` which includes
the `pyright-langserver` executable. You can install `pyright` on your system
through `npm` with `sudo npm install -g pyright` or similar.

View File

@ -2,6 +2,29 @@
ALE R Integration *ale-r-options*
===============================================================================
languageserver *ale-r-languageserver*
g:ale_r_languageserver_cmd *g:ale_r_languageserver_cmd*
*b:ale_r_languageserver_cmd*
Type: |String|
Default: `'languageserver::run()'`
This option can be configured to change the execution command for
languageserver.
See the languageserver documentation for more options.
g:ale_r_languageserver_config *g:ale_r_languageserver_config*
*b:ale_r_languageserver_config*
Type: |Dictionary|
Default: `{}`
This option can be configured to change settings for languageserver. See the
languageserver documentation for more information.
===============================================================================
lintr *ale-r-lintr*
@ -22,7 +45,7 @@ g:ale_r_lintr_lint_package *g:ale_r_lintr_lint_package*
Default: `0`
When set to `1`, the file will be checked with `lintr::lint_package` instead
of `lintr::lint`. This prevents erroneous namespace warnings when linting
of `lintr::lint`. This prevents erroneous namespace warnings when linting
package files.
@ -36,8 +59,8 @@ g:ale_r_styler_options *g:ale_r_styler_options*
This option can be configured to change the options for styler.
The value of this option will be used as the `style` argument for the
`styler::style_file` options. Consult the styler documentation
The value of this option will be used as the `style` argument for the
`styler::style_file` options. Consult the styler documentation
for more information.

View File

@ -22,12 +22,12 @@ Integration Information
3. rls -- If you have `rls` installed, you might prefer using this linter
over cargo. rls implements the Language Server Protocol for incremental
compilation of Rust code, and can check Rust files while you type. `rls`
requires Rust files to contained in Cargo projects.
requires Rust files to be contained in Cargo projects.
4. analyzer -- If you have rust-analyzer installed, you might prefer using
this linter over cargo and rls. rust-analyzer also implements the
Language Server Protocol for incremental compilation of Rust code, and is
the next iteration of rls. rust-analyzer, like rls, requires Rust files
to contained in Cargo projects.
to be contained in Cargo projects.
5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to
consistently reformat your Rust code.

View File

@ -141,6 +141,7 @@ Notes:
* `erubis`
* `ruumba`
* Erlang
* `elvis`!!
* `erlc`
* `SyntaxErl`
* Fish
@ -196,6 +197,7 @@ Notes:
* `hie`
* `hindent`
* `hlint`
* `ormolu`
* `stack-build`!!
* `stack-ghc`
* `stylish-haskell`
@ -266,6 +268,7 @@ Notes:
* Lua
* `luac`
* `luacheck`
* `luafmt`
* Mail
* `alex`!!
* `languagetool`!!
@ -325,6 +328,7 @@ Notes:
* Perl6
* `perl6 -c`
* PHP
* `intelephense`
* `langserver`
* `phan`
* `phpcbf`
@ -334,6 +338,7 @@ Notes:
* `phpmd`
* `phpstan`
* `psalm`!!
* `tlint`
* PO
* `alex`!!
* `msgfmt`
@ -362,6 +367,7 @@ Notes:
* `purescript-language-server`
* `purty`
* Python
* `autoimport`
* `autopep8`
* `bandit`
* `black`
@ -384,6 +390,7 @@ Notes:
* `qmlfmt`
* `qmllint`
* R
* `languageserver`
* `lintr`
* `styler`
* Racket
@ -518,6 +525,7 @@ Notes:
* YAML
* `prettier`
* `swaglint`
* `yamlfix`
* `yamllint`
* YANG
* `yang-lsp`

View File

@ -15,7 +15,6 @@ Install prettier either globally or locally: >
npm install prettier -g # global
npm install prettier # local
<
===============================================================================
swaglint *ale-yaml-swaglint*
@ -49,6 +48,43 @@ g:ale_yaml_swaglint_use_global *g:ale_yaml_swaglint_use_global*
See |ale-integrations-local-executables|
===============================================================================
yamlfix *ale-yaml-yamlfix*
Website: https://lyz-code.github.io/yamlfix
Installation
-------------------------------------------------------------------------------
Install yamlfix: >
pip install yamlfix
<
Options
-------------------------------------------------------------------------------
g:ale_yaml_yamlfix_executable *g:ale_yaml_yamlfix_executable*
*b:ale_yaml_yamlfix_executable*
Type: |String|
Default: `'yamlfix'`
See |ale-integrations-local-executables|
g:ale_yaml_yamlfix_options *g:ale_yaml_yamlfix_options*
*b:ale_yaml_yamlfix_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to yamlfix.
g:ale_yaml_yamlfix_use_global *g:ale_yaml_yamlfix_use_global*
*b:ale_yaml_yamlfix_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
yamllint *ale-yaml-yamllint*

View File

@ -673,13 +673,31 @@ for a full list of options.
-------------------------------------------------------------------------------
5.7 Refactoring: Rename, Actions *ale-refactor*
ALE supports renaming symbols in symbols in code such as variables or class
names with the |ALERename| command.
ALE supports renaming symbols in code such as variables or class names with
the |ALERename| command.
|ALECodeAction| will execute actions on the cursor or applied to a visual
range selection, such as automatically fixing errors.
Actions will appear in the right click mouse menu by default for GUI versions
of Vim, unless disabled by setting |g:ale_popup_menu_enabled| to `0`.
Make sure to set your Vim to move the cursor position whenever you right
click, and enable the mouse menu: >
set mouse=a
set mousemodel=popup_setpos
<
You may wish to remove some other menu items you don't want to see: >
silent! aunmenu PopUp.Select\ Word
silent! aunmenu PopUp.Select\ Sentence
silent! aunmenu PopUp.Select\ Paragraph
silent! aunmenu PopUp.Select\ Line
silent! aunmenu PopUp.Select\ Block
silent! aunmenu PopUp.Select\ Blockwise
silent! aunmenu PopUp.Select\ All
<
===============================================================================
6. Global Options *ale-options*
@ -1676,6 +1694,7 @@ g:ale_lsp_root *g:ale_lsp_root*
If neither variable yields a result, a linter-specific function is invoked to
detect a project root. If this, too, yields no result, the linter is disabled.
g:ale_max_buffer_history_size *g:ale_max_buffer_history_size*
Type: |Number|
@ -1784,6 +1803,19 @@ g:ale_pattern_options_enabled *g:ale_pattern_options_enabled*
will not set buffer variables per |g:ale_pattern_options|.
g:ale_popup_menu_enabled *g:ale_popup_menu_enabled*
Type: |Number|
Default: `has('gui_running')`
When this option is set to `1`, ALE will show code actions and rename
capabilities in the right click mouse menu when there's a LSP server or
tsserver available. See |ale-refactor|.
This setting must be set to `1` before ALE is loaded for this behavior
to be enabled. See |ale-lint-settings-on-startup|.
g:ale_rename_tsserver_find_in_comments *g:ale_rename_tsserver_find_in_comments*
Type: |Number|
@ -1808,7 +1840,7 @@ g:ale_rename_tsserver_find_in_strings *g:ale_rename_tsserver_find_in_strings*
g:ale_set_balloons *g:ale_set_balloons*
*b:ale_set_balloons*
Type: |Number|
Type: |Number| or |String|
Default: `has('balloon_eval') && has('gui_running')`
When this option is set to `1`, balloon messages will be displayed for
@ -1819,6 +1851,13 @@ g:ale_set_balloons *g:ale_set_balloons*
supporting "Hover" information, per |ale-hover|, then brief information
about the symbol under the cursor will be displayed in a balloon.
This option can be set to `'hover'` to only enable balloons for hover
message, so diagnostics are never shown in balloons. You may wish to
configure use this setting only in GUI Vim like so: >
let g:ale_set_balloons = has('gui_running') ? 'hover' : 0
<
Balloons can be enabled for terminal versions of Vim that support balloons,
but some versions of Vim will produce strange mouse behavior when balloons
are enabled. To configure balloons for your terminal, you should first
@ -2601,6 +2640,7 @@ documented in additional help files.
elm-make..............................|ale-elm-elm-make|
erlang..................................|ale-erlang-options|
dialyzer..............................|ale-erlang-dialyzer|
elvis.................................|ale-erlang-elvis|
erlc..................................|ale-erlang-erlc|
syntaxerl.............................|ale-erlang-syntaxerl|
eruby...................................|ale-eruby-options|
@ -2654,6 +2694,7 @@ documented in additional help files.
stack-ghc.............................|ale-haskell-stack-ghc|
stylish-haskell.......................|ale-haskell-stylish-haskell|
hie...................................|ale-haskell-hie|
ormolu................................|ale-haskell-ormolu|
hcl.....................................|ale-hcl-options|
terraform-fmt.........................|ale-hcl-terraform-fmt|
html....................................|ale-html-options|
@ -2713,6 +2754,7 @@ documented in additional help files.
lua.....................................|ale-lua-options|
luac..................................|ale-lua-luac|
luacheck..............................|ale-lua-luacheck|
luafmt................................|ale-lua-luafmt|
markdown................................|ale-markdown-options|
markdownlint..........................|ale-markdown-markdownlint|
mdl...................................|ale-markdown-mdl|
@ -2764,6 +2806,8 @@ documented in additional help files.
psalm.................................|ale-php-psalm|
php-cs-fixer..........................|ale-php-php-cs-fixer|
php...................................|ale-php-php|
tlint.................................|ale-php-tlint|
intelephense..........................|ale-php-intelephense|
po......................................|ale-po-options|
write-good............................|ale-po-write-good|
pod.....................................|ale-pod-options|
@ -2789,6 +2833,7 @@ documented in additional help files.
pyrex (cython)..........................|ale-pyrex-options|
cython................................|ale-pyrex-cython|
python..................................|ale-python-options|
autoimport............................|ale-python-autoimport|
autopep8..............................|ale-python-autopep8|
bandit................................|ale-python-bandit|
black.................................|ale-python-black|
@ -2810,6 +2855,7 @@ documented in additional help files.
qml.....................................|ale-qml-options|
qmlfmt................................|ale-qml-qmlfmt|
r.......................................|ale-r-options|
languageserver........................|ale-r-languageserver|
lintr.................................|ale-r-lintr|
styler................................|ale-r-styler|
reasonml................................|ale-reasonml-options|
@ -2926,6 +2972,7 @@ documented in additional help files.
yaml....................................|ale-yaml-options|
prettier..............................|ale-yaml-prettier|
swaglint..............................|ale-yaml-swaglint|
yamlfix...............................|ale-yaml-yamlfix|
yamllint..............................|ale-yaml-yamllint|
yang....................................|ale-yang-options|
yang-lsp..............................|ale-yang-lsp|
@ -3111,12 +3158,6 @@ ALERename *ALERename*
The symbol where the cursor is resting will be the symbol renamed, and a
prompt will open to request a new name.
ALE will refuse to complete a rename operation if there are files to modify
which have not yet been saved in Vim. If the command is run with a bang
(`:ALERename!`), all warnings will be suppressed, and files that are still
open in Vim and not saved will be ignored and left in a state where symbols
in those files will not be updated.
ALECodeAction *ALECodeAction*

View File

@ -158,7 +158,10 @@ let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0)
" This variable can be overridden to set the GO111MODULE environment variable.
let g:ale_go_go111module = get(g:, 'ale_go_go111module', '')
if g:ale_set_balloons
" If 1, enable a popup menu for commands.
let g:ale_popup_menu_enabled = get(g:, 'ale_popup_menu_enabled', has('gui_running'))
if g:ale_set_balloons is 1 || g:ale_set_balloons is# 'hover'
call ale#balloon#Enable()
endif
@ -166,6 +169,10 @@ if g:ale_completion_enabled
call ale#completion#Enable()
endif
if g:ale_popup_menu_enabled
call ale#code_action#EnablePopUpMenu()
endif
" Define commands for moving through warnings and errors.
command! -bar -nargs=* ALEPrevious
\ :call ale#loclist_jumping#WrapJump('before', <q-args>)
@ -238,7 +245,7 @@ command! -bar ALEComplete :call ale#completion#GetCompletions('ale-manual')
command! -bar ALEImport :call ale#completion#Import()
" Rename symbols using tsserver and LSP
command! -bar -bang ALERename :call ale#rename#Execute({'force_save': '<bang>' is# '!'})
command! -bar -bang ALERename :call ale#rename#Execute()
" Apply code actions to a range.
command! -bar -range ALECodeAction :call ale#codefix#Execute(<range>)

View File

@ -150,6 +150,7 @@ formatting.
* [erubis](https://github.com/kwatch/erubis)
* [ruumba](https://github.com/ericqweinstein/ruumba)
* Erlang
* [elvis](https://github.com/inaka/elvis) :floppy_disk:
* [erlc](http://erlang.org/doc/man/erlc.html)
* [SyntaxErl](https://github.com/ten0s/syntaxerl)
* Fish
@ -205,6 +206,7 @@ formatting.
* [hie](https://github.com/haskell/haskell-ide-engine)
* [hindent](https://hackage.haskell.org/package/hindent)
* [hlint](https://hackage.haskell.org/package/hlint)
* [ormolu](https://github.com/tweag/ormolu)
* [stack-build](https://haskellstack.org/) :floppy_disk:
* [stack-ghc](https://haskellstack.org/)
* [stylish-haskell](https://github.com/jaspervdj/stylish-haskell)
@ -275,6 +277,7 @@ formatting.
* Lua
* [luac](https://www.lua.org/manual/5.1/luac.html)
* [luacheck](https://github.com/mpeterv/luacheck)
* [luafmt](https://github.com/trixnz/lua-fmt)
* Mail
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
@ -334,6 +337,7 @@ formatting.
* Perl6
* [perl6 -c](https://perl6.org) :warning:
* PHP
* [intelephense](https://github.com/bmewburn/intelephense-docs)
* [langserver](https://github.com/felixfbecker/php-language-server)
* [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions
* [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer)
@ -343,6 +347,7 @@ formatting.
* [phpmd](https://phpmd.org)
* [phpstan](https://github.com/phpstan/phpstan)
* [psalm](https://getpsalm.org) :floppy_disk:
* [tlint](https://github.com/tightenco/tlint)
* PO
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [msgfmt](https://www.gnu.org/software/gettext/manual/html_node/msgfmt-Invocation.html)
@ -371,6 +376,7 @@ formatting.
* [purescript-language-server](https://github.com/nwolverson/purescript-language-server)
* [purty](https://gitlab.com/joneshf/purty)
* Python
* [autoimport](https://lyz-code.github.io/autoimport/)
* [autopep8](https://github.com/hhatto/autopep8)
* [bandit](https://github.com/PyCQA/bandit) :warning:
* [black](https://github.com/ambv/black)
@ -393,6 +399,7 @@ formatting.
* [qmlfmt](https://github.com/jesperhh/qmlfmt)
* [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint)
* R
* [languageserver](https://github.com/REditorSupport/languageserver)
* [lintr](https://github.com/jimhester/lintr)
* [styler](https://github.com/r-lib/styler)
* Racket
@ -527,6 +534,7 @@ formatting.
* YAML
* [prettier](https://github.com/prettier/prettier)
* [swaglint](https://github.com/byCedric/swaglint)
* [yamlfix](https://lyz-code.github.io/yamlfix)
* [yamllint](https://yamllint.readthedocs.io/)
* YANG
* [yang-lsp](https://github.com/theia-ide/yang-lsp)

View File

View File

@ -0,0 +1,16 @@
Before:
let b:file = fnamemodify(bufname(''), ':.')
call ale#assert#SetUpLinterTest('erlang', 'elvis')
After:
call ale#assert#TearDownLinterTest()
Execute(Default command should be correct):
AssertLinter 'elvis',
\ ale#Escape('elvis') . ' rock --output-format=parsable ' . ale#Escape(b:file)
Execute(Executable should be configurable):
let b:ale_erlang_elvis_executable = '/path/to/elvis'
AssertLinter '/path/to/elvis',
\ ale#Escape('/path/to/elvis') . ' rock --output-format=parsable ' . ale#Escape(b:file)

View File

@ -0,0 +1,26 @@
Before:
call ale#assert#SetUpLinterTest('php', 'intelephense')
After:
call ale#assert#TearDownLinterTest()
Execute(The default executable path should be correct):
AssertLinter 'intelephense',
\ ale#Escape('intelephense') . ' --stdio'
Execute(The project path should be correct for .git directories):
call ale#test#SetFilename('php-intelephense-project/with-git/test.php')
silent! call mkdir('php-intelephense-project/with-git/.git', 'p')
AssertLSPProject ale#path#Simplify(g:dir . '/php-intelephense-project/with-git')
Execute(The project path should be correct for composer.json file):
call ale#test#SetFilename('php-intelephense-project/with-composer/test.php')
AssertLSPProject ale#path#Simplify(g:dir . '/php-intelephense-project/with-composer')
Execute(The project cache should be saved in a temp dir):
call ale#test#SetFilename('php-intelephense-project/with-composer/test.php')
let g:ale_php_intelephense_config = { 'storagePath': '/tmp/intelephense' }
AssertLSPProject ale#path#Simplify(g:dir . '/php-intelephense-project/with-composer')

View File

@ -0,0 +1,22 @@
Before:
call ale#assert#SetUpLinterTest('r', 'languageserver')
After:
call ale#assert#TearDownLinterTest()
Execute(The default executable path should be correct):
AssertLinter 'Rscript', 'Rscript --vanilla -e ' . ale#Escape('languageserver::run()')
Execute(The project root should be detected correctly):
AssertLSPProject '.'
call ale#test#SetFilename('r_paths/dummy/test.R')
AssertLSPProject ale#path#Simplify(g:dir . '/r_paths')
Execute(Should accept configuration settings):
AssertLSPConfig {}
let b:ale_r_languageserver_config = {'r': {'lsp': {'debug': 'true', 'diagnostics': 'true'}}}
AssertLSPConfig {'r': {'lsp': {'debug': 'true', 'diagnostics': 'true'}}}

View File

@ -40,6 +40,7 @@ Execute(Should handle Rust completion results correctly):
\ {'word': 'from', 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from', 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'from', 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\ {'word': 'to_vec', 'menu': 'pub fn to_vec(&self) -> Vec<T> where T: Clone,', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})},
\],
\ ale#completion#ParseLSPCompletions({
\ "jsonrpc":"2.0",
@ -184,6 +185,11 @@ Execute(Should handle Rust completion results correctly):
\ "label":"from",
\ "kind":3,
\ "detail":"fn from(s: Cow<'a, str>) -> String"
\ },
\ {
\ "label":"to_vec",
\ "kind":3,
\ "detail":"pub fn to_vec(&self) -> Vec<T>\nwhere\n T: Clone,"
\ }
\ ]
\ })

View File

@ -0,0 +1,50 @@
Before:
Save g:ale_python_autoimport_executable
Save g:ale_python_autoimport_options
" Use an invalid global executable, so we don't match it.
let g:ale_python_autoimport_executable = 'xxxinvalid'
let g:ale_python_autoimport_options = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
silent cd ..
silent cd command_callback
let g:dir = getcwd()
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
After:
Restore
unlet! b:bin_dir
call ale#test#RestoreDirectory()
Execute(The autoimport callback should return the correct default values):
AssertEqual
\ 0,
\ ale#fixers#autoimport#Fix(bufnr(''))
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
AssertEqual
\ {
\ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/autoimport')) . ' -',
\ },
\ ale#fixers#autoimport#Fix(bufnr(''))
Execute(The autoimport callback should respect custom options):
let g:ale_python_autoimport_options = '--multi-line=3 --trailing-comma'
AssertEqual
\ 0,
\ ale#fixers#autoimport#Fix(bufnr(''))
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
AssertEqual
\ {
\ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/autoimport'))
\ . ' --multi-line=3 --trailing-comma -',
\ },
\ ale#fixers#autoimport#Fix(bufnr(''))

View File

@ -0,0 +1,35 @@
Before:
Save g:ale_lua_luafmt_executable
Save g:ale_lua_luafmt_options
" Use an invalid global executable, so we don't match it.
let g:ale_lua_luafmt_executable = 'xxxinvalid'
let g:ale_lua_luafmt_options = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
After:
Restore
call ale#test#RestoreDirectory()
Execute(The luafmt callback should return the correct default values):
call ale#test#SetFilename('../lua_files/testfile.lua')
AssertEqual
\ {
\ 'command': ale#Escape('xxxinvalid') . ' --stdin',
\ },
\ ale#fixers#luafmt#Fix(bufnr(''))
Execute(The luafmt callback should include custom luafmt options):
let g:ale_lua_luafmt_options = "--skip-children"
call ale#test#SetFilename('../lua_files/testfile.lua')
AssertEqual
\ {
\ 'command': ale#Escape('xxxinvalid')
\ . ' ' . g:ale_lua_luafmt_options
\ . ' --stdin',
\ },
\ ale#fixers#luafmt#Fix(bufnr(''))

View File

@ -0,0 +1,24 @@
Before:
Save g:ale_haskell_ormolu_executable
Save g:ale_haskell_ormolu_options
After:
Restore
Execute(The ormolu callback should return the correct default values):
AssertEqual
\ {
\ 'command': ale#Escape('ormolu')
\ },
\ ale#fixers#ormolu#Fix(bufnr(''))
Execute(The ormolu executable and options should be configurable):
let g:ale_nix_nixpkgsfmt_executable = '/path/to/ormolu'
let g:ale_nix_nixpkgsfmt_options = '-h'
AssertEqual
\ {
\ 'command': ale#Escape('/path/to/ormolu')
\ . ' -h',
\ },
\ ale#fixers#nixpkgsfmt#Fix(bufnr(''))

View File

@ -5,6 +5,7 @@ Before:
let g:ale_php_phpcbf_executable = 'phpcbf_test'
let g:ale_php_phpcbf_standard = ''
let g:ale_php_phpcbf_options = ''
let g:ale_php_phpcbf_use_global = 0
call ale#test#SetDirectory('/testplugin/test/fixers')
@ -54,6 +55,15 @@ Execute(The phpcbf callback should include the phpcbf_standard option):
\ {'command': ale#Escape(ale#path#Simplify(g:dir . '/php_paths/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . '--standard=phpcbf_ruleset.xml' . ' -'},
\ ale#fixers#phpcbf#Fix(bufnr(''))
Execute(User provided options should be used):
let g:ale_php_phpcbf_options = '--my-user-provided-option my-value'
call ale#test#SetFilename('php_paths/project-with-phpcbf/foo/test.php')
AssertEqual
\ {'command': ale#Escape(ale#path#Simplify(g:dir . '/php_paths/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . ale#Pad('--my-user-provided-option my-value') . ' -'},
\ ale#fixers#phpcbf#Fix(bufnr(''))
Before:
Save g:ale_php_phpcbf_executable
Save g:ale_php_phpcbf_standard
@ -61,6 +71,7 @@ Before:
let g:ale_php_phpcbf_executable = 'phpcbf_test'
let g:ale_php_phpcbf_standard = ''
let g:ale_php_phpcbf_options = ''
let g:ale_php_phpcbf_use_global = 0
call ale#test#SetDirectory('/testplugin/test/fixers')

View File

@ -0,0 +1,50 @@
Before:
Save g:ale_python_yamlfix_executable
Save g:ale_python_yamlfix_options
" Use an invalid global executable, so we don't match it.
let g:ale_python_yamlfix_executable = 'xxxinvalid'
let g:ale_python_yamlfix_options = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
silent cd ..
silent cd command_callback
let g:dir = getcwd()
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
After:
Restore
unlet! b:bin_dir
call ale#test#RestoreDirectory()
Execute(The yamlfix callback should return the correct default values):
AssertEqual
\ 0,
\ ale#fixers#yamlfix#Fix(bufnr(''))
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.yaml')
AssertEqual
\ {
\ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/yamlfix')) . ' -',
\ },
\ ale#fixers#yamlfix#Fix(bufnr(''))
Execute(The yamlfix callback should respect custom options):
let g:ale_yaml_yamlfix_options = '--multi-line=3 --trailing-comma'
AssertEqual
\ 0,
\ ale#fixers#yamlfix#Fix(bufnr(''))
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.yaml')
AssertEqual
\ {
\ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/yamlfix'))
\ . ' --multi-line=3 --trailing-comma -',
\ },
\ ale#fixers#yamlfix#Fix(bufnr(''))

View File

@ -0,0 +1,37 @@
Before:
runtime ale_linters/erlang/elvis.vim
After:
call ale#linter#Reset()
Execute(Warning messages should be handled):
AssertEqual
\ [
\ {
\ 'lnum': 11,
\ 'text': "Replace the 'if' expression on line 11 with a 'case' expression or function clauses.",
\ 'type': 'W',
\ },
\ {
\ 'lnum': 20,
\ 'text': 'Remove the debug call to io:format/1 on line 20.',
\ 'type': 'W',
\ },
\ ],
\ ale_linters#erlang#elvis#Handle(bufnr(''), [
\ "src/foo.erl:11:no_if_expression:Replace the 'if' expression on line 11 with a 'case' expression or function clauses.",
\ 'src/foo.erl:20:no_debug_call:Remove the debug call to io:format/1 on line 20.',
\ ])
Execute(Line length message shouldn't contain the line itself):
AssertEqual
\ [
\ {
\ 'lnum': 24,
\ 'text': 'Line 24 is too long.',
\ 'type': 'W',
\ },
\ ],
\ ale_linters#erlang#elvis#Handle(bufnr(''), [
\ 'src/foo.erl:24:line_length:Line 24 is too long: io:format("Look ma, too long!"),.',
\ ])

View File

@ -13,7 +13,16 @@ Execute(phpcs errors should be handled):
\ 'type': 'E',
\ 'sub_type': 'style',
\ 'text': 'Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)',
\ }],
\ },
\ {
\ 'lnum': 22,
\ 'col': 3,
\ 'type': 'E',
\ 'sub_type': 'style',
\ 'text': 'All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks)',
\ },
\ ],
\ ale_linters#php#phpcs#Handle(bufnr(''), [
\ '/path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)',
\ "/path/to/some-filename.php:22:3: error - All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '\"\n'.",
\ ])

View File

@ -0,0 +1,34 @@
Before:
runtime ale_linters/php/tlint.vim
After:
call ale#linter#Reset()
Execute(The tlint handler should calculate line numbers):
AssertEqual
\ [
\ {
\ 'lnum': '5',
\ 'col': 0,
\ 'sub_type':
\ 'style',
\ 'type': 'W',
\ 'text': ['! There should be no unused imports.', 'There should be no unused imports.', '', '', '', '', '', '', '', '']
\ },
\ {
\ 'lnum': '15',
\ 'col': 0,
\ 'sub_type':
\ 'style',
\ 'type': 'W',
\ 'text': ['! There should be no method visibility in test methods.', 'There should be no method visibility in test methods.', '', '', '', '', '', '', '', '']
\ },
\ ],
\ ale_linters#php#tlint#Handle(347, [
\ "Lints for /Users/jose/Code/Tighten/tester/tests/Unit/ExampleTest.php",
\ "============",
\ "! There should be no unused imports.",
\ "5 : `use Illuminate\Foundation\Testing\RefreshDatabase;`",
\ "! There should be no method visibility in test methods.",
\ "15 : ` public function testBasicTest()`",
\ ])

View File

View File

@ -105,11 +105,9 @@ Execute(Failed codefix responses should be handled correctly):
\)
AssertEqual g:handle_code_action_called, 0
Given typescript(Some typescript file):
foo
somelongerline
somelongerline ()
bazxyzxyzxyz
Execute(getCodeFixes from tsserver should be handled):
@ -283,7 +281,7 @@ Execute(tsserver codefix requests should be sent):
runtime ale_linters/typescript/tsserver.vim
let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'code': 2304}]}}
call setpos('.', [bufnr(''), 2, 5, 0])
call setpos('.', [bufnr(''), 2, 16, 0])
" ALECodeAction
call ale#codefix#Execute(0)
@ -303,9 +301,9 @@ Execute(tsserver codefix requests should be sent):
\ ale#lsp#tsserver_message#Change(bufnr('')),
\ [0, 'ts@getCodeFixes', {
\ 'startLine': 2,
\ 'startOffset': 5,
\ 'startOffset': 16,
\ 'endLine': 2,
\ 'endOffset': 6,
\ 'endOffset': 17,
\ 'file': expand('%:p'),
\ 'errorCodes': [2304],
\ }]
@ -316,8 +314,8 @@ Execute(tsserver codefix requests should be sent only for error with code):
call ale#linter#Reset()
runtime ale_linters/typescript/tsserver.vim
let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5}, {'lnum': 2, 'col': 5, 'code': 2304}]}}
call setpos('.', [bufnr(''), 2, 5, 0])
let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 16}, {'lnum': 2, 'col': 16, 'code': 2304}]}}
call setpos('.', [bufnr(''), 2, 16, 0])
" ALECodeAction
call ale#codefix#Execute(0)
@ -337,9 +335,9 @@ Execute(tsserver codefix requests should be sent only for error with code):
\ ale#lsp#tsserver_message#Change(bufnr('')),
\ [0, 'ts@getCodeFixes', {
\ 'startLine': 2,
\ 'startOffset': 5,
\ 'startOffset': 16,
\ 'endLine': 2,
\ 'endOffset': 6,
\ 'endOffset': 17,
\ 'file': expand('%:p'),
\ 'errorCodes': [2304],
\ }]
@ -424,43 +422,6 @@ Execute(getEditsForRefactor should print error on failure):
AssertEqual ['echom ''Error while getting edits for refactor. Reason: oops'''], g:expr_list
" TODO: I can't figure out how to run ALECodeAction on range
" in test function. Therefore I can't write properly working
" test. If somebody knows how to do that help is appreciated.
"
" Execute(tsserver getApplicableRefactors requests should be sent):
" call ale#linter#Reset()
"
" runtime ale_linters/typescript/tsserver.vim
" let g:ale_buffer_info = {bufnr(''): {'loclist': []}}
" call setpos('.', [bufnr(''), 2, 5, 0])
" normal "v$"
"
" execute "ALECodeAction"
"
" " We shouldn't register the callback yet.
" AssertEqual '''''', string(g:Callback)
"
" AssertEqual type(function('type')), type(g:InitCallback)
" call g:InitCallback()
"
" AssertEqual 'code_actions', g:capability_checked
" AssertEqual
" \ 'function(''ale#codefix#HandleTSServerResponse'')',
" \ string(g:Callback)
" AssertEqual
" \ [
" \ ale#lsp#tsserver_message#Change(bufnr('')),
" \ [0, 'ts@getApplicableRefactors', {
" \ 'startLine': 2,
" \ 'startOffset': 5,
" \ 'endLine': 2,
" \ 'endOffset': 15,
" \ 'file': expand('%:p'),
" \ }]
" \ ],
" \ g:message_list
Execute(Failed LSP responses should be handled correctly):
call ale#codefix#HandleLSPResponse(
\ 1,
@ -545,23 +506,15 @@ Execute(LSP code action requests should be sent):
\ string(g:Callback)
AssertEqual
\ [
\ [1, 'workspace/didChangeConfiguration', {'settings': {'python': {}}}],
\ [1, 'textDocument/didChange', {
\ 'contentChanges': [{'text': "def main():\n a = 1\n b = a + 2\n"}],
\ 'textDocument': {
\ 'uri': ale#path#ToURI(expand('%:p')),
\ 'version': g:ale_lsp_next_version_id - 1,
\ },
\ }],
\ [0, 'textDocument/codeAction', {
\ 'context': {
\ 'diagnostics': [{'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}]
\ 'diagnostics': [{'range': {'end': {'character': 6, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}]
\ },
\ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}},
\ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))}
\ }]
\ ],
\ g:message_list
\ g:message_list[-1:]
Execute(LSP code action requests should be sent only for error with code):
call ale#linter#Reset()
@ -585,20 +538,12 @@ Execute(LSP code action requests should be sent only for error with code):
\ string(g:Callback)
AssertEqual
\ [
\ [1, 'workspace/didChangeConfiguration', {'settings': {'python': {}}}],
\ [1, 'textDocument/didChange', {
\ 'contentChanges': [{'text': "def main():\n a = 1\n b = a + 2\n"}],
\ 'textDocument': {
\ 'uri': ale#path#ToURI(expand('%:p')),
\ 'version': g:ale_lsp_next_version_id - 1,
\ },
\ }],
\ [0, 'textDocument/codeAction', {
\ 'context': {
\ 'diagnostics': [{'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}]
\ 'diagnostics': [{'range': {'end': {'character': 6, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}]
\ },
\ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}},
\ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))}
\ }]
\ ],
\ g:message_list
\ g:message_list[-1:]

View File

@ -101,7 +101,7 @@ Execute(tsserver quickinfo responses will null missing bodies should be handled)
AssertEqual {}, ale#hover#GetMap()
Execute(tsserver quickinfo displayString values should be displayed):
call ale#hover#SetMap({3: {}})
call ale#hover#SetMap({3: {'buffer': bufnr('')}})
call ale#hover#HandleTSServerResponse(
\ 1,
\ {
@ -169,7 +169,7 @@ Execute(LSP hover response with lists of strings and marked strings should be ha
AssertEqual {}, ale#hover#GetMap()
Execute(tsserver responses for documentation requests should be handled):
call ale#hover#SetMap({3: {'show_documentation': 1}})
call ale#hover#SetMap({3: {'show_documentation': 1, 'buffer': bufnr('')}})
call ale#hover#HandleTSServerResponse(
\ 1,

View File

@ -35,7 +35,7 @@ After:
Execute(The file changed event function should set b:ale_file_changed):
let g:ale_lint_on_enter = 0
if has('gui')
if has('gui_running')
new
else
e test

View File

@ -269,7 +269,7 @@ Execute(tsserver rename requests should be sent):
\ }]
\ ],
\ g:message_list
AssertEqual {'42': {'old_name': 'somelongerline', 'new_name': 'a-new-name', 'force_save': 0}},
AssertEqual {'42': {'old_name': 'somelongerline', 'new_name': 'a-new-name'}},
\ ale#rename#GetMap()
Given python(Some Python file):
@ -470,7 +470,7 @@ Execute(LSP rename requests should be sent):
let b:ale_linters = ['pyls']
call setpos('.', [bufnr(''), 1, 5, 0])
ALERename!
ALERename
" We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback)
@ -500,5 +500,5 @@ Execute(LSP rename requests should be sent):
\ ],
\ g:message_list
AssertEqual {'42': {'old_name': 'foo', 'new_name': 'a-new-name', 'force_save': 1}},
AssertEqual {'42': {'old_name': 'foo', 'new_name': 'a-new-name'}},
\ ale#rename#GetMap()

View File

@ -127,3 +127,51 @@ Execute(The dash dialect should be used for the shell and the base function):
Execute(dash should be used for shellcheck):
AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a Bash shellcheck shell directive):
# shellcheck shell=bash
Execute(bash dialect should be detected appropriately):
AssertEqual 'bash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a sh shellcheck shell directive):
#shellcheck shell=sh
Execute(sh dialect should be detected appropriately):
AssertEqual 'sh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a tcsh shellcheck shell directive):
# shellcheck shell=tcsh
Execute(tcsh dialect should be detected appropriately):
AssertEqual 'tcsh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a zsh shellcheck shell directive):
# shellcheck shell=zsh
Execute(zsh dialect should be detected appropriately):
AssertEqual 'zsh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a csh shellcheck shell directive):
# shellcheck shell=csh
Execute(zsh dialect should be detected appropriately):
AssertEqual 'csh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a ksh shellcheck shell directive):
# shellcheck shell=ksh
Execute(ksh dialect should be detected appropriately):
AssertEqual 'ksh', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a dash shellcheck shell directive):
# shellcheck shell=dash
Execute(dash dialect should be detected appropriately):
AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))
Given(A file with a ash shellcheck shell directive):
# shellcheck shell=ash
Execute(dash dialect should be detected for ash that shellcheck does not support):
AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr(''))