diff options
59 files changed, 1228 insertions, 314 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..d9b95d6f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# Top-most EditorConfig file +root = true + +# Match and apply these rules for all file +# types you open in your code editor +[*] +# Unix-style newlines +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true @@ -1,5 +1,6 @@ /init.vim /doc/tags .* +!.editorconfig *.obj tags diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8df52844..26129564 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,7 +129,7 @@ giving some unfair preference to any particular tool or language. The "online documentation" file used for this project lives in `doc/ale.txt`. This is the file used for generating `:help` text inside Vim itself. There are -some guidlines to follow for this file. +some guidelines to follow for this file. 1. Keep all text within a column size of 79 characters, inclusive. 2. Open a section with 79 `=` or `-` characters, for headings and subheadings. @@ -36,13 +36,14 @@ servers with similar enough protocols, like `tsserver`. 2. [How can I keep the sign gutter open?](#faq-keep-signs) 3. [How can I change the signs ALE uses?](#faq-change-signs) 4. [How can I show errors or warnings in my statusline?](#faq-statusline) - 5. [How can I change the format for echo messages?](#faq-echo-format) - 6. [How can I execute some code when ALE stops linting?](#faq-autocmd) - 7. [How can I navigate between errors quickly?](#faq-navigation) - 8. [How can I run linters only when I save files?](#faq-lint-on-save) - 9. [How can I use the quickfix list instead of the loclist?](#faq-quickfix) - 10. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint) - 11. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad) + 5. [How can I show errors or warnings in my lightline?](#faq-lightline) + 6. [How can I change the format for echo messages?](#faq-echo-format) + 7. [How can I execute some code when ALE stops linting?](#faq-autocmd) + 8. [How can I navigate between errors quickly?](#faq-navigation) + 9. [How can I run linters only when I save files?](#faq-lint-on-save) + 10. [How can I use the quickfix list instead of the loclist?](#faq-quickfix) + 11. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint) + 12. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad) <a name="supported-languages"></a> @@ -103,17 +104,18 @@ formatting. | Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) | | JavaScript | [eslint](http://eslint.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [flow](https://flowtype.org/), [prettier](https://github.com/prettier/prettier), prettier-eslint >= 4.2.0, prettier-standard, [standard](http://standardjs.com/), [xo](https://github.com/sindresorhus/xo) | JSON | [jsonlint](http://zaa.ch/jsonlint/), [prettier](https://github.com/prettier/prettier) | -| Kotlin | [kotlinc](https://kotlinlang.org) !!, [ktlint](https://ktlint.github.io) !! see `:help ale-integration-kotlin` for configuration instructions +| Kotlin | [kotlinc](https://kotlinlang.org) !!, [ktlint](https://ktlint.github.io) !! see `:help ale-integration-kotlin` for configuration instructions | | LaTeX | [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck), [proselint](http://proselint.com/) | +| LLVM | [llc](https://llvm.org/docs/CommandGuide/llc.html) | | Lua | [luacheck](https://github.com/mpeterv/luacheck) | -| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale) | +| Markdown | [mdl](https://github.com/mivok/markdownlint), [proselint](http://proselint.com/), [vale](https://github.com/ValeLint/vale), [remark-lint](https://github.com/wooorm/remark-lint) !! | | MATLAB | [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) | | Nim | [nim check](https://nim-lang.org/docs/nimc.html) !! | | nix | [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate) | | nroff | [proselint](http://proselint.com/)| | Objective-C | [clang](http://clang.llvm.org/) | | Objective-C++ | [clang](http://clang.llvm.org/) | -| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions +| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions | | Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic) | | PHP | [hack](http://hacklang.org/), [langserver](https://github.com/felixfbecker/php-language-server), [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer) | | Pod | [proselint](http://proselint.com/)| @@ -121,7 +123,7 @@ formatting. | Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) | | Python | [autopep8](https://github.com/hhatto/autopep8), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pylint](https://www.pylint.org/) !!, [yapf](https://github.com/google/yapf) | | R | [lintr](https://github.com/jimhester/lintr) | -| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions +| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-integration-reason-merlin` for configuration instructions | | reStructuredText | [proselint](http://proselint.com/) | | RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) | | Ruby | [brakeman](http://brakemanscanner.org/) !!, [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) !!, [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) | @@ -129,7 +131,7 @@ formatting. | SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) | | SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint), [prettier](https://github.com/prettier/prettier) | | Scala | [scalac](http://scala-lang.org), [scalastyle](http://www.scalastyle.org) | -| Slim | [slim-lint](https://github.com/sds/slim-lint) +| Slim | [slim-lint](https://github.com/sds/slim-lint) | | SML | [smlnj](http://www.smlnj.org/) | | Solidity | [solium](https://github.com/duaraghav8/Solium) | | Stylus | [stylelint](https://github.com/stylelint/stylelint) | @@ -144,7 +146,7 @@ formatting. | Vim | [vint](https://github.com/Kuniwak/vint) | | Vim help^ | [proselint](http://proselint.com/)| | XHTML | [proselint](http://proselint.com/)| -| XML | [xmllint](http://xmlsoft.org/xmllint.html/)| +| XML | [xmllint](http://xmlsoft.org/xmllint.html)| | YAML | [swaglint](https://github.com/byCedric/swaglint), [yamllint](https://yamllint.readthedocs.io/) | <a name="usage"></a> @@ -407,9 +409,70 @@ set statusline=%{LinterStatus()} See `:help ale#statusline#Count()` for more information. +<a name="faq-lightline"></a> + +### 5.v. How can I show errors or warnings in my lightline? + +[lightline](https://github.com/itchyny/lightline.vim) does not have built-in +support for ALE, nevertheless it's easy to do it yourself: + +```vim +" This is regular lightline configuration, we just added +" 'linter_warnings', 'linter_errors' and 'linter_ok' to +" the active right panel. Feel free to move it anywhere. +" `component_expand' and `component_type' are required. +" +" For more info on how this works, see lightline documentation. +let g:lightline = { + \ 'active': { + \ 'right': [ [ 'lineinfo' ], + \ [ 'percent' ], + \ [ 'linter_warnings', 'linter_errors', 'linter_ok' ], + \ [ 'fileformat', 'fileencoding', 'filetype' ] ] + \ }, + \ 'component_expand': { + \ 'linter_warnings': 'LightlineLinterWarnings', + \ 'linter_errors': 'LightlineLinterErrors', + \ 'linter_ok': 'LightlineLinterOK' + \ }, + \ 'component_type': { + \ 'linter_warnings': 'warning', + \ 'linter_errors': 'error', + \ 'linter_ok': 'ok' + \ }, + \ } + +autocmd User ALELint call lightline#update() + +" ale + lightline +function! LightlineLinterWarnings() abort + let l:counts = ale#statusline#Count(bufnr('')) + let l:all_errors = l:counts.error + l:counts.style_error + let l:all_non_errors = l:counts.total - l:all_errors + return l:counts.total == 0 ? '' : printf('%d --', all_non_errors) +endfunction + +function! LightlineLinterErrors() abort + let l:counts = ale#statusline#Count(bufnr('')) + let l:all_errors = l:counts.error + l:counts.style_error + let l:all_non_errors = l:counts.total - l:all_errors + return l:counts.total == 0 ? '' : printf('%d >>', all_errors) +endfunction + +function! LightlineLinterOK() abort + let l:counts = ale#statusline#Count(bufnr('')) + let l:all_errors = l:counts.error + l:counts.style_error + let l:all_non_errors = l:counts.total - l:all_errors + return l:counts.total == 0 ? '✓' : '' +endfunction +``` + +See `:help ale#statusline#Count()` and [lightline documentation](https://github.com/itchyny/lightline.vim#advanced-configuration) +for more information. + <a name="faq-echo-format"></a> -### 5.v. How can I change the format for echo messages? +### 5.vi. How can I change the format for echo messages? There are 3 global options that allow customizing the echoed message. @@ -434,7 +497,7 @@ Will give you: <a name="faq-autocmd"></a> -### 5.vi. How can I execute some code when ALE stops linting? +### 5.vii. How can I execute some code when ALE stops linting? ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html) event whenever has a linter has been successfully executed and processed. This @@ -449,7 +512,7 @@ augroup END <a name="faq-navigation"></a> -### 5.vii. How can I navigate between errors quickly? +### 5.viii. How can I navigate between errors quickly? ALE offers some commands with `<Plug>` keybinds for moving between warnings and errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors @@ -465,7 +528,7 @@ For more information, consult the online documentation with <a name="faq-lint-on-save"></a> -### 5.viii. How can I run linters only when I save files? +### 5.ix. How can I run linters only when I save files? ALE offers an option `g:ale_lint_on_save` for enabling running the linters when files are saved. This option is enabled by default. If you only @@ -485,7 +548,7 @@ files, you can set `g:ale_lint_on_save` to `0`. <a name="faq-quickfix"></a> -### 5.ix. How can I use the quickfix list instead of the loclist? +### 5.x. How can I use the quickfix list instead of the loclist? The quickfix list can be enabled by turning the `g:ale_set_quickfix` option on. If you wish to also disable the loclist, you can disable @@ -512,7 +575,7 @@ let g:ale_keep_list_window_open = 1 <a name="faq-jsx-stylelint-eslint"></a> -### 5.x. How can I check JSX files with both stylelint and eslint? +### 5.xi. How can I check JSX files with both stylelint and eslint? If you configure ALE options correctly in your vimrc file, and install the right tools, you can check JSX files with stylelint and eslint. @@ -545,7 +608,7 @@ no linter will be run twice for the same file. <a name="faq-my-battery-is-sad"></a> -### 5.xi. Will this plugin eat all of my laptop battery power? +### 5.xii. Will this plugin eat all of my laptop battery power? ALE takes advantage of the power of various tools to check your code. This of course means that CPU time will be used to continuously check your code. If you diff --git a/ale_linters/elm/make.vim b/ale_linters/elm/make.vim index 4038e3b4..3783b5e3 100644 --- a/ale_linters/elm/make.vim +++ b/ale_linters/elm/make.vim @@ -71,11 +71,11 @@ function! ale_linters#elm#make#GetCommand(buffer) abort " The elm-make compiler, at the time of this writing, uses '/dev/null' as " a sort of flag to tell the compiler not to generate an output file, - " which is why this is hard coded here. + " which is why this is hard coded here. It does not use NUL on Windows. " Source: https://github.com/elm-lang/elm-make/blob/master/src/Flags.hs let l:elm_cmd = ale#Escape(l:elm_exe) \ . ' --report=json' - \ . ' --output=' . ale#Escape(g:ale#util#nul_file) + \ . ' --output=/dev/null' return l:dir_set_cmd . ' ' . l:elm_cmd . ' %t' endfunction diff --git a/ale_linters/llvm/llc.vim b/ale_linters/llvm/llc.vim new file mode 100644 index 00000000..0a4903eb --- /dev/null +++ b/ale_linters/llvm/llc.vim @@ -0,0 +1,35 @@ +" Author: rhysd <https://rhysd.github.io> +" Description: Support for checking LLVM IR with llc + +call ale#Set('llvm_llc_executable', 'llc') + +function! ale_linters#llvm#llc#GetExecutable(buffer) abort + return ale#Var(a:buffer, 'llvm_llc_executable') +endfunction + +function! ale_linters#llvm#llc#GetCommand(buffer) abort + return ale#Escape(ale_linters#llvm#llc#GetExecutable(a:buffer)) + \ . ' -filetype=null -o=' + \ . ale#Escape(g:ale#util#nul_file) +endfunction + +function! ale_linters#llvm#llc#HandleErrors(buffer, lines) abort + " Handle '{path}: {file}:{line}:{col}: error: {message}' format + let l:pattern = '\v^[a-zA-Z]?:?[^:]+: [^:]+:(\d+):(\d+): (.+)$' + let l:matches = ale#util#GetMatches(a:lines, l:pattern) + + return map(l:matches, "{ + \ 'lnum': str2nr(v:val[1]), + \ 'col': str2nr(v:val[2]), + \ 'text': v:val[3], + \ 'type': 'E', + \}") +endfunction + +call ale#linter#Define('llvm', { +\ 'name': 'llc', +\ 'executable_callback': 'ale_linters#llvm#llc#GetExecutable', +\ 'output_stream': 'stderr', +\ 'command_callback': 'ale_linters#llvm#llc#GetCommand', +\ 'callback': 'ale_linters#llvm#llc#HandleErrors', +\}) diff --git a/ale_linters/lua/luacheck.vim b/ale_linters/lua/luacheck.vim index e15b7301..9f9ca4c4 100644 --- a/ale_linters/lua/luacheck.vim +++ b/ale_linters/lua/luacheck.vim @@ -26,6 +26,12 @@ function! ale_linters#lua#luacheck#Handle(buffer, lines) abort let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) + if !ale#Var(a:buffer, 'warn_about_trailing_whitespace') + \ && l:match[3] is# 'W' + \ && index(range(611, 614), str2nr(l:match[4])) >= 0 + continue + endif + call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, diff --git a/ale_linters/markdown/remark_lint.vim b/ale_linters/markdown/remark_lint.vim new file mode 100644 index 00000000..5b3b3d47 --- /dev/null +++ b/ale_linters/markdown/remark_lint.vim @@ -0,0 +1,28 @@ +" Author rhysd https://rhysd.github.io/ +" Description: remark-lint for Markdown files + +function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort + " matches: ' 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint' + let l:pattern = '^ \+\(\d\+\):\(\d\+\) \(warning\|error\) \(.\+\)$' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:pattern) + call add(l:output, { + \ 'lnum': l:match[1] + 0, + \ 'col': l:match[2] + 0, + \ 'type': l:match[3] is# 'error' ? 'E' : 'W', + \ 'text': l:match[4], + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('markdown', { +\ 'name': 'remark-lint', +\ 'executable': 'remark', +\ 'command': 'remark --no-stdout --no-color %s', +\ 'callback': 'ale_linters#markdown#remark_lint#Handle', +\ 'lint_file': 1, +\ 'output_stream': 'stderr', +\}) diff --git a/ale_linters/scala/scalastyle.vim b/ale_linters/scala/scalastyle.vim index ea56c0e4..f78fd749 100644 --- a/ale_linters/scala/scalastyle.vim +++ b/ale_linters/scala/scalastyle.vim @@ -8,10 +8,21 @@ let g:ale_scalastyle_config_loc = \ get(g:, 'ale_scalastyle_config_loc', '') function! ale_linters#scala#scalastyle#Handle(buffer, lines) abort + " Look for help output from scalastyle first, which indicates that no + " configuration file was found. + for l:line in a:lines[:10] + if l:line =~# '-c, --config' + return [{ + \ 'lnum': 1, + \ 'text': '(See :help ale-scala-scalastyle)' + \ . ' No scalastyle configuration file was found.', + \}] + endif + endfor + " Matches patterns like the following: " " warning file=/home/blurble/Doop.scala message=Missing or badly formed ScalaDoc: Extra @param foobles line=190 - let l:patterns = [ \ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\)$', \ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\) column=\(\d\+\)$', diff --git a/autoload/ale.vim b/autoload/ale.vim index 6941a9a5..6500b309 100644 --- a/autoload/ale.vim +++ b/autoload/ale.vim @@ -38,17 +38,51 @@ function! ale#FileTooLarge() abort return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0 endfunction +let s:getcmdwintype_exists = exists('*getcmdwintype') + " A function for checking various conditions whereby ALE just shouldn't " attempt to do anything, say if particular buffer types are open in Vim. function! ale#ShouldDoNothing(buffer) abort + " The checks are split into separate if statements to make it possible to + " profile each check individually with Vim's profiling tools. + + " Don't perform any checks when newer NeoVim versions are exiting. + if get(v:, 'exiting', v:null) isnot v:null + return 1 + endif + " Do nothing for blacklisted files - " OR if ALE is running in the sandbox - return index(g:ale_filetype_blacklist, &filetype) >= 0 - \ || (exists('*getcmdwintype') && !empty(getcmdwintype())) - \ || ale#util#InSandbox() - \ || !ale#Var(a:buffer, 'enabled') - \ || ale#FileTooLarge() - \ || getbufvar(a:buffer, '&l:statusline') =~# 'CtrlPMode.*funky' + if index(g:ale_filetype_blacklist, getbufvar(a:buffer, '&filetype')) >= 0 + return 1 + endif + + " Do nothing if running from command mode + if s:getcmdwintype_exists && !empty(getcmdwintype()) + return 1 + endif + + " Do nothing if running in the sandbox + if ale#util#InSandbox() + return 1 + endif + + " Do nothing if ALE is disabled. + if !ale#Var(a:buffer, 'enabled') + return 1 + endif + + " Do nothing if the file is too large. + if ale#FileTooLarge() + return 1 + endif + + " Do nothing from CtrlP buffers with CtrlP-funky. + if exists(':CtrlPFunky') is 2 + \&& getbufvar(a:buffer, '&l:statusline') =~# 'CtrlPMode.*funky' + return 1 + endif + + return 0 endfunction " (delay, [linting_flag, buffer_number]) @@ -84,7 +118,7 @@ function! s:ALEQueueImpl(delay, linting_flag, buffer) abort " Remember that we want to check files for this buffer. " We will remember this until we finally run the linters, via any event. if a:linting_flag is# 'lint_file' - let s:should_lint_file_for_buffer[bufnr('%')] = 1 + let s:should_lint_file_for_buffer[a:buffer] = 1 endif if s:lint_timer != -1 diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim index 340432f7..6238b4a9 100644 --- a/autoload/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -3,15 +3,6 @@ let s:cursor_timer = -1 let s:last_pos = [0, 0, 0] -let s:error_delay_ms = 1000 * 60 * 2 - -if !exists('s:dont_queue_until') - let s:dont_queue_until = -1 -endif - -if !exists('s:dont_echo_until') - let s:dont_echo_until = -1 -endif " Return a formatted message according to g:ale_echo_msg_format variable function! s:GetMessage(linter, type, text) abort @@ -84,12 +75,12 @@ function! ale#cursor#EchoCursorWarning(...) abort endfunction function! s:EchoImpl() abort - if ale#ShouldDoNothing(bufnr('')) + " Only echo the warnings in normal mode, otherwise we will get problems. + if mode() isnot# 'n' return endif - " Only echo the warnings in normal mode, otherwise we will get problems. - if mode() isnot# 'n' + if ale#ShouldDoNothing(bufnr('')) return endif @@ -108,15 +99,8 @@ function! s:EchoImpl() abort endfunction function! ale#cursor#EchoCursorWarningWithDelay() abort - return ale#CallWithCooldown( - \ 'dont_echo_with_delay_until', - \ function('s:EchoWithDelayImpl'), - \ [], - \) -endfunction - -function! s:EchoWithDelayImpl() abort - if ale#ShouldDoNothing(bufnr('')) + " Only echo the warnings in normal mode, otherwise we will get problems. + if mode() isnot# 'n' return endif @@ -129,18 +113,23 @@ function! s:EchoWithDelayImpl() abort " we should echo something. Otherwise we can end up doing processing " the echo message far too frequently. if l:pos != s:last_pos + let l:delay = ale#Var(bufnr(''), 'echo_delay') + let s:last_pos = l:pos - let s:cursor_timer = timer_start(10, function('ale#cursor#EchoCursorWarning')) + let s:cursor_timer = timer_start( + \ l:delay, + \ function('ale#cursor#EchoCursorWarning') + \) endif endfunction function! ale#cursor#ShowCursorDetail() abort - if ale#ShouldDoNothing(bufnr('')) + " Only echo the warnings in normal mode, otherwise we will get problems. + if mode() isnot# 'n' return endif - " Only echo the warnings in normal mode, otherwise we will get problems. - if mode() isnot# 'n' + if ale#ShouldDoNothing(bufnr('')) return endif diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index 29cb44f3..890d3df2 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -801,6 +801,11 @@ endfunction " clear the state of everything, and remove the Dictionary for managing " the buffer. function! ale#engine#Cleanup(buffer) abort + " Don't bother with cleanup code when newer NeoVim versions are exiting. + if get(v:, 'exiting', v:null) isnot v:null + return + endif + if !has_key(g:ale_buffer_info, a:buffer) return endif diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim index efae11c1..a7f6b378 100644 --- a/autoload/ale/events.vim +++ b/autoload/ale/events.vim @@ -1,15 +1,27 @@ " Author: w0rp <devw0rp@gmail.com> +function! ale#events#QuitEvent(buffer) abort + " Remember when ALE is quitting for BufWrite, etc. + call setbufvar(a:buffer, 'ale_quitting', ale#util#ClockMilliseconds()) +endfunction + +function! ale#events#QuitRecently(buffer) abort + let l:time = getbufvar(a:buffer, 'ale_quitting', 0) + + return l:time && ale#util#ClockMilliseconds() - l:time < 1000 +endfunction + function! ale#events#SaveEvent(buffer) abort call setbufvar(a:buffer, 'ale_save_event_fired', 1) - let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save + let l:should_lint = ale#Var(a:buffer, 'enabled') + \ && g:ale_lint_on_save if g:ale_fix_on_save let l:will_fix = ale#fix#Fix('save_file') let l:should_lint = l:should_lint && !l:will_fix endif - if l:should_lint + if l:should_lint && !ale#events#QuitRecently(a:buffer) call ale#Queue(0, 'lint_file', a:buffer) endif endfunction @@ -24,6 +36,8 @@ function! s:LintOnEnter(buffer) abort endfunction function! ale#events#EnterEvent(buffer) abort + " When entering a buffer, we are no longer quitting it. + call setbufvar(a:buffer, 'ale_quitting', 0) let l:filetype = getbufvar(a:buffer, '&filetype') call setbufvar(a:buffer, 'ale_original_filetype', l:filetype) diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim index e1210f17..a9bb7d48 100644 --- a/autoload/ale/fix.vim +++ b/autoload/ale/fix.vim @@ -56,7 +56,9 @@ function! ale#fix#ApplyQueuedFixes() abort " If ALE linting is enabled, check for problems with the file again after " fixing problems. - if g:ale_enabled && l:should_lint + if g:ale_enabled + \&& l:should_lint + \&& !ale#events#QuitRecently(l:buffer) call ale#Queue(0, l:data.should_save ? 'lint_file' : '') endif endfunction diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim index 9569d215..d26c71ab 100644 --- a/autoload/ale/fix/registry.vim +++ b/autoload/ale/fix/registry.vim @@ -39,7 +39,7 @@ let s:default_registry = { \ }, \ 'prettier': { \ 'function': 'ale#fixers#prettier#Fix', -\ 'suggested_filetypes': ['javascript', 'typescript', 'json', 'css', 'scss'], +\ 'suggested_filetypes': ['javascript', 'typescript', 'json', 'css', 'scss', 'less'], \ 'description': 'Apply prettier to a file.', \ }, \ 'prettier_eslint': { @@ -57,6 +57,11 @@ let s:default_registry = { \ 'suggested_filetypes': [], \ 'description': 'Remove all blank lines at the end of a file.', \ }, +\ 'trim_whitespace': { +\ 'function': 'ale#fixers#generic#TrimWhitespace', +\ 'suggested_filetypes': [], +\ 'description': 'Remove all trailing whitespace characters at the end of every line.', +\ }, \ 'yapf': { \ 'function': 'ale#fixers#yapf#Fix', \ 'suggested_filetypes': ['python'], @@ -97,6 +102,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go files with go fmt.', \ }, +\ 'tslint': { +\ 'function': 'ale#fixers#tslint#Fix', +\ 'suggested_filetypes': ['typescript'], +\ 'description': 'Fix typescript files with tslint --fix.', +\ }, \} " Reset the function registry to the default entries. diff --git a/autoload/ale/fixers/generic.vim b/autoload/ale/fixers/generic.vim index fdc8eab1..cb8865b4 100644 --- a/autoload/ale/fixers/generic.vim +++ b/autoload/ale/fixers/generic.vim @@ -10,3 +10,16 @@ function! ale#fixers#generic#RemoveTrailingBlankLines(buffer, lines) abort return a:lines[:l:end_index] endfunction + +" Remove all whitespaces at the end of lines +function! ale#fixers#generic#TrimWhitespace(buffer, lines) abort + let l:index = 0 + let l:lines_new = range(len(a:lines)) + + for l:line in a:lines + let l:lines_new[l:index] = substitute(l:line, '\s\+$', '', 'g') + let l:index = l:index + 1 + endfor + + return l:lines_new +endfunction diff --git a/autoload/ale/fixers/prettier.vim b/autoload/ale/fixers/prettier.vim index 4adc3b08..d66e00f0 100644 --- a/autoload/ale/fixers/prettier.vim +++ b/autoload/ale/fixers/prettier.vim @@ -49,7 +49,7 @@ function! ale#fixers#prettier#Fix(buffer) abort if match(l:options, '--parser') == -1 if l:filetype is# 'typescript' let l:parser = 'typescript' - elseif l:filetype =~# 'css\|scss' + elseif l:filetype =~# 'css\|scss\|less' let l:parser = 'postcss' elseif l:filetype is# 'json' let l:parser = 'json' diff --git a/autoload/ale/fixers/tslint.vim b/autoload/ale/fixers/tslint.vim new file mode 100644 index 00000000..4d905a08 --- /dev/null +++ b/autoload/ale/fixers/tslint.vim @@ -0,0 +1,22 @@ +" Author: carakan <carakan@gmail.com> +" Description: Fixing files with tslint. + +function! ale#fixers#tslint#Fix(buffer) abort + let l:executable = ale_linters#typescript#tslint#GetExecutable(a:buffer) + + let l:tslint_config_path = ale#path#ResolveLocalPath( + \ a:buffer, + \ 'tslint.json', + \ ale#Var(a:buffer, 'typescript_tslint_config_path') + \) + let l:tslint_config_option = !empty(l:tslint_config_path) + \ ? ' -c ' . ale#Escape(l:tslint_config_path) + \ : '' + + return { + \ 'command': ale#node#Executable(a:buffer, l:executable) + \ . l:tslint_config_option + \ . ' --fix %t', + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim index 4f14697c..d788b779 100644 --- a/autoload/ale/python.vim +++ b/autoload/ale/python.vim @@ -71,7 +71,7 @@ function! ale#python#FindVirtualenv(buffer) abort endfor endfor - return '' + return $VIRTUAL_ENV endfunction " Run an executable check for Python scripts. diff --git a/autoload/ale/sign.vim b/autoload/ale/sign.vim index dc3c1109..1c439bc8 100644 --- a/autoload/ale/sign.vim +++ b/autoload/ale/sign.vim @@ -209,7 +209,17 @@ function! s:UpdateLineNumbers(buffer, current_sign_list, loclist) abort endif endfunction -function! s:BuildSignMap(current_sign_list, grouped_items) abort +function! s:BuildSignMap(buffer, current_sign_list, grouped_items) abort + let l:max_signs = ale#Var(a:buffer, 'max_signs') + + if l:max_signs is 0 + let l:selected_grouped_items = [] + elseif type(l:max_signs) is type(0) && l:max_signs > 0 + let l:selected_grouped_items = a:grouped_items[:l:max_signs - 1] + else + let l:selected_grouped_items = a:grouped_items + endif + let l:sign_map = {} let l:sign_offset = g:ale_sign_offset @@ -235,7 +245,7 @@ function! s:BuildSignMap(current_sign_list, grouped_items) abort let l:sign_map[l:line] = l:sign_info endfor - for l:group in a:grouped_items + for l:group in l:selected_grouped_items let l:line = l:group[0].lnum let l:sign_info = get(l:sign_map, l:line, { \ 'current_id_list': [], @@ -346,7 +356,11 @@ function! ale#sign#SetSigns(buffer, loclist) abort let l:grouped_items = s:GroupLoclistItems(a:buffer, a:loclist) " Build a map of current and new signs, with the lines as the keys. - let l:sign_map = s:BuildSignMap(l:current_sign_list, l:grouped_items) + let l:sign_map = s:BuildSignMap( + \ a:buffer, + \ l:current_sign_list, + \ l:grouped_items, + \) let l:command_list = ale#sign#GetSignCommands( \ a:buffer, diff --git a/autoload/ale/test.vim b/autoload/ale/test.vim index 5fe4bed0..8fc4fe43 100644 --- a/autoload/ale/test.vim +++ b/autoload/ale/test.vim @@ -50,5 +50,5 @@ function! ale#test#SetFilename(path) abort \ ? a:path \ : l:dir . '/' . a:path - silent noautocmd execute 'file ' . fnameescape(ale#path#Winify(l:full_path)) + silent! noautocmd execute 'file ' . fnameescape(ale#path#Winify(l:full_path)) endfunction diff --git a/doc/ale-less.txt b/doc/ale-less.txt new file mode 100644 index 00000000..a6b5998e --- /dev/null +++ b/doc/ale-less.txt @@ -0,0 +1,12 @@ +=============================================================================== +ALE Less Integration *ale-less-options* + + +=============================================================================== +prettier *ale-less-prettier* + +See |ale-javascript-prettier| for information about the available options. + + +=============================================================================== + diff --git a/doc/ale-llvm.txt b/doc/ale-llvm.txt new file mode 100644 index 00000000..2f4a46bd --- /dev/null +++ b/doc/ale-llvm.txt @@ -0,0 +1,19 @@ +=============================================================================== +ALE LLVM Integration *ale-llvm-options* + + +=============================================================================== +llc *ale-llvm-llc* + +g:ale_llvm_llc_executable *g:ale_llvm_llc_executable* + *b:ale_llvm_llc_executable* + + Type: |String| + Default: "llc" + + The command to use for checking. This variable is useful when llc command + has suffix like "llc-5.0". + + +=============================================================================== + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale-scala-scalastyle.txt b/doc/ale-scala.txt index c819e003..9c9472f6 100644 --- a/doc/ale-scala-scalastyle.txt +++ b/doc/ale-scala.txt @@ -5,14 +5,28 @@ ALE Scala Integration *ale-scala-options* =============================================================================== scalastyle *ale-scala-scalastyle* +`scalastyle` requires a configuration file for a project to run. When no +configuration file can be found, ALE will report a problem saying that a +configuration file is required at line 1. + +To disable `scalastyle` globally, use |g:ale_linters| like so: > + let g:ale_linters = {'scala': ['scalac']} " Enable only scalac instead +< + +See |g:ale_linters| for more information on disabling linters. + + g:ale_scalastyle_config_loc *g:ale_scalastyle_config_loc* Type: |String| Default: `''` - A string containing the location of a global fallback config file. - By default, ALE will look for a config file named `scalastyle_config.xml` or - `scalastyle-config.xml` in the current file's directory or parent directories. + A string containing the location of a global fallback configuration file. + + By default, ALE will look for a configuration file named + `scalastyle_config.xml` or `scalastyle-config.xml` in the current file's + directory or parent directories. + g:ale_scala_scalastyle_options *g:ale_scala_scalastyle_options* @@ -21,5 +35,6 @@ g:ale_scala_scalastyle_options *g:ale_scala_scalastyle_options* A string containing additional options to pass to scalastyle. + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale.txt b/doc/ale.txt index ba08a454..fb0b5a76 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -95,6 +95,10 @@ CONTENTS *ale-contents* kotlin................................|ale-kotlin-options| kotlinc.............................|ale-kotlin-kotlinc| ktlint..............................|ale-kotlin-ktlint| + less..................................|ale-less-options| + prettier............................|ale-less-prettier| + llvm..................................|ale-llvm-options| + llc.................................|ale-llvm-llc| lua...................................|ale-lua-options| luacheck............................|ale-lua-luacheck| objc..................................|ale-objc-options| @@ -255,8 +259,9 @@ Notes: * JSON: `jsonlint`, `prettier` * Kotlin: `kotlinc`, `ktlint` * LaTeX (tex): `chktex`, `lacheck`, `proselint` +* LLVM: `llc` * Lua: `luacheck` -* Markdown: `mdl`, `proselint`, `vale` +* Markdown: `mdl`, `proselint`, `vale`, `remark-lint` * MATLAB: `mlint` * Nim: `nim check`!! * nix: `nix-instantiate` @@ -321,7 +326,7 @@ circumstances, which can be configured with the associated options. * When you open a new or modified buffer. - |g:ale_lint_on_enter| * When you save a buffer. - |g:ale_lint_on_save| * When the filetype changes for a buffer. - |g:ale_lint_on_filetype_changed| -* If ALE is used to check ccode manually. - |:ALELint| +* If ALE is used to check code manually. - |:ALELint| In addition to the above options, ALE can also check buffers for errors when you leave insert mode with |g:ale_lint_on_insert_leave|, which is off by @@ -339,7 +344,7 @@ circumstances. * When you open a new or modified buffer. - |g:ale_lint_on_enter| * When you save a buffer. - |g:ale_lint_on_save| * When the filetype changes for a buffer. - |g:ale_lint_on_filetype_changed| -* If ALE is used to check ccode manually. - |:ALELint| +* If ALE is used to check code manually. - |:ALELint| ALE will report problems with your code in the following ways, listed with their relevant options. @@ -538,6 +543,18 @@ g:ale_echo_cursor *g:ale_echo_cursor* The format of the message can be customizable in |g:ale_echo_msg_format|. +g:ale_echo_delay *g:ale_echo_delay* + *b:ale_echo_delay* + Type: |Number| + Default: `10` + + Given any integer, this option controls the number of milliseconds before + ALE will echo a message for a problem near the cursor. + + The value can be increased to decrease the amount of processing ALE will do + for files displaying a large number of problems. + + g:ale_echo_msg_error_str *g:ale_echo_msg_error_str* Type: |String| @@ -856,6 +873,23 @@ g:ale_max_buffer_history_size *g:ale_max_buffer_history_size* History can be disabled completely with |g:ale_history_enabled|. +g:ale_max_signs *g:ale_max_signs* + *b:ale_max_signs* + Type: |Number| + Default: `-1` + + When set to any positive integer, ALE will not render any more than the + given number of signs for any one buffer. + + When set to `0`, no signs will be set, but sign processing will still be + done, so existing signs can be removed. + + When set to any other value, no limit will be imposed on the number of signs + set. + + For disabling sign processing, see |g:ale_set_signs|. + + g:ale_maximum_file_size *g:ale_maximum_file_size* *b:ale_maximum_file_size* Type: |Number| @@ -1003,6 +1037,8 @@ g:ale_set_signs *g:ale_set_signs* When multiple problems exist on the same line, the signs will take precedence in the order above, from highest to lowest. + To limit the number of signs ALE will set, see |g:ale_max_signs|. + g:ale_sign_column_always *g:ale_sign_column_always* diff --git a/plugin/ale.vim b/plugin/ale.vim index a9ab88a1..a0d9b271 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -118,6 +118,9 @@ call ale#Set('list_window_size', 10) " This flag can be set to 0 to disable setting signs. " This is enabled by default only if the 'signs' feature exists. let g:ale_set_signs = get(g:, 'ale_set_signs', has('signs')) +" This flag can be set to some integer to control the maximum number of signs +" that ALE will set. +let g:ale_max_signs = get(g:, 'ale_max_signs', -1) " This flag can be set to 1 to enable changing the sign column colors when " there are errors. @@ -152,6 +155,8 @@ let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning') " This flag can be set to 0 to disable echoing when the cursor moves. let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1) +" Controls the milliseconds delay before echoing a message. +let g:ale_echo_delay = get(g:, 'ale_echo_delay', 10) " This flag can be set to 0 to disable balloon support. call ale#Set('set_balloons', has('balloon_eval')) @@ -378,6 +383,7 @@ augroup ALECleanupGroup autocmd! " Clean up buffers automatically when they are unloaded. autocmd BufUnload * call ale#engine#Cleanup(str2nr(expand('<abuf>'))) + autocmd QuitPre * call ale#events#QuitEvent(str2nr(expand('<abuf>'))) augroup END " Backwards Compatibility diff --git a/test/command_callback/test_brakeman_command_callback.vader b/test/command_callback/test_brakeman_command_callback.vader index b97c5809..f98801b3 100644 --- a/test/command_callback/test_brakeman_command_callback.vader +++ b/test/command_callback/test_brakeman_command_callback.vader @@ -25,7 +25,7 @@ Execute(The brakeman command callback should find a valid Rails app root): AssertEqual \ 'brakeman -f json -q -p ' - \ . ale#Escape(simplify(g:dir . '/../ruby_fixtures/valid_rails_app')), + \ . ale#Escape(ale#path#Winify(g:dir . '/../ruby_fixtures/valid_rails_app')), \ ale_linters#ruby#brakeman#GetCommand(bufnr('')) Execute(The brakeman command callback should include configured options): @@ -35,5 +35,5 @@ Execute(The brakeman command callback should include configured options): AssertEqual \ 'brakeman -f json -q --combobulate -p ' - \ . ale#Escape(simplify(g:dir . '/../ruby_fixtures/valid_rails_app')), + \ . ale#Escape(ale#path#Winify(g:dir . '/../ruby_fixtures/valid_rails_app')), \ ale_linters#ruby#brakeman#GetCommand(bufnr('')) diff --git a/test/command_callback/test_c_clang_tidy_command_callback.vader b/test/command_callback/test_c_clang_tidy_command_callback.vader index 722a14f1..6f75d777 100644 --- a/test/command_callback/test_c_clang_tidy_command_callback.vader +++ b/test/command_callback/test_c_clang_tidy_command_callback.vader @@ -26,7 +26,7 @@ After: Execute(The clangtidy command default should be correct): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s', + \ . ' -checks=' . ale#Escape('*') . ' %s', \ ale_linters#c#clangtidy#GetCommand(bufnr('')) Execute(You should be able to remove the -checks option for clang-tidy): @@ -42,7 +42,7 @@ Execute(You should be able to set other checks for clang-tidy): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''-*,clang-analyzer-*'' %s', + \ . ' -checks=' . ale#Escape('-*,clang-analyzer-*') . ' %s', \ ale_linters#c#clangtidy#GetCommand(bufnr('')) Execute(You should be able to manually set compiler flags for clang-tidy): @@ -50,7 +50,8 @@ Execute(You should be able to manually set compiler flags for clang-tidy): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -- -Wall', + \ . ' -checks=' . ale#Escape('*') . ' %s' + \ . ' -- -Wall', \ ale_linters#c#clangtidy#GetCommand(bufnr('')) \ Execute(The build directory should be configurable): @@ -58,7 +59,8 @@ Execute(The build directory should be configurable): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -p ' . ale#Escape('/foo/bar'), + \ . ' -checks=' . ale#Escape('*') . ' %s' + \ . ' -p ' . ale#Escape('/foo/bar'), \ ale_linters#c#clangtidy#GetCommand(bufnr('')) Execute(The build directory setting should override the options): @@ -67,7 +69,8 @@ Execute(The build directory setting should override the options): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -p ' . ale#Escape('/foo/bar'), + \ . ' -checks=' . ale#Escape('*') . ' %s' + \ . ' -p ' . ale#Escape('/foo/bar'), \ ale_linters#c#clangtidy#GetCommand(bufnr('')) Execute(The build directory should be ignored for header files): @@ -78,14 +81,16 @@ Execute(The build directory should be ignored for header files): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -- -Wall', + \ . ' -checks=' . ale#Escape('*') . ' %s' + \ . ' -- -Wall', \ ale_linters#c#clangtidy#GetCommand(bufnr('')) \ call ale#test#SetFilename('test.h') AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -- -Wall', + \ . ' -checks=' . ale#Escape('*') . ' %s' + \ . ' -- -Wall', \ ale_linters#c#clangtidy#GetCommand(bufnr('')) Execute(The executable should be configurable): @@ -93,5 +98,5 @@ Execute(The executable should be configurable): AssertEqual \ ale#Escape('foobar') - \ . ' -checks=''*'' %s', + \ . ' -checks=' . ale#Escape('*') . ' %s', \ ale_linters#c#clangtidy#GetCommand(bufnr('')) diff --git a/test/command_callback/test_c_cppcheck_command_callbacks.vader b/test/command_callback/test_c_cppcheck_command_callbacks.vader index daf61fbd..e6fe1b7d 100644 --- a/test/command_callback/test_c_cppcheck_command_callbacks.vader +++ b/test/command_callback/test_c_cppcheck_command_callbacks.vader @@ -43,7 +43,7 @@ Execute(cppcheck for C++ should detect compile_commands.json files): call ale#test#SetFilename('cppcheck_paths/one/foo.cpp') AssertEqual - \ 'cd ' . ale#Escape(g:dir . '/cppcheck_paths/one') . ' && ' + \ 'cd ' . ale#Escape(ale#path#Winify(g:dir . '/cppcheck_paths/one')) . ' && ' \ . ale#Escape('cppcheck') \ . ' -q --language=c --project=compile_commands.json --enable=style %t', \ ale_linters#c#cppcheck#GetCommand(bufnr('')) diff --git a/test/command_callback/test_clang_tidy_command_callback.vader b/test/command_callback/test_clang_tidy_command_callback.vader index f9e5781c..f82efffe 100644 --- a/test/command_callback/test_clang_tidy_command_callback.vader +++ b/test/command_callback/test_clang_tidy_command_callback.vader @@ -26,7 +26,7 @@ After: Execute(The clangtidy command default should be correct): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s', + \ . ' -checks=' . ale#Escape('*') . ' %s', \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) Execute(You should be able to remove the -checks option for clang-tidy): @@ -42,7 +42,7 @@ Execute(You should be able to set other checks for clang-tidy): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''-*,clang-analyzer-*'' %s', + \ . ' -checks=' . ale#Escape('-*,clang-analyzer-*') . ' %s', \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) Execute(You should be able to manually set compiler flags for clang-tidy): @@ -50,7 +50,7 @@ Execute(You should be able to manually set compiler flags for clang-tidy): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -- -Wall', + \ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall', \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) \ Execute(The build directory should be configurable): @@ -58,7 +58,7 @@ Execute(The build directory should be configurable): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -p ' . ale#Escape('/foo/bar'), + \ . ' -checks=' . ale#Escape('*') . ' %s -p ' . ale#Escape('/foo/bar'), \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) Execute(The build directory setting should override the options): @@ -67,7 +67,7 @@ Execute(The build directory setting should override the options): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -p ' . ale#Escape('/foo/bar'), + \ . ' -checks=' . ale#Escape('*') . ' %s -p ' . ale#Escape('/foo/bar'), \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) Execute(The build directory should be ignored for header files): @@ -78,14 +78,14 @@ Execute(The build directory should be ignored for header files): AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -- -Wall', + \ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall', \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) \ call ale#test#SetFilename('test.hpp') AssertEqual \ ale#Escape('clang-tidy') - \ . ' -checks=''*'' %s -- -Wall', + \ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall', \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) Execute(The executable should be configurable): @@ -93,5 +93,5 @@ Execute(The executable should be configurable): AssertEqual \ ale#Escape('foobar') - \ . ' -checks=''*'' %s', + \ . ' -checks=' . ale#Escape('*') . ' %s', \ ale_linters#cpp#clangtidy#GetCommand(bufnr('')) diff --git a/test/command_callback/test_cpp_cppcheck_command_callbacks.vader b/test/command_callback/test_cpp_cppcheck_command_callbacks.vader index 18391184..f7b37d4f 100644 --- a/test/command_callback/test_cpp_cppcheck_command_callbacks.vader +++ b/test/command_callback/test_cpp_cppcheck_command_callbacks.vader @@ -43,7 +43,7 @@ Execute(cppcheck for C++ should detect compile_commands.json files): call ale#test#SetFilename('cppcheck_paths/one/foo.cpp') AssertEqual - \ 'cd ' . ale#Escape(g:dir . '/cppcheck_paths/one') . ' && ' + \ 'cd ' . ale#Escape(ale#path#Winify(g:dir . '/cppcheck_paths/one')) . ' && ' \ . ale#Escape('cppcheck') \ . ' -q --language=c++ --project=compile_commands.json --enable=style %t', \ ale_linters#cpp#cppcheck#GetCommand(bufnr('')) diff --git a/test/command_callback/test_cs_mcsc_command_callbacks.vader b/test/command_callback/test_cs_mcsc_command_callbacks.vader index b513b655..441cef53 100644 --- a/test/command_callback/test_cs_mcsc_command_callbacks.vader +++ b/test/command_callback/test_cs_mcsc_command_callbacks.vader @@ -3,118 +3,77 @@ Before: Save g:ale_cs_mcsc_source Save g:ale_cs_mcsc_assembly_path Save g:ale_cs_mcsc_assemblies + Save g:ale_buffer_info + + let g:ale_buffer_info = {bufnr(''): {'temporary_file_list': []}} unlet! g:ale_cs_mcsc_options unlet! g:ale_cs_mcsc_source unlet! g:ale_cs_mcsc_assembly_path unlet! g:ale_cs_mcsc_assemblies - let g:temppath = fnamemodify(tempname(), ':p:h') - let g:temppathpattern = substitute(escape(g:temppath, '\\/.*$^~[]'), '[\\/]*$', '[\\\\/]\\+\\S\\+','') - let g:sometempfile = fnamemodify(g:temppath .'/some_temp_file.tmp', ':p') + function! GetCommand() + let l:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) + let l:command = join(split(l:command)) + + return substitute(l:command, ':[^ ]\+ -t:module', ':TEMP -t:module', '') + endfunction runtime ale_linters/cs/mcsc.vim After: Restore + unlet! b:ale_cs_mcsc_options unlet! g:ale_cs_mcsc_source unlet! g:ale_cs_mcsc_assembly_path unlet! g:ale_cs_mcsc_assemblies - unlet! g:temppath - unlet! g:temppathpattern - unlet! g:sometempfile - call ale#linter#Reset() -Execute(Check for proper default command): + delfunction GetCommand - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command, '\s\+', ' ', 'g') + call ale#linter#Reset() +Execute(Check for proper default command): AssertEqual - \ b:command, - \ 'cd ".";mcs -unsafe -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' + \ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() Execute(The options should be be used in the command): - let g:ale_cs_mcsc_options = '-pkg:dotnet' - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command, '\s\+', ' ', 'g') - AssertEqual - \ b:command, - \ 'cd ".";mcs -unsafe ' . g:ale_cs_mcsc_options . ' -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' + \ 'cd ".";mcs -unsafe ' . g:ale_cs_mcsc_options . ' -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() Execute(The souce path should be be used in the command): - call ale#engine#Cleanup(bufnr('')) - call ale#engine#InitBufferInfo(bufnr('')) - let g:ale_cs_mcsc_source='../foo/bar' - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command, '\s\+', ' ', 'g') - AssertEqual - \ b:command, - \ 'cd "' . g:ale_cs_mcsc_source . '";mcs -unsafe -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' + \ 'cd "' . g:ale_cs_mcsc_source . '";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() Execute(The list of search pathes for assemblies should be be used in the command if not empty): - call ale#engine#Cleanup(bufnr('')) - call ale#engine#InitBufferInfo(bufnr('')) - - let g:ale_cs_mcsc_assembly_path = [ - \ '/usr/lib/mono', - \ '../foo/bar' - \] - - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command, '\s\+', ' ', 'g') + let g:ale_cs_mcsc_assembly_path = ['/usr/lib/mono', '../foo/bar'] AssertEqual - \ b:command, - \ 'cd ".";mcs -unsafe -lib:"' . join(g:ale_cs_mcsc_assembly_path,'","') . '" -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' - - let g:ale_cs_mcsc_assembly_path = [ - \] + \ 'cd ".";mcs -unsafe -lib:"' . join(g:ale_cs_mcsc_assembly_path,'","') . '" -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command, '\s\+', ' ', 'g') + let g:ale_cs_mcsc_assembly_path = [] AssertEqual - \ b:command, - \ 'cd ".";mcs -unsafe -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' + \ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() Execute(The list of assemblies should be be used in the command if not empty): - call ale#engine#Cleanup(bufnr('')) - call ale#engine#InitBufferInfo(bufnr('')) - - let g:ale_cs_mcsc_assemblies = [ - \ 'foo.dll', - \ 'bar.dll' - \] - - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command,'\s\+',' ','g') + let g:ale_cs_mcsc_assemblies = ['foo.dll', 'bar.dll'] AssertEqual - \ b:command, - \ 'cd ".";mcs -unsafe -r:"' . join(g:ale_cs_mcsc_assemblies,'","') . '" -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' + \ 'cd ".";mcs -unsafe -r:"' . join(g:ale_cs_mcsc_assemblies,'","') . '" -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() - let g:ale_cs_mcsc_assemblies = [ - \] - - let b:command = ale_linters#cs#mcsc#GetCommand(bufnr('')) - let b:command = substitute(b:command, '-out:' . g:temppathpattern, '-out:' . g:sometempfile, '') - let b:command = substitute(b:command,'\s\+',' ','g') + let g:ale_cs_mcsc_assemblies = [] AssertEqual - \ b:command, - \ 'cd ".";mcs -unsafe -out:' . g:sometempfile . ' -t:module -recurse:"*.cs"' - + \ 'cd ".";mcs -unsafe -out:TEMP -t:module -recurse:"*.cs"', + \ GetCommand() diff --git a/test/command_callback/test_cuda_nvcc_command_callbacks.vader b/test/command_callback/test_cuda_nvcc_command_callbacks.vader index 88123e5d..af199d37 100644 --- a/test/command_callback/test_cuda_nvcc_command_callbacks.vader +++ b/test/command_callback/test_cuda_nvcc_command_callbacks.vader @@ -24,11 +24,13 @@ Execute(The executable should be configurable): Execute(The executable should be used in the command): AssertEqual - \ ale#Escape('nvcc') . ' -cuda -std=c++11 %s -o /dev/null', + \ ale#Escape('nvcc') . ' -cuda -std=c++11 %s' + \ . ' -o ' . g:ale#util#nul_file, \ ale_linters#cuda#nvcc#GetCommand(bufnr('')) let b:ale_cuda_nvcc_executable = 'foobar' AssertEqual - \ ale#Escape('foobar') . ' -cuda -std=c++11 %s -o /dev/null', + \ ale#Escape('foobar') . ' -cuda -std=c++11 %s' + \ . ' -o ' . g:ale#util#nul_file, \ ale_linters#cuda#nvcc#GetCommand(bufnr('')) diff --git a/test/command_callback/test_erlang_syntaxerl_command_callback.vader b/test/command_callback/test_erlang_syntaxerl_command_callback.vader index 1df2be39..a9a1a500 100644 --- a/test/command_callback/test_erlang_syntaxerl_command_callback.vader +++ b/test/command_callback/test_erlang_syntaxerl_command_callback.vader @@ -6,13 +6,11 @@ Before: runtime ale_linters/erlang/syntaxerl.vim - After: Restore call ale#linter#Reset() - Execute (The executable should be correct): AssertEqual 'syntaxerl', ale_linters#erlang#syntaxerl#GetExecutable(bufnr('')) @@ -25,22 +23,32 @@ Execute (The executable should be correct): Execute (The executable should be presented in the feature check command): let g:ale_erlang_syntaxerl_executable = '/some/other/syntaxerl' - AssertEqual "'/some/other/syntaxerl' -h", ale_linters#erlang#syntaxerl#FeatureCheck(bufnr('')) + + AssertEqual + \ ale#Escape('/some/other/syntaxerl') . ' -h', + \ ale_linters#erlang#syntaxerl#FeatureCheck(bufnr('')) let b:ale_erlang_syntaxerl_executable = '/yet/another/syntaxerl' - AssertEqual "'/yet/another/syntaxerl' -h", ale_linters#erlang#syntaxerl#FeatureCheck(bufnr('')) + AssertEqual + \ ale#Escape('/yet/another/syntaxerl') . ' -h', + \ ale_linters#erlang#syntaxerl#FeatureCheck(bufnr('')) Execute (The executable should be presented in the command): let g:ale_erlang_syntaxerl_executable = '/some/other/syntaxerl' - AssertEqual "'/some/other/syntaxerl' %t", ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), []) + + AssertEqual + \ ale#Escape('/some/other/syntaxerl') . ' %t', + \ ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), []) let b:ale_erlang_syntaxerl_executable = '/yet/another/syntaxerl' - AssertEqual "'/yet/another/syntaxerl' %t", ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), []) + AssertEqual + \ ale#Escape('/yet/another/syntaxerl') . ' %t', + \ ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), []) Execute (The -b option should be used when available): - AssertEqual "'syntaxerl' %t", ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), [ + AssertEqual ale#Escape('syntaxerl') . ' %t', ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), [ \ 'Syntax checker for Erlang (0.14.0)', \ 'Usage: syntaxerl [-d | --debug] <FILENAME>', \ ' syntaxerl <-h | --help>', @@ -48,7 +56,7 @@ Execute (The -b option should be used when available): \ ' -h, --help Show this message', \ ]) - AssertEqual "'syntaxerl' -b %s %t", ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), [ + AssertEqual ale#Escape('syntaxerl') . ' -b %s %t', ale_linters#erlang#syntaxerl#GetCommand(bufnr(''), [ \ 'Syntax checker for Erlang (0.14.0)', \ 'Usage: syntaxerl [-b | --base <FILENAME>] [-d | --debug] <FILENAME>', \ ' syntaxerl <-h | --help>', diff --git a/test/command_callback/test_flake8_command_callback.vader b/test/command_callback/test_flake8_command_callback.vader index c564b54f..a510f4c1 100644 --- a/test/command_callback/test_flake8_command_callback.vader +++ b/test/command_callback/test_flake8_command_callback.vader @@ -8,6 +8,8 @@ Before: unlet! g:ale_python_flake8_options unlet! g:ale_python_flake8_use_global + let b:bin_dir = has('win32') ? 'Scripts' : 'bin' + runtime ale_linters/python/flake8.vim call ale#test#SetDirectory('/testplugin/test/command_callback') @@ -16,6 +18,9 @@ After: unlet! g:ale_python_flake8_args + unlet! b:bin_dir + unlet! b:executable + call ale#test#RestoreDirectory() call ale#linter#Reset() call ale_linters#python#flake8#ClearVersionCache() @@ -25,26 +30,29 @@ Execute(The flake8 callbacks should return the correct default values): \ 'flake8', \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ '''flake8'' --version', + \ ale#Escape('flake8') . ' --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ '''flake8'' --format=default --stdin-display-name %s -', + \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) " Try with older versions. call ale_linters#python#flake8#ClearVersionCache() AssertEqual - \ '''flake8'' --format=default -', + \ ale#Escape('flake8') . ' --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) Execute(The flake8 command callback should let you set options): let g:ale_python_flake8_options = '--some-option' AssertEqual - \ '''flake8'' --some-option --format=default --stdin-display-name %s -', + \ ale#Escape('flake8') + \ . ' --some-option --format=default' + \ . ' --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.4']) call ale_linters#python#flake8#ClearVersionCache() AssertEqual - \ '''flake8'' --some-option --format=default -', + \ ale#Escape('flake8') + \ . ' --some-option --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) Execute(You should be able to set a custom executable and it should be escaped): @@ -54,23 +62,29 @@ Execute(You should be able to set a custom executable and it should be escaped): \ 'executable with spaces', \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ '''executable with spaces'' --version', + \ ale#Escape('executable with spaces') . ' --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ '''executable with spaces'' --format=default --stdin-display-name %s -', + \ ale#Escape('executable with spaces') + \ . ' --format=default' + \ . ' --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) Execute(The flake8 callbacks should detect virtualenv directories): silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') + let b:executable = ale#path#Winify( + \ g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/flake8' + \) + AssertEqual - \ g:dir . '/python_paths/with_virtualenv/env/bin/flake8', + \ b:executable, \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ '''' . g:dir . '/python_paths/with_virtualenv/env/bin/flake8'' --version', + \ ale#Escape(b:executable) . ' --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ '''' . g:dir . '/python_paths/with_virtualenv/env/bin/flake8''' + \ ale#Escape(b:executable) \ . ' --format=default --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) @@ -78,35 +92,35 @@ Execute(The FindProjectRoot should detect the project root directory for namespa silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_manifest/namespace/foo/bar.py') AssertEqual - \ fnameescape(g:dir . '/python_paths/namespace_package_manifest'), + \ ale#path#Winify(g:dir . '/python_paths/namespace_package_manifest'), \ ale#python#FindProjectRoot(bufnr('')) Execute(The FindProjectRoot should detect the project root directory for namespace package via setup.cf): silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_setup/namespace/foo/bar.py') AssertEqual - \ fnameescape(g:dir . '/python_paths/namespace_package_setup'), + \ ale#path#Winify(g:dir . '/python_paths/namespace_package_setup'), \ ale#python#FindProjectRoot(bufnr('')) Execute(The FindProjectRoot should detect the project root directory for namespace package via pytest.ini): silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_pytest/namespace/foo/bar.py') AssertEqual - \ fnameescape(g:dir . '/python_paths/namespace_package_pytest'), + \ ale#path#Winify(g:dir . '/python_paths/namespace_package_pytest'), \ ale#python#FindProjectRoot(bufnr('')) Execute(The FindProjectRoot should detect the project root directory for namespace package via tox.ini): silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_tox/namespace/foo/bar.py') AssertEqual - \ fnameescape(g:dir . '/python_paths/namespace_package_tox'), + \ ale#path#Winify(g:dir . '/python_paths/namespace_package_tox'), \ ale#python#FindProjectRoot(bufnr('')) Execute(The FindProjectRoot should detect the project root directory for non-namespace package): silent execute 'file ' . fnameescape(g:dir . '/python_paths/no_virtualenv/subdir/foo/bar.py') AssertEqual - \ fnameescape(g:dir . '/python_paths/no_virtualenv/subdir'), + \ ale#path#Winify(g:dir . '/python_paths/no_virtualenv/subdir'), \ ale#python#FindProjectRoot(bufnr('')) " Some users currently run flake8 this way, so we should support it. @@ -120,10 +134,10 @@ Execute(Using `python -m flake8` should be supported for running flake8): \ 'python', \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ '''python'' -m flake8 --version', + \ ale#Escape('python') . ' -m flake8 --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ '''python'' -m flake8 --some-option --format=default -', + \ ale#Escape('python') . ' -m flake8 --some-option --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) call ale_linters#python#flake8#ClearVersionCache() @@ -135,10 +149,10 @@ Execute(Using `python -m flake8` should be supported for running flake8): \ 'python', \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ '''python'' -m flake8 --version', + \ ale#Escape('python') . ' -m flake8 --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ '''python'' -m flake8 --some-option --format=default -', + \ ale#Escape('python') . ' -m flake8 --some-option --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) Execute(Using `python2 -m flake8` should be use with the old args option): @@ -157,8 +171,8 @@ Execute(Using `python2 -m flake8` should be use with the old args option): \ 'python2', \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ '''python2'' -m flake8 --version', + \ ale#Escape('python2') . ' -m flake8 --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ '''python2'' -m flake8 --format=default -', + \ ale#Escape('python2') . ' -m flake8 --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) diff --git a/test/command_callback/test_fusionlint_command_callback.vader b/test/command_callback/test_fusionlint_command_callback.vader index 5398066c..34a44133 100644 --- a/test/command_callback/test_fusionlint_command_callback.vader +++ b/test/command_callback/test_fusionlint_command_callback.vader @@ -1,24 +1,34 @@ Before: + Save g:ale_fuse_fusionlint_options + Save g:ale_fuse_fusionlint_executable + + unlet! g:ale_fuse_fusionlint_options + unlet! g:ale_fuse_fusionlint_executable + runtime ale_linters/fuse/fusionlint.vim After: + Restore + call ale#linter#Reset() - let g:ale_fuse_fusionlint_options = '' - let g:ale_fuse_fusionlint_executable = 'fusion-lint' Execute(The fuse fusionlint command callback should return the correct default string): - AssertEqual '''fusion-lint'' --filename %s -i', + AssertEqual ale#Escape('fusion-lint') . ' --filename %s -i', \ join(split(ale_linters#fuse#fusionlint#GetCommand(1))) Execute(The fuse fusionlint command callback should let you set options): let g:ale_fuse_fusionlint_options = '--example-option argument' - AssertEqual '''fusion-lint'' --example-option argument --filename %s -i', + AssertEqual + \ ale#Escape('fusion-lint') + \ . ' --example-option argument --filename %s -i', \ join(split(ale_linters#fuse#fusionlint#GetCommand(1))) Execute(The fusionlint executable should be configurable): let g:ale_fuse_fusionlint_executable = 'util/linter.fuse' AssertEqual 'util/linter.fuse', ale_linters#fuse#fusionlint#GetExecutable(1) - AssertEqual '''util/linter.fuse'' --filename %s -i', + AssertEqual + \ ale#Escape('util/linter.fuse') + \ . ' --filename %s -i', \ join(split(ale_linters#fuse#fusionlint#GetCommand(1))) diff --git a/test/command_callback/test_javac_command_callback.vader b/test/command_callback/test_javac_command_callback.vader index 706839e4..8033e4f6 100644 --- a/test/command_callback/test_javac_command_callback.vader +++ b/test/command_callback/test_javac_command_callback.vader @@ -1,97 +1,151 @@ Before: + call ale#test#SetDirectory('/testplugin/test/command_callback') + + Save g:ale_java_javac_options + Save g:ale_java_javac_classpath + + unlet! g:ale_java_javac_options + unlet! g:ale_java_javac_classpath + + let g:cp_sep = has('unix') ? ':' : ';' + + function! GetCommand(previous_output) abort + let l:command = ale_linters#java#javac#GetCommand( + \ bufnr(''), + \ a:previous_output + \) + + let l:split_command = split(l:command) + let l:index = index(l:split_command, '-d') + + let l:split_command[l:index + 1] = 'TEMP' + + return join(l:split_command) + endfunction + runtime ale_linters/java/javac.vim call ale#engine#InitBufferInfo(bufnr('')) - silent! cd /testplugin/test/command_callback + call ale#test#SetFilename('dummy.java') After: + call ale#test#RestoreDirectory() + + Restore + + unlet! g:cp_sep + + delfunction GetCommand + call ale#linter#Reset() " We need to clean up the buffer to remove the temporary directories created " for the command. call ale#engine#Cleanup(bufnr('')) - let g:ale_java_javac_options = '' - let g:ale_java_javac_classpath = '' Execute(The javac callback should return the correct default value): - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), []) - - Assert match(b:command, '\v^javac +-Xlint +-d +''/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual 'javac -Xlint -d TEMP %t', GetCommand([]) Execute(The javac callback should use g:ale_java_javac_classpath correctly): let g:ale_java_javac_classpath = 'foo.jar' - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), []) - - Assert match(b:command, '\v^javac +-Xlint +-cp ''+foo\.jar'' +-d ''+/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual + \ 'javac -Xlint' + \ . ' -cp ' . ale#Escape('foo.jar') + \ . ' -d TEMP %t', + \ GetCommand([]) Execute(The javac callback should include discovered classpaths): - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ - \ '[DEBUG] Ignore this.', - \ '[INFO] Something we should ignore.', - \ '/foo/bar.jar', - \ '/xyz/abc.jar', - \]) - - Assert match(b:command, '\v^javac +-Xlint +-cp ''+/foo/bar\.jar:/xyz/abc\.jar'' +-d +''/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual + \ 'javac -Xlint -cp ' + \ . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep)) + \ . ' -d TEMP %t', + \ GetCommand([ + \ '[DEBUG] Ignore this.', + \ '[INFO] Something we should ignore.', + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \ ]) Execute(The javac callback should combine discovered classpaths and manual ones): let g:ale_java_javac_classpath = 'configured.jar' - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ - \ '[DEBUG] Ignore this.', - \ '[INFO] Something we should ignore.', - \ '/foo/bar.jar', - \ '/xyz/abc.jar', - \]) - - Assert match(b:command, '\v^javac +-Xlint +-cp +''/foo/bar\.jar:/xyz/abc\.jar:configured\.jar'' +-d ''+/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command - - let g:ale_java_javac_classpath = 'configured.jar:configured2.jar' - - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ - \ '[DEBUG] Ignore this.', - \ '[INFO] Something we should ignore.', - \ '/foo/bar.jar', - \ '/xyz/abc.jar', - \]) - - Assert match(b:command, '\v^javac +-Xlint +-cp +''/foo/bar\.jar:/xyz/abc\.jar:configured\.jar:configured2\.jar'' +-d +''/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual + \ 'javac -Xlint -cp ' + \ . ale#Escape(join( + \ [ + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \ 'configured.jar', + \ ], + \ g:cp_sep + \ )) + \ . ' -d TEMP %t', + \ GetCommand([ + \ '[DEBUG] Ignore this.', + \ '[INFO] Something we should ignore.', + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \ ]) + + let g:ale_java_javac_classpath = 'configured.jar' . g:cp_sep . 'configured2.jar' + + AssertEqual + \ 'javac -Xlint -cp ' + \ . ale#Escape(join( + \ [ + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \ 'configured.jar', + \ 'configured2.jar', + \ ], + \ g:cp_sep + \ )) + \ . ' -d TEMP %t', + \ GetCommand([ + \ '[DEBUG] Ignore this.', + \ '[INFO] Something we should ignore.', + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \ ]) Execute(The javac callback should detect source directories): call ale#engine#Cleanup(bufnr('')) :e! java_paths/src/main/java/com/something/dummy call ale#engine#InitBufferInfo(bufnr('')) - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), []) - - Assert match(b:command, '\v^javac +-Xlint +-sourcepath ''/.*java_paths/src/main/java/'' +-d +''/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual + \ 'javac -Xlint' + \ . ' -sourcepath ' . ale#Escape( + \ ale#path#Winify(g:dir . '/java_paths/src/main/java/') + \ ) + \ . ' -d TEMP %t', + \ GetCommand([]) Execute(The javac callback should combine detected source directories and classpaths): call ale#engine#Cleanup(bufnr('')) - :e! java_paths/src/main/java/com/something/dummy + call ale#test#SetFilename('java_paths/src/main/java/com/something/dummy.java') call ale#engine#InitBufferInfo(bufnr('')) - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ - \ '[DEBUG] Ignore this.', - \ '[INFO] Something we should ignore.', - \ '/foo/bar.jar', - \ '/xyz/abc.jar', - \]) - - Assert match(b:command, '\v^javac +-Xlint +-cp +''/foo/bar\.jar:/xyz/abc\.jar'' +-sourcepath ''/.*java_paths/src/main/java/'' +-d +''/tmp/[0-9a-zA-Z/]+'' +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual + \ 'javac -Xlint' + \ . ' -cp ' . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep)) + \ . ' -sourcepath ' . ale#Escape( + \ ale#path#Winify(g:dir . '/java_paths/src/main/java/') + \ ) + \ . ' -d TEMP %t', + \ GetCommand([ + \ '[DEBUG] Ignore this.', + \ '[INFO] Something we should ignore.', + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \ ]) Execute(The javac callback should use g:ale_java_javac_options correctly): - let g:ale_java_javac_options = '--anything --else' let b:command = ale_linters#java#javac#GetCommand(bufnr(''), []) - Assert match(b:command, '\v^javac +-Xlint +-d +''/tmp/[0-9a-zA-Z/]+'' --anything --else +\%t$') >= 0, - \ 'Invalid command string: ' . b:command + AssertEqual + \ 'javac -Xlint' + \ . ' -d TEMP --anything --else %t', + \ GetCommand([]) diff --git a/test/command_callback/test_jscs_command_callback.vader b/test/command_callback/test_jscs_command_callback.vader index 8245337e..f118c039 100644 --- a/test/command_callback/test_jscs_command_callback.vader +++ b/test/command_callback/test_jscs_command_callback.vader @@ -7,19 +7,19 @@ After: Execute(Should return the correct default values): AssertEqual - \ 'jscs', - \ ale_linters#javascript#jscs#GetExecutable(bufnr('')) + \ 'jscs', + \ ale_linters#javascript#jscs#GetExecutable(bufnr('')) AssertEqual - \ '''jscs'' --reporter inline --no-colors -', - \ ale_linters#javascript#jscs#GetCommand(bufnr('')) + \ ale#Escape('jscs') . ' --reporter inline --no-colors -', + \ ale_linters#javascript#jscs#GetCommand(bufnr('')) Execute(Should allow using a custom executable): let g:ale_javascript_jscs_executable = 'foobar' AssertEqual - \ 'foobar', - \ ale_linters#javascript#jscs#GetExecutable(bufnr('')) + \ 'foobar', + \ ale_linters#javascript#jscs#GetExecutable(bufnr('')) AssertEqual - \ '''foobar'' --reporter inline --no-colors -', - \ ale_linters#javascript#jscs#GetCommand(bufnr('')) + \ ale#Escape('foobar') . ' --reporter inline --no-colors -', + \ ale_linters#javascript#jscs#GetCommand(bufnr('')) diff --git a/test/command_callback/test_llc_command_callback.vader b/test/command_callback/test_llc_command_callback.vader new file mode 100644 index 00000000..296b277a --- /dev/null +++ b/test/command_callback/test_llc_command_callback.vader @@ -0,0 +1,39 @@ +Before: + Save g:ale_llvm_llc_executable + + unlet! g:ale_llvm_llc_executable + unlet! b:ale_llvm_llc_executable + + runtime ale_linters/llvm/llc.vim + + function! AssertHasPrefix(str, prefix) abort + let msg = printf("'%s' is expected to be prefixed with '%s'", a:str, a:prefix) + AssertEqual stridx(a:str, a:prefix), 0, msg + endfunction + +After: + unlet! g:ale_llvm_llc_executable + unlet! b:ale_llvm_llc_executable + delfunction AssertHasPrefix + Restore + +Execute(llc command is customizable): + let cmd = ale_linters#llvm#llc#GetCommand(bufnr('')) + call AssertHasPrefix(cmd, ale#Escape('llc')) + + let g:ale_llvm_llc_executable = 'llc-5.0' + let cmd = ale_linters#llvm#llc#GetCommand(bufnr('')) + call AssertHasPrefix(cmd, ale#Escape('llc-5.0')) + + let b:ale_llvm_llc_executable = 'llc-4.0' + let cmd = ale_linters#llvm#llc#GetCommand(bufnr('')) + call AssertHasPrefix(cmd, ale#Escape('llc-4.0')) + +Execute(GetCommand() escapes the returned path): + let b:ale_llvm_llc_executable = '/path/space contained/llc' + let cmd = ale_linters#llvm#llc#GetCommand(bufnr('')) + call AssertHasPrefix(cmd, ale#Escape('/path/space contained/llc')) + +Execute(GetExecutable() does not escape the returned path): + let b:ale_llvm_llc_executable = '/path/space contained/llc' + AssertEqual ale_linters#llvm#llc#GetExecutable(bufnr('')), '/path/space contained/llc' diff --git a/test/command_callback/test_luacheck_command_callback.vader b/test/command_callback/test_luacheck_command_callback.vader index c4ee98a8..6f7f3a00 100644 --- a/test/command_callback/test_luacheck_command_callback.vader +++ b/test/command_callback/test_luacheck_command_callback.vader @@ -7,18 +7,18 @@ After: let g:ale_lua_luacheck_executable = 'luacheck' Execute(The lua luacheck command callback should return the correct default string): - AssertEqual '''luacheck'' --formatter plain --codes --filename %s -', + AssertEqual ale#Escape('luacheck') . ' --formatter plain --codes --filename %s -', \ join(split(ale_linters#lua#luacheck#GetCommand(1))) Execute(The lua luacheck command callback should let you set options): let g:ale_lua_luacheck_options = '--config filename' - AssertEqual '''luacheck'' --config filename --formatter plain --codes --filename %s -', + AssertEqual ale#Escape('luacheck') . ' --config filename --formatter plain --codes --filename %s -', \ join(split(ale_linters#lua#luacheck#GetCommand(1))) Execute(The luacheck executable should be configurable): let g:ale_lua_luacheck_executable = 'luacheck.sh' AssertEqual 'luacheck.sh', ale_linters#lua#luacheck#GetExecutable(1) - AssertEqual '''luacheck.sh'' --formatter plain --codes --filename %s -', + AssertEqual ale#Escape('luacheck.sh') . ' --formatter plain --codes --filename %s -', \ join(split(ale_linters#lua#luacheck#GetCommand(1))) diff --git a/test/command_callback/test_mypy_command_callback.vader b/test/command_callback/test_mypy_command_callback.vader index 8df7193d..4ccc008e 100644 --- a/test/command_callback/test_mypy_command_callback.vader +++ b/test/command_callback/test_mypy_command_callback.vader @@ -1,20 +1,35 @@ Before: + Save g:ale_python_mypy_executable + Save g:ale_python_mypy_options + Save g:ale_python_mypy_use_global + + unlet! g:ale_python_mypy_executable + unlet! g:ale_python_mypy_options + unlet! g:ale_python_mypy_use_global + + let b:bin_dir = has('win32') ? 'Scripts' : 'bin' + runtime ale_linters/python/mypy.vim + call ale#test#SetDirectory('/testplugin/test/command_callback') + call ale#test#SetFilename('test.py') After: + Restore + + unlet! b:bin_dir + unlet! b:executable + call ale#test#RestoreDirectory() call ale#linter#Reset() - let g:ale_python_mypy_executable = 'mypy' - let g:ale_python_mypy_options = '' - let g:ale_python_mypy_use_global = 0 Execute(The mypy callbacks should return the correct default values): AssertEqual \ 'mypy', \ ale_linters#python#mypy#GetExecutable(bufnr('')) AssertEqual - \ 'cd ''' . g:dir . ''' && ''mypy'' --show-column-numbers ' + \ 'cd ' . ale#Escape(g:dir) . ' && ' . ale#Escape('mypy') + \ . ' --show-column-numbers ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) @@ -25,7 +40,8 @@ Execute(The mypy executable should be configurable, and escaped properly): \ 'executable with spaces', \ ale_linters#python#mypy#GetExecutable(bufnr('')) AssertEqual - \ 'cd ''' . g:dir . ''' && ''executable with spaces'' --show-column-numbers ' + \ 'cd ' . ale#Escape(g:dir) . ' && ' . ale#Escape('executable with spaces') + \ . ' --show-column-numbers ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) @@ -33,7 +49,8 @@ Execute(The mypy command callback should let you set options): let g:ale_python_mypy_options = '--some-option' AssertEqual - \ 'cd ''' . g:dir . ''' && ''mypy'' --show-column-numbers --some-option ' + \ 'cd ' . ale#Escape(g:dir) . ' && ' . ale#Escape('mypy') + \ . ' --show-column-numbers --some-option ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) @@ -44,19 +61,24 @@ Execute(The mypy command should switch directories to the detected project root) \ 'mypy', \ ale_linters#python#mypy#GetExecutable(bufnr('')) AssertEqual - \ 'cd ''' . g:dir . '/python_paths/no_virtualenv/subdir'' && ''mypy'' --show-column-numbers ' + \ 'cd ' . ale#Escape(ale#path#Winify(g:dir . '/python_paths/no_virtualenv/subdir')) + \ . ' && ' . ale#Escape('mypy') + \ . ' --show-column-numbers ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) Execute(The mypy callbacks should detect virtualenv directories and switch to the project root): silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') + let b:executable = ale#path#Winify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/mypy') + AssertEqual - \ g:dir . '/python_paths/with_virtualenv/env/bin/mypy', + \ b:executable, \ ale_linters#python#mypy#GetExecutable(bufnr('')) AssertEqual - \ 'cd ''' . g:dir . '/python_paths/with_virtualenv/subdir'' && ''' - \ . g:dir . '/python_paths/with_virtualenv/env/bin/mypy'' --show-column-numbers ' + \ 'cd ' . ale#Escape(ale#path#Winify(g:dir . '/python_paths/with_virtualenv/subdir')) + \ . ' && ' . ale#Escape(b:executable) + \ . ' --show-column-numbers ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) @@ -68,6 +90,8 @@ Execute(You should able able to use the global mypy instead): \ 'mypy', \ ale_linters#python#mypy#GetExecutable(bufnr('')) AssertEqual - \ 'cd ''' . g:dir . '/python_paths/with_virtualenv/subdir'' && ''mypy'' --show-column-numbers ' + \ 'cd ' . ale#Escape(ale#path#Winify(g:dir . '/python_paths/with_virtualenv/subdir')) + \ . ' && ' . ale#Escape('mypy') + \ . ' --show-column-numbers ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) diff --git a/test/command_callback/test_php_langserver_callbacks.vader b/test/command_callback/test_php_langserver_callbacks.vader index 38630f4b..0c7e69ef 100644 --- a/test/command_callback/test_php_langserver_callbacks.vader +++ b/test/command_callback/test_php_langserver_callbacks.vader @@ -33,13 +33,13 @@ Execute(Vendor executables should be detected): call ale#test#SetFilename('php-langserver-project/test.php') AssertEqual - \ g:dir . '/php-langserver-project/vendor/bin/php-language-server.php', + \ ale#path#Winify(g:dir . '/php-langserver-project/vendor/bin/php-language-server.php'), \ ale_linters#php#langserver#GetExecutable(bufnr('')) AssertEqual - \ 'php ' . ale#Escape( + \ 'php ' . ale#Escape(ale#path#Winify( \ g:dir \ . '/php-langserver-project/vendor/bin/php-language-server.php' - \ ), + \ )), \ ale_linters#php#langserver#GetCommand(bufnr('')) Execute(The language string should be correct): diff --git a/test/command_callback/test_puglint_command_callback.vader b/test/command_callback/test_puglint_command_callback.vader index 6d189899..11946582 100644 --- a/test/command_callback/test_puglint_command_callback.vader +++ b/test/command_callback/test_puglint_command_callback.vader @@ -21,11 +21,12 @@ Execute(puglint should detect local executables and package.json): call ale#test#SetFilename('puglint_project/test.pug') AssertEqual - \ g:dir . '/puglint_project/node_modules/.bin/pug-lint', + \ ale#path#Winify(g:dir . '/puglint_project/node_modules/.bin/pug-lint'), \ ale_linters#pug#puglint#GetExecutable(bufnr('')) + AssertEqual - \ ale#Escape(g:dir . '/puglint_project/node_modules/.bin/pug-lint') - \ . ' -c ' . ale#Escape(g:dir . '/puglint_project/package.json') + \ ale#Escape(ale#path#Winify(g:dir . '/puglint_project/node_modules/.bin/pug-lint')) + \ . ' -c ' . ale#Escape(ale#path#Winify(g:dir . '/puglint_project/package.json')) \ . ' -r inline %t', \ ale_linters#pug#puglint#GetCommand(bufnr('')) @@ -35,9 +36,10 @@ Execute(puglint should use global executables if configured): call ale#test#SetFilename('puglint_project/test.pug') AssertEqual 'pug-lint', ale_linters#pug#puglint#GetExecutable(bufnr('')) + AssertEqual \ ale#Escape('pug-lint') - \ . ' -c ' . ale#Escape(g:dir . '/puglint_project/package.json') + \ . ' -c ' . ale#Escape(ale#path#Winify(g:dir . '/puglint_project/package.json')) \ . ' -r inline %t', \ ale_linters#pug#puglint#GetCommand(bufnr('')) @@ -45,8 +47,8 @@ Execute(puglint should detect .pug-lintrc): call ale#test#SetFilename('puglint_project/puglint_rc_dir/subdir/test.pug') AssertEqual - \ ale#Escape(g:dir . '/puglint_project/node_modules/.bin/pug-lint') - \ . ' -c ' . ale#Escape(g:dir . '/puglint_project/puglint_rc_dir/.pug-lintrc') + \ ale#Escape(ale#path#Winify(g:dir . '/puglint_project/node_modules/.bin/pug-lint')) + \ . ' -c ' . ale#Escape(ale#path#Winify(g:dir . '/puglint_project/puglint_rc_dir/.pug-lintrc')) \ . ' -r inline %t', \ ale_linters#pug#puglint#GetCommand(bufnr('')) @@ -54,8 +56,8 @@ Execute(puglint should detect .pug-lintrc.js): call ale#test#SetFilename('puglint_project/puglint_rc_js_dir/subdir/test.pug') AssertEqual - \ ale#Escape(g:dir . '/puglint_project/node_modules/.bin/pug-lint') - \ . ' -c ' . ale#Escape(g:dir . '/puglint_project/puglint_rc_js_dir/.pug-lintrc.js') + \ ale#Escape(ale#path#Winify(g:dir . '/puglint_project/node_modules/.bin/pug-lint')) + \ . ' -c ' . ale#Escape(ale#path#Winify(g:dir . '/puglint_project/puglint_rc_js_dir/.pug-lintrc.js')) \ . ' -r inline %t', \ ale_linters#pug#puglint#GetCommand(bufnr('')) @@ -63,7 +65,7 @@ Execute(puglint should detect .pug-lintrc.json): call ale#test#SetFilename('puglint_project/puglint_rc_json_dir/subdir/test.pug') AssertEqual - \ ale#Escape(g:dir . '/puglint_project/node_modules/.bin/pug-lint') - \ . ' -c ' . ale#Escape(g:dir . '/puglint_project/puglint_rc_json_dir/.pug-lintrc.json') + \ ale#Escape(ale#path#Winify(g:dir . '/puglint_project/node_modules/.bin/pug-lint')) + \ . ' -c ' . ale#Escape(ale#path#Winify(g:dir . '/puglint_project/puglint_rc_json_dir/.pug-lintrc.json')) \ . ' -r inline %t', \ ale_linters#pug#puglint#GetCommand(bufnr('')) diff --git a/test/command_callback/test_pycodestyle_command_callback.vader b/test/command_callback/test_pycodestyle_command_callback.vader index a5163461..58aefa20 100644 --- a/test/command_callback/test_pycodestyle_command_callback.vader +++ b/test/command_callback/test_pycodestyle_command_callback.vader @@ -9,15 +9,17 @@ After: Restore Execute(The pycodestyle command callback should return default string): - AssertEqual '''pycodestyle'' -', + AssertEqual ale#Escape('pycodestyle') . ' -', \ ale_linters#python#pycodestyle#GetCommand(bufnr('')) Execute(The pycodestyle command callback should allow options): let g:ale_python_pycodestyle_options = '--exclude=test*.py' - AssertEqual '''pycodestyle'' --exclude=test*.py -', + + AssertEqual ale#Escape('pycodestyle') . ' --exclude=test*.py -', \ ale_linters#python#pycodestyle#GetCommand(bufnr('')) Execute(The pycodestyle executable should be configurable): let g:ale_python_pycodestyle_executable = '~/.local/bin/pycodestyle' - AssertEqual '''~/.local/bin/pycodestyle'' -', + + AssertEqual ale#Escape('~/.local/bin/pycodestyle') . ' -', \ ale_linters#python#pycodestyle#GetCommand(bufnr('')) diff --git a/test/command_callback/test_pylint_command_callback.vader b/test/command_callback/test_pylint_command_callback.vader index f8f44ab6..447409b2 100644 --- a/test/command_callback/test_pylint_command_callback.vader +++ b/test/command_callback/test_pylint_command_callback.vader @@ -1,22 +1,34 @@ Before: + Save g:ale_python_pylint_executable + Save g:ale_python_pylint_options + Save g:ale_python_pylint_use_global + + unlet! g:ale_python_pylint_executable + unlet! g:ale_python_pylint_options + unlet! g:ale_python_pylint_use_global + runtime ale_linters/python/pylint.vim call ale#test#SetDirectory('/testplugin/test/command_callback') + let b:bin_dir = has('win32') ? 'Scripts' : 'bin' + let b:command_tail = ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' After: + Restore + call ale#test#RestoreDirectory() call ale#linter#Reset() - let g:ale_python_pylint_executable = 'pylint' - let g:ale_python_pylint_options = '' - let g:ale_python_pylint_use_global = 0 + + unlet! b:bin_dir + unlet! b:executable Execute(The pylint callbacks should return the correct default values): AssertEqual \ 'pylint', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ '''pylint'' ' . b:command_tail, + \ ale#Escape('pylint') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint executable should be configurable, and escaped properly): @@ -26,14 +38,14 @@ Execute(The pylint executable should be configurable, and escaped properly): \ 'executable with spaces', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ '''executable with spaces'' ' . b:command_tail, + \ ale#Escape('executable with spaces') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint command callback should let you set options): let g:ale_python_pylint_options = '--some-option' AssertEqual - \ '''pylint'' --some-option' . b:command_tail, + \ ale#Escape('pylint') . ' --some-option' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint callbacks shouldn't detect virtualenv directories where they don't exist): @@ -43,17 +55,22 @@ Execute(The pylint callbacks shouldn't detect virtualenv directories where they \ 'pylint', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ '''pylint'' ' . b:command_tail, + \ ale#Escape('pylint') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint callbacks should detect virtualenv directories): silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') + let b:executable = ale#path#Winify( + \ g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/pylint' + \) + AssertEqual - \ g:dir . '/python_paths/with_virtualenv/env/bin/pylint', + \ b:executable, \ ale_linters#python#pylint#GetExecutable(bufnr('')) + AssertEqual - \ ''''. g:dir . '/python_paths/with_virtualenv/env/bin/pylint'' ' . b:command_tail, + \ ale#Escape(b:executable) . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(You should able able to use the global pylint instead): @@ -64,5 +81,5 @@ Execute(You should able able to use the global pylint instead): \ 'pylint', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ '''pylint'' ' . b:command_tail, + \ ale#Escape('pylint') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) diff --git a/test/fixers/test_prettier_fixer_callback.vader b/test/fixers/test_prettier_fixer_callback.vader index cc7d34d0..471a8632 100644 --- a/test/fixers/test_prettier_fixer_callback.vader +++ b/test/fixers/test_prettier_fixer_callback.vader @@ -114,3 +114,17 @@ Execute(Append '--parser postcss' for filetype=css): \ . ' --write', \ }, \ ale#fixers#prettier#Fix(bufnr('')) + +Execute(Append '--parser postcss' for filetype=less): + set filetype=less + call ale#test#SetFilename('../prettier-test-files/testfile.less') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_javascript_prettier_executable) + \ . ' %t' + \ . ' --parser postcss' + \ . ' --write', + \ }, + \ ale#fixers#prettier#Fix(bufnr('')) diff --git a/test/fixers/test_trim_whitespace.vader b/test/fixers/test_trim_whitespace.vader new file mode 100644 index 00000000..2ffbcb04 --- /dev/null +++ b/test/fixers/test_trim_whitespace.vader @@ -0,0 +1,28 @@ +Before: + call ale#test#SetDirectory('/testplugin/test/fixers') + +After: + call ale#test#RestoreDirectory() + +Execute(Should delete all whitespace at the end of different lines): + AssertEqual + \ [ + \ 'def foo():', + \ ' some_variable = this_is_a_longer_function(', + \ 'first_argument,', + \ ' second_argument,', + \ ' third_with_function_call(', + \ 'foo,', + \ ' bar,', + \ '))', + \ ], + \ ale#fixers#generic#TrimWhitespace(bufnr(''), [ + \ 'def foo():', + \ ' some_variable = this_is_a_longer_function(', + \ 'first_argument,', + \ ' second_argument,', + \ ' third_with_function_call(', + \ 'foo,', + \ ' bar,', + \ '))', + \ ]) diff --git a/test/fixers/test_tslint_fixer_callback.vader b/test/fixers/test_tslint_fixer_callback.vader new file mode 100644 index 00000000..5bfafe24 --- /dev/null +++ b/test/fixers/test_tslint_fixer_callback.vader @@ -0,0 +1,41 @@ +Before: + Save g:ale_typescript_tslint_executable + Save g:ale_typescript_tslint_config_path + + let g:ale_typescript_tslint_executable = 'xxxinvalid' + let g:ale_typescript_tslint_config_path = 'tslint.json' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd .. + silent cd command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The tslint callback should return the correct default values): + call ale#test#SetFilename('../prettier-test-files/testfile.ts') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_typescript_tslint_executable) + \ . ' -c ' . ale#Escape('tslint.json') + \ . ' --fix %t', + \ }, + \ ale#fixers#tslint#Fix(bufnr('')) + +Execute(The tslint callback should include custom tslint config option): + let g:ale_typescript_tslint_config_path = '.tslintrc' + call ale#test#SetFilename('../prettier-test-files/testfile.ts') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_typescript_tslint_executable) + \ . ' -c ' . ale#Escape(g:ale_typescript_tslint_config_path) + \ . ' --fix %t', + \ }, + \ ale#fixers#tslint#Fix(bufnr('')) diff --git a/test/handler/test_llc_handler.vader b/test/handler/test_llc_handler.vader new file mode 100644 index 00000000..edea2337 --- /dev/null +++ b/test/handler/test_llc_handler.vader @@ -0,0 +1,56 @@ +Before: + runtime! ale_linters/llvm/llc.vim + +Execute(llc handler should parse errors output for STDIN): + AssertEqual + \ [ + \ { + \ 'lnum': 10, + \ 'col': 7, + \ 'text': "error: value doesn't match function result type 'i32'", + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 10, + \ 'col': 13, + \ 'text': "error: use of undefined value '@foo'", + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#llvm#llc#HandleErrors(bufnr(''), [ + \ "llc: <stdin>:10:7: error: value doesn't match function result type 'i32'", + \ 'ret i64 0', + \ ' ^', + \ '', + \ "llc: <stdin>:10:13: error: use of undefined value '@foo'", + \ 'call void @foo(i64 %0)', + \ ' ^', + \ ]) + +Execute(llc handler should parse errors output for some file): + call ale#test#SetFilename('test.ll') + AssertEqual + \ [ + \ { + \ 'lnum': 10, + \ 'col': 7, + \ 'text': "error: value doesn't match function result type 'i32'", + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 10, + \ 'col': 13, + \ 'text': "error: use of undefined value '@foo'", + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#llvm#llc#HandleErrors(bufnr(''), [ + \ "llc: /path/to/test.ll:10:7: error: value doesn't match function result type 'i32'", + \ 'ret i64 0', + \ ' ^', + \ '', + \ "llc: /path/to/test.ll:10:13: error: use of undefined value '@foo'", + \ 'call void @foo(i64 %0)', + \ ' ^', + \ ]) + diff --git a/test/handler/test_lua_handler.vader b/test/handler/test_lua_handler.vader index af1c134e..712c7c59 100644 --- a/test/handler/test_lua_handler.vader +++ b/test/handler/test_lua_handler.vader @@ -1,4 +1,8 @@ +Before: + Save g:ale_warn_about_trailing_whitespace + After: + Restore call ale#linter#Reset() Execute(The luacheck handler should parse lines correctly): @@ -30,3 +34,25 @@ Execute(The luacheck handler should parse lines correctly): \ ' /file/path/here.lua:3:5: (W213) unused loop variable ''k''', \ ' /file/path/here.lua:3:19: (W113) accessing undefined variable ''x''', \ ]) + +Execute(The luacheck handler should respect the warn_about_trailing_whitespace option): + runtime ale_linters/lua/luacheck.vim + + let g:ale_warn_about_trailing_whitespace = 0 + + AssertEqual + \ [ + \ { + \ 'lnum': 5, + \ 'col': 43, + \ 'text': 'W212: unused argument ''g''', + \ 'type': 'W', + \ } + \ ], + \ ale_linters#lua#luacheck#Handle(347, [ + \ '/file/path/here.lua:15:97: (W614) trailing whitespace in a comment', + \ '/file/path/here.lua:16:60: (W612) line contains trailing whitespace', + \ '/file/path/here.lua:17:1: (W611) line contains only whitespace', + \ '/file/path/here.lua:27:57: (W613) trailing whitespace in a string', + \ '/file/path/here.lua:5:43: (W212) unused argument ''g''', + \ ]) diff --git a/test/handler/test_remark_lint_handler.vader b/test/handler/test_remark_lint_handler.vader new file mode 100644 index 00000000..f63e0c5b --- /dev/null +++ b/test/handler/test_remark_lint_handler.vader @@ -0,0 +1,27 @@ +Before: + runtime ale_linters/markdown/remark_lint.vim + +Execute(Warning and error messages should be handled correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'col': 4, + \ 'type': 'W', + \ 'text': 'Incorrect list-item indent: add 1 space list-item-indent remark-lint', + \ }, + \ { + \ 'lnum': 3, + \ 'col': 5, + \ 'type': 'E', + \ 'text': 'Incorrect list-item indent: remove 1 space list-item-indent remark-lint', + \ }, + \ ], + \ ale_linters#markdown#remark_lint#Handle(1, [ + \ 'foo.md', + \ ' 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint', + \ ' 3:5 error Incorrect list-item indent: remove 1 space list-item-indent remark-lint', + \ '', + \ '⚠ 1 warnings', + \ '✘ 1 errors', + \]) diff --git a/test/handler/test_scalastyle_handler.vader b/test/handler/test_scalastyle_handler.vader index b03d18e7..32da79c0 100644 --- a/test/handler/test_scalastyle_handler.vader +++ b/test/handler/test_scalastyle_handler.vader @@ -1,6 +1,10 @@ -Execute(The scalastyle handler should parse lines correctly): +Before: runtime! ale_linters/scala/scalastyle.vim +After: + call ale#linter#Reset() + +Execute(The scalastyle handler should parse lines correctly): AssertEqual \ [ \ { @@ -34,5 +38,16 @@ Execute(The scalastyle handler should parse lines correctly): \ 'Finished in 934 ms', \ ]) -After: - call ale#linter#Reset() +Execute(The scalastyle linter should complain when there is no configuration file): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'text': '(See :help ale-scala-scalastyle) No scalastyle configuration file was found.', + \ }, + \ ], + \ ale_linters#scala#scalastyle#Handle(347, [ + \ 'scalastyle 1.0.0', + \ 'Usage: scalastyle [options] <source directory>', + \ ' -c, --config FILE configuration file (required)', + \ ]) diff --git a/test/sign/test_sign_limits.vader b/test/sign/test_sign_limits.vader new file mode 100644 index 00000000..b8868aeb --- /dev/null +++ b/test/sign/test_sign_limits.vader @@ -0,0 +1,57 @@ +Before: + Save g:ale_max_signs + + let g:ale_max_signs = -1 + + function! SetNProblems(sign_count) + let l:loclist = [] + let l:range = range(1, a:sign_count) + call setline(1, l:range) + + for l:index in l:range + call add(l:loclist, { + \ 'bufnr': bufnr(''), + \ 'lnum': l:index, + \ 'col': 1, + \ 'type': 'E', + \ 'text': 'a', + \}) + endfor + + call ale#sign#SetSigns(bufnr(''), l:loclist) + + return sort(map(ale#sign#FindCurrentSigns(bufnr(''))[1], 'v:val[0]'), 'n') + endfunction + +After: + Restore + + unlet! b:ale_max_signs + + delfunction SetNProblems + + sign unplace * + +Execute(There should be no limit on signs with negative numbers): + AssertEqual range(1, 42), SetNProblems(42) + +Execute(0 signs should be set when the max is 0): + let g:ale_max_signs = 0 + + AssertEqual [], SetNProblems(42) + +Execute(1 signs should be set when the max is 1): + let g:ale_max_signs = 1 + + AssertEqual [1], SetNProblems(42) + +Execute(10 signs should be set when the max is 10): + let g:ale_max_signs = 10 + + " We'll check that we set signs for the first 10 items, not other lines. + AssertEqual range(1, 10), SetNProblems(42) + +Execute(5 signs should be set when the max is 5 for the buffer): + let b:ale_max_signs = 5 + + AssertEqual range(1, 5), SetNProblems(42) diff --git a/test/test_ale_init_au_groups.vader b/test/test_autocmd_commands.vader index 2685f50b..17e3b16d 100644 --- a/test/test_ale_init_au_groups.vader +++ b/test/test_autocmd_commands.vader @@ -199,6 +199,12 @@ Execute (g:ale_echo_cursor = 1 should bind cursor events): \ 'InsertLeave * call ale#cursor#EchoCursorWarning()', \], CheckAutocmd('ALECursorGroup') +Execute (ALECleanupGroup should include the right commands): + AssertEqual [ + \ 'BufUnload * call ale#engine#Cleanup(str2nr(expand(''<abuf>'')))', + \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))', + \], CheckAutocmd('ALECleanupGroup') + Execute(Enabling completion should set up autocmd events correctly): let g:ale_completion_enabled = 0 call ale#completion#Enable() diff --git a/test/test_lint_error_delay.vader b/test/test_lint_error_delay.vader index 4c7f0947..7f081794 100644 --- a/test/test_lint_error_delay.vader +++ b/test/test_lint_error_delay.vader @@ -17,10 +17,6 @@ Execute(ALE should stop linting for a while after exceptions are thrown): AssertThrows call ale#Lint() call ale#Lint() -Execute(ALE should stop queuing echo messages for a while after exceptions are thrown): - AssertThrows call ale#cursor#EchoCursorWarningWithDelay() - call ale#cursor#EchoCursorWarningWithDelay() - Execute(ALE should stop echoing messages for a while after exceptions are thrown): AssertThrows call ale#cursor#EchoCursorWarning() call ale#cursor#EchoCursorWarning() diff --git a/test/test_no_linting_on_write_quit.vader b/test/test_no_linting_on_write_quit.vader new file mode 100644 index 00000000..d3baeaa1 --- /dev/null +++ b/test/test_no_linting_on_write_quit.vader @@ -0,0 +1,97 @@ +Before: + Save g:ale_echo_cursor + Save g:ale_fix_on_save + Save g:ale_fixers + Save g:ale_lint_on_save + + let g:ale_echo_cursor = 0 + let g:ale_run_synchronously = 1 + + function! TestCallback(buffer, output) + return [{'lnum': 1, 'col': 1, 'text': 'xxx'}] + endfunction + + function AddLine(buffer, lines) abort + return a:lines + ['x'] + endfunction + + let g:ale_fixers = { + \ 'testft': ['AddLine'], + \} + + call ale#linter#Define('testft', { + \ 'name': 'testlinter', + \ 'callback': 'TestCallback', + \ 'executable': has('win32') ? 'cmd' : 'true', + \ 'command': 'true', + \}) + +Given testft (An empty file): + +After: + Restore + + unlet! g:ale_run_synchronously + unlet! b:ale_quitting + delfunction TestCallback + delfunction AddLine + + call ale#linter#Reset() + call setloclist(0, []) + +Execute(No linting should be done on :wq or :x): + let g:ale_lint_on_save = 1 + let g:ale_fix_on_save = 0 + + " First try just the SaveEvent, to be sure that we set errors in the test. + call ale#events#SaveEvent(bufnr('')) + + AssertEqual 1, len(getloclist(0)) + + " Now try doing it again, but where we run the quit event first. + call setloclist(0, []) + call ale#events#QuitEvent(bufnr('')) + call ale#events#SaveEvent(bufnr('')) + + AssertEqual [], getloclist(0) + +Execute(No linting should be for :w after :q fails): + let g:ale_lint_on_save = 1 + let g:ale_fix_on_save = 0 + + call ale#events#QuitEvent(bufnr('')) + + " Simulate 2 seconds passing. + let b:ale_quitting -= 1000 + + call ale#events#SaveEvent(bufnr('')) + + AssertEqual 1, len(getloclist(0)) + +Execute(No linting should be done on :wq or :x after fixing files): + let g:ale_lint_on_save = 0 + let g:ale_fix_on_save = 1 + + call ale#events#SaveEvent(bufnr('')) + + AssertEqual 1, len(getloclist(0)) + + " Now try doing it again, but where we run the quit event first. + call setloclist(0, []) + call ale#events#QuitEvent(bufnr('')) + call ale#events#SaveEvent(bufnr('')) + + AssertEqual [], getloclist(0) + +Execute(Linting should be done after :q fails and fixing files): + let g:ale_lint_on_save = 0 + let g:ale_fix_on_save = 1 + + call ale#events#QuitEvent(bufnr('')) + + " Simulate 2 seconds passing. + let b:ale_quitting -= 1000 + + call ale#events#SaveEvent(bufnr('')) + + AssertEqual 1, len(getloclist(0)) diff --git a/test/test_python_virtualenv.vader b/test/test_python_virtualenv.vader new file mode 100644 index 00000000..b44c5fa2 --- /dev/null +++ b/test/test_python_virtualenv.vader @@ -0,0 +1,12 @@ +Before: + Save $VIRTUAL_ENV + let $VIRTUAL_ENV = "/opt/example/" + +After: + Restore + +Execute(ale#python#FindVirtualenv falls back to $VIRTUAL_ENV when no directories match): + AssertEqual + \ ale#python#FindVirtualenv(bufnr('%')), + \ '/opt/example/', + \ 'Expected VIRTUAL_ENV environment variable to be used, but it was not' diff --git a/test/test_quitting_variable.vader b/test/test_quitting_variable.vader new file mode 100644 index 00000000..bef344a8 --- /dev/null +++ b/test/test_quitting_variable.vader @@ -0,0 +1,39 @@ +Before: + Save g:ale_enabled + + unlet! b:ale_quitting + let g:ale_enabled = 0 + +After: + Restore + + unlet! b:ale_quitting + unlet! b:time_before + +Execute(QuitEvent should set b:ale_quitting some time from the clock): + let b:time_before = ale#util#ClockMilliseconds() + + call ale#events#QuitEvent(bufnr('')) + + Assert b:ale_quitting >= b:time_before + Assert b:ale_quitting <= ale#util#ClockMilliseconds() + +Execute(EnterEvent should set b:ale_quitting to 0): + let b:ale_quitting = 1 + + call ale#events#EnterEvent(bufnr('')) + + AssertEqual 0, b:ale_quitting + +Execute(The QuitRecently function should work when the variable isn't set): + AssertEqual 0, ale#events#QuitRecently(bufnr('')) + +Execute(The QuitRecently function should return 1 when ALE quit recently): + let b:ale_quitting = ale#util#ClockMilliseconds() + + AssertEqual 1, ale#events#QuitRecently(bufnr('')) + +Execute(The QuitRecently function should return 0 when a second has passed): + let b:ale_quitting = ale#util#ClockMilliseconds() - 1001 + + AssertEqual 0, ale#events#QuitRecently(bufnr('')) diff --git a/test/test_should_do_nothing_conditions.vader b/test/test_should_do_nothing_conditions.vader index 4d6facf9..3afa11ac 100644 --- a/test/test_should_do_nothing_conditions.vader +++ b/test/test_should_do_nothing_conditions.vader @@ -1,7 +1,22 @@ Before: Save &l:statusline + let b:funky_command_created = 0 + + " We will test for the existence of this command, so create one if needed. + if !exists(':CtrlPFunky') + command CtrlPFunky echo + let b:funky_command_created = 1 + endif + After: + if b:funky_command_created + delcommand CtrlPFunky + let b:funky_command_created = 0 + endif + + unlet! b:funky_command_created + Restore Execute(ALE shouldn't do much of anything for ctrlp-funky buffers): |