diff --git a/ale_linters/go/gosimple.vim b/ale_linters/go/gosimple.vim index 4b7d340..9188e0d 100644 --- a/ale_linters/go/gosimple.vim +++ b/ale_linters/go/gosimple.vim @@ -6,4 +6,5 @@ call ale#linter#Define('go', { \ 'executable': 'gosimple', \ 'command': 'gosimple %t', \ 'callback': 'ale#handlers#unix#HandleAsWarning', +\ 'output_stream': 'both' \}) diff --git a/ale_linters/go/staticcheck.vim b/ale_linters/go/staticcheck.vim index c78b320..cb4a5c7 100644 --- a/ale_linters/go/staticcheck.vim +++ b/ale_linters/go/staticcheck.vim @@ -6,4 +6,5 @@ call ale#linter#Define('go', { \ 'executable': 'staticcheck', \ 'command': 'staticcheck %t', \ 'callback': 'ale#handlers#unix#HandleAsWarning', +\ 'output_stream': 'both' \}) diff --git a/ale_linters/javascript/standard.vim b/ale_linters/javascript/standard.vim index fc534eb..aa6a3a7 100644 --- a/ale_linters/javascript/standard.vim +++ b/ale_linters/javascript/standard.vim @@ -14,17 +14,9 @@ endfunction function! ale_linters#javascript#standard#GetCommand(buffer) abort let l:executable = ale_linters#javascript#standard#GetExecutable(a:buffer) - - if ale#Has('win32') && l:executable =~? '\.js$' - " .js files have to be executed with Node on Windows. - let l:head = 'node ' . ale#Escape(l:executable) - else - let l:head = ale#Escape(l:executable) - endif - let l:options = ale#Var(a:buffer, 'javascript_standard_options') - return l:head + return ale#node#Executable(a:buffer, l:executable) \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' --stdin %s' endfunction diff --git a/ale_linters/sh/shell.vim b/ale_linters/sh/shell.vim index 8f5ca3a..cf5e4e6 100644 --- a/ale_linters/sh/shell.vim +++ b/ale_linters/sh/shell.vim @@ -17,18 +17,10 @@ if !exists('g:ale_sh_shell_default_shell') endif function! ale_linters#sh#shell#GetExecutable(buffer) abort - let l:banglines = getbufline(a:buffer, 1) + let l:shell_type = ale#handlers#sh#GetShellType(a:buffer) - " Take the shell executable from the hashbang, if we can. - if len(l:banglines) == 1 && l:banglines[0] =~# '^#!' - " Remove options like -e, etc. - let l:line = substitute(l:banglines[0], '--\?[a-zA-Z0-9]\+', '', 'g') - - for l:possible_shell in ['bash', 'tcsh', 'csh', 'zsh', 'sh'] - if l:line =~# l:possible_shell . '\s*$' - return l:possible_shell - endif - endfor + if !empty(l:shell_type) + return l:shell_type endif return ale#Var(a:buffer, 'sh_shell_default_shell') diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim index 5353683..3a2d33f 100644 --- a/ale_linters/sh/shellcheck.vim +++ b/ale_linters/sh/shellcheck.vim @@ -19,25 +19,35 @@ function! ale_linters#sh#shellcheck#GetExecutable(buffer) abort return ale#Var(a:buffer, 'sh_shellcheck_executable') endfunction -function! s:GetDialectArgument() abort - if exists('b:is_bash') && b:is_bash - return '-s bash' - elseif exists('b:is_sh') && b:is_sh - return '-s sh' - elseif exists('b:is_kornshell') && b:is_kornshell - return '-s ksh' +function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort + let l:shell_type = ale#handlers#sh#GetShellType(a:buffer) + + if !empty(l:shell_type) + return l:shell_type + endif + + " If there's no hashbang, try using Vim's buffer variables. + if get(b:, 'is_bash') + return 'bash' + elseif get(b:, 'is_sh') + return 'sh' + elseif get(b:, 'is_kornshell') + return 'ksh' endif return '' endfunction function! ale_linters#sh#shellcheck#GetCommand(buffer) abort + let l:options = ale#Var(a:buffer, 'sh_shellcheck_options') let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions') + let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer) return ale_linters#sh#shellcheck#GetExecutable(a:buffer) - \ . ' ' . ale#Var(a:buffer, 'sh_shellcheck_options') - \ . ' ' . (!empty(l:exclude_option) ? '-e ' . l:exclude_option : '') - \ . ' ' . s:GetDialectArgument() . ' -f gcc -' + \ . (!empty(l:options) ? ' ' . l:options : '') + \ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '') + \ . (!empty(l:dialect) ? ' -s ' . l:dialect : '') + \ . ' -f gcc -' endfunction call ale#linter#Define('sh', { diff --git a/autoload/ale.vim b/autoload/ale.vim index 9defbd8..6941a9a 100644 --- a/autoload/ale.vim +++ b/autoload/ale.vim @@ -48,6 +48,7 @@ function! ale#ShouldDoNothing(buffer) abort \ || ale#util#InSandbox() \ || !ale#Var(a:buffer, 'enabled') \ || ale#FileTooLarge() + \ || getbufvar(a:buffer, '&l:statusline') =~# 'CtrlPMode.*funky' endfunction " (delay, [linting_flag, buffer_number]) diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index 74ae0d9..c49bc9b 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -286,10 +286,6 @@ function! ale#engine#SetResults(buffer, loclist) abort if g:ale_set_quickfix || g:ale_set_loclist call ale#list#SetLists(a:buffer, a:loclist) - - if l:linting_is_done - call ale#list#CloseWindowIfNeeded(a:buffer) - endif endif if exists('*ale#statusline#Update') diff --git a/autoload/ale/fixers/clangformat.vim b/autoload/ale/fixers/clangformat.vim index b2ed7da..b50b704 100644 --- a/autoload/ale/fixers/clangformat.vim +++ b/autoload/ale/fixers/clangformat.vim @@ -1,3 +1,4 @@ +scriptencoding utf-8 " Author: Peter Renström " Description: Fixing C/C++ files with clang-format. diff --git a/autoload/ale/fixers/eslint.vim b/autoload/ale/fixers/eslint.vim index ce65c48..ce39349 100644 --- a/autoload/ale/fixers/eslint.vim +++ b/autoload/ale/fixers/eslint.vim @@ -2,22 +2,23 @@ " Description: Fixing files with eslint. function! s:FindConfig(buffer) abort - for l:filename in [ - \ '.eslintrc.js', - \ '.eslintrc.yaml', - \ '.eslintrc.yml', - \ '.eslintrc.json', - \ '.eslintrc', - \ 'package.json', - \] - let l:config = ale#path#FindNearestFile(a:buffer, l:filename) + for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) + for l:basename in [ + \ '.eslintrc.js', + \ '.eslintrc.yaml', + \ '.eslintrc.yml', + \ '.eslintrc.json', + \ '.eslintrc', + \] + let l:config = ale#path#Simplify(l:path . '/' . l:basename) - if !empty(l:config) - return l:config - endif + if filereadable(l:config) + return l:config + endif + endfor endfor - return '' + return ale#path#FindNearestFile(a:buffer, 'package.json') endfunction function! ale#fixers#eslint#Fix(buffer) abort @@ -28,17 +29,9 @@ function! ale#fixers#eslint#Fix(buffer) abort return 0 endif - if ale#Has('win32') && l:executable =~? 'eslint\.js$' - " For Windows, if we detect an eslint.js script, we need to execute - " it with node, or the file can be opened with a text editor. - let l:head = 'node ' . ale#Escape(l:executable) - else - let l:head = ale#Escape(l:executable) - endif - return { - \ 'command': l:head - \ . ' --config ' . ale#Escape(l:config) + \ 'command': ale#node#Executable(a:buffer, l:executable) + \ . ' -c ' . ale#Escape(l:config) \ . ' --fix %t', \ 'read_temporary_file': 1, \} diff --git a/autoload/ale/fixers/standard.vim b/autoload/ale/fixers/standard.vim index 6a0c6b6..443560e 100644 --- a/autoload/ale/fixers/standard.vim +++ b/autoload/ale/fixers/standard.vim @@ -11,16 +11,8 @@ endfunction function! ale#fixers#standard#Fix(buffer) abort let l:executable = ale#fixers#standard#GetExecutable(a:buffer) - if ale#Has('win32') && l:executable =~? 'cmd\.js$' - " For Windows, if we detect an standard.js script, we need to execute - " it with node, or the file can be opened with a text editor. - let l:head = 'node ' . ale#Escape(l:executable) - else - let l:head = ale#Escape(l:executable) - endif - return { - \ 'command': l:head + \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ' --fix %t', \ 'read_temporary_file': 1, \} diff --git a/autoload/ale/fixers/stylelint.vim b/autoload/ale/fixers/stylelint.vim index 7d5abb7..899fcf4 100644 --- a/autoload/ale/fixers/stylelint.vim +++ b/autoload/ale/fixers/stylelint.vim @@ -15,16 +15,8 @@ endfunction function! ale#fixers#stylelint#Fix(buffer) abort let l:executable = ale#fixers#stylelint#GetExecutable(a:buffer) - if ale#Has('win32') && l:executable =~? 'stylelint\.js$' - " For Windows, if we detect an stylelint.js script, we need to execute - " it with node, or the file can be opened with a text editor. - let l:head = 'node ' . ale#Escape(l:executable) - else - let l:head = ale#Escape(l:executable) - endif - return { - \ 'command': l:head + \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ' --fix %t', \ 'read_temporary_file': 1, \} diff --git a/autoload/ale/handlers/eslint.vim b/autoload/ale/handlers/eslint.vim index 6c5d75c..4ef7489 100644 --- a/autoload/ale/handlers/eslint.vim +++ b/autoload/ale/handlers/eslint.vim @@ -17,17 +17,9 @@ endfunction function! ale#handlers#eslint#GetCommand(buffer) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) - if ale#Has('win32') && l:executable =~? 'eslint\.js$' - " For Windows, if we detect an eslint.js script, we need to execute - " it with node, or the file can be opened with a text editor. - let l:head = 'node ' . ale#Escape(l:executable) - else - let l:head = ale#Escape(l:executable) - endif - let l:options = ale#Var(a:buffer, 'javascript_eslint_options') - return l:head + return ale#node#Executable(a:buffer, l:executable) \ . (!empty(l:options) ? ' ' . l:options : '') \ . ' -f unix --stdin --stdin-filename %s' endfunction diff --git a/autoload/ale/handlers/sh.vim b/autoload/ale/handlers/sh.vim new file mode 100644 index 0000000..894879e --- /dev/null +++ b/autoload/ale/handlers/sh.vim @@ -0,0 +1,20 @@ +" Author: w0rp + +" Get the shell type for a buffer, based on the hashbang line. +function! ale#handlers#sh#GetShellType(buffer) abort + let l:bang_line = get(getbufline(a:buffer, 1), 0, '') + + " Take the shell executable from the hashbang, if we can. + if l:bang_line[:1] is# '#!' + " Remove options like -e, etc. + let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g') + + for l:possible_shell in ['bash', 'tcsh', 'csh', 'zsh', 'sh'] + if l:command =~# l:possible_shell . '\s*$' + return l:possible_shell + endif + endfor + endif + + return '' +endfunction diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim index 80c045f..2cd773f 100644 --- a/autoload/ale/linter.vim +++ b/autoload/ale/linter.vim @@ -25,6 +25,7 @@ let s:default_ale_linters = { \ 'csh': ['shell'], \ 'go': ['gofmt', 'golint', 'go vet'], \ 'help': [], +\ 'python': ['flake8', 'mypy', 'pylint'], \ 'rust': ['cargo'], \ 'spec': [], \ 'text': [], diff --git a/autoload/ale/list.vim b/autoload/ale/list.vim index 7b2bf2c..ecf088a 100644 --- a/autoload/ale/list.vim +++ b/autoload/ale/list.vim @@ -56,6 +56,10 @@ function! s:FixList(list) abort return l:new_list endfunction +function! s:BufWinId(buffer) abort + return exists('*bufwinid') ? bufwinid(str2nr(a:buffer)) : 0 +endfunction + function! s:SetListsImpl(timer_id, buffer, loclist) abort let l:title = expand('#' . a:buffer . ':p') @@ -72,7 +76,7 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort " If windows support is off, bufwinid() may not exist. " We'll set result in the current window, which might not be correct, " but is better than nothing. - let l:win_id = exists('*bufwinid') ? bufwinid(str2nr(a:buffer)) : 0 + let l:win_id = s:BufWinId(a:buffer) if has('nvim') call setloclist(l:win_id, s:FixList(a:loclist), ' ', l:title) @@ -82,13 +86,11 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort endif endif - let l:keep_open = ale#Var(a:buffer, 'keep_list_window_open') - " Open a window to show the problems if we need to. " " We'll check if the current buffer's List is not empty here, so the " window will only be opened if the current buffer has problems. - if s:ShouldOpen(a:buffer) && (l:keep_open || !empty(a:loclist)) + if s:ShouldOpen(a:buffer) && !empty(a:loclist) let l:winnr = winnr() let l:mode = mode() let l:reset_visual_selection = l:mode is? 'v' || l:mode is# "\" @@ -96,10 +98,10 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort if g:ale_set_quickfix if !ale#list#IsQuickfixOpen() - execute 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) + silent! execute 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) endif elseif g:ale_set_loclist - execute 'lopen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) + silent! execute 'lopen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) endif " If focus changed, restore it (jump to the last window). @@ -117,10 +119,23 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort endif endif endif + + " If ALE isn't currently checking for more problems, close the window if + " needed now. This check happens inside of this timer function, so + " the window can be closed reliably. + if !ale#engine#IsCheckingBuffer(a:buffer) + call s:CloseWindowIfNeeded(a:buffer) + endif endfunction function! ale#list#SetLists(buffer, loclist) abort if get(g:, 'ale_set_lists_synchronously') == 1 + \|| getbufvar(a:buffer, 'ale_save_event_fired', 0) + " Update lists immediately if running a test synchronously, or if the + " buffer was saved. + " + " The lists need to be updated immediately when saving a buffer so + " that we can reliably close window automatically, if so configured. call s:SetListsImpl(-1, a:buffer, a:loclist) else call ale#util#StartPartialTimer( @@ -131,7 +146,7 @@ function! ale#list#SetLists(buffer, loclist) abort endif endfunction -function! s:CloseWindowIfNeededImpl(timer_id, buffer) abort +function! s:CloseWindowIfNeeded(buffer) abort if ale#Var(a:buffer, 'keep_list_window_open') || !s:ShouldOpen(a:buffer) return endif @@ -143,22 +158,14 @@ function! s:CloseWindowIfNeededImpl(timer_id, buffer) abort if empty(getqflist()) cclose endif - elseif g:ale_set_loclist && empty(getloclist(0)) - lclose + else + let l:win_id = s:BufWinId(a:buffer) + + if g:ale_set_loclist && empty(getloclist(l:win_id)) + lclose + endif endif " Ignore 'Cannot close last window' errors. catch /E444/ endtry endfunction - -function! ale#list#CloseWindowIfNeeded(buffer) abort - if get(g:, 'ale_set_lists_synchronously') == 1 - call s:CloseWindowIfNeededImpl(-1, a:buffer) - else - call ale#util#StartPartialTimer( - \ 0, - \ function('s:CloseWindowIfNeededImpl'), - \ [a:buffer], - \) - endif -endfunction diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim index b5525c9..b6c890c 100644 --- a/autoload/ale/lsp.vim +++ b/autoload/ale/lsp.vim @@ -242,10 +242,14 @@ function! s:HandleCommandMessage(job_id, message) abort call ale#lsp#HandleMessage(l:conn, a:message) endfunction -function! s:RegisterProject(conn, project_root) abort - if !has_key(a:conn.projects, a:project_root) +function! ale#lsp#RegisterProject(conn, project_root) abort + " Empty strings can't be used for Dictionary keys in NeoVim, due to E713. + " This appears to be a nonsensical bug in NeoVim. + let l:key = empty(a:project_root) ? '<>' : a:project_root + + if !has_key(a:conn.projects, l:key) " Tools without project roots are ready right away, like tsserver. - let a:conn.projects[a:project_root] = { + let a:conn.projects[l:key] = { \ 'initialized': empty(a:project_root), \ 'init_request_id': 0, \ 'message_queue': [], @@ -253,6 +257,12 @@ function! s:RegisterProject(conn, project_root) abort endif endfunction +function! ale#lsp#GetProject(conn, project_root) abort + let l:key = empty(a:project_root) ? '<>' : a:project_root + + return get(a:conn.projects, l:key, {}) +endfunction + " Start a program for LSP servers which run with executables. " " The job ID will be returned for for the program if it ran, otherwise @@ -285,7 +295,7 @@ function! ale#lsp#StartProgram(executable, command, project_root, callback) abor let l:conn.id = l:job_id " Add the callback to the List if it's not there already. call uniq(sort(add(l:conn.callback_list, a:callback))) - call s:RegisterProject(l:conn, a:project_root) + call ale#lsp#RegisterProject(l:conn, a:project_root) return l:job_id endfunction @@ -311,7 +321,7 @@ function! ale#lsp#ConnectToAddress(address, project_root, callback) abort let l:conn.id = a:address " Add the callback to the List if it's not there already. call uniq(sort(add(l:conn.callback_list, a:callback))) - call s:RegisterProject(l:conn, a:project_root) + call ale#lsp#RegisterProject(l:conn, a:project_root) return 1 endfunction @@ -344,7 +354,7 @@ function! ale#lsp#Send(conn_id, message, ...) abort return 0 endif - let l:project = get(l:conn.projects, l:project_root, {}) + let l:project = ale#lsp#GetProject(l:conn, l:project_root) if empty(l:project) return 0 diff --git a/autoload/ale/node.vim b/autoload/ale/node.vim index 54b53fb..f75280b 100644 --- a/autoload/ale/node.vim +++ b/autoload/ale/node.vim @@ -1,6 +1,8 @@ " Author: w0rp " Description: Functions for working with Node executables. +call ale#Set('windows_node_executable_path', 'node.exe') + " Given a buffer number, a base variable name, and a list of paths to search " for in ancestor directories, detect the executable path for a Node program. " @@ -20,3 +22,21 @@ function! ale#node#FindExecutable(buffer, base_var_name, path_list) abort return ale#Var(a:buffer, a:base_var_name . '_executable') endfunction + +" Create a executable string which executes a Node.js script command with a +" Node.js executable if needed. +" +" The executable string should not be escaped before passing it to this +" function, the executable string will be escaped when returned by this +" function. +" +" The executable is only prefixed for Windows machines +function! ale#node#Executable(buffer, executable) abort + if ale#Has('win32') && a:executable =~? '\.js$' + let l:node = ale#Var(a:buffer, 'windows_node_executable_path') + + return ale#Escape(l:node) . ' ' . ale#Escape(a:executable) + endif + + return ale#Escape(a:executable) +endfunction diff --git a/autoload/ale/sign.vim b/autoload/ale/sign.vim index 7ba8364..dc3c110 100644 --- a/autoload/ale/sign.vim +++ b/autoload/ale/sign.vim @@ -184,16 +184,6 @@ function! s:GroupLoclistItems(buffer, loclist) abort return l:grouped_items endfunction -function! ale#sign#SetSignColumnHighlight(has_problems) abort - highlight clear SignColumn - - if a:has_problems - highlight link SignColumn ALESignColumnWithErrors - else - highlight link SignColumn ALESignColumnWithoutErrors - endif -endfunction - function! s:UpdateLineNumbers(buffer, current_sign_list, loclist) abort let l:line_map = {} let l:line_numbers_changed = 0 @@ -224,24 +214,32 @@ function! s:BuildSignMap(current_sign_list, grouped_items) abort let l:sign_offset = g:ale_sign_offset for [l:line, l:sign_id, l:name] in a:current_sign_list - let l:sign_map[l:line] = { - \ 'current_id': l:sign_id, - \ 'current_name': l:name, + let l:sign_info = get(l:sign_map, l:line, { + \ 'current_id_list': [], + \ 'current_name_list': [], \ 'new_id': 0, \ 'new_name': '', \ 'items': [], - \} + \}) + " Increment the sign offset for new signs, by the maximum sign ID. if l:sign_id > l:sign_offset let l:sign_offset = l:sign_id endif + + " Remember the sign names and IDs in separate Lists, so they are easy + " to work with. + call add(l:sign_info.current_id_list, l:sign_id) + call add(l:sign_info.current_name_list, l:name) + + let l:sign_map[l:line] = l:sign_info endfor for l:group in a:grouped_items let l:line = l:group[0].lnum let l:sign_info = get(l:sign_map, l:line, { - \ 'current_id': 0, - \ 'current_name': '', + \ 'current_id_list': [], + \ 'current_name_list': [], \ 'new_id': 0, \ 'new_name': '', \ 'items': [], @@ -250,11 +248,18 @@ function! s:BuildSignMap(current_sign_list, grouped_items) abort let l:sign_info.new_name = ale#sign#GetSignName(l:group) let l:sign_info.items = l:group - if l:sign_info.current_name isnot# l:sign_info.new_name + let l:index = index( + \ l:sign_info.current_name_list, + \ l:sign_info.new_name + \) + + if l:index >= 0 + " We have a sign with this name already, so use the same ID. + let l:sign_info.new_id = l:sign_info.current_id_list[l:index] + else + " This sign name replaces the previous name, so use a new ID. let l:sign_info.new_id = l:sign_offset + 1 let l:sign_offset += 1 - else - let l:sign_info.new_id = l:sign_info.current_id endif let l:sign_map[l:line] = l:sign_info @@ -288,7 +293,7 @@ function! ale#sign#GetSignCommands(buffer, was_sign_set, sign_map) abort let l:item.sign_id = l:info.new_id endfor - if l:info.new_id isnot l:info.current_id + if index(l:info.current_id_list, l:info.new_id) < 0 call add(l:command_list, 'sign place ' \ . (l:info.new_id) \ . ' line=' . l:line_str @@ -301,12 +306,14 @@ function! ale#sign#GetSignCommands(buffer, was_sign_set, sign_map) abort " Remove signs without new IDs. for l:info in values(a:sign_map) - if l:info.current_id && l:info.current_id isnot l:info.new_id - call add(l:command_list, 'sign unplace ' - \ . (l:info.current_id) - \ . ' buffer=' . a:buffer - \) - endif + for l:current_id in l:info.current_id_list + if l:current_id isnot l:info.new_id + call add(l:command_list, 'sign unplace ' + \ . l:current_id + \ . ' buffer=' . a:buffer + \) + endif + endfor endfor " Remove the dummy sign to close the sign column if we need to. @@ -347,7 +354,19 @@ function! ale#sign#SetSigns(buffer, loclist) abort \ l:sign_map, \) + " Change the sign column color if the option is on. + if g:ale_change_sign_column_color && !empty(a:loclist) + highlight clear SignColumn + highlight link SignColumn ALESignColumnWithErrors + endif + for l:command in l:command_list silent! execute l:command endfor + + " Reset the sign column color when there are no more errors. + if g:ale_change_sign_column_color && empty(a:loclist) + highlight clear SignColumn + highlight link SignColumn ALESignColumnWithoutErrors + endif endfunction diff --git a/doc/ale.txt b/doc/ale.txt index 6c3be18..1fd801a 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -918,6 +918,22 @@ b:ale_warn_about_trailing_whitespace *b:ale_warn_about_trailing_whitespace* This option may be configured on a per buffer basis. +g:ale_windows_node_executable_path *g:ale_windows_node_executable_path* + *b:ale_windows_node_executable_path* + + Type: |String| + Default: `'node.exe'` + + This variable is used as the path to the executable to use for executing + scripts with Node.js on Windows. + + For Windows, any file with a `.js` file extension needs to be executed with + the node executable explicitly. Otherwise, Windows could try and open the + scripts with other applications, like a text editor. Therefore, these + scripts are executed with whatever executable is configured with this + setting. + + ------------------------------------------------------------------------------- 3.1. Highlights *ale-highlights* diff --git a/test/command_callback/test_shellcheck_command_callback.vader b/test/command_callback/test_shellcheck_command_callback.vader new file mode 100644 index 0000000..0d8fef6 --- /dev/null +++ b/test/command_callback/test_shellcheck_command_callback.vader @@ -0,0 +1,47 @@ +Before: + Save g:ale_sh_shellcheck_exclusions + Save g:ale_sh_shellcheck_executable + Save g:ale_sh_shellcheck_options + + unlet! g:ale_sh_shellcheck_exclusions + unlet! g:ale_sh_shellcheck_executable + unlet! g:ale_sh_shellcheck_options + + runtime ale_linters/sh/shellcheck.vim + +After: + Restore + + unlet! b:ale_sh_shellcheck_exclusions + unlet! b:ale_sh_shellcheck_executable + unlet! b:ale_sh_shellcheck_options + unlet! b:is_bash + + call ale#linter#Reset() + +Execute(The default shellcheck command should be correct): + AssertEqual + \ 'shellcheck -f gcc -', + \ ale_linters#sh#shellcheck#GetCommand(bufnr('')) + +Execute(The shellcheck command should accept options): + let b:ale_sh_shellcheck_options = '--foobar' + + AssertEqual + \ 'shellcheck --foobar -f gcc -', + \ ale_linters#sh#shellcheck#GetCommand(bufnr('')) + +Execute(The shellcheck command should accept options and exclusions): + let b:ale_sh_shellcheck_options = '--foobar' + let b:ale_sh_shellcheck_exclusions = 'foo,bar' + + AssertEqual + \ 'shellcheck --foobar -e foo,bar -f gcc -', + \ ale_linters#sh#shellcheck#GetCommand(bufnr('')) + +Execute(The shellcheck command should include the dialect): + let b:is_bash = 1 + + AssertEqual + \ 'shellcheck -s bash -f gcc -', + \ ale_linters#sh#shellcheck#GetCommand(bufnr('')) diff --git a/test/command_callback/test_standard_command_callback.vader b/test/command_callback/test_standard_command_callback.vader index fa90175..193ead8 100644 --- a/test/command_callback/test_standard_command_callback.vader +++ b/test/command_callback/test_standard_command_callback.vader @@ -67,7 +67,7 @@ Execute(.js files should be executed with node on Windows): \ ale_linters#javascript#standard#GetExecutable(bufnr('')) AssertEqual - \ 'node ' . ale#Escape(b:executable) . ' --stdin %s', + \ ale#Escape('node.exe') . ' ' . ale#Escape(b:executable) . ' --stdin %s', \ ale_linters#javascript#standard#GetCommand(bufnr('')) Execute(The global executable should be used otherwise): diff --git a/test/eslint-test-files/package.json b/test/eslint-test-files/package.json new file mode 100644 index 0000000..e69de29 diff --git a/test/eslint-test-files/react-app/subdir-with-config/.eslintrc b/test/eslint-test-files/react-app/subdir-with-config/.eslintrc new file mode 100644 index 0000000..e69de29 diff --git a/test/eslint-test-files/react-app/subdir-with-package-json/package.json b/test/eslint-test-files/react-app/subdir-with-package-json/package.json new file mode 100644 index 0000000..e69de29 diff --git a/test/fixers/test_eslint_fixer_callback.vader b/test/fixers/test_eslint_fixer_callback.vader index 58f7561..21eb450 100644 --- a/test/fixers/test_eslint_fixer_callback.vader +++ b/test/fixers/test_eslint_fixer_callback.vader @@ -13,22 +13,45 @@ Execute(The path to eslint.js should be run on Unix): \ 'read_temporary_file': 1, \ 'command': \ ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) - \ . ' --config ' . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/.eslintrc.js')) + \ . ' -c ' . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/.eslintrc.js')) \ . ' --fix %t', \ }, \ ale#fixers#eslint#Fix(bufnr('')) -Execute(The eslint fixer with eslint.js should be run with node on Windows): - call ale#test#SetFilename('../eslint-test-files/react-app/subdir/testfile.js') - let g:ale_has_override['win32'] = 1 +Execute(The lower priority configuration file in a nested directory should be preferred): + call ale#test#SetFilename('../eslint-test-files/react-app/subdir-with-config/testfile.js') - " We have to execute the file with node. AssertEqual \ { \ 'read_temporary_file': 1, - \ 'command': 'node ' - \ . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) - \ . ' --config ' . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/.eslintrc.js')) + \ 'command': + \ ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' -c ' . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/subdir-with-config/.eslintrc')) + \ . ' --fix %t', + \ }, + \ ale#fixers#eslint#Fix(bufnr('')) + +Execute(package.json should be used as a last resort): + call ale#test#SetFilename('../eslint-test-files/react-app/subdir-with-package-json/testfile.js') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': + \ ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' -c ' . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/.eslintrc.js')) + \ . ' --fix %t', + \ }, + \ ale#fixers#eslint#Fix(bufnr('')) + + call ale#test#SetFilename('../eslint-test-files/package.json') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': + \ ale#Escape(simplify(g:dir . '/../eslint-test-files/node_modules/.bin/eslint')) + \ . ' -c ' . ale#Escape(simplify(g:dir . '/../eslint-test-files/package.json')) \ . ' --fix %t', \ }, \ ale#fixers#eslint#Fix(bufnr('')) diff --git a/test/fixers/test_standard_fixer_callback.vader b/test/fixers/test_standard_fixer_callback.vader index 934b07b..88169bb 100644 --- a/test/fixers/test_standard_fixer_callback.vader +++ b/test/fixers/test_standard_fixer_callback.vader @@ -25,7 +25,7 @@ Execute(The standard fixer with standard.js should be run with node on Windows): AssertEqual \ { \ 'read_temporary_file': 1, - \ 'command': 'node ' + \ 'command': ale#Escape('node.exe') . ' ' \ . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/node_modules/standard/bin/cmd.js')) \ . ' --fix %t', \ }, diff --git a/test/fixers/test_stylelint_fixer_callback.vader b/test/fixers/test_stylelint_fixer_callback.vader index 6c99196..482704d 100644 --- a/test/fixers/test_stylelint_fixer_callback.vader +++ b/test/fixers/test_stylelint_fixer_callback.vader @@ -25,7 +25,7 @@ Execute(The stylelint fixer with stylelint.js should be run with node on Windows AssertEqual \ { \ 'read_temporary_file': 1, - \ 'command': 'node ' + \ 'command': ale#Escape('node.exe') . ' ' \ . ale#Escape(simplify(g:dir . '/../eslint-test-files/react-app/node_modules/stylelint/bin/stylelint.js')) \ . ' --fix %t', \ }, diff --git a/test/lsp/test_lsp_connections.vader b/test/lsp/test_lsp_connections.vader index 1faa7a0..5549b1f 100644 --- a/test/lsp/test_lsp_connections.vader +++ b/test/lsp/test_lsp_connections.vader @@ -3,6 +3,7 @@ Before: After: unlet! b:data + unlet! b:conn Execute(GetNextMessageID() should increment appropriately): " We should get the initial ID, and increment a bit. @@ -220,3 +221,51 @@ Execute(ale#lsp#ReadMessageData() should handle a message with part of a second \ . '{"id":2,"jsonrpc":"2.0","result":{"foo":"barÜ"}}' \ . b:data \ ) + +Execute(Projects with regular project roots should be registered correctly): + let b:conn = {'projects': {}} + + call ale#lsp#RegisterProject(b:conn, '/foo/bar') + + AssertEqual + \ { + \ 'projects': { + \ '/foo/bar': {'initialized': 0, 'message_queue': [], 'init_request_id': 0}, + \ }, + \ }, + \ b:conn + +Execute(Projects with regular project roots should be fetched correctly): + let b:conn = { + \ 'projects': { + \ '/foo/bar': {'initialized': 0, 'message_queue': [], 'init_request_id': 0}, + \ }, + \} + + AssertEqual + \ {'initialized': 0, 'message_queue': [], 'init_request_id': 0}, + \ ale#lsp#GetProject(b:conn, '/foo/bar') + +Execute(Projects with empty project roots should be registered correctly): + let b:conn = {'projects': {}} + + call ale#lsp#RegisterProject(b:conn, '') + + AssertEqual + \ { + \ 'projects': { + \ '<>': {'initialized': 1, 'message_queue': [], 'init_request_id': 0}, + \ }, + \ }, + \ b:conn + +Execute(Projects with empty project roots should be fetched correctly): + let b:conn = { + \ 'projects': { + \ '<>': {'initialized': 1, 'message_queue': [], 'init_request_id': 0}, + \ }, + \} + + AssertEqual + \ {'initialized': 1, 'message_queue': [], 'init_request_id': 0}, + \ ale#lsp#GetProject(b:conn, '') diff --git a/test/sign/test_sign_column_highlighting.vader b/test/sign/test_sign_column_highlighting.vader index 882b03d..4457a45 100644 --- a/test/sign/test_sign_column_highlighting.vader +++ b/test/sign/test_sign_column_highlighting.vader @@ -1,4 +1,6 @@ Before: + Save g:ale_change_sign_column_color + function! ParseHighlight(name) abort redir => l:output silent execute 'highlight ' . a:name @@ -20,14 +22,34 @@ Before: let g:sign_highlight = ParseHighlight('SignColumn') After: + Restore + delfunction ParseHighlight call SetHighlight('SignColumn', g:sign_highlight) delfunction SetHighlight unlet! g:sign_highlight + sign unplace * + +Execute(The SignColumn highlight shouldn't be changed if the option is off): + let g:ale_change_sign_column_color = 0 + let b:sign_highlight = ParseHighlight('SignColumn') + + call ale#sign#SetSigns(bufnr(''), [ + \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'W', 'text': 'x'}, + \]) + AssertEqual b:sign_highlight, ParseHighlight('SignColumn') + + call ale#sign#SetSigns(bufnr(''), []) + AssertEqual b:sign_highlight, ParseHighlight('SignColumn') + Execute(The SignColumn highlight should be set and reset): - call ale#sign#SetSignColumnHighlight(1) + let g:ale_change_sign_column_color = 1 + + call ale#sign#SetSigns(bufnr(''), [ + \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'W', 'text': 'x'}, + \]) AssertEqual 'links to ALESignColumnWithErrors', ParseHighlight('SignColumn') - call ale#sign#SetSignColumnHighlight(0) + call ale#sign#SetSigns(bufnr(''), []) AssertEqual 'links to ALESignColumnWithoutErrors', ParseHighlight('SignColumn') diff --git a/test/sign/test_sign_placement.vader b/test/sign/test_sign_placement.vader index abae765..a196905 100644 --- a/test/sign/test_sign_placement.vader +++ b/test/sign/test_sign_placement.vader @@ -266,3 +266,14 @@ Execute(It should be possible to clear signs with empty lists): Execute(No exceptions should be thrown when setting signs for invalid buffers): call ale#sign#SetSigns(123456789, [{'lnum': 15, 'col': 2, 'type': 'W', 'text': 'e'}]) + +Execute(Signs should be removed when lines have multiple sign IDs on them): + " We can fail to remove signs if there are multiple signs on one line, + " say after deleting lines in Vim, etc. + exec 'sign place 1000347 line=3 name=ALEErrorSign buffer=' . bufnr('') + exec 'sign place 1000348 line=3 name=ALEWarningSign buffer=' . bufnr('') + exec 'sign place 1000349 line=10 name=ALEErrorSign buffer=' . bufnr('') + exec 'sign place 1000350 line=10 name=ALEWarningSign buffer=' . bufnr('') + + call ale#sign#SetSigns(bufnr(''), []) + AssertEqual [], ParseSigns() diff --git a/test/test_eslint_executable_detection.vader b/test/test_eslint_executable_detection.vader index 30ae38d..411fa13 100644 --- a/test/test_eslint_executable_detection.vader +++ b/test/test_eslint_executable_detection.vader @@ -58,7 +58,7 @@ Execute(eslint.js executables should be run with node on Windows): " We have to execute the file with node. AssertEqual - \ 'node ''' - \ . g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js' - \ . ''' -f unix --stdin --stdin-filename %s', + \ ale#Escape('node.exe') . ' ' + \ . ale#Escape(g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js') + \ . ' -f unix --stdin --stdin-filename %s', \ ale#handlers#eslint#GetCommand(bufnr('')) diff --git a/test/test_list_opening.vader b/test/test_list_opening.vader index 7d386d8..63b30ef 100644 --- a/test/test_list_opening.vader +++ b/test/test_list_opening.vader @@ -6,12 +6,14 @@ Before: Save g:ale_keep_list_window_open Save g:ale_list_window_size Save g:ale_buffer_info + Save g:ale_set_lists_synchronously let g:ale_set_loclist = 1 let g:ale_set_quickfix = 0 let g:ale_open_list = 0 let g:ale_keep_list_window_open = 0 let g:ale_list_window_size = 10 + let g:ale_set_lists_synchronously = 1 let g:loclist = [ \ {'bufnr': bufnr(''), 'lnum': 5, 'col': 5, 'text': 'x'}, @@ -70,17 +72,14 @@ Execute(The quickfix window should open for just the loclist): " It should not open for an empty list. call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert !ale#list#IsQuickfixOpen() " With a non-empty loclist, the window must open. call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert ale#list#IsQuickfixOpen() " Clear the list and it should close again. call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert !ale#list#IsQuickfixOpen() Execute(The quickfix window height should be correct for the loclist): @@ -88,7 +87,6 @@ Execute(The quickfix window height should be correct for the loclist): let g:ale_list_window_size = 7 call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) AssertEqual 7, GetQuickfixHeight() @@ -97,7 +95,6 @@ Execute(The quickfix window height should be correct for the loclist with buffer let b:ale_list_window_size = 8 call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) AssertEqual 8, GetQuickfixHeight() @@ -107,16 +104,13 @@ Execute(The quickfix window should stay open for just the loclist): " The window should stay open after even after it is made blank again. call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert ale#list#IsQuickfixOpen() Execute(The quickfix window should not open by default when quickfix is on): let g:ale_set_quickfix = 1 call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert !ale#list#IsQuickfixOpen() Execute(The quickfix window should open for the quickfix list): @@ -129,24 +123,20 @@ Execute(The quickfix window should open for the quickfix list): " It should not open for an empty list. call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert !ale#list#IsQuickfixOpen(), 'The quickfix window was opened when the list was empty' " With a non-empty quickfix list, the window must open. call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert ale#list#IsQuickfixOpen(), 'The quickfix window was closed when the list was not empty' " Clear this List. The window should stay open, as there are other items. let g:ale_buffer_info[bufnr('')].loclist = [] call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert ale#list#IsQuickfixOpen(), 'The quickfix window closed even though there are items in another buffer' " Clear the other List now. Now the window should close. call remove(g:ale_buffer_info, bufnr('') + 1) call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert !ale#list#IsQuickfixOpen(), 'The quickfix window was not closed' Execute(The quickfix window should stay open for the quickfix list): @@ -156,9 +146,7 @@ Execute(The quickfix window should stay open for the quickfix list): " The window should stay open after even after it is made blank again. call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert ale#list#IsQuickfixOpen() Execute(The quickfix window height should be correct for the quickfix list): @@ -167,7 +155,6 @@ Execute(The quickfix window height should be correct for the quickfix list): let g:ale_list_window_size = 7 call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) AssertEqual 7, GetQuickfixHeight() @@ -177,7 +164,6 @@ Execute(The quickfix window height should be correct for the quickfix list with let b:ale_list_window_size = 8 call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) AssertEqual 8, GetQuickfixHeight() @@ -192,9 +178,7 @@ Execute(The buffer ale_keep_list_window_open option should be respected): let b:ale_keep_list_window_open = 1 call ale#list#SetLists(bufnr('%'), g:loclist) - call ale#list#CloseWindowIfNeeded(bufnr('')) call ale#list#SetLists(bufnr('%'), []) - call ale#list#CloseWindowIfNeeded(bufnr('')) Assert ale#list#IsQuickfixOpen() @@ -205,12 +189,19 @@ Execute(The ale_open_list='on_save' option should work): " The list shouldn't open yet, the event wasn't fired. Assert !ale#list#IsQuickfixOpen() + " Turn this option off, to ensure that we update lists immediately when we + " save buffers. + let g:ale_set_lists_synchronously = 0 let b:ale_save_event_fired = 1 call ale#list#SetLists(bufnr('%'), g:loclist) " Now the list should have opened. Assert ale#list#IsQuickfixOpen() + call ale#list#SetLists(bufnr('%'), []) + " The window should close again when the loclist is empty. + Assert !ale#list#IsQuickfixOpen() + Execute(The window shouldn't open on save when ale_open_list=0): let b:ale_open_list = 0 let b:ale_save_event_fired = 1 diff --git a/test/test_set_list_timers.vader b/test/test_set_list_timers.vader index 90aacb5..f8fcb6a 100644 --- a/test/test_set_list_timers.vader +++ b/test/test_set_list_timers.vader @@ -27,12 +27,3 @@ Execute(The SetLists function should work when run in a timer): \ 'type': 'E', \ 'pattern': '', \}], getloclist(0) - -Execute(The CloseWindowIfNeeded function should work when run in a timer): - let g:ale_open_list = 1 - lopen - - call ale#list#CloseWindowIfNeeded(bufnr('')) - sleep 1ms - - Assert !ale#list#IsQuickfixOpen(), 'The window was not closed!' diff --git a/test/test_shell_detection.vader b/test/test_shell_detection.vader new file mode 100644 index 0000000..37cf43c --- /dev/null +++ b/test/test_shell_detection.vader @@ -0,0 +1,83 @@ +Before: + runtime ale_linters/sh/shell.vim + runtime ale_linters/sh/shellcheck.vim + +After: + call ale#linter#Reset() + + unlet! b:is_bash + unlet! b:is_sh + unlet! b:is_kornshell + +Given(A file with a Bash hashbang): + #!/bin/bash + +Execute(/bin/bash should be detected appropriately): + AssertEqual 'bash', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'bash', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'bash', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file with /bin/sh): + #!/usr/bin/env sh -eu --foobar + +Execute(/bin/sh should be detected appropriately): + AssertEqual 'sh', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'sh', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'sh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file with bash as an argument to env): + #!/usr/bin/env bash + +Execute(/usr/bin/env bash should be detected appropriately): + AssertEqual 'bash', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'bash', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'bash', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file with a tcsh hash bang and arguments): + #!/usr/bin/env tcsh -eu --foobar + +Execute(tcsh should be detected appropriately): + AssertEqual 'tcsh', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'tcsh', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'tcsh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file with a zsh hash bang and arguments): + #!/usr/bin/env zsh -eu --foobar + +Execute(zsh should be detected appropriately): + AssertEqual 'zsh', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'zsh', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'zsh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file with a csh hash bang and arguments): + #!/usr/bin/env csh -eu --foobar + +Execute(zsh should be detected appropriately): + AssertEqual 'csh', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'csh', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'csh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file with a sh hash bang and arguments): + #!/usr/bin/env sh -eu --foobar + +Execute(sh should be detected appropriately): + AssertEqual 'sh', ale#handlers#sh#GetShellType(bufnr('')) + AssertEqual 'sh', ale_linters#sh#shell#GetExecutable(bufnr('')) + AssertEqual 'sh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Given(A file without a hashbang): + +Execute(The bash dialect should be used for shellcheck if b:is_bash is 1): + let b:is_bash = 1 + + AssertEqual 'bash', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Execute(The sh dialect should be used for shellcheck if b:is_sh is 1): + let b:is_sh = 1 + + AssertEqual 'sh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) + +Execute(The ksh dialect should be used for shellcheck if b:is_kornshell is 1): + let b:is_kornshell = 1 + + AssertEqual 'ksh', ale_linters#sh#shellcheck#GetDialectArgument(bufnr('')) diff --git a/test/test_should_do_nothing_conditions.vader b/test/test_should_do_nothing_conditions.vader new file mode 100644 index 0000000..4d6facf --- /dev/null +++ b/test/test_should_do_nothing_conditions.vader @@ -0,0 +1,12 @@ +Before: + Save &l:statusline + +After: + Restore + +Execute(ALE shouldn't do much of anything for ctrlp-funky buffers): + Assert !ale#ShouldDoNothing(bufnr('')), 'The preliminary check failed' + + let &l:statusline = '%#CtrlPMode2# prt %*%#CtrlPMode1# line %* ={%#CtrlPMode1# funky %*}= <-> %=%<%#CtrlPMode2# %{getcwd()} %*' + + Assert ale#ShouldDoNothing(bufnr(''))