Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bartek thindil Jasicki
2020-11-27 13:38:24 +01:00
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 ### 3.iii. Installation with Vundle
You can install this plugin using [Vundle](https://github.com/VundleVim/Vundle.vim) 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 ```vim
Plugin 'dense-analysis/ale' Plugin 'dense-analysis/ale'
``` ```
Then run the command `:PluginInstall` in Vim.
See the Vundle documentation for more information. See the Vundle documentation for more information.
<a name="installation-with-vim-plug"></a> <a name="installation-with-vim-plug"></a>
@@ -354,13 +356,16 @@ See the Vundle documentation for more information.
### 3.iiii. Installation with Vim-Plug ### 3.iiii. Installation with Vim-Plug
You can install this plugin using [Vim-Plug](https://github.com/junegunn/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` by adding the GitHub path for this repository to your `~/.vimrc`:
and running `:PlugInstall`.
```vim ```vim
Plug 'dense-analysis/ale' Plug 'dense-analysis/ale'
``` ```
Then run the command `:PlugInstall` in Vim.
See the Vim-Plug documentation for more information.
<a name="contributing"></a> <a name="contributing"></a>
## 4. Contributing ## 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: " 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) " /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 = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) 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', \ 'name': 'tsserver',
\ 'lsp': 'tsserver', \ 'lsp': 'tsserver',
\ 'executable': {b -> ale#node#FindExecutable(b, 'typescript_tsserver', [ \ 'executable': {b -> ale#node#FindExecutable(b, 'typescript_tsserver', [
\ '.yarn/sdks/typescript/bin/tsserver',
\ 'node_modules/.bin/tsserver', \ 'node_modules/.bin/tsserver',
\ ])}, \ ])},
\ 'command': '%e', \ 'command': '%e',

View File

