diff options
35 files changed, 416 insertions, 167 deletions
@@ -185,7 +185,7 @@ formatting. | Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) | | Vim | [vint](https://github.com/Kuniwak/vint) | | Vim help^ | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) | -| Vue | [prettier](https://github.com/prettier/prettier) | +| Vue | [prettier](https://github.com/prettier/prettier), [vls](https://github.com/vuejs/vetur/tree/master/server) | | XHTML | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) | | XML | [xmllint](http://xmlsoft.org/xmllint.html) | | YAML | [swaglint](https://github.com/byCedric/swaglint), [yamllint](https://yamllint.readthedocs.io/) | diff --git a/ale_linters/cpp/cquery.vim b/ale_linters/cpp/cquery.vim index 2fd77d46..7997c843 100644 --- a/ale_linters/cpp/cquery.vim +++ b/ale_linters/cpp/cquery.vim @@ -30,5 +30,4 @@ call ale#linter#Define('cpp', { \ 'command_callback': 'ale_linters#cpp#cquery#GetCommand', \ 'project_root_callback': 'ale_linters#cpp#cquery#GetProjectRoot', \ 'initialization_options_callback': 'ale_linters#cpp#cquery#GetInitializationOptions', -\ 'language': 'cpp', \}) diff --git a/ale_linters/dart/language_server.vim b/ale_linters/dart/language_server.vim index bed77c52..2265e37a 100644 --- a/ale_linters/dart/language_server.vim +++ b/ale_linters/dart/language_server.vim @@ -20,6 +20,5 @@ call ale#linter#Define('dart', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#dart#language_server#GetExecutable', \ 'command_callback': 'ale_linters#dart#language_server#GetExecutable', -\ 'language': 'dart', \ 'project_root_callback': 'ale_linters#dart#language_server#GetProjectRoot', \}) diff --git a/ale_linters/glsl/glslls.vim b/ale_linters/glsl/glslls.vim index c19f28c2..77e30f9c 100644 --- a/ale_linters/glsl/glslls.vim +++ b/ale_linters/glsl/glslls.vim @@ -29,6 +29,5 @@ call ale#linter#Define('glsl', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#glsl#glslls#GetExecutable', \ 'command_callback': 'ale_linters#glsl#glslls#GetCommand', -\ 'language': 'glsl', \ 'project_root_callback': 'ale_linters#glsl#glslls#GetProjectRoot', \}) diff --git a/ale_linters/javascript/flow_ls.vim b/ale_linters/javascript/flow_ls.vim new file mode 100644 index 00000000..20fc2217 --- /dev/null +++ b/ale_linters/javascript/flow_ls.vim @@ -0,0 +1,38 @@ +" Author: t_t <jamestthompson3@gmail.com> +" Description: Integrate ALE with flow-language-server. + +call ale#Set('javascript_flow_ls_executable', 'flow') +call ale#Set('javascript_flow_ls_use_global', +\ get(g:, 'ale_use_global_executables', 0) +\) + +function! ale_linters#javascript#flow_ls#GetExecutable(buffer) abort + return ale#node#FindExecutable(a:buffer, 'javascript_flow_ls', [ + \ 'node_modules/.bin/flow', + \]) +endfunction + +function! ale_linters#javascript#flow_ls#GetCommand(buffer) abort + let l:executable = ale_linters#javascript#flow_ls#GetExecutable(a:buffer) + + return ale#Escape(l:executable) . ' lsp --from ale-lsp' +endfunction + +function! ale_linters#javascript#flow_ls#FindProjectRoot(buffer) abort + let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig') + + if !empty(l:flow_config) + return fnamemodify(l:flow_config, ':h') + endif + + return '' +endfunction + +call ale#linter#Define('javascript', { +\ 'name': 'flow-language-server', +\ 'lsp': 'stdio', +\ 'executable_callback': 'ale_linters#javascript#flow_ls#GetExecutable', +\ 'command_callback': 'ale_linters#javascript#flow_ls#GetCommand', +\ 'project_root_callback': 'ale_linters#javascript#flow_ls#FindProjectRoot', +\ 'language': 'javascript', +\}) diff --git a/ale_linters/php/langserver.vim b/ale_linters/php/langserver.vim index 0f3ead66..38b42df9 100644 --- a/ale_linters/php/langserver.vim +++ b/ale_linters/php/langserver.vim @@ -25,6 +25,5 @@ call ale#linter#Define('php', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#php#langserver#GetExecutable', \ 'command_callback': 'ale_linters#php#langserver#GetCommand', -\ 'language': 'php', \ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot', \}) diff --git a/ale_linters/python/pyls.vim b/ale_linters/python/pyls.vim index 010cb31f..ae71f022 100644 --- a/ale_linters/python/pyls.vim +++ b/ale_linters/python/pyls.vim @@ -23,7 +23,6 @@ call ale#linter#Define('python', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#python#pyls#GetExecutable', \ 'command_callback': 'ale_linters#python#pyls#GetCommand', -\ 'language': 'python', \ 'project_root_callback': 'ale#python#FindProjectRoot', \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \}) diff --git a/ale_linters/python/pyre.vim b/ale_linters/python/pyre.vim index 13f77d68..5efef409 100644 --- a/ale_linters/python/pyre.vim +++ b/ale_linters/python/pyre.vim @@ -23,7 +23,6 @@ call ale#linter#Define('python', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#python#pyre#GetExecutable', \ 'command_callback': 'ale_linters#python#pyre#GetCommand', -\ 'language': 'python', \ 'project_root_callback': 'ale#python#FindProjectRoot', \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \}) diff --git a/ale_linters/rust/rls.vim b/ale_linters/rust/rls.vim index d5160b14..cd13291d 100644 --- a/ale_linters/rust/rls.vim +++ b/ale_linters/rust/rls.vim @@ -30,6 +30,5 @@ call ale#linter#Define('rust', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#rust#rls#GetExecutable', \ 'command_callback': 'ale_linters#rust#rls#GetCommand', -\ 'language': 'rust', \ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot', \}) diff --git a/ale_linters/sh/language_server.vim b/ale_linters/sh/language_server.vim index 2f66e27b..385d1119 100644 --- a/ale_linters/sh/language_server.vim +++ b/ale_linters/sh/language_server.vim @@ -28,6 +28,5 @@ call ale#linter#Define('sh', { \ 'lsp': 'stdio', \ 'executable_callback': 'ale_linters#sh#language_server#GetExecutable', \ 'command_callback': 'ale_linters#sh#language_server#GetCommand', -\ 'language': 'sh', \ 'project_root_callback': 'ale_linters#sh#language_server#GetProjectRoot', \}) diff --git a/ale_linters/vue/vls.vim b/ale_linters/vue/vls.vim new file mode 100644 index 00000000..0d4bf9f6 --- /dev/null +++ b/ale_linters/vue/vls.vim @@ -0,0 +1,32 @@ +" Author: Alexander Olofsson <alexander.olofsson@liu.se> +" Description: Vue vls Language Server integration for ALE + +call ale#Set('vue_vls_executable', 'vls') +call ale#Set('vue_vls_use_global', get(g:, 'ale_use_global_executables', 0)) + +function! ale_linters#vue#vls#GetExecutable(buffer) abort + return ale#node#FindExecutable(a:buffer, 'vue_vls', [ + \ 'node_modules/.bin/vls', + \]) +endfunction + +function! ale_linters#vue#vls#GetCommand(buffer) abort + let l:exe = ale#Escape(ale_linters#vue#vls#GetExecutable(a:buffer)) + + return l:exe . ' --stdio' +endfunction + +function! ale_linters#vue#vls#GetProjectRoot(buffer) abort + let l:package_path = ale#path#FindNearestFile(a:buffer, 'package.json') + + return !empty(l:package_path) ? fnamemodify(l:package_path, ':h') : '' +endfunction + +call ale#linter#Define('vue', { +\ 'name': 'vls', +\ 'lsp': 'stdio', +\ 'executable_callback': 'ale_linters#vue#vls#GetExecutable', +\ 'command_callback': 'ale_linters#vue#vls#GetCommand', +\ 'language': 'vue', +\ 'project_root_callback': 'ale_linters#vue#vls#GetProjectRoot', +\}) diff --git a/autoload/ale.vim b/autoload/ale.vim index dcc12150..f61418f6 100644 --- a/autoload/ale.vim +++ b/autoload/ale.vim @@ -191,15 +191,12 @@ endfunction " " Every variable name will be prefixed with 'ale_'. function! ale#Var(buffer, variable_name) abort - let l:nr = str2nr(a:buffer) let l:full_name = 'ale_' . a:variable_name + let l:vars = getbufvar(str2nr(a:buffer), '', 0) - if bufexists(l:nr) - let l:vars = getbufvar(l:nr, '') - elseif has_key(g:, 'ale_fix_buffer_data') - let l:vars = get(g:ale_fix_buffer_data, l:nr, {'vars': {}}).vars - else - let l:vars = {} + if l:vars is 0 + " Look for variables from deleted buffers, saved from :ALEFix + let l:vars = get(get(g:ale_fix_buffer_data, a:buffer, {}), 'vars', {}) endif return get(l:vars, l:full_name, g:[l:full_name]) @@ -210,10 +207,10 @@ endfunction " Every variable name will be prefixed with 'ale_'. function! ale#Set(variable_name, default) abort let l:full_name = 'ale_' . a:variable_name - let l:value = get(g:, l:full_name, a:default) - let g:[l:full_name] = l:value - return l:value + if !has_key(g:, l:full_name) + let g:[l:full_name] = a:default + endif endfunction " Escape a string suitably for each platform. diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim new file mode 100644 index 00000000..eae41596 --- /dev/null +++ b/autoload/ale/assert.vim @@ -0,0 +1,50 @@ +function! s:GetLinter() abort + let l:linters = ale#linter#GetLintersLoaded() + let l:filetype_linters = get(values(l:linters), 0, []) + + if len(l:linters) is 0 || len(l:filetype_linters) is 0 + throw 'No linters were loaded' + endif + + if len(l:linters) > 1 || len(l:filetype_linters) > 1 + throw 'More than one linter was loaded' + endif + + return l:filetype_linters[0] +endfunction + +" Load the currently loaded linter for a test case, and check that the command +" matches the given string. +function! ale#assert#Linter(expected_executable, expected_command) abort + let l:buffer = bufnr('') + let l:linter = s:GetLinter() + let l:executable = ale#linter#GetExecutable(l:buffer, l:linter) + + if has_key(l:linter, 'command_chain') + let l:command = [] + + for l:chain_item in l:linter.command_chain + if empty(l:command) + call add(l:command, call(l:chain_item.callback, [l:buffer])) + else + call add(l:command, call(l:chain_item.callback, [l:buffer, []])) + endif + endfor + else + let l:command = ale#linter#GetCommand(l:buffer, l:linter) + " Replace %e with the escaped executable, so tests keep passing after + " linters are changed to use %e. + let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g') + endif + + AssertEqual + \ [a:expected_executable, a:expected_command], + \ [l:executable, l:command] +endfunction + +command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>) + +" A dummy function for making sure this module is loaded. +function! ale#assert#Init() abort + call ale#linter#Reset() +endfunction diff --git a/autoload/ale/command.vim b/autoload/ale/command.vim index 558fe233..b4bf3794 100644 --- a/autoload/ale/command.vim +++ b/autoload/ale/command.vim @@ -20,7 +20,7 @@ endfunction " %s -> with the current filename " %t -> with the name of an unused file in a temporary directory " %% -> with a literal % -function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort +function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed) abort let l:temporary_file = '' let l:command = a:command @@ -28,6 +28,11 @@ function! ale#command#FormatCommand(buffer, command, pipe_file_if_needed) abort " with an ugly string. let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g') + " Replace %e with the escaped executable, if available. + if !empty(a:executable) && l:command =~# '%e' + let l:command = substitute(l:command, '%e', '\=ale#Escape(a:executable)', 'g') + endif + " Replace all %s occurrences in the string with the name of the current " file. if l:command =~# '%s' diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index d97b6937..a64d8f9f 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -189,6 +189,7 @@ function! s:HandleExit(job_id, exit_code) abort let l:linter = l:job_info.linter let l:output = l:job_info.output let l:buffer = l:job_info.buffer + let l:executable = l:job_info.executable let l:next_chain_index = l:job_info.next_chain_index if g:ale_history_enabled @@ -212,7 +213,7 @@ function! s:HandleExit(job_id, exit_code) abort endif if l:next_chain_index < len(get(l:linter, 'command_chain', [])) - call s:InvokeChain(l:buffer, l:linter, l:next_chain_index, l:output) + call s:InvokeChain(l:buffer, l:executable, l:linter, l:next_chain_index, l:output) return endif @@ -440,6 +441,12 @@ endfunction " Returns 1 when the job was started successfully. function! s:RunJob(options) abort let l:command = a:options.command + + if empty(l:command) + return 0 + endif + + let l:executable = a:options.executable let l:buffer = a:options.buffer let l:linter = a:options.linter let l:output_stream = a:options.output_stream @@ -447,11 +454,12 @@ function! s:RunJob(options) abort let l:read_buffer = a:options.read_buffer let l:info = g:ale_buffer_info[l:buffer] - if empty(l:command) - return 0 - endif - - let [l:temporary_file, l:command] = ale#command#FormatCommand(l:buffer, l:command, l:read_buffer) + let [l:temporary_file, l:command] = ale#command#FormatCommand( + \ l:buffer, + \ l:executable, + \ l:command, + \ l:read_buffer, + \) if s:CreateTemporaryFileForJob(l:buffer, l:temporary_file) " If a temporary filename has been formatted in to the command, then @@ -512,6 +520,7 @@ function! s:RunJob(options) abort let s:job_info_map[l:job_id] = { \ 'linter': l:linter, \ 'buffer': l:buffer, + \ 'executable': l:executable, \ 'output': [], \ 'next_chain_index': l:next_chain_index, \} @@ -604,8 +613,9 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort \} endfunction -function! s:InvokeChain(buffer, linter, chain_index, input) abort +function! s:InvokeChain(buffer, executable, linter, chain_index, input) abort let l:options = ale#engine#ProcessChain(a:buffer, a:linter, a:chain_index, a:input) + let l:options.executable = a:executable return s:RunJob(l:options) endfunction @@ -699,7 +709,7 @@ function! s:RunLinter(buffer, linter) abort let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) if ale#engine#IsExecutable(a:buffer, l:executable) - return s:InvokeChain(a:buffer, a:linter, 0, []) + return s:InvokeChain(a:buffer, l:executable, a:linter, 0, []) endif endif diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index 1e056200..62674b87 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -1,10 +1,3 @@ -" This global Dictionary tracks the ALE fix data for jobs, etc. -" This Dictionary should not be accessed outside of the plugin. It is only -" global so it can be modified in Vader tests. -if !has_key(g:, 'ale_fix_buffer_data') - let g:ale_fix_buffer_data = {} -endif - if !has_key(s:, 'job_info_map') let s:job_info_map = {} endif @@ -219,6 +212,7 @@ function! s:RunJob(options) abort let [l:temporary_file, l:command] = ale#command#FormatCommand( \ l:buffer, + \ '', \ l:command, \ l:read_buffer, \) diff --git a/autoload/ale/fixers/isort.vim b/autoload/ale/fixers/isort.vim index 74ba3bc8..9070fb27 100644 --- a/autoload/ale/fixers/isort.vim +++ b/autoload/ale/fixers/isort.vim @@ -2,9 +2,12 @@ " Description: Fixing Python imports with isort. call ale#Set('python_isort_executable', 'isort') +call ale#Set('python_isort_options', '') call ale#Set('python_isort_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#fixers#isort#Fix(buffer) abort + let l:options = ale#Var(a:buffer, 'python_isort_options') + let l:executable = ale#python#FindExecutable( \ a:buffer, \ 'python_isort', @@ -17,6 +20,6 @@ function! ale#fixers#isort#Fix(buffer) abort return { \ 'command': ale#path#BufferCdString(a:buffer) - \ . ale#Escape(l:executable) . ' -', + \ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -', \} endfunction diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim index 299f5dad..9e518551 100644 --- a/autoload/ale/linter.vim +++ b/autoload/ale/linter.vim @@ -47,6 +47,13 @@ function! ale#linter#Reset() abort let s:linters = {} endfunction +" Return a reference to the linters loaded. +" This is only for tests. +" Do not call this function. +function! ale#linter#GetLintersLoaded() abort + return s:linters +endfunction + function! s:IsCallback(value) abort return type(a:value) == type('') || type(a:value) == type(function('type')) endfunction @@ -59,7 +66,7 @@ function! s:LanguageGetter(buffer) dict abort return l:self.language endfunction -function! ale#linter#PreProcess(linter) abort +function! ale#linter#PreProcess(filetype, linter) abort if type(a:linter) != type({}) throw 'The linter object must be a Dictionary' endif @@ -193,13 +200,20 @@ function! ale#linter#PreProcess(linter) abort endif if l:needs_lsp_details - if has_key(a:linter, 'language') - if has_key(a:linter, 'language_callback') + if has_key(a:linter, 'language_callback') + if has_key(a:linter, 'language') throw 'Only one of `language` or `language_callback` ' \ . 'should be set' endif - let l:obj.language = get(a:linter, 'language') + let l:obj.language_callback = get(a:linter, 'language_callback') + + if !s:IsCallback(l:obj.language_callback) + throw '`language_callback` must be a callback for LSP linters' + endif + else + " Default to using the filetype as the language. + let l:obj.language = get(a:linter, 'language', a:filetype) if type(l:obj.language) != type('') throw '`language` must be a string' @@ -207,12 +221,6 @@ function! ale#linter#PreProcess(linter) abort " Make 'language_callback' return the 'language' value. let l:obj.language_callback = function('s:LanguageGetter') - else - let l:obj.language_callback = get(a:linter, 'language_callback') - - if !s:IsCallback(l:obj.language_callback) - throw '`language_callback` must be a callback for LSP linters' - endif endif let l:obj.project_root_callback = get(a:linter, 'project_root_callback') @@ -286,7 +294,7 @@ function! ale#linter#Define(filetype, linter) abort let s:linters[a:filetype] = [] endif - let l:new_linter = ale#linter#PreProcess(a:linter) + let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter) call add(s:linters[a:filetype], l:new_linter) endfunction diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim index 9e72362b..31299fc5 100644 --- a/autoload/ale/lsp_linter.vim +++ b/autoload/ale/lsp_linter.vim @@ -147,14 +147,14 @@ function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort else let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) - if !executable(l:executable) + if empty(l:executable) || !executable(l:executable) return {} endif - let l:command = ale#job#PrepareCommand( - \ a:buffer, - \ ale#linter#GetCommand(a:buffer, a:linter), - \) + let l:command = ale#linter#GetCommand(a:buffer, a:linter) + " Format the command, so %e can be formatted into it. + let l:command = ale#command#FormatCommand(a:buffer, l:executable, l:command, 0)[1] + let l:command = ale#job#PrepareCommand(a:buffer, l:command) let l:conn_id = ale#lsp#StartProgram( \ l:executable, \ l:command, diff --git a/doc/ale-python.txt b/doc/ale-python.txt index de706896..be8ad118 100644 --- a/doc/ale-python.txt +++ b/doc/ale-python.txt @@ -145,6 +145,14 @@ g:ale_python_isort_executable *g:ale_python_isort_executable* See |ale-integrations-local-executables| +g:ale_python_isort_options *g:ale_python_isort_options* + *b:ale_python_isort_options* + Type: |String| + Default: `''` + + This variable can be set to pass extra options to isort. + + g:ale_python_isort_use_global *g:ale_python_isort_use_global* *b:ale_python_isort_use_global* Type: |Number| diff --git a/doc/ale-vue.txt b/doc/ale-vue.txt index 937b603b..a2c2786f 100644 --- a/doc/ale-vue.txt +++ b/doc/ale-vue.txt @@ -7,5 +7,25 @@ prettier *ale-vue-prettier* See |ale-javascript-prettier| for information about the available options. + +=============================================================================== +vls *ale-vue-vls* + +g:ale_vue_vls_executable *g:ale_vue_vls_executable* + *b:ale_vue_vls_executable* + Type: |String| + Default: `'vls'` + + See |ale-integrations-local-executables| + + +g:ale_vue_vls_use_global *g:ale_vue_vls_use_global* + *b:ale_vue_vls_use_global* + Type: |Number| + Default: `get(g:, 'ale_use_global_executables', 0)` + + See |ale-integrations-local-executables| + + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale.txt b/doc/ale.txt index 6cc0026d..60178ee1 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -274,6 +274,7 @@ CONTENTS *ale-contents* write-good..........................|ale-vim-help-write-good| vue...................................|ale-vue-options| prettier............................|ale-vue-prettier| + vls.................................|ale-vue-vls| xhtml.................................|ale-xhtml-options| write-good..........................|ale-xhtml-write-good| xml...................................|ale-xml-options| @@ -419,7 +420,7 @@ Notes: * Verilog: `iverilog`, `verilator` * Vim: `vint` * Vim help^: `alex`!!, `proselint`, `write-good` -* Vue: `prettier` +* Vue: `prettier`, `vls` * XHTML: `alex`!!, `proselint`, `write-good` * XML: `xmllint` * YAML: `swaglint`, `yamllint` @@ -642,9 +643,6 @@ ALE supports the following LSP/tsserver features. ------------------------------------------------------------------------------- 5.1 Completion *ale-completion* -NOTE: At the moment, only `tsserver` for TypeScript code is supported for -completion. - ALE offers limited support for automatic completion of code while you type. Completion is only supported while a least one LSP linter is enabled. ALE will only suggest symbols provided by the LSP servers. @@ -2384,9 +2382,12 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()* with a callback returning an address to connect to. ALE will not start a server automatically. - When this argument is not empty, only one of either - `language` or `language_callback` must be defined, - and `project_root_callback` must be defined. + When this argument is not empty + `project_root_callback` must be defined. + + `language` or `language_callback` can be defined to + describe the language for a file. The filetype will + be used as the language by default. LSP linters handle diagnostics automatically, so the `callback` argument must not be defined. @@ -2419,8 +2420,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()* being checked. This string will be sent to the LSP to tell it what type of language is being checked. - This argument must only be set if the `lsp` argument - is also set to a non-empty string. + If this or `language_callback` isn't set, the + language will default to the value of the filetype + given to |ale#linter#Define|. `language_callback` A |String| or |Funcref| for a callback function accepting a buffer number. A |String| should be @@ -2491,14 +2493,22 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()* For example: > 'command': 'ghc -fno-code -v0 %t', < + Any substring `%e` will be replaced with the escaped executable supplied + with `executable` or `executable_callback`. This provides a convenient way + to define a command string which needs to include a dynamic executable name, + but which is otherwise static. + + For example: > + 'command': '%e --some-argument', +< The character sequence `%%` can be used to emit a literal `%` into a command, so literal character sequences `%s` and `%t` can be escaped by using `%%s` and `%%t` instead, etc. If a callback for a command generates part of a command string which might - possibly contain `%%`, `%s`, or `%t` where the special formatting behaviour - is not desired, the |ale#engine#EscapeCommandPart()| function can be used to - replace those characters to avoid formatting issues. + possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting + behavior is not desired, the |ale#engine#EscapeCommandPart()| function can + be used to replace those characters to avoid formatting issues. *ale-linter-loading-behavior* *ale-linter-loading-behaviour* diff --git a/plugin/ale.vim b/plugin/ale.vim index 3bd12015..16a40268 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -44,6 +44,8 @@ endif " This global variable is used internally by ALE for tracking information for " each buffer which linters are being run against. let g:ale_buffer_info = {} +" This global Dictionary tracks data for fixing code. Don't mess with it. +let g:ale_fix_buffer_data = {} " User Configuration diff --git a/test/command_callback/test_tslint_command_callback.vader b/test/command_callback/test_tslint_command_callback.vader index edab72c8..0c2f3abf 100644 --- a/test/command_callback/test_tslint_command_callback.vader +++ b/test/command_callback/test_tslint_command_callback.vader @@ -1,4 +1,6 @@ Before: + call ale#assert#Init() + Save g:ale_typescript_tslint_executable Save g:ale_typescript_tslint_config_path Save g:ale_typescript_tslint_rules_dir @@ -26,26 +28,25 @@ After: call ale#linter#Reset() Execute(The default tslint command should be correct): - AssertEqual + AssertLinter + \ 'tslint', \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' - \ . ale#Escape('tslint') . ' --format json %t', - \ ale_linters#typescript#tslint#GetCommand(bufnr('')) + \ . ale#Escape('tslint') . ' --format json %t' Execute(The rules directory option should be included if set): let b:ale_typescript_tslint_rules_dir = '/foo/bar' - AssertEqual + AssertLinter + \ 'tslint', \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' \ . ale#Escape('tslint') . ' --format json' \ . ' -r ' . ale#Escape('/foo/bar') - \ . ' %t', - \ ale_linters#typescript#tslint#GetCommand(bufnr('')) + \ . ' %t' Execute(The executable should be configurable and escaped): let b:ale_typescript_tslint_executable = 'foo bar' - AssertEqual 'foo bar', ale_linters#typescript#tslint#GetExecutable(bufnr('')) - AssertEqual + AssertLinter + \ 'foo bar', \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' - \ . ale#Escape('foo bar') . ' --format json %t', - \ ale_linters#typescript#tslint#GetCommand(bufnr('')) + \ . ale#Escape('foo bar') . ' --format json %t' diff --git a/test/command_callback/test_write_good_command_callback.vader b/test/command_callback/test_write_good_command_callback.vader index 8d9e9a00..4b5ed7b7 100644 --- a/test/command_callback/test_write_good_command_callback.vader +++ b/test/command_callback/test_write_good_command_callback.vader @@ -1,4 +1,6 @@ Before: + call ale#assert#Init() + Save g:ale_writegood_options Save g:ale_writegood_executable Save g:ale_writegood_use_global @@ -7,6 +9,8 @@ Before: unlet! g:ale_writegood_executable unlet! g:ale_writegood_use_global + runtime ale_linters/markdown/write-good.vim + call ale#test#SetDirectory('/testplugin/test/command_callback') call ale#test#SetFilename('testfile.txt') @@ -16,42 +20,36 @@ After: Restore call ale#test#RestoreDirectory() + call ale#linter#Reset() Execute(The global executable should be used when the local one cannot be found): - AssertEqual 'write-good', ale#handlers#writegood#GetExecutable(bufnr('')) - AssertEqual + AssertLinter + \ 'write-good', \ ale#Escape('write-good') . ' %t', - \ ale#handlers#writegood#GetCommand(bufnr('')) Execute(The options should be used in the command): let g:ale_writegood_options = '--foo --bar' - AssertEqual + AssertLinter + \ 'write-good', \ ale#Escape('write-good') . ' --foo --bar %t', - \ ale#handlers#writegood#GetCommand(bufnr('')) Execute(Should use the node_modules/.bin executable, if available): call ale#test#SetFilename('write-good-node-modules/test.txt') - AssertEqual + AssertLinter \ ale#path#Simplify(g:dir . '/write-good-node-modules/node_modules/.bin/write-good'), - \ ale#handlers#writegood#GetExecutable(bufnr('')) - AssertEqual \ ale#Escape(ale#path#Simplify(g:dir . '/write-good-node-modules/node_modules/.bin/write-good')) \ . ' %t', - \ ale#handlers#writegood#GetCommand(bufnr('')) Execute(Should use the node_modules/write-good executable, if available): call ale#test#SetFilename('write-good-node-modules-2/test.txt') - AssertEqual + AssertLinter \ ale#path#Simplify(g:dir . '/write-good-node-modules-2/node_modules/write-good/bin/write-good.js'), - \ ale#handlers#writegood#GetExecutable(bufnr('')) - AssertEqual \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/write-good-node-modules-2/node_modules/write-good/bin/write-good.js')) \ . ' %t', - \ ale#handlers#writegood#GetCommand(bufnr('')) Execute(Should let users configure a global executable and override local paths): call ale#test#SetFilename('write-good-node-modules-2/test.txt') @@ -59,7 +57,4 @@ Execute(Should let users configure a global executable and override local paths) let g:ale_writegood_executable = 'foo-bar' let g:ale_writegood_use_global = 1 - AssertEqual 'foo-bar', ale#handlers#writegood#GetExecutable(bufnr('')) - AssertEqual - \ ale#Escape('foo-bar') . ' %t', - \ ale#handlers#writegood#GetCommand(bufnr('')) + AssertLinter 'foo-bar', ale#Escape('foo-bar') . ' %t' diff --git a/test/completion/test_lsp_completion_messages.vader b/test/completion/test_lsp_completion_messages.vader index 8ba2ad38..e5aac176 100644 --- a/test/completion/test_lsp_completion_messages.vader +++ b/test/completion/test_lsp_completion_messages.vader @@ -59,6 +59,7 @@ After: runtime autoload/ale/completion.vim runtime autoload/ale/lsp.vim + runtime autoload/ale/lsp_linter.vim Given typescript(Some typescript file): foo diff --git a/test/fixers/test_isort_fixer_callback.vader b/test/fixers/test_isort_fixer_callback.vader index 7c2b515f..56c08d26 100644 --- a/test/fixers/test_isort_fixer_callback.vader +++ b/test/fixers/test_isort_fixer_callback.vader @@ -1,5 +1,6 @@ Before: Save g:ale_python_isort_executable + Save g:ale_python_isort_options " Use an invalid global executable, so we don't match it. let g:ale_python_isort_executable = 'xxxinvalid' @@ -30,3 +31,19 @@ Execute(The isort callback should return the correct default values): \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort')) . ' -', \ }, \ ale#fixers#isort#Fix(bufnr('')) + +Execute(The isort callback should respect custom options): + let g:ale_python_isort_options = '--multi-line=3 --trailing-comma' + + AssertEqual + \ 0, + \ ale#fixers#isort#Fix(bufnr('')) + + silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') + AssertEqual + \ { + \ 'command': 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo')) . ' && ' + \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort')) + \ . ' --multi-line=3 --trailing-comma -', + \ }, + \ ale#fixers#isort#Fix(bufnr('')) diff --git a/test/lsp/test_did_save_event.vader b/test/lsp/test_did_save_event.vader index 97774372..b696ee4b 100644 --- a/test/lsp/test_did_save_event.vader +++ b/test/lsp/test_did_save_event.vader @@ -75,6 +75,7 @@ After: runtime autoload/ale/completion.vim runtime autoload/ale/lsp.vim + runtime autoload/ale/lsp_linter.vim Given foobar (Some imaginary filetype): <contents> diff --git a/test/lsp/test_lsp_command_formatting.vader b/test/lsp/test_lsp_command_formatting.vader new file mode 100644 index 00000000..f436397f --- /dev/null +++ b/test/lsp/test_lsp_command_formatting.vader @@ -0,0 +1,37 @@ +Before: + runtime autoload/ale/lsp.vim + + let g:args = [] + + " Mock the StartProgram function so we can just capture the arguments. + function! ale#lsp#StartProgram(...) abort + let g:args = a:000 + endfunction + +After: + unlet! g:args + + runtime autoload/ale/lsp.vim + +Execute(Command formatting should be applied correctly for LSP linters): + call ale#lsp_linter#StartLSP( + \ bufnr(''), + \ { + \ 'language_callback': {-> 'x'}, + \ 'project_root_callback': {-> '/foo/bar'}, + \ 'lsp': 'stdio', + \ 'executable': has('win32') ? 'cmd': 'true', + \ 'command': '%e --foo', + \ }, + \ {->0} + \) + + if has('win32') + AssertEqual + \ ['cmd', 'cmd /s/c "cmd --foo"', '/foo/bar'], + \ g:args[:2] + else + AssertEqual + \ ['true', [&shell, '-c', '''true'' --foo'], '/foo/bar'], + \ g:args[:2] + endif diff --git a/test/test_ale_var.vader b/test/test_ale_var.vader index fb674d93..5f42fe95 100644 --- a/test/test_ale_var.vader +++ b/test/test_ale_var.vader @@ -34,8 +34,3 @@ Execute(ale#Var should return the global variable for unknown variables): let g:ale_fix_buffer_data = {} AssertEqual 'abc', ale#Var(1347347, 'some_variable') - -Execute(ale#Var should return the global variables when the ALE fix variable is undefined): - unlet! g:ale_fix_buffer_data - - AssertEqual 'abc', ale#Var(1347347, 'some_variable') diff --git a/test/test_find_references.vader b/test/test_find_references.vader index c2290ca3..150e0471 100644 --- a/test/test_find_references.vader +++ b/test/test_find_references.vader @@ -58,7 +58,7 @@ After: unlet! g:item_list unlet! g:preview_called - runtime autoload/ale/linter.vim + runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/preview.vim diff --git a/test/test_format_command.vader b/test/test_format_command.vader index f6143a5a..71285efa 100644 --- a/test/test_format_command.vader +++ b/test/test_format_command.vader @@ -15,10 +15,10 @@ After: delfunction CheckTempFile Execute(FormatCommand should do nothing to basic command strings): - AssertEqual ['', 'awesome-linter do something'], ale#command#FormatCommand(bufnr('%'), 'awesome-linter do something', 0) + AssertEqual ['', 'awesome-linter do something'], ale#command#FormatCommand(bufnr('%'), '', 'awesome-linter do something', 0) Execute(FormatCommand should handle %%, and ignore other percents): - AssertEqual ['', '% %%d %%f %x %'], ale#command#FormatCommand(bufnr('%'), '%% %%%d %%%f %x %', 0) + AssertEqual ['', '% %%d %%f %x %'], ale#command#FormatCommand(bufnr('%'), '', '%% %%%d %%%f %x %', 0) Execute(FormatCommand should convert %s to the current filename): AssertEqual @@ -26,10 +26,10 @@ Execute(FormatCommand should convert %s to the current filename): \ '', \ 'foo ' . ale#Escape(expand('%:p')) . ' bar ' . ale#Escape(expand('%:p')) \ ], - \ ale#command#FormatCommand(bufnr('%'), 'foo %s bar %s', 0) + \ ale#command#FormatCommand(bufnr('%'), '', 'foo %s bar %s', 0) Execute(FormatCommand should convert %t to a new temporary filename): - let g:result = ale#command#FormatCommand(bufnr('%'), 'foo %t bar %t', 0) + let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0) call CheckTempFile(g:result[0]) @@ -43,7 +43,7 @@ Execute(FormatCommand should convert %t to a new temporary filename): AssertEqual g:match[1], g:match[2] Execute(FormatCommand should let you combine %s and %t): - let g:result = ale#command#FormatCommand(bufnr('%'), 'foo %t bar %s', 0) + let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %s', 0) call CheckTempFile(g:result[0]) @@ -56,11 +56,34 @@ Execute(FormatCommand should let you combine %s and %t): " The second item should be equal to the original filename. AssertEqual ale#Escape(expand('%:p')), g:match[2] +Execute(FormatCommand should replace %e with the escaped executable): + if has('win32') + AssertEqual + \ ['', 'foo foo'], + \ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0) + AssertEqual + \ ['', '"foo bar"'], + \ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0) + AssertEqual + \ ['', '%e %e'], + \ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0) + else + AssertEqual + \ ['', '''foo'' ''foo'''], + \ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0) + AssertEqual + \ ['', '''foo bar'''], + \ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0) + AssertEqual + \ ['', '%e %e'], + \ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0) + endif + Execute(EscapeCommandPart should escape all percent signs): AssertEqual '%%s %%t %%%% %%s %%t %%%%', ale#engine#EscapeCommandPart('%s %t %% %s %t %%') Execute(EscapeCommandPart should pipe in temporary files appropriately): - let g:result = ale#command#FormatCommand(bufnr('%'), 'foo bar', 1) + let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar', 1) call CheckTempFile(g:result[0]) @@ -68,7 +91,7 @@ Execute(EscapeCommandPart should pipe in temporary files appropriately): Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] AssertEqual ale#Escape(g:result[0]), g:match[1] - let g:result = ale#command#FormatCommand(bufnr('%'), 'foo bar %t', 1) + let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar %t', 1) call CheckTempFile(g:result[0]) diff --git a/test/test_go_to_definition.vader b/test/test_go_to_definition.vader index 78373a65..749f4d7e 100644 --- a/test/test_go_to_definition.vader +++ b/test/test_go_to_definition.vader @@ -48,7 +48,7 @@ After: unlet! g:expr_list unlet! b:ale_linters - runtime autoload/ale/linter.vim + runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim diff --git a/test/test_hover.vader b/test/test_hover.vader index 15f164f0..a18fc651 100644 --- a/test/test_hover.vader +++ b/test/test_hover.vader @@ -61,7 +61,7 @@ After: delfunction HandleValidLSPResult - runtime autoload/ale/linter.vim + runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader index 48a4a394..f0ec023a 100644 --- a/test/test_linter_defintion_processing.vader +++ b/test/test_linter_defintion_processing.vader @@ -5,11 +5,11 @@ After: unlet g:linter Execute (PreProcess should throw when the linter object is not a Dictionary): - AssertThrows call ale#linter#PreProcess('') + AssertThrows call ale#linter#PreProcess('testft', '') AssertEqual 'The linter object must be a Dictionary', g:vader_exception Execute (PreProcess should throw when there is no name): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', @@ -17,7 +17,7 @@ Execute (PreProcess should throw when there is no name): AssertEqual '`name` must be defined to name the linter', g:vader_exception Execute (PreProcess should throw when there is no callback): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'executable': 'echo', \ 'command': 'echo', @@ -25,7 +25,7 @@ Execute (PreProcess should throw when there is no callback): AssertEqual '`callback` must be defined with a callback to accept output', g:vader_exception Execute (PreProcess should throw when then callback is not a function): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 1, \ 'executable': 'echo', @@ -34,7 +34,7 @@ Execute (PreProcess should throw when then callback is not a function): AssertEqual '`callback` must be defined with a callback to accept output', g:vader_exception Execute (PreProcess should throw when there is no executable or executable_callback): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'command': 'echo', @@ -42,7 +42,7 @@ Execute (PreProcess should throw when there is no executable or executable_callb AssertEqual 'Either `executable` or `executable_callback` must be defined', g:vader_exception Execute (PreProcess should throw when executable is not a string): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 123, @@ -51,7 +51,7 @@ Execute (PreProcess should throw when executable is not a string): AssertEqual '`executable` must be a string if defined', g:vader_exception Execute (PreProcess should throw when executable_callback is not a callback): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable_callback': 123, @@ -60,7 +60,7 @@ Execute (PreProcess should throw when executable_callback is not a callback): AssertEqual '`executable_callback` must be a callback if defined', g:vader_exception Execute (PreProcess should throw when there is no command): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -68,7 +68,7 @@ Execute (PreProcess should throw when there is no command): AssertEqual 'Either `command`, `executable_callback`, `command_chain` must be defined', g:vader_exception Execute (PreProcess should throw when command is not a string): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -77,7 +77,7 @@ Execute (PreProcess should throw when command is not a string): AssertEqual '`command` must be a string if defined', g:vader_exception Execute (PreProcess should throw when command_callback is not a callback): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -86,7 +86,7 @@ Execute (PreProcess should throw when command_callback is not a callback): AssertEqual '`command_callback` must be a callback if defined', g:vader_exception Execute (PreProcess should when the output stream isn't a valid string): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -96,7 +96,7 @@ Execute (PreProcess should when the output stream isn't a valid string): AssertEqual "`output_stream` must be 'stdout', 'stderr', or 'both'", g:vader_exception Execute (PreProcess should not throw when everything is correct): - call ale#linter#PreProcess({ + call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -104,7 +104,7 @@ Execute (PreProcess should not throw when everything is correct): \}) Execute (PreProcess should accept an stdout output_stream): - call ale#linter#PreProcess({ + call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -113,7 +113,7 @@ Execute (PreProcess should accept an stdout output_stream): \}) Execute (PreProcess should accept an stderr output_stream): - call ale#linter#PreProcess({ + call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -122,7 +122,7 @@ Execute (PreProcess should accept an stderr output_stream): \}) Execute (PreProcess should accept a 'both' output_stream): - call ale#linter#PreProcess({ + call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', @@ -137,7 +137,7 @@ Execute(PreProcess should complain if the command_chain is not a List): \ 'executable': 'x', \ 'command_chain': 'x', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`command_chain` must be a List', g:vader_exception Execute(PreProcess should complain if the command_chain is empty): @@ -147,7 +147,7 @@ Execute(PreProcess should complain if the command_chain is empty): \ 'executable': 'x', \ 'command_chain': [], \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`command_chain` must contain at least one item', g:vader_exception Execute(PreProcess should complain if the command_chain has no callback): @@ -157,7 +157,7 @@ Execute(PreProcess should complain if the command_chain has no callback): \ 'executable': 'x', \ 'command_chain': [{}], \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'The `command_chain` item 0 must define a `callback` function', g:vader_exception Execute(PreProcess should complain if the command_chain callback is not a function): @@ -167,7 +167,7 @@ Execute(PreProcess should complain if the command_chain callback is not a functi \ 'executable': 'x', \ 'command_chain': [{'callback': 2}], \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'The `command_chain` item 0 must define a `callback` function', g:vader_exception Execute(PreProcess should accept a chain with one callback): @@ -177,7 +177,7 @@ Execute(PreProcess should accept a chain with one callback): \ 'executable': 'x', \ 'command_chain': [{'callback': 'foo'}], \} - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) Execute(PreProcess should complain about invalid output_stream values in the chain): let g:linter = { @@ -186,7 +186,7 @@ Execute(PreProcess should complain about invalid output_stream values in the cha \ 'executable': 'x', \ 'command_chain': [{'callback': 'foo', 'output_stream': ''}], \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual "The `command_chain` item 0 `output_stream` flag must be 'stdout', 'stderr', or 'both'", g:vader_exception Execute(PreProcess should complain about valid output_stream values in the chain): @@ -196,11 +196,11 @@ Execute(PreProcess should complain about valid output_stream values in the chain \ 'executable': 'x', \ 'command_chain': [{'callback': 'foo', 'output_stream': 'stdout'}], \} - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) let g:linter.command_chain[0].output_stream = 'stderr' - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) let g:linter.command_chain[0].output_stream = 'both' - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) Execute(PreProcess should complain about invalid chain items at higher indices): let g:linter = { @@ -209,7 +209,7 @@ Execute(PreProcess should complain about invalid chain items at higher indices): \ 'executable': 'x', \ 'command_chain': [{'callback': 'foo'}, {'callback': 123}], \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'The `command_chain` item 1 must define a `callback` function', g:vader_exception Execute(PreProcess should complain when conflicting command options are used): @@ -220,19 +220,19 @@ Execute(PreProcess should complain when conflicting command options are used): \ 'command': 'foo', \ 'command_chain': [{'callback': 'foo'}], \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `command`, `command_callback`, or `command_chain` should be set', g:vader_exception unlet g:linter.command let g:linter.command_callback = 'foo' - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `command`, `command_callback`, or `command_chain` should be set', g:vader_exception let g:linter.command = 'foo' unlet g:linter.command_chain - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `command`, `command_callback`, or `command_chain` should be set', g:vader_exception Execute(PreProcess should process the read_buffer option correctly): @@ -244,35 +244,35 @@ Execute(PreProcess should process the read_buffer option correctly): \ 'read_buffer': '0', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`read_buffer` must be `0` or `1`', g:vader_exception let g:linter.read_buffer = 0 - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) let g:linter.read_buffer = 1 - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) unlet g:linter.read_buffer let g:linter.command_chain[0].read_buffer = '0' - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'The `command_chain` item 0 value for `read_buffer` must be `0` or `1`', g:vader_exception let g:linter.command_chain[0].read_buffer = 0 - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) let g:linter.command_chain[1].read_buffer = '0' - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'The `command_chain` item 1 value for `read_buffer` must be `0` or `1`', g:vader_exception let g:linter.command_chain[1].read_buffer = 1 - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) Execute(PreProcess should set a default value for read_buffer): let g:linter = { @@ -282,7 +282,7 @@ Execute(PreProcess should set a default value for read_buffer): \ 'command': 'x', \} - AssertEqual 1, ale#linter#PreProcess(g:linter).read_buffer + AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer Execute(PreProcess should process the lint_file option correctly): let g:linter = { @@ -293,25 +293,25 @@ Execute(PreProcess should process the lint_file option correctly): \ 'lint_file': 'x', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`lint_file` must be `0` or `1`', g:vader_exception let g:linter.lint_file = 0 - AssertEqual 0, ale#linter#PreProcess(g:linter).lint_file + AssertEqual 0, ale#linter#PreProcess('testft', g:linter).lint_file " The default for read_buffer should be 1 when lint_file is 0 - AssertEqual 1, ale#linter#PreProcess(g:linter).read_buffer + AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer let g:linter.lint_file = 1 - AssertEqual 1, ale#linter#PreProcess(g:linter).lint_file + AssertEqual 1, ale#linter#PreProcess('testft', g:linter).lint_file " The default for read_buffer should change to 0 when lint_file is 1. - AssertEqual 0, ale#linter#PreProcess(g:linter).read_buffer + AssertEqual 0, ale#linter#PreProcess('testft', g:linter).read_buffer let g:linter.read_buffer = 1 " We shouldn't be able to set both options to 1 at the same time. - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `lint_file` or `read_buffer` can be `1`', g:vader_exception Execute(PreProcess should set a default value for lint_file): @@ -322,7 +322,7 @@ Execute(PreProcess should set a default value for lint_file): \ 'command': 'x', \} - AssertEqual 0, ale#linter#PreProcess(g:linter).lint_file + AssertEqual 0, ale#linter#PreProcess('testft', g:linter).lint_file Execute(PreProcess should set a default value for aliases): let g:linter = { @@ -332,7 +332,7 @@ Execute(PreProcess should set a default value for aliases): \ 'command': 'x', \} - AssertEqual [], ale#linter#PreProcess(g:linter).aliases + AssertEqual [], ale#linter#PreProcess('testft', g:linter).aliases Execute(PreProcess should complain about invalid `aliases` values): let g:linter = { @@ -343,12 +343,12 @@ Execute(PreProcess should complain about invalid `aliases` values): \ 'aliases': 'foo', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`aliases` must be a List of String values', g:vader_exception let g:linter.aliases = [1] - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`aliases` must be a List of String values', g:vader_exception Execute(PreProcess should accept `aliases` lists): @@ -360,11 +360,11 @@ Execute(PreProcess should accept `aliases` lists): \ 'aliases': [], \} - AssertEqual [], ale#linter#PreProcess(g:linter).aliases + AssertEqual [], ale#linter#PreProcess('testft', g:linter).aliases let g:linter.aliases = ['foo', 'bar'] - AssertEqual ['foo', 'bar'], ale#linter#PreProcess(g:linter).aliases + AssertEqual ['foo', 'bar'], ale#linter#PreProcess('testft', g:linter).aliases Execute(PreProcess should accept tsserver LSP configuration): let g:linter = { @@ -376,17 +376,17 @@ Execute(PreProcess should accept tsserver LSP configuration): \ 'project_root_callback': 'x', \} - AssertEqual 'tsserver', ale#linter#PreProcess(g:linter).lsp + AssertEqual 'tsserver', ale#linter#PreProcess('testft', g:linter).lsp call remove(g:linter, 'executable') let g:linter.executable_callback = 'X' - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) call remove(g:linter, 'command') let g:linter.command_callback = 'X' - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) Execute(PreProcess should accept stdio LSP configuration): let g:linter = { @@ -398,17 +398,17 @@ Execute(PreProcess should accept stdio LSP configuration): \ 'project_root_callback': 'x', \} - AssertEqual 'stdio', ale#linter#PreProcess(g:linter).lsp + AssertEqual 'stdio', ale#linter#PreProcess('testft', g:linter).lsp call remove(g:linter, 'executable') let g:linter.executable_callback = 'X' - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) call remove(g:linter, 'command') let g:linter.command_callback = 'X' - call ale#linter#PreProcess(g:linter) + call ale#linter#PreProcess('testft', g:linter) Execute(PreProcess should accept LSP server configurations): let g:linter = { @@ -419,7 +419,7 @@ Execute(PreProcess should accept LSP server configurations): \ 'project_root_callback': 'x', \} - AssertEqual 'socket', ale#linter#PreProcess(g:linter).lsp + AssertEqual 'socket', ale#linter#PreProcess('testft', g:linter).lsp Execute(PreProcess should accept let you specify the language as just a string): let g:linter = { @@ -430,7 +430,7 @@ Execute(PreProcess should accept let you specify the language as just a string): \ 'project_root_callback': 'x', \} - AssertEqual 'foobar', ale#linter#PreProcess(g:linter).language_callback(0) + AssertEqual 'foobar', ale#linter#PreProcess('testft', g:linter).language_callback(0) Execute(PreProcess should complain about using language and language_callback together): let g:linter = { @@ -442,16 +442,26 @@ Execute(PreProcess should complain about using language and language_callback to \ 'project_root_callback': 'x', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `language` or `language_callback` should be set', g:vader_exception +Execute(PreProcess should use the filetype as the language string by default): + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'project_root_callback': 'x', + \} + + AssertEqual 'testft', ale#linter#PreProcess('testft', g:linter).language_callback(0) + Execute(PreProcess should require an address_callback for LSP socket configurations): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`address_callback` must be defined for getting the LSP address', g:vader_exception Execute(PreProcess should complain about address_callback for non-LSP linters): @@ -463,7 +473,7 @@ Execute(PreProcess should complain about address_callback for non-LSP linters): \ 'address_callback': 'X', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`address_callback` cannot be used when lsp != ''socket''', g:vader_exception Execute(PreProcess should complain about using initialization_options and initialization_options_callback together): @@ -477,11 +487,11 @@ Execute(PreProcess should complain about using initialization_options and initia \ 'initialization_options_callback': 'x', \} - AssertThrows call ale#linter#PreProcess(g:linter) + AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `initialization_options` or `initialization_options_callback` should be set', g:vader_exception Execute (PreProcess should throw when initialization_options_callback is not a callback): - AssertThrows call ale#linter#PreProcess({ + AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address_callback': 'X', |