diff options
-rw-r--r-- | ISSUE_TEMPLATE.md | 10 | ||||
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | README.md | 27 | ||||
-rw-r--r-- | ale_linters/cpp/clang.vim | 2 | ||||
-rw-r--r-- | ale_linters/yaml/yamllint.vim | 20 | ||||
-rw-r--r-- | autoload/ale/debugging.vim | 48 | ||||
-rw-r--r-- | autoload/ale/engine.vim | 66 | ||||
-rw-r--r-- | autoload/ale/history.vim | 58 | ||||
-rw-r--r-- | autoload/ale/linter.vim | 5 | ||||
-rw-r--r-- | doc/ale.txt | 72 | ||||
-rw-r--r-- | plugin/ale.vim | 22 | ||||
-rw-r--r-- | test/test_ale_info.vader | 140 | ||||
-rw-r--r-- | test/test_ale_toggle.vader | 112 | ||||
-rw-r--r-- | test/test_history_saving.vader | 95 | ||||
-rw-r--r-- | test/test_vim8_processid_parsing.vader | 5 |
15 files changed, 667 insertions, 26 deletions
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..730e6fa4 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,10 @@ +For bugs, paste output from your clipboard after running :ALEInfoToClipboard +here. If that doesn't work for some reason, try running :ALEInfo and copying +the output from that here instead. If everything is broken, run around in +circles and scream. + +If you are experiencing a bug where ALE is not correctly parsing the output of +commands, set g:ale_history_log_output to 1, and run ALE again, and then +:ALEInfo should include the full output of each command which ran. + +Whatever the case, describe the your issue here. @@ -2,11 +2,20 @@ SHELL := /usr/bin/env bash IMAGE ?= w0rp/ale CURRENT_IMAGE_ID = 107e4efc4267 DOCKER_FLAGS = --rm -v $(PWD):/testplugin -v $(PWD)/test:/home "$(IMAGE)" +tests = test/* test-setup: docker images -q w0rp/ale | grep ^$(CURRENT_IMAGE_ID) > /dev/null || \ docker pull $(IMAGE) +vader: test-setup + @:; \ + vims=$$(docker run --rm $(IMAGE) ls /vim-build/bin | grep -E '^n?vim'); \ + if [ -z "$$vims" ]; then echo "No Vims found!"; exit 1; fi; \ + for vim in $$vims; do \ + docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! $(tests)'; \ + done + test: test-setup @:; \ vims=$$(docker run --rm $(IMAGE) ls /vim-build/bin | grep -E '^n?vim'); \ @@ -18,7 +27,7 @@ test: test-setup echo "Running tests for $$vim"; \ echo '========================================'; \ echo; \ - docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! test/*' || EXIT=$$?; \ + docker run -a stderr $(DOCKER_FLAGS) $$vim '+Vader! $(tests)' || EXIT=$$?; \ done; \ echo; \ echo '========================================'; \ @@ -34,6 +34,7 @@ In other words, this plugin allows you to lint while you type. 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) <a name="supported-languages"></a> @@ -410,3 +411,29 @@ ALE will alias the `jsx` filetype so it uses the `css` filetype linters, and use the original Array of selected linters for `jsx` from the `g:ale_linters` object. All available linters will be used for the filetype `javascript`, and no linter will be run twice for the same file. + +<a name="faq-my-battery-is-sad"></a> + +### 4.xi. 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 +are concerned about the CPU time ALE will spend, which will of course imply +some cost to battery life, you can adjust your settings to make your CPU do +less work. + +First, consider increasing the delay before which ALE will run any linters +while you type. ALE uses a timeout which is cancelled and reset every time you +type, and this delay can be increased so linters are run less often. See +`:help g:ale_lint_delay` for more information. + +If you don't wish to run linters while you type, you can disable that +behaviour. Set `g:ale_lint_on_text_changed` to `0`, and consider setting +`g:ale_lint_on_save` to `1` to enable linting when you save files. You won't +get as frequent error checking, but ALE shouldn't block your ability to edit a +document after you save a file, so the asynchronous nature of the plugin will +still be an advantage. + +If you are still concerned, you can turn the automatic linting off altogether, +including the option `g:ale_lint_on_enter`, and you can run ALE manually with +`:call ale#Lint()`. diff --git a/ale_linters/cpp/clang.vim b/ale_linters/cpp/clang.vim index 8ae48bc4..9c2c73cf 100644 --- a/ale_linters/cpp/clang.vim +++ b/ale_linters/cpp/clang.vim @@ -13,7 +13,7 @@ call ale#linter#Define('cpp', { \ 'name': 'clang', \ 'output_stream': 'stderr', \ 'executable': 'clang++', -\ 'command': 'clang++ -S -x c -fsyntax-only ' +\ 'command': 'clang++ -S -x c++ -fsyntax-only ' \ . g:ale_cpp_clang_options \ . ' -', \ 'callback': 'ale#handlers#HandleGCCFormat', diff --git a/ale_linters/yaml/yamllint.vim b/ale_linters/yaml/yamllint.vim index 0a1ca7d0..42006fb4 100644 --- a/ale_linters/yaml/yamllint.vim +++ b/ale_linters/yaml/yamllint.vim @@ -1,5 +1,21 @@ " Author: KabbAmine <amine.kabb@gmail.com> +let g:ale_yaml_yamllint_executable = +\ get(g:, 'ale_yaml_yamllint_executable', 'yamllint') + +let g:ale_yaml_yamllint_options = +\ get(g:, 'ale_yaml_yamllint_options', '') + +function! ale_linters#yaml#yamllint#GetExecutable(buffer) abort + return g:ale_yaml_yamllint_executable +endfunction + +function! ale_linters#yaml#yamllint#GetCommand(buffer) abort + return ale_linters#yaml#yamllint#GetExecutable(a:buffer) + \ . ' ' . g:ale_yaml_yamllint_options + \ . ' -f parsable %t' +endfunction + function! ale_linters#yaml#yamllint#Handle(buffer, lines) abort " Matches patterns line the following: " something.yaml:1:1: [warning] missing document start "---" (document-start) @@ -36,7 +52,7 @@ endfunction call ale#linter#Define('yaml', { \ 'name': 'yamllint', -\ 'executable': 'yamllint', -\ 'command': 'yamllint -f parsable %t', +\ 'executable_callback': 'ale_linters#yaml#yamllint#GetExecutable', +\ 'command_callback': 'ale_linters#yaml#yamllint#GetCommand', \ 'callback': 'ale_linters#yaml#yamllint#Handle', \}) diff --git a/autoload/ale/debugging.vim b/autoload/ale/debugging.vim index e56aea5b..60c1b37c 100644 --- a/autoload/ale/debugging.vim +++ b/autoload/ale/debugging.vim @@ -60,6 +60,43 @@ function! s:EchoGlobalVariables() abort endfor endfunction +function! s:EchoCommandHistory() abort + let l:buffer = bufnr('%') + + if !has_key(g:ale_buffer_info, l:buffer) + return + endif + + for l:item in g:ale_buffer_info[l:buffer].history + let l:status_message = l:item.status + + " Include the exit code in output if we have it. + if l:item.status ==# 'finished' + let l:status_message .= ' - exit code ' . l:item.exit_code + endif + + echom '(' . l:status_message . ') ' . string(l:item.command) + + if g:ale_history_log_output && has_key(l:item, 'output') + if empty(l:item.output) + echom '' + echom '<<<NO OUTPUT RETURNED>>>' + echom '' + else + echom '' + echom '<<<OUTPUT STARTS>>>' + + for l:line in l:item.output + echom l:line + endfor + + echom '<<<OUTPUT ENDS>>>' + echom '' + endif + endif + endfor +endfunction + function! ale#debugging#Info() abort let l:filetype = &filetype @@ -91,4 +128,15 @@ function! ale#debugging#Info() abort echom ' Global Variables:' echom '' call s:EchoGlobalVariables() + echom ' Command History:' + echom '' + call s:EchoCommandHistory() +endfunction + +function! ale#debugging#InfoToClipboard() abort + redir @+> + silent call ale#debugging#Info() + redir END + + echom 'ALEInfo copied to your clipboard' endfunction diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index d816a96b..61db4a1c 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -9,21 +9,19 @@ " output: The array of lines for the output of the job. let s:job_info_map = {} +function! ale#engine#ParseVim8ProcessID(job_string) abort + return matchstr(a:job_string, '\d\+') + 0 +endfunction + function! s:GetJobID(job) abort if has('nvim') "In NeoVim, job values are just IDs. return a:job endif - " In Vim 8, the job is a special variable, and we open a channel for each - " job. We'll use the ID of the channel instead as the job ID. - try - return ch_info(job_getchannel(a:job)).id - catch - endtry - - " If we fail to get the channel ID for a job, just return a 0 ID. - return 0 + " For Vim 8, the job is a different variable type, and we can parse the + " process ID from the string. + return ale#engine#ParseVim8ProcessID(string(a:job)) endfunction function! ale#engine#InitBufferInfo(buffer) abort @@ -33,12 +31,14 @@ function! ale#engine#InitBufferInfo(buffer) abort " new_loclist holds loclist items while jobs are being run. " temporary_file_list holds temporary files to be cleaned up " temporary_directory_list holds temporary directories to be cleaned up + " history holds a list of previously run commands for this buffer let g:ale_buffer_info[a:buffer] = { \ 'job_list': [], \ 'loclist': [], \ 'new_loclist': [], \ 'temporary_file_list': [], \ 'temporary_directory_list': [], + \ 'history': [], \} endif endfunction @@ -212,6 +212,11 @@ function! s:HandleExit(job) abort return endif + " Log the output of the command for ALEInfo if we should. + if g:ale_history_enabled && g:ale_history_log_output + call ale#history#RememberOutput(l:buffer, l:job_id, l:output[:]) + endif + let l:linter_loclist = ale#util#GetFunction(l:linter.callback)(l:buffer, l:output) " Make some adjustments to the loclists to fix common problems. @@ -268,7 +273,23 @@ function! ale#engine#SetResults(buffer, loclist) abort endif endfunction -function! s:HandleExitNeoVim(job, data, event) abort +function! s:SetExitCode(job, exit_code) abort + let l:job_id = s:GetJobID(a:job) + + if !has_key(s:job_info_map, l:job_id) + return + endif + + let l:buffer = s:job_info_map[l:job_id].buffer + + call ale#history#SetExitCode(l:buffer, l:job_id, a:exit_code) +endfunction + +function! s:HandleExitNeoVim(job, exit_code, event) abort + if g:ale_history_enabled + call s:SetExitCode(a:job, a:exit_code) + endif + call s:HandleExit(a:job) endfunction @@ -276,6 +297,12 @@ function! s:HandleExitVim(channel) abort call s:HandleExit(ch_getjob(a:channel)) endfunction +" Vim returns the exit status with one callback, +" and the channel will close later in another callback. +function! s:HandleExitStatusVim(job, exit_code) abort + call s:SetExitCode(a:job, a:exit_code) +endfunction + function! s:FixLocList(buffer, loclist) abort " Some errors have line numbers beyond the end of the file, " so we need to adjust them so they set the error at the last line @@ -413,6 +440,12 @@ function! s:RunJob(options) abort \ 'close_cb': function('s:HandleExitVim'), \} + if g:ale_history_enabled + " We only need to capture the exit status if we are going to + " save it in the history. Otherwise, we don't care. + let l:job_options.exit_cb = function('s:HandleExitStatusVim') + endif + if l:output_stream ==# 'stderr' " Read from stderr instead of stdout. let l:job_options.err_cb = function('s:GatherOutputVim') @@ -437,19 +470,30 @@ function! s:RunJob(options) abort let l:job = job_start(l:command, l:job_options) endif + let l:status = 'failed' + let l:job_id = 0 + " Only proceed if the job is being run. if has('nvim') || (l:job !=# 'no process' && job_status(l:job) ==# 'run') " Add the job to the list of jobs, so we can track them. call add(g:ale_buffer_info[l:buffer].job_list, l:job) + let l:status = 'started' + let l:job_id = s:GetJobID(l:job) " Store the ID for the job in the map to read back again. - let s:job_info_map[s:GetJobID(l:job)] = { + let s:job_info_map[l:job_id] = { \ 'linter': l:linter, \ 'buffer': l:buffer, \ 'output': [], \ 'next_chain_index': l:next_chain_index, \} endif + + if g:ale_history_enabled + call ale#history#Add(l:buffer, l:status, l:job_id, l:command) + else + let g:ale_buffer_info[l:buffer].history = [] + endif endfunction " Determine which commands to run for a link in a command chain, or diff --git a/autoload/ale/history.vim b/autoload/ale/history.vim new file mode 100644 index 00000000..78703be1 --- /dev/null +++ b/autoload/ale/history.vim @@ -0,0 +1,58 @@ +" Author: w0rp <devw0rp@gmail.com> +" Description: Tools for managing command history +" +function! ale#history#Add(buffer, status, job_id, command) abort + if g:ale_max_buffer_history_size <= 0 + " Don't save anything if the history isn't a positive number. + let g:ale_buffer_info[a:buffer].history = [] + + return + endif + + let l:history = g:ale_buffer_info[a:buffer].history + + " Remove the first item if we hit the max history size. + if len(l:history) >= g:ale_max_buffer_history_size + let l:history = l:history[1:] + endif + + call add(l:history, { + \ 'status': a:status, + \ 'job_id': a:job_id, + \ 'command': a:command, + \}) + + let g:ale_buffer_info[a:buffer].history = l:history +endfunction + +function! s:FindHistoryItem(buffer, job_id) abort + " Search backwards to find a matching job ID. IDs might be recycled, + " so finding the last one should be good enough. + for l:obj in reverse(g:ale_buffer_info[a:buffer].history[:]) + if l:obj.job_id == a:job_id + return l:obj + endif + endfor + + return {} +endfunction + +" Set an exit code for a command which finished. +function! ale#history#SetExitCode(buffer, job_id, exit_code) abort + let l:obj = s:FindHistoryItem(a:buffer, a:job_id) + + if !empty(l:obj) + " If we find a match, then set the code and status. + let l:obj.exit_code = a:exit_code + let l:obj.status = 'finished' + endif +endfunction + +" Set the output for a command which finished. +function! ale#history#RememberOutput(buffer, job_id, output) abort + let l:obj = s:FindHistoryItem(a:buffer, a:job_id) + + if !empty(l:obj) + let l:obj.output = a:output + endif +endfunction diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim index e586c1f3..e7b3b99d 100644 --- a/autoload/ale/linter.vim +++ b/autoload/ale/linter.vim @@ -18,10 +18,13 @@ let s:default_ale_linter_aliases = { " The user defined linter selections will be merged with this Dictionary. " " No linters are used for plaintext files by default. +" +" Only cargo is enabled for Rust by default. let s:default_ale_linters = { -\ 'zsh': ['shell'], \ 'csh': ['shell'], +\ 'rust': ['cargo'], \ 'text': [], +\ 'zsh': ['shell'], \} " Testing/debugging helper to unload all linters. diff --git a/doc/ale.txt b/doc/ale.txt index 855abd1e..f21983b5 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -40,6 +40,7 @@ CONTENTS *ale-contents* 4.28. phpmd...........................|ale-linter-options-phpmd| 4.29. xo..............................|ale-linter-options-xo| 4.30. javac...........................|ale-linter-options-javac| + 4.31. yamllint........................|ale-linter-options-yamllint| 5. Linter Integration Notes.............|ale-linter-integration| 5.1. merlin..........................|ale-linter-integration-ocaml-merlin| 5.2. rust.............................|ale-integration-rust| @@ -185,6 +186,35 @@ g:ale_enabled *g:ale_enabled* the |ALEToggle| command, which changes this option. +g:ale_history_enabled *g:ale_history_enabled* + + Type: |Number| + Default: `1` + + When set to `1`, ALE will remember the last few commands which were run + for every buffer which is open. This information can be viewed with the + |ALEInfo| command. The size of the buffer can be controlled with the + |g:ale_max_buffer_history_size| option. + + This option can be disabled if storing a command history is not desired. + + +g:ale_history_log_output *g:ale_history_log_output* + + Type: |Number| + Default: `0` + + When set to `1`, ALE will store the output of commands which have completed + successfully in the command history, and the output will be displayed when + using |ALEInfo|. + + |g:ale_history_enabled| must be set to `1` for this output to be stored or + printed. + + ALE will likely consume a lot of memory if this option is on, so it should + only be used for debugging problems with linters. + + g:ale_keep_list_window_open *g:ale_keep_list_window_open* Type: |Number| @@ -288,8 +318,10 @@ g:ale_linters *g:ale_linters* following values: > { - \ 'zsh': ['shell'], \ 'csh': ['shell'], + \ 'rust': ['cargo'], + \ 'text': [], + \ 'zsh': ['shell'], \} < This option can be used to enable only a particular set of linters for a @@ -308,6 +340,19 @@ g:ale_linters *g:ale_linters* let g:ale_linters = {'c': 'all'} < +g:ale_max_buffer_history_size *g:ale_max_buffer_history_size* + + Type: |Number| + Default: `20` + + This setting controls the maximum number of commands which will be stored in + the command history used for |ALEInfo|. Command history will be rotated in + a FIFO manner. If set to a number <= 0, then the history will be + continuously set to an empty |List|. + + History can be disabled completely with |g:ale_history_enabled|. + + g:ale_open_list *g:ale_open_list* Type: |Number| @@ -997,6 +1042,24 @@ g:ale_java_javac_options *g:ale_java_javac_options* This variable can be set to pass additional options to javac. +------------------------------------------------------------------------------ +4.31. yamllint *ale-linter-options-yamllint* + +g:ale_yaml_yamllint_executable *g:ale_yaml_yamllint_executable* + + Type: |String| + Default: `'yamllint'` + + This variable can be set to change the path to yamllint. + + +g:ale_yaml_yamllint_options *g:ale_yaml_yamllint_options* + + Type: |String| + Default: `''` + + This variable can be set to pass additional options to yamllint. + =============================================================================== 5. Linter Integration Notes *ale-linter-integration* @@ -1028,6 +1091,13 @@ Some linters may have requirements for some other plugins being installed. recommended to turn off |g:ale_lint_on_text_changed| and to turn on |g:ale_lint_on_save|. + Only cargo is enabled by default. To switch to using rustc instead of cargo, + configure |g:ale_linters| appropriately: > + + " See the help text for the option for more information. + let g:ale_linters = {'rust': ['rustc']} +< + Also note that rustc 1.12. or later is needed. =============================================================================== diff --git a/plugin/ale.vim b/plugin/ale.vim index 45b0b908..fd598d4c 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -49,7 +49,7 @@ let g:ale_buffer_info = {} " This option prevents ALE autocmd commands from being run for particular " filetypes which can cause issues. -let g:ale_filetype_blacklist = ['nerdtree', 'unite'] +let g:ale_filetype_blacklist = ['nerdtree', 'unite', 'tags'] " This Dictionary configures which linters are enabled for which languages. let g:ale_linters = get(g:, 'ale_linters', {}) @@ -131,6 +131,15 @@ let g:ale_statusline_format = get(g:, 'ale_statusline_format', let g:ale_warn_about_trailing_whitespace = \ get(g:, 'ale_warn_about_trailing_whitespace', 1) +" A flag for controlling the maximum size of the command history to store. +let g:ale_max_buffer_history_size = get(g:, 'ale_max_buffer_history_size', 20) + +" A flag for enabling or disabling the command history. +let g:ale_history_enabled = get(g:, 'ale_history_enabled', 1) + +" A flag for storing the full output of commands in the history. +let g:ale_history_log_output = get(g:, 'ale_history_log_output', 0) + function! s:ALEInitAuGroups() abort augroup ALERunOnTextChangedGroup autocmd! @@ -159,6 +168,13 @@ function! s:ALEInitAuGroups() abort autocmd CursorMoved,CursorHold * call ale#cursor#EchoCursorWarningWithDelay() endif augroup END + + if !g:ale_enabled + augroup! ALERunOnTextChangedGroup + augroup! ALERunOnEnterGroup + augroup! ALERunOnSaveGroup + augroup! ALECursorGroup + endif endfunction function! s:ALEToggle() abort @@ -176,7 +192,7 @@ function! s:ALEToggle() abort endfor " Remove highlights for the current buffer now. - if g:ale_set_higlights + if g:ale_set_highlights call ale#highlight#UpdateHighlights() endif endif @@ -196,6 +212,8 @@ command! ALEToggle :call s:ALEToggle() " Define command to get information about current filetype. command! ALEInfo :call ale#debugging#Info() +" The same, but copy output to your clipboard. +command! ALEInfoToClipboard :call ale#debugging#InfoToClipboard() " <Plug> mappings for commands nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return> diff --git a/test/test_ale_info.vader b/test/test_ale_info.vader index 838abe7f..ecea899b 100644 --- a/test/test_ale_info.vader +++ b/test/test_ale_info.vader @@ -34,10 +34,18 @@ Before: \ 'let g:ale_statusline_format = [''%d error(s)'', ''%d warning(s)'', ''OK'']', \ 'let g:ale_warn_about_trailing_whitespace = 1', \], "\n") + let g:command_header = "\n Command History:\n" After: unlet! g:output unlet! g:globals_string + unlet! g:command_header + let g:ale_buffer_info = {} + let g:ale_history_log_output = 0 + unlet! g:ale_testft_testlinter1_foo + unlet! g:ale_testft_testlinter1_bar + unlet! g:ale_testft2_testlinter2_foo + unlet! g:ale_testft2_testlinter2_bar Given nolintersft (Empty buffer with no linters): Execute (ALEInfo with no linters should return the right output): @@ -49,7 +57,7 @@ Execute (ALEInfo with no linters should return the right output): \Available Linters: []\n \ Enabled Linters: []\n \ Linter Variables:\n - \" . g:globals_string, g:output + \" . g:globals_string . g:command_header, g:output Given (Empty buffer with no filetype): Execute (ALEInfo with no filetype should return the right output): @@ -61,7 +69,7 @@ Execute (ALEInfo with no filetype should return the right output): \Available Linters: []\n \ Enabled Linters: []\n \ Linter Variables:\n - \" . g:globals_string, g:output + \" . g:globals_string . g:command_header, g:output Given testft (Empty buffer): Execute (ALEInfo with a single linter should return the right output): @@ -74,7 +82,7 @@ Execute (ALEInfo with a single linter should return the right output): \Available Linters: ['testlinter1']\n \ Enabled Linters: ['testlinter1']\n \ Linter Variables:\n - \" . g:globals_string, g:output + \" . g:globals_string . g:command_header, g:output Given testft (Empty buffer): Execute (ALEInfo with two linters should return the right output): @@ -88,7 +96,7 @@ Execute (ALEInfo with two linters should return the right output): \Available Linters: ['testlinter1', 'testlinter2']\n \ Enabled Linters: ['testlinter1', 'testlinter2']\n \ Linter Variables:\n - \" . g:globals_string, g:output + \" . g:globals_string . g:command_header, g:output Given testft (Empty buffer): Execute (ALEInfo should calculate enabled linters correctly): @@ -118,7 +126,7 @@ Execute (ALEInfo should only return linters for current filetype): \Available Linters: ['testlinter1']\n \ Enabled Linters: ['testlinter1']\n \ Linter Variables:\n - \" . g:globals_string, g:output + \" . g:globals_string . g:command_header, g:output Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo with compound filetypes should return linters for both of them): @@ -132,7 +140,7 @@ Execute (ALEInfo with compound filetypes should return linters for both of them) \Available Linters: ['testlinter1', 'testlinter2']\n \ Enabled Linters: ['testlinter1', 'testlinter2']\n \ Linter Variables:\n - \" . g:globals_string, g:output + \" . g:globals_string . g:command_header, g:output Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should return appropriately named global variables): @@ -155,4 +163,122 @@ Execute (ALEInfo should return appropriately named global variables): \let g:ale_testft2_testlinter2_bar = {'x': 'y'}\n \let g:ale_testft2_testlinter2_foo = 123\n \let g:ale_testft_testlinter1_bar = ['abc']\n - \let g:ale_testft_testlinter1_foo = 'abc'" . g:globals_string, g:output + \let g:ale_testft_testlinter1_foo = 'abc'" + \ . g:globals_string . g:command_header, g:output + +Given testft.testft2 (Empty buffer with two filetypes): +Execute (ALEInfo should return command history): + let g:ale_buffer_info[bufnr('%')] = { + \ 'history': [ + \ {'status': 'started', 'job_id': 347, 'command': 'first command'}, + \ {'status': 'started', 'job_id': 347, 'command': ['/bin/bash', '\c', 'last command']}, + \ ], + \} + + call ale#linter#Define('testft', g:testlinter1) + call ale#linter#Define('testft2', g:testlinter2) + redir => g:output + silent ALEInfo + redir END + AssertEqual + \ join([ + \ '', + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ' Linter Variables:', + \ g:globals_string . g:command_header, + \ '(started) ''first command''', + \ '(started) [''/bin/bash'', ''\c'', ''last command'']', + \ ], "\n"), + \ g:output + +Given testft.testft2 (Empty buffer with two filetypes): +Execute (ALEInfo command history should print exit codes correctly): + let g:ale_buffer_info[bufnr('%')] = { + \ 'history': [ + \ {'status': 'finished', 'exit_code': 0, 'job_id': 347, 'command': 'first command'}, + \ {'status': 'finished', 'exit_code': 1, 'job_id': 347, 'command': ['/bin/bash', '\c', 'last command']}, + \ ], + \} + + call ale#linter#Define('testft', g:testlinter1) + call ale#linter#Define('testft2', g:testlinter2) + redir => g:output + silent ALEInfo + redir END + AssertEqual + \ join([ + \ '', + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ' Linter Variables:', + \ g:globals_string . g:command_header, + \ '(finished - exit code 0) ''first command''', + \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', + \ ], "\n"), + \ g:output + +Given testft.testft2 (Empty buffer with two filetypes): +Execute (ALEInfo command history should print command output if logging is on): + let g:ale_history_log_output = 1 + + let g:ale_buffer_info[bufnr('%')] = { + \ 'history': [ + \ { + \ 'status': 'finished', + \ 'exit_code': 0, + \ 'job_id': 347, + \ 'command': 'first command', + \ 'output': ['some', 'first command output'], + \ }, + \ { + \ 'status': 'finished', + \ 'exit_code': 1, + \ 'job_id': 347, + \ 'command': ['/bin/bash', '\c', 'last command'], + \ 'output': ['different second command output'], + \ }, + \ { + \ 'status': 'finished', + \ 'exit_code': 0, + \ 'job_id': 347, + \ 'command': 'command with no output', + \ 'output': [], + \ }, + \ ], + \} + + call ale#linter#Define('testft', g:testlinter1) + call ale#linter#Define('testft2', g:testlinter2) + redir => g:output + silent ALEInfo + redir END + AssertEqual + \ join([ + \ '', + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ' Linter Variables:', + \ g:globals_string . g:command_header, + \ '(finished - exit code 0) ''first command''', + \ '', + \ '<<<OUTPUT STARTS>>>', + \ 'some', + \ 'first command output', + \ '<<<OUTPUT ENDS>>>', + \ '', + \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', + \ '', + \ '<<<OUTPUT STARTS>>>', + \ 'different second command output', + \ '<<<OUTPUT ENDS>>>', + \ '', + \ '(finished - exit code 0) ''command with no output''', + \ '', + \ '<<<NO OUTPUT RETURNED>>>', + \ '', + \ ], "\n"), + \ g:output diff --git a/test/test_ale_toggle.vader b/test/test_ale_toggle.vader new file mode 100644 index 00000000..61557e8a --- /dev/null +++ b/test/test_ale_toggle.vader @@ -0,0 +1,112 @@ +Before: + let g:expected_loclist = [{ + \ 'bufnr': bufnr('%'), + \ 'lnum': 2, + \ 'vcol': 0, + \ 'col': 3, + \ 'text': 'foo bar', + \ 'type': 'E', + \ 'nr': -1, + \ 'pattern': '', + \ 'valid': 1, + \}] + let g:expected_groups = [ + \ 'ALECleanupGroup', + \ 'ALECursorGroup', + \ 'ALEHighlightBufferGroup', + \ 'ALERunOnEnterGroup', + \ 'ALERunOnTextChangedGroup', + \] + + function! ToggleTestCallback(buffer, output) + return [{ + \ 'bufnr': a:buffer, + \ 'lnum': 2, + \ 'vcol': 0, + \ 'col': 3, + \ 'text': a:output[0], + \ 'type': 'E', + \ 'nr': -1, + \}] + endfunction + + function! ParseAuGroups() + redir => l:output + silent exec 'autocmd' + redir end + + let l:results = [] + + for l:line in split(l:output, "\n") + let l:match = matchlist(l:line, '^ALE[a-zA-Z]\+Group') + + if !empty(l:match) + call add(l:results, l:match[0]) + endif + endfor + + call uniq(sort(l:results)) + + return l:results + endfunction + + call ale#linter#Define('foobar', { + \ 'name': 'testlinter', + \ 'callback': 'ToggleTestCallback', + \ 'executable': 'echo', + \ 'command': 'echo foo bar', + \}) + +After: + unlet! g:expected_loclist + unlet! g:expected_groups + + let g:ale_buffer_info = {} + call ale#linter#Reset() + + " Toggle ALE back on if we fail when it's disabled. + if !g:ale_enabled + ALEToggle + endif + + delfunction ToggleTestCallback + delfunction ParseAuGroups + +Given foobar (Some imaginary filetype): + foo + bar + baz + +Execute(ALEToggle should reset everything and then run again): + AssertEqual 'foobar', &filetype + + call ale#Lint() + call ale#engine#WaitForJobs(2000) + + " First check that everything is there... + AssertEqual g:expected_loclist, getloclist(0) + AssertEqual [1000001], ale#sign#FindCurrentSigns(bufnr('%')) + AssertEqual + \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], + \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') + AssertEqual g:expected_groups, ParseAuGroups() + + " Now Toggle ALE off. + ALEToggle + + " Everything should be cleared. + AssertEqual [], getloclist(0) + AssertEqual [], ale#sign#FindCurrentSigns(bufnr('%')) + AssertEqual [], getmatches() + AssertEqual ['ALECleanupGroup', 'ALEHighlightBufferGroup'], ParseAuGroups() + + " Toggle ALE on, everything should be set up and run again. + ALEToggle + call ale#engine#WaitForJobs(2000) + + AssertEqual g:expected_loclist, getloclist(0) + AssertEqual [1000001], ale#sign#FindCurrentSigns(bufnr('%')) + AssertEqual + \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], + \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') + AssertEqual g:expected_groups, ParseAuGroups() diff --git a/test/test_history_saving.vader b/test/test_history_saving.vader new file mode 100644 index 00000000..303a02fa --- /dev/null +++ b/test/test_history_saving.vader @@ -0,0 +1,95 @@ +Before: + let g:history = [] + let g:ale_buffer_info = {} + let g:ale_max_buffer_history_size = 20 + + function! CollectResults(buffer, output) + return [] + endfunction + + call ale#linter#Define('foobar', { + \ 'name': 'testlinter', + \ 'callback': 'CollectResults', + \ 'executable': 'echo', + \ 'command': 'echo command history test', + \ 'read_buffer': 0, + \}) + +After: + let g:ale_history_enabled = 1 + let g:ale_history_log_output = 0 + unlet g:history + let g:ale_buffer_info = {} + let g:ale_max_buffer_history_size = 20 + call ale#linter#Reset() + delfunction CollectResults + +Given foobar (Some imaginary filetype): + anything + +Execute(History should be set when commands are run): + AssertEqual 'foobar', &filetype + + call ale#Lint() + call ale#engine#WaitForJobs(2000) + + let g:history = g:ale_buffer_info[bufnr('%')].history + + AssertEqual 1, len(g:history) + AssertEqual sort(['status', 'exit_code', 'job_id', 'command']), sort(keys(g:history[0])) + AssertEqual ['/bin/bash', '-c', 'echo command history test'], g:history[0].command + AssertEqual 'finished', g:history[0].status + AssertEqual 0, g:history[0].exit_code + " The Job ID will change each time, but we can check the type. + AssertEqual type(1), type(g:history[0].job_id) + +Execute(History should be not set when disabled): + AssertEqual 'foobar', &filetype + + let g:ale_history_enabled = 0 + + call ale#Lint() + call ale#engine#WaitForJobs(2000) + + AssertEqual 0, len(g:ale_buffer_info[bufnr('%')].history) + +Execute(History should include command output if logging is enabled): + AssertEqual 'foobar', &filetype + + let g:ale_history_log_output = 1 + + call ale#Lint() + call ale#engine#WaitForJobs(2000) + + let g:history = g:ale_buffer_info[bufnr('%')].history + + AssertEqual 1, len(g:history) + AssertEqual ['command history test'], g:history[0].output + +Execute(History items should be popped after going over the max): + let g:ale_buffer_info[1] = { + \ 'history': map(range(20), '{''status'': ''started'', ''job_id'': v:val, ''command'': ''foobar''}'), + \} + + call ale#history#Add(1, 'started', 347, 'last command') + + AssertEqual + \ ( + \ map(range(1, 19), '{''status'': ''started'', ''job_id'': v:val, ''command'': ''foobar''}') + \ + [{'status': 'started', 'job_id': 347, 'command': 'last command'}] + \ ), + \ g:ale_buffer_info[1].history + +Execute(Nothing should be added to history if the size is too low): + let g:ale_max_buffer_history_size = 0 + let g:ale_buffer_info[1] = {'history': []} + + call ale#history#Add(1, 'started', 347, 'last command') + + AssertEqual [], g:ale_buffer_info[1].history + + let g:ale_max_buffer_history_size = -2 + + call ale#history#Add(1, 'started', 347, 'last command') + + AssertEqual [], g:ale_buffer_info[1].history diff --git a/test/test_vim8_processid_parsing.vader b/test/test_vim8_processid_parsing.vader new file mode 100644 index 00000000..5ec564e0 --- /dev/null +++ b/test/test_vim8_processid_parsing.vader @@ -0,0 +1,5 @@ +Execute(Vim8 Process ID parsing should work): + AssertEqual 123, ale#engine#ParseVim8ProcessID('process 123 run') + AssertEqual 347, ale#engine#ParseVim8ProcessID('process 347 failed') + AssertEqual 789, ale#engine#ParseVim8ProcessID('process 789 dead') + AssertEqual 0, ale#engine#ParseVim8ProcessID('no process') |