@@ -2,23 +2,39 @@
" Description: balloonexpr support for ALE. " Description: balloonexpr support for ALE.
function! ale#balloon#MessageForPos(bufnr, lnum, col) abort 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. " 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 \|| !g:ale_enabled
\|| !getbufvar(a:bufnr, 'ale_enabled', 1) \|| !getbufvar(a:bufnr, 'ale_enabled', 1)
return '' return ''
endif endif
let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist if l:show_problems
let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col) 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 " 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 return l:loclist[l:index].text
elseif exists('*balloon_show') || getbufvar( elseif l:show_hover && (
\ a:bufnr, \ exists('*balloon_show')
\ 'ale_set_balloons_legacy_echo', \ || getbufvar(
\ get(g:, 'ale_set_balloons_legacy_echo', 0) \ 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 " Request LSP/tsserver hover information, but only if this version of
" Vim supports the balloon_show function, or if we turned a legacy " 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> " Author: Jerko Steiner <jerko.steiner@gmail.com>
" Description: Code action support for LSP / tsserver " 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 function! ale#code_action#HandleCodeAction(code_action, options) abort
let l:current_buffer = bufnr('') let l:current_buffer = bufnr('')
let l:changes = a:code_action.changes let l:changes = a:code_action.changes
let l:should_save = get(a:options, 'should_save') 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 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( call ale#code_action#ApplyChanges(
\ l:file_code_edit.fileName, \ l:file_code_edit.fileName,
\ l:file_code_edit.textChanges, \ l:file_code_edit.textChanges,
@@ -125,7 +121,12 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
endif endif
call extend(l:middle, l:insertions[1:]) 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_before_change = len(l:lines)
let l:lines = l:start + l:middle + l:lines[l:end_line :] 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]) call setpos('.', [0, l:pos[0], l:pos[1], 0])
endif 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 endfunction
function! s:UpdateCursor(cursor, start, end, offset) abort function! s:UpdateCursor(cursor, start, end, offset) abort
@@ -263,3 +278,105 @@ function! ale#code_action#BuildChangesList(changes_map) abort
return l:changes return l:changes
endfunction 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> " 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 = {} let s:codefix_map = {}
@@ -21,23 +21,65 @@ function! s:message(message) abort
call ale#util#Execute('echom ' . string(a:message)) call ale#util#Execute('echom ' . string(a:message))
endfunction 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 function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
if !has_key(a:response, 'request_seq') if !has_key(a:response, 'request_seq')
\ || !has_key(s:codefix_map, a:response.request_seq) \ || !has_key(s:codefix_map, a:response.request_seq)
return return
endif 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, 'command', '') is# 'getCodeFixes'
if get(a:response, 'success', v:false) is v:false if get(a:response, 'success', v:false) is v:false
\&& l:MenuCallback is v:null
let l:message = get(a:response, 'message', 'unknown') let l:message = get(a:response, 'message', 'unknown')
call s:message('Error while getting code fixes. Reason: ' . l:message) call s:message('Error while getting code fixes. Reason: ' . l:message)
return return
endif 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.') call s:message('No code fixes available.')
return return
@@ -45,14 +87,15 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
let l:code_fix_to_apply = 0 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 let l:code_fix_to_apply = 1
else else
let l:codefix_no = 1 let l:codefix_no = 1
let l:codefixstring = "Code Fixes:\n" let l:codefixstring = "Code Fixes:\n"
for l:codefix in a:response.body for l:codefix in l:result
let l:codefixstring .= l:codefix_no . ') ' . l:codefix.description . "\n" let l:codefixstring .= l:codefix_no . ') '
\ . l:codefix.description . "\n"
let l:codefix_no += 1 let l:codefix_no += 1
endfor endfor
@@ -66,21 +109,22 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
endif endif
endif endif
let l:changes = a:response.body[l:code_fix_to_apply - 1].changes call ale#codefix#ApplyTSServerCodeAction(
\ l:data,
call ale#code_action#HandleCodeAction({ \ l:result[l:code_fix_to_apply - 1],
\ 'description': 'codefix', \)
\ 'changes': l:changes,
\}, {})
elseif get(a:response, 'command', '') is# 'getApplicableRefactors' elseif get(a:response, 'command', '') is# 'getApplicableRefactors'
if get(a:response, 'success', v:false) is v:false if get(a:response, 'success', v:false) is v:false
\&& l:MenuCallback is v:null
let l:message = get(a:response, 'message', 'unknown') let l:message = get(a:response, 'message', 'unknown')
call s:message('Error while getting applicable refactors. Reason: ' . l:message) call s:message('Error while getting applicable refactors. Reason: ' . l:message)
return return
endif 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.') call s:message('No applicable refactors available.')
return return
@@ -88,7 +132,7 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
let l:refactors = [] let l:refactors = []
for l:item in a:response.body for l:item in l:result
for l:action in l:item.actions for l:action in l:item.actions
call add(l:refactors, { call add(l:refactors, {
\ 'name': l:action.description, \ 'name': l:action.description,
@@ -97,11 +141,21 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
endfor endfor
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:refactor_no = 1
let l:refactorstring = "Applicable refactors:\n" let l:refactorstring = "Applicable refactors:\n"
for l:refactor in l:refactors 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 let l:refactor_no += 1
endfor 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:id = l:refactors[l:refactor_to_apply - 1].id
let l:message = ale#lsp#tsserver_message#GetEditsForRefactor( call ale#codefix#ApplyTSServerCodeAction(
\ l:location.buffer, \ l:data,
\ l:location.line, \ l:refactors[l:refactor_to_apply - 1],
\ l:location.column,
\ l:location.end_line,
\ l:location.end_column,
\ l:id[0],
\ l:id[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' elseif get(a:response, 'command', '') is# 'getEditsForRefactor'
if get(a:response, 'success', v:false) is v:false if get(a:response, 'success', v:false) is v:false
let l:message = get(a:response, 'message', 'unknown') let l:message = get(a:response, 'message', 'unknown')
@@ -137,10 +182,48 @@ function! ale#codefix#HandleTSServerResponse(conn_id, response) abort
return return
endif endif
call ale#code_action#HandleCodeAction({ call ale#code_action#HandleCodeAction(
\ 'description': 'editsForRefactor', \ {
\ 'changes': a:response.body.edits, \ '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 endif
endfunction endfunction
@@ -158,17 +241,32 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort
let l:changes = ale#code_action#BuildChangesList(l:changes_map) let l:changes = ale#code_action#BuildChangesList(l:changes_map)
call ale#code_action#HandleCodeAction({ call ale#code_action#HandleCodeAction(
\ 'description': 'applyEdit', \ {
\ 'changes': l:changes, \ 'description': 'applyEdit',
\}, {}) \ 'changes': l:changes,
\ },
\ {}
\)
elseif has_key(a:response, 'id') elseif has_key(a:response, 'id')
\&& has_key(s:codefix_map, 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') let l:result = get(a:response, 'result')
\ || type(a:response.result) != v:t_list
\ || len(a:response.result) == 0 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') call s:message('No code actions received from server')
return return
@@ -177,8 +275,9 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort
let l:codeaction_no = 1 let l:codeaction_no = 1
let l:codeactionstring = "Code Fixes:\n" let l:codeactionstring = "Code Fixes:\n"
for l:codeaction in a:response.result for l:codeaction in l:result
let l:codeactionstring .= l:codeaction_no . ') ' . l:codeaction.title . "\n" let l:codeactionstring .= l:codeaction_no . ') '
\ . l:codeaction.title . "\n"
let l:codeaction_no += 1 let l:codeaction_no += 1
endfor endfor
@@ -191,42 +290,44 @@ function! ale#codefix#HandleLSPResponse(conn_id, response) abort
return return
endif 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') call ale#codefix#ApplyLSPCodeAction(l:data, l:item)
\ && 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
endif endif
endfunction 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 let l:id = a:lsp_details.connection_id
if !ale#lsp#HasCapability(l:id, 'code_actions') 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 let l:buffer = a:lsp_details.buffer
if a:linter.lsp is# 'tsserver' if a:linter.lsp is# 'tsserver'
if a:line == a:end_line && a:column == a:end_column let l:nearest_error =
if !has_key(g:ale_buffer_info, l:buffer) \ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column)
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
if l:nearest_error isnot v:null
let l:message = ale#lsp#tsserver_message#GetCodeFixes( let l:message = ale#lsp#tsserver_message#GetCodeFixes(
\ l:buffer, \ l:buffer,
\ a:line, \ a:line,
\ a:column, \ a:column,
\ a:line, \ a:line,
\ a:column, \ a:column,
\ [l:nearest_error], \ [l:nearest_error.code],
\) \)
else else
let l:message = ale#lsp#tsserver_message#GetApplicableRefactors( 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. " completions won't know what text is nearby.
call ale#lsp#NotifyForChanges(l:id, l:buffer) call ale#lsp#NotifyForChanges(l:id, l:buffer)
if a:line == a:end_line && a:column == a:end_column let l:diagnostics = []
if !has_key(g:ale_buffer_info, l:buffer) let l:nearest_error =
return \ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column)
endif
let l:nearest_error = v:null if l:nearest_error isnot v:null
let l:nearest_error_diff = -1 let l:diagnostics = [
\ {
for l:error in get(g:ale_buffer_info[l:buffer], 'loclist', []) \ 'code': l:nearest_error.code,
if has_key(l:error, 'code') && l:error.lnum == a:line \ 'message': l:nearest_error.text,
let l:diff = abs(l:error.col - a:column) \ 'range': {
\ 'start': {
if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff \ 'line': l:nearest_error.lnum - 1,
let l:nearest_error_diff = l:diff \ 'character': l:nearest_error.col - 1,
let l:nearest_error = l:error \ },
endif \ 'end': {
endif \ 'line': l:nearest_error.end_lnum - 1,
endfor \ 'character': l:nearest_error.end_col,
\ },
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,
\ [],
\)
endif endif
let l:message = ale#lsp#message#CodeAction(
\ l:buffer,
\ a:line,
\ a:column,
\ a:end_line,
\ a:end_column,
\ l:diagnostics,
\)
endif endif
let l:Callback = a:linter.lsp is# 'tsserver' 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 l:request_id = ale#lsp#Send(l:id, l:message)
let s:codefix_map[l:request_id] = { let s:codefix_map[l:request_id] = {
\ 'connection_id': l:id, \ 'connection_id': l:id,
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'line': a:line, \ 'line': a:line,
\ 'column': a:column, \ 'column': a:column,
\ 'end_line': a:end_line, \ 'end_line': a:end_line,
\ 'end_column': a:end_column, \ 'end_column': a:end_column,
\ 'menu_callback': a:MenuCallback,
\} \}
endfunction endfunction
function! s:ExecuteGetCodeFix(linter, range) abort function! s:ExecuteGetCodeFix(linter, range, MenuCallback) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
if a:range == 0 if a:range == 0
let [l:line, l:column] = getpos('.')[1:2] let [l:line, l:column] = getpos('.')[1:2]
let l:end_line = l:line let l:end_line = l:line
let l:end_column = l:column 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 else
let [l:line, l:column] = getpos("'<")[1:2] let [l:line, l:column] = getpos("'<")[1:2]
let [l:end_line, l:end_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:end_column = min([l:end_column, len(getline(l:end_line))])
let l:Callback = function( 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) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
endfunction 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 = [] let l:lsp_linters = []
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
@@ -377,12 +469,16 @@ function! ale#codefix#Execute(range) abort
endfor endfor
if empty(l:lsp_linters) 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 return
endif endif
for l:lsp_linter in l:lsp_linters 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 endfor
endfunction endfunction

View File

@@ -606,11 +606,14 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:doc = l:doc.value let l:doc = l:doc.value
endif endif
" Collapse whitespaces and line breaks into a single space.
let l:detail = substitute(get(l:item, 'detail', ''), '\_s\+', ' ', 'g')
let l:result = { let l:result = {
\ 'word': l:word, \ 'word': l:word,
\ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')), \ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')),
\ 'icase': 1, \ 'icase': 1,
\ 'menu': get(l:item, 'detail', ''), \ 'menu': l:detail,
\ 'info': (type(l:doc) is v:t_string ? l:doc : ''), \ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
\} \}
" This flag is used to tell if this completion came from ALE or not. " 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'], \ 'suggested_filetypes': ['help'],
\ 'description': 'Align help tags to the right margin', \ 'description': 'Align help tags to the right margin',
\ }, \ },
\ 'autoimport': {
\ 'function': 'ale#fixers#autoimport#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Fix import issues with autoimport.',
\ },
\ 'autopep8': { \ 'autopep8': {
\ 'function': 'ale#fixers#autopep8#Fix', \ 'function': 'ale#fixers#autopep8#Fix',
\ 'suggested_filetypes': ['python'], \ 'suggested_filetypes': ['python'],
@@ -105,6 +110,11 @@ let s:default_registry = {
\ 'suggested_filetypes': [], \ 'suggested_filetypes': [],
\ 'description': 'Remove all trailing whitespace characters at the end of every line.', \ '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': { \ 'yapf': {
\ 'function': 'ale#fixers#yapf#Fix', \ 'function': 'ale#fixers#yapf#Fix',
\ 'suggested_filetypes': ['python'], \ 'suggested_filetypes': ['python'],
@@ -375,11 +385,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['html', 'htmldjango'], \ 'suggested_filetypes': ['html', 'htmldjango'],
\ 'description': 'Fix HTML files with html-beautify.', \ 'description': 'Fix HTML files with html-beautify.',
\ }, \ },
\ 'luafmt': {
\ 'function': 'ale#fixers#luafmt#Fix',
\ 'suggested_filetypes': ['lua'],
\ 'description': 'Fix Lua files with luafmt.',
\ },
\ 'dhall': { \ 'dhall': {
\ 'function': 'ale#fixers#dhall#Fix', \ 'function': 'ale#fixers#dhall#Fix',
\ 'suggested_filetypes': ['dhall'], \ 'suggested_filetypes': ['dhall'],
\ 'description': 'Fix Dhall files with dhall-format.', \ '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. " 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. " Description: Fixing files with phpcbf.
call ale#Set('php_phpcbf_standard', '') call ale#Set('php_phpcbf_standard', '')
call ale#Set('php_phpcbf_options', '')
call ale#Set('php_phpcbf_executable', 'phpcbf') call ale#Set('php_phpcbf_executable', 'phpcbf')
call ale#Set('php_phpcbf_use_global', get(g:, 'ale_use_global_executables', 0)) 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 { 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 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/.bin/eslint_d',
\ 'node_modules/eslint/bin/eslint.js', \ 'node_modules/eslint/bin/eslint.js',
\ 'node_modules/.bin/eslint', \ 'node_modules/.bin/eslint',
\ '.yarn/sdks/eslint/bin/eslint',
\] \]
let s:sep = has('win32') ? '\' : '/' let s:sep = has('win32') ? '\' : '/'

View File

@@ -1,8 +1,32 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: This file adds support for using the shellcheck linter " 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 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) if !empty(l:shell_type)
" Use the dash dialect for /bin/ash, etc. " 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 if get(a:response, 'success', v:false) is v:true
\&& get(a:response, 'body', v:null) isnot v:null \&& 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 " If we pass the show_documentation flag, we should show the full
" documentation, and always in the preview window. " documentation, and always in the preview window.
if get(l:options, 'show_documentation', 0) if get(l:options, 'show_documentation', 0)
@@ -40,7 +42,7 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
endif endif
elseif get(l:options, 'hover_from_balloonexpr', 0) elseif get(l:options, 'hover_from_balloonexpr', 0)
\&& exists('*balloon_show') \&& 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) call balloon_show(a:response.body.displayString)
elseif get(l:options, 'truncated_echo', 0) elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(split(a:response.body.displayString, "\n")[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) let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents)
if !empty(l:lines) if !empty(l:lines)
let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons')
if get(l:options, 'hover_from_balloonexpr', 0) if get(l:options, 'hover_from_balloonexpr', 0)
\&& exists('*balloon_show') \&& 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")) call balloon_show(join(l:lines, "\n"))
elseif get(l:options, 'truncated_echo', 0) elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(l:lines[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, \ 'should_save': 1,
\ 'force_save': get(l:options, 'force_save'),
\ }, \ },
\) \)
endfunction endfunction
@@ -118,7 +117,6 @@ function! ale#rename#HandleLSPResponse(conn_id, response) abort
\ }, \ },
\ { \ {
\ 'should_save': 1, \ 'should_save': 1,
\ 'force_save': get(l:options, 'force_save'),
\ }, \ },
\) \)
endif endif
@@ -177,7 +175,7 @@ function! s:ExecuteRename(linter, options) abort
call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback)
endfunction endfunction
function! ale#rename#Execute(options) abort function! ale#rename#Execute() abort
let l:lsp_linters = [] let l:lsp_linters = []
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
@@ -205,7 +203,6 @@ function! ale#rename#Execute(options) abort
call s:ExecuteRename(l:lsp_linter, { call s:ExecuteRename(l:lsp_linter, {
\ 'old_name': l:old_name, \ 'old_name': l:old_name,
\ 'new_name': l:new_name, \ 'new_name': l:new_name,
\ 'force_save': get(a:options, 'force_save') is 1,
\}) \})
endfor endfor
endfunction endfunction

View File

@@ -486,7 +486,7 @@ function! ale#util#Input(message, value) abort
endfunction endfunction
function! ale#util#HasBuflineApi() abort function! ale#util#HasBuflineApi() abort
return exists('*deletebufline') && exists('*setbufline') return exists('*deletebufline') && exists('*appendbufline') && exists('*getpos') && exists('*setpos')
endfunction endfunction
" Sets buffer contents to lines " 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. " Use a Vim API for setting lines in other buffers, if available.
if l:has_bufline_api if l:has_bufline_api
call setbufline(a:buffer, 1, l:new_lines) let l:save_cursor = getpos('.')
call deletebufline(a:buffer, l:first_line_to_remove, '$') 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. " Fall back on setting lines the old way, for the current buffer.
else else
let l:old_line_length = line('$') 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 This variable can be changed to specify the profile that is used to
run dialyzer with rebar3. 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* 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'` 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: 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. 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: 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| 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* 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. 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: 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. 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* autopep8 *ale-python-autopep8*
@@ -687,7 +713,7 @@ g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv*
=============================================================================== ===============================================================================
pyright *ale-python-pyright* 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 the `pyright-langserver` executable. You can install `pyright` on your system
through `npm` with `sudo npm install -g pyright` or similar. through `npm` with `sudo npm install -g pyright` or similar.

View File

@@ -2,6 +2,29 @@
ALE R Integration *ale-r-options* 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* lintr *ale-r-lintr*
@@ -22,7 +45,7 @@ g:ale_r_lintr_lint_package *g:ale_r_lintr_lint_package*
Default: `0` Default: `0`
When set to `1`, the file will be checked with `lintr::lint_package` instead 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. 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. 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 The value of this option will be used as the `style` argument for the
`styler::style_file` options. Consult the styler documentation `styler::style_file` options. Consult the styler documentation
for more information. for more information.

View File

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

View File

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

View File

@@ -15,7 +15,6 @@ Install prettier either globally or locally: >
npm install prettier -g # global npm install prettier -g # global
npm install prettier # local npm install prettier # local
< <
=============================================================================== ===============================================================================
swaglint *ale-yaml-swaglint* 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| 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* yamllint *ale-yaml-yamllint*

View File

@@ -673,13 +673,31 @@ for a full list of options.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.7 Refactoring: Rename, Actions *ale-refactor* 5.7 Refactoring: Rename, Actions *ale-refactor*
ALE supports renaming symbols in symbols in code such as variables or class ALE supports renaming symbols in code such as variables or class names with
names with the |ALERename| command. the |ALERename| command.
|ALECodeAction| will execute actions on the cursor or applied to a visual |ALECodeAction| will execute actions on the cursor or applied to a visual
range selection, such as automatically fixing errors. 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* 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 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. 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* g:ale_max_buffer_history_size *g:ale_max_buffer_history_size*
Type: |Number| 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|. 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* g:ale_rename_tsserver_find_in_comments *g:ale_rename_tsserver_find_in_comments*
Type: |Number| 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* g:ale_set_balloons *g:ale_set_balloons*
*b:ale_set_balloons* *b:ale_set_balloons*
Type: |Number| Type: |Number| or |String|
Default: `has('balloon_eval') && has('gui_running')` Default: `has('balloon_eval') && has('gui_running')`
When this option is set to `1`, balloon messages will be displayed for 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 supporting "Hover" information, per |ale-hover|, then brief information
about the symbol under the cursor will be displayed in a balloon. 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, Balloons can be enabled for terminal versions of Vim that support balloons,
but some versions of Vim will produce strange mouse behavior when balloons but some versions of Vim will produce strange mouse behavior when balloons
are enabled. To configure balloons for your terminal, you should first 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| elm-make..............................|ale-elm-elm-make|
erlang..................................|ale-erlang-options| erlang..................................|ale-erlang-options|
dialyzer..............................|ale-erlang-dialyzer| dialyzer..............................|ale-erlang-dialyzer|
elvis.................................|ale-erlang-elvis|
erlc..................................|ale-erlang-erlc| erlc..................................|ale-erlang-erlc|
syntaxerl.............................|ale-erlang-syntaxerl| syntaxerl.............................|ale-erlang-syntaxerl|
eruby...................................|ale-eruby-options| eruby...................................|ale-eruby-options|
@@ -2654,6 +2694,7 @@ documented in additional help files.
stack-ghc.............................|ale-haskell-stack-ghc| stack-ghc.............................|ale-haskell-stack-ghc|
stylish-haskell.......................|ale-haskell-stylish-haskell| stylish-haskell.......................|ale-haskell-stylish-haskell|
hie...................................|ale-haskell-hie| hie...................................|ale-haskell-hie|
ormolu................................|ale-haskell-ormolu|
hcl.....................................|ale-hcl-options| hcl.....................................|ale-hcl-options|
terraform-fmt.........................|ale-hcl-terraform-fmt| terraform-fmt.........................|ale-hcl-terraform-fmt|
html....................................|ale-html-options| html....................................|ale-html-options|
@@ -2713,6 +2754,7 @@ documented in additional help files.
lua.....................................|ale-lua-options| lua.....................................|ale-lua-options|
luac..................................|ale-lua-luac| luac..................................|ale-lua-luac|
luacheck..............................|ale-lua-luacheck| luacheck..............................|ale-lua-luacheck|
luafmt................................|ale-lua-luafmt|
markdown................................|ale-markdown-options| markdown................................|ale-markdown-options|
markdownlint..........................|ale-markdown-markdownlint| markdownlint..........................|ale-markdown-markdownlint|
mdl...................................|ale-markdown-mdl| mdl...................................|ale-markdown-mdl|
@@ -2764,6 +2806,8 @@ documented in additional help files.
psalm.................................|ale-php-psalm| psalm.................................|ale-php-psalm|
php-cs-fixer..........................|ale-php-php-cs-fixer| php-cs-fixer..........................|ale-php-php-cs-fixer|
php...................................|ale-php-php| php...................................|ale-php-php|
tlint.................................|ale-php-tlint|
intelephense..........................|ale-php-intelephense|
po......................................|ale-po-options| po......................................|ale-po-options|
write-good............................|ale-po-write-good| write-good............................|ale-po-write-good|
pod.....................................|ale-pod-options| pod.....................................|ale-pod-options|
@@ -2789,6 +2833,7 @@ documented in additional help files.
pyrex (cython)..........................|ale-pyrex-options| pyrex (cython)..........................|ale-pyrex-options|
cython................................|ale-pyrex-cython| cython................................|ale-pyrex-cython|
python..................................|ale-python-options| python..................................|ale-python-options|
autoimport............................|ale-python-autoimport|
autopep8..............................|ale-python-autopep8| autopep8..............................|ale-python-autopep8|
bandit................................|ale-python-bandit| bandit................................|ale-python-bandit|
black.................................|ale-python-black| black.................................|ale-python-black|
@@ -2810,6 +2855,7 @@ documented in additional help files.
qml.....................................|ale-qml-options| qml.....................................|ale-qml-options|
qmlfmt................................|ale-qml-qmlfmt| qmlfmt................................|ale-qml-qmlfmt|
r.......................................|ale-r-options| r.......................................|ale-r-options|
languageserver........................|ale-r-languageserver|
lintr.................................|ale-r-lintr| lintr.................................|ale-r-lintr|
styler................................|ale-r-styler| styler................................|ale-r-styler|
reasonml................................|ale-reasonml-options| reasonml................................|ale-reasonml-options|
@@ -2926,6 +2972,7 @@ documented in additional help files.
yaml....................................|ale-yaml-options| yaml....................................|ale-yaml-options|
prettier..............................|ale-yaml-prettier| prettier..............................|ale-yaml-prettier|
swaglint..............................|ale-yaml-swaglint| swaglint..............................|ale-yaml-swaglint|
yamlfix...............................|ale-yaml-yamlfix|
yamllint..............................|ale-yaml-yamllint| yamllint..............................|ale-yaml-yamllint|
yang....................................|ale-yang-options| yang....................................|ale-yang-options|
yang-lsp..............................|ale-yang-lsp| 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 The symbol where the cursor is resting will be the symbol renamed, and a
prompt will open to request a new name. 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* 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. " This variable can be overridden to set the GO111MODULE environment variable.
let g:ale_go_go111module = get(g:, 'ale_go_go111module', '') 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() call ale#balloon#Enable()
endif endif
@@ -166,6 +169,10 @@ if g:ale_completion_enabled
call ale#completion#Enable() call ale#completion#Enable()
endif endif
if g:ale_popup_menu_enabled
call ale#code_action#EnablePopUpMenu()
endif
" Define commands for moving through warnings and errors. " Define commands for moving through warnings and errors.
command! -bar -nargs=* ALEPrevious command! -bar -nargs=* ALEPrevious
\ :call ale#loclist_jumping#WrapJump('before', <q-args>) \ :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() command! -bar ALEImport :call ale#completion#Import()
" Rename symbols using tsserver and LSP " 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. " Apply code actions to a range.
command! -bar -range ALECodeAction :call ale#codefix#Execute(<range>) command! -bar -range ALECodeAction :call ale#codefix#Execute(<range>)

View File

@@ -150,6 +150,7 @@ formatting.
* [erubis](https://github.com/kwatch/erubis) * [erubis](https://github.com/kwatch/erubis)
* [ruumba](https://github.com/ericqweinstein/ruumba) * [ruumba](https://github.com/ericqweinstein/ruumba)
* Erlang * Erlang
* [elvis](https://github.com/inaka/elvis) :floppy_disk:
* [erlc](http://erlang.org/doc/man/erlc.html) * [erlc](http://erlang.org/doc/man/erlc.html)
* [SyntaxErl](https://github.com/ten0s/syntaxerl) * [SyntaxErl](https://github.com/ten0s/syntaxerl)
* Fish * Fish
@@ -205,6 +206,7 @@ formatting.
* [hie](https://github.com/haskell/haskell-ide-engine) * [hie](https://github.com/haskell/haskell-ide-engine)
* [hindent](https://hackage.haskell.org/package/hindent) * [hindent](https://hackage.haskell.org/package/hindent)
* [hlint](https://hackage.haskell.org/package/hlint) * [hlint](https://hackage.haskell.org/package/hlint)
* [ormolu](https://github.com/tweag/ormolu)
* [stack-build](https://haskellstack.org/) :floppy_disk: * [stack-build](https://haskellstack.org/) :floppy_disk:
* [stack-ghc](https://haskellstack.org/) * [stack-ghc](https://haskellstack.org/)
* [stylish-haskell](https://github.com/jaspervdj/stylish-haskell) * [stylish-haskell](https://github.com/jaspervdj/stylish-haskell)
@@ -275,6 +277,7 @@ formatting.
* Lua * Lua
* [luac](https://www.lua.org/manual/5.1/luac.html) * [luac](https://www.lua.org/manual/5.1/luac.html)
* [luacheck](https://github.com/mpeterv/luacheck) * [luacheck](https://github.com/mpeterv/luacheck)
* [luafmt](https://github.com/trixnz/lua-fmt)
* Mail * Mail
* [alex](https://github.com/wooorm/alex) :floppy_disk: * [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk: * [languagetool](https://languagetool.org/) :floppy_disk:
@@ -334,6 +337,7 @@ formatting.
* Perl6 * Perl6
* [perl6 -c](https://perl6.org) :warning: * [perl6 -c](https://perl6.org) :warning:
* PHP * PHP
* [intelephense](https://github.com/bmewburn/intelephense-docs)
* [langserver](https://github.com/felixfbecker/php-language-server) * [langserver](https://github.com/felixfbecker/php-language-server)
* [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions * [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions
* [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer) * [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer)
@@ -343,6 +347,7 @@ formatting.
* [phpmd](https://phpmd.org) * [phpmd](https://phpmd.org)
* [phpstan](https://github.com/phpstan/phpstan) * [phpstan](https://github.com/phpstan/phpstan)
* [psalm](https://getpsalm.org) :floppy_disk: * [psalm](https://getpsalm.org) :floppy_disk:
* [tlint](https://github.com/tightenco/tlint)
* PO * PO
* [alex](https://github.com/wooorm/alex) :floppy_disk: * [alex](https://github.com/wooorm/alex) :floppy_disk:
* [msgfmt](https://www.gnu.org/software/gettext/manual/html_node/msgfmt-Invocation.html) * [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) * [purescript-language-server](https://github.com/nwolverson/purescript-language-server)
* [purty](https://gitlab.com/joneshf/purty) * [purty](https://gitlab.com/joneshf/purty)
* Python * Python
* [autoimport](https://lyz-code.github.io/autoimport/)
* [autopep8](https://github.com/hhatto/autopep8) * [autopep8](https://github.com/hhatto/autopep8)
* [bandit](https://github.com/PyCQA/bandit) :warning: * [bandit](https://github.com/PyCQA/bandit) :warning:
* [black](https://github.com/ambv/black) * [black](https://github.com/ambv/black)
@@ -393,6 +399,7 @@ formatting.
* [qmlfmt](https://github.com/jesperhh/qmlfmt) * [qmlfmt](https://github.com/jesperhh/qmlfmt)
* [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint) * [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint)
* R * R
* [languageserver](https://github.com/REditorSupport/languageserver)
* [lintr](https://github.com/jimhester/lintr) * [lintr](https://github.com/jimhester/lintr)
* [styler](https://github.com/r-lib/styler) * [styler](https://github.com/r-lib/styler)
* Racket * Racket
@@ -527,6 +534,7 @@ formatting.
* YAML * YAML
* [prettier](https://github.com/prettier/prettier) * [prettier](https://github.com/prettier/prettier)
* [swaglint](https://github.com/byCedric/swaglint) * [swaglint](https://github.com/byCedric/swaglint)
* [yamlfix](https://lyz-code.github.io/yamlfix)
* [yamllint](https://yamllint.readthedocs.io/) * [yamllint](https://yamllint.readthedocs.io/)
* YANG * YANG
* [yang-lsp](https://github.com/theia-ide/yang-lsp) * [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: &''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: 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': '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({ \ ale#completion#ParseLSPCompletions({
\ "jsonrpc":"2.0", \ "jsonrpc":"2.0",
@@ -184,6 +185,11 @@ Execute(Should handle Rust completion results correctly):
\ "label":"from", \ "label":"from",
\ "kind":3, \ "kind":3,
\ "detail":"fn from(s: Cow<'a, str>) -> String" \ "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_executable = 'phpcbf_test'
let g:ale_php_phpcbf_standard = '' let g:ale_php_phpcbf_standard = ''
let g:ale_php_phpcbf_options = ''
let g:ale_php_phpcbf_use_global = 0 let g:ale_php_phpcbf_use_global = 0
call ale#test#SetDirectory('/testplugin/test/fixers') 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' . ' -'}, \ {'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('')) \ 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: Before:
Save g:ale_php_phpcbf_executable Save g:ale_php_phpcbf_executable
Save g:ale_php_phpcbf_standard Save g:ale_php_phpcbf_standard
@@ -61,6 +71,7 @@ Before:
let g:ale_php_phpcbf_executable = 'phpcbf_test' let g:ale_php_phpcbf_executable = 'phpcbf_test'
let g:ale_php_phpcbf_standard = '' let g:ale_php_phpcbf_standard = ''
let g:ale_php_phpcbf_options = ''
let g:ale_php_phpcbf_use_global = 0 let g:ale_php_phpcbf_use_global = 0
call ale#test#SetDirectory('/testplugin/test/fixers') 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', \ 'type': 'E',
\ 'sub_type': 'style', \ 'sub_type': 'style',
\ 'text': 'Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)', \ '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(''), [ \ 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: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 AssertEqual g:handle_code_action_called, 0
Given typescript(Some typescript file): Given typescript(Some typescript file):
foo foo
somelongerline somelongerline ()
bazxyzxyzxyz bazxyzxyzxyz
Execute(getCodeFixes from tsserver should be handled): Execute(getCodeFixes from tsserver should be handled):
@@ -283,7 +281,7 @@ Execute(tsserver codefix requests should be sent):
runtime ale_linters/typescript/tsserver.vim runtime ale_linters/typescript/tsserver.vim
let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'code': 2304}]}} 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 " ALECodeAction
call ale#codefix#Execute(0) call ale#codefix#Execute(0)
@@ -303,9 +301,9 @@ Execute(tsserver codefix requests should be sent):
\ ale#lsp#tsserver_message#Change(bufnr('')), \ ale#lsp#tsserver_message#Change(bufnr('')),
\ [0, 'ts@getCodeFixes', { \ [0, 'ts@getCodeFixes', {
\ 'startLine': 2, \ 'startLine': 2,
\ 'startOffset': 5, \ 'startOffset': 16,
\ 'endLine': 2, \ 'endLine': 2,
\ 'endOffset': 6, \ 'endOffset': 17,
\ 'file': expand('%:p'), \ 'file': expand('%:p'),
\ 'errorCodes': [2304], \ 'errorCodes': [2304],
\ }] \ }]
@@ -316,8 +314,8 @@ Execute(tsserver codefix requests should be sent only for error with code):
call ale#linter#Reset() call ale#linter#Reset()
runtime ale_linters/typescript/tsserver.vim runtime ale_linters/typescript/tsserver.vim
let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5}, {'lnum': 2, 'col': 5, 'code': 2304}]}} let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 16}, {'lnum': 2, 'col': 16, 'code': 2304}]}}
call setpos('.', [bufnr(''), 2, 5, 0]) call setpos('.', [bufnr(''), 2, 16, 0])
" ALECodeAction " ALECodeAction
call ale#codefix#Execute(0) 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('')), \ ale#lsp#tsserver_message#Change(bufnr('')),
\ [0, 'ts@getCodeFixes', { \ [0, 'ts@getCodeFixes', {
\ 'startLine': 2, \ 'startLine': 2,
\ 'startOffset': 5, \ 'startOffset': 16,
\ 'endLine': 2, \ 'endLine': 2,
\ 'endOffset': 6, \ 'endOffset': 17,
\ 'file': expand('%:p'), \ 'file': expand('%:p'),
\ 'errorCodes': [2304], \ '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 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): Execute(Failed LSP responses should be handled correctly):
call ale#codefix#HandleLSPResponse( call ale#codefix#HandleLSPResponse(
\ 1, \ 1,
@@ -545,23 +506,15 @@ Execute(LSP code action requests should be sent):
\ string(g:Callback) \ string(g:Callback)
AssertEqual 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', { \ [0, 'textDocument/codeAction', {
\ 'context': { \ '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}}, \ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}},
\ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))} \ '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): Execute(LSP code action requests should be sent only for error with code):
call ale#linter#Reset() call ale#linter#Reset()
@@ -585,20 +538,12 @@ Execute(LSP code action requests should be sent only for error with code):
\ string(g:Callback) \ string(g:Callback)
AssertEqual 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', { \ [0, 'textDocument/codeAction', {
\ 'context': { \ '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}}, \ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}},
\ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))} \ '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() AssertEqual {}, ale#hover#GetMap()
Execute(tsserver quickinfo displayString values should be displayed): Execute(tsserver quickinfo displayString values should be displayed):
call ale#hover#SetMap({3: {}}) call ale#hover#SetMap({3: {'buffer': bufnr('')}})
call ale#hover#HandleTSServerResponse( call ale#hover#HandleTSServerResponse(
\ 1, \ 1,
\ { \ {
@@ -169,7 +169,7 @@ Execute(LSP hover response with lists of strings and marked strings should be ha
AssertEqual {}, ale#hover#GetMap() AssertEqual {}, ale#hover#GetMap()
Execute(tsserver responses for documentation requests should be handled): 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( call ale#hover#HandleTSServerResponse(
\ 1, \ 1,

View File

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

View File

@@ -269,7 +269,7 @@ Execute(tsserver rename requests should be sent):
\ }] \ }]
\ ], \ ],
\ g:message_list \ 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() \ ale#rename#GetMap()
Given python(Some Python file): Given python(Some Python file):
@@ -470,7 +470,7 @@ Execute(LSP rename requests should be sent):
let b:ale_linters = ['pyls'] let b:ale_linters = ['pyls']
call setpos('.', [bufnr(''), 1, 5, 0]) call setpos('.', [bufnr(''), 1, 5, 0])
ALERename! ALERename
" We shouldn't register the callback yet. " We shouldn't register the callback yet.
AssertEqual '''''', string(g:Callback) AssertEqual '''''', string(g:Callback)
@@ -500,5 +500,5 @@ Execute(LSP rename requests should be sent):
\ ], \ ],
\ g:message_list \ 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() \ 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): Execute(dash should be used for shellcheck):
AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) 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(''))