summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUE_TEMPLATE.md10
-rw-r--r--Makefile11
-rw-r--r--README.md27
-rw-r--r--ale_linters/cpp/clang.vim2
-rw-r--r--ale_linters/yaml/yamllint.vim20
-rw-r--r--autoload/ale/debugging.vim48
-rw-r--r--autoload/ale/engine.vim66
-rw-r--r--autoload/ale/history.vim58
-rw-r--r--autoload/ale/linter.vim5
-rw-r--r--doc/ale.txt72
-rw-r--r--plugin/ale.vim22
-rw-r--r--test/test_ale_info.vader140
-rw-r--r--test/test_ale_toggle.vader112
-rw-r--r--test/test_history_saving.vader95
-rw-r--r--test/test_vim8_processid_parsing.vader5
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.
diff --git a/Makefile b/Makefile
index a8c1da4d..5e939c1e 100644
--- a/Makefile
+++ b/Makefile
@@ -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 '========================================'; \
diff --git a/README.md b/README.md
index 86492003..a821a5f4 100644
--- a/README.md
+++ b/README.md
@@ -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')