First pass at optimizing ale to autoload (#80)

* First pass at optimizing ale to autoload

First off, the structure/function names should be revised a bit,
but I will wait for @w0rp's input before unifying the naming style.
Second off, the docs probably need some more work, I just did some
simple find-and-replace work.

With that said, this pull brings major performance gains for ale. On my
slowest system, fully loading ale and all its code takes around 150ms.

I have moved all of ale's autoload-able code to autoload/, and in
addition, implemented lazy-loading of linters. This brings load time on
that same system down to 5ms.

The only downside of lazy loading is that `g:ale_linters` cannot be
changed at runtime; however, it also speeds up performance at runtime by
simplfying the logic greatly.

Please let me know what you think!

Closes #59

* Address Travis/Vint errors

For some reason, ale isn't running vint for me...

* Incorporate feedback, make fixes

Lazy-loading logic is much improved.

* Add header comments; remove incorrect workaround

* Remove unneeded plugin guards

* Fix lazy-loading linter logic

Set the wrong variable....

* Fix capitialization
This commit is contained in:
Bjorn Neergaard 2016-10-10 13:51:29 -05:00 committed by w0rp
parent 0680f875fe
commit 7f0ce89d2b
44 changed files with 337 additions and 336 deletions

View File

@ -12,7 +12,7 @@ if !exists('g:ale_c_gcc_options')
let g:ale_c_gcc_options = '-Wall' let g:ale_c_gcc_options = '-Wall'
endif endif
call ALEAddLinter('c', { call ale#linter#Define('c', {
\ 'name': 'gcc', \ 'name': 'gcc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'gcc', \ 'executable': 'gcc',

View File

@ -7,7 +7,7 @@ endif
let g:loaded_ale_linters_coffee_coffee = 1 let g:loaded_ale_linters_coffee_coffee = 1
call ALEAddLinter('coffee', { call ale#linter#Define('coffee', {
\ 'name': 'coffee', \ 'name': 'coffee',
\ 'executable': 'coffee', \ 'executable': 'coffee',
\ 'command': 'coffee -cp -s', \ 'command': 'coffee -cp -s',

View File

@ -44,7 +44,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('coffee', { call ale#linter#Define('coffee', {
\ 'name': 'coffeelint', \ 'name': 'coffeelint',
\ 'executable': 'coffeelint', \ 'executable': 'coffeelint',
\ 'command': 'coffeelint --stdin --reporter csv', \ 'command': 'coffeelint --stdin --reporter csv',

View File

@ -12,7 +12,7 @@ if !exists('g:ale_cpp_gcc_options')
let g:ale_cpp_gcc_options = '-Wall' let g:ale_cpp_gcc_options = '-Wall'
endif endif
call ALEAddLinter('cpp', { call ale#linter#Define('cpp', {
\ 'name': 'gcc', \ 'name': 'gcc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'gcc', \ 'executable': 'gcc',

View File

@ -7,7 +7,7 @@ endif
let g:loaded_ale_linters_css_csslint = 1 let g:loaded_ale_linters_css_csslint = 1
call ALEAddLinter('css', { call ale#linter#Define('css', {
\ 'name': 'csslint', \ 'name': 'csslint',
\ 'executable': 'csslint', \ 'executable': 'csslint',
\ 'command': g:ale#util#stdin_wrapper . ' .css csslint --format=compact', \ 'command': g:ale#util#stdin_wrapper . ' .css csslint --format=compact',

View File

@ -61,7 +61,7 @@ function! ale_linters#d#dmd#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('d', { call ale#linter#Define('d', {
\ 'name': 'dmd', \ 'name': 'dmd',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'dmd', \ 'executable': 'dmd',

View File

@ -60,7 +60,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('fortran', { call ale#linter#Define('fortran', {
\ 'name': 'gcc', \ 'name': 'gcc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'gcc', \ 'executable': 'gcc',

View File

@ -58,7 +58,7 @@ function! ale_linters#haskell#ghc#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'ghc', \ 'name': 'ghc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'ghc', \ 'executable': 'ghc',
@ -66,7 +66,7 @@ call ALEAddLinter('haskell', {
\ 'callback': 'ale_linters#haskell#ghc#Handle', \ 'callback': 'ale_linters#haskell#ghc#Handle',
\}) \})
call ALEAddLinter('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'stack-ghc', \ 'name': 'stack-ghc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'stack', \ 'executable': 'stack',

View File

@ -40,7 +40,7 @@ function! ale_linters#html#htmlhint#Handle(buffer, lines) abort
return output return output
endfunction endfunction
call ALEAddLinter('html', { call ale#linter#Define('html', {
\ 'name': 'htmlhint', \ 'name': 'htmlhint',
\ 'executable': 'htmlhint', \ 'executable': 'htmlhint',
\ 'command': 'htmlhint --format=unix stdin', \ 'command': 'htmlhint --format=unix stdin',

View File

@ -71,7 +71,7 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort
return output return output
endfunction endfunction
call ALEAddLinter('html', { call ale#linter#Define('html', {
\ 'name': 'tidy', \ 'name': 'tidy',
\ 'executable': g:ale_html_tidy_executable, \ 'executable': g:ale_html_tidy_executable,
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',

View File

@ -49,14 +49,14 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('javascript', { call ale#linter#Define('javascript', {
\ 'name': 'eslint', \ 'name': 'eslint',
\ 'executable': g:ale_javascript_eslint_executable, \ 'executable': g:ale_javascript_eslint_executable,
\ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s', \ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s',
\ 'callback': 'ale_linters#javascript#eslint#Handle', \ 'callback': 'ale_linters#javascript#eslint#Handle',
\}) \})
call ALEAddLinter('javascript.jsx', { call ale#linter#Define('javascript.jsx', {
\ 'name': 'eslint', \ 'name': 'eslint',
\ 'executable': g:ale_javascript_eslint_executable, \ 'executable': g:ale_javascript_eslint_executable,
\ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s', \ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s',

View File

@ -43,14 +43,14 @@ function! ale_linters#javascript#jscs#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('javascript', { call ale#linter#Define('javascript', {
\ 'name': 'jscs', \ 'name': 'jscs',
\ 'executable': 'jscs', \ 'executable': 'jscs',
\ 'command': 'jscs -r unix -n -', \ 'command': 'jscs -r unix -n -',
\ 'callback': 'ale_linters#javascript#jscs#Handle', \ 'callback': 'ale_linters#javascript#jscs#Handle',
\}) \})
call ALEAddLinter('javascript.jsx', { call ale#linter#Define('javascript.jsx', {
\ 'name': 'jscs', \ 'name': 'jscs',
\ 'executable': 'jscs', \ 'executable': 'jscs',
\ 'command': 'jscs -r unix -n -', \ 'command': 'jscs -r unix -n -',

View File

@ -70,14 +70,14 @@ function! ale_linters#javascript#jshint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('javascript', { call ale#linter#Define('javascript', {
\ 'name': 'jshint', \ 'name': 'jshint',
\ 'executable': g:ale_javascript_jshint_executable, \ 'executable': g:ale_javascript_jshint_executable,
\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand', \ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',
\ 'callback': 'ale_linters#javascript#jshint#Handle', \ 'callback': 'ale_linters#javascript#jshint#Handle',
\}) \})
call ALEAddLinter('javascript.jsx', { call ale#linter#Define('javascript.jsx', {
\ 'name': 'jshint', \ 'name': 'jshint',
\ 'executable': g:ale_javascript_jshint_executable, \ 'executable': g:ale_javascript_jshint_executable,
\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand', \ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',

View File

@ -35,7 +35,7 @@ function! ale_linters#json#jsonlint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('json', { call ale#linter#Define('json', {
\ 'name': 'jsonlint', \ 'name': 'jsonlint',
\ 'executable': 'jsonlint', \ 'executable': 'jsonlint',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',

View File

@ -37,7 +37,7 @@ function! ale_linters#perl#perl#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('perl', { call ale#linter#Define('perl', {
\ 'name': 'perl', \ 'name': 'perl',
\ 'executable': 'perl', \ 'executable': 'perl',
\ 'output_stream': 'both', \ 'output_stream': 'both',

View File

@ -37,7 +37,7 @@ function! ale_linters#perl#perlcritic#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('perl', { call ale#linter#Define('perl', {
\ 'name': 'perlcritic', \ 'name': 'perlcritic',
\ 'executable': 'perlcritic', \ 'executable': 'perlcritic',
\ 'output_stream': 'sdtout', \ 'output_stream': 'sdtout',

View File

@ -36,7 +36,7 @@ function! ale_linters#php#php#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('php', { call ale#linter#Define('php', {
\ 'name': 'php', \ 'name': 'php',
\ 'executable': 'php', \ 'executable': 'php',
\ 'output_stream': 'both', \ 'output_stream': 'both',

View File

@ -50,7 +50,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('php', { call ale#linter#Define('php', {
\ 'name': 'phpcs', \ 'name': 'phpcs',
\ 'executable': 'phpcs', \ 'executable': 'phpcs',
\ 'command_callback': 'ale_linters#php#phpcs#GetCommand', \ 'command_callback': 'ale_linters#php#phpcs#GetCommand',

View File

@ -35,7 +35,7 @@ function! ale_linters#pug#puglint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('pug', { call ale#linter#Define('pug', {
\ 'name': 'puglint', \ 'name': 'puglint',
\ 'executable': 'pug-lint', \ 'executable': 'pug-lint',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',

View File

@ -34,7 +34,7 @@ function! ale_linters#pyrex#cython#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('pyrex', { call ale#linter#Define('pyrex', {
\ 'name': 'cython', \ 'name': 'cython',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'cython', \ 'executable': 'cython',

View File

@ -47,7 +47,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('python', { call ale#linter#Define('python', {
\ 'name': 'flake8', \ 'name': 'flake8',
\ 'executable': 'flake8', \ 'executable': 'flake8',
\ 'command': 'flake8 -', \ 'command': 'flake8 -',

View File

@ -40,7 +40,7 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('ruby', { call ale#linter#Define('ruby', {
\ 'name': 'rubocop', \ 'name': 'rubocop',
\ 'executable': 'rubocop', \ 'executable': 'rubocop',
\ 'command': 'rubocop --format emacs --stdin _', \ 'command': 'rubocop --format emacs --stdin _',

View File

@ -6,7 +6,7 @@ endif
let g:loaded_ale_linters_sass_sasslint = 1 let g:loaded_ale_linters_sass_sasslint = 1
call ALEAddLinter('sass', { call ale#linter#Define('sass', {
\ 'name': 'sasslint', \ 'name': 'sasslint',
\ 'executable': 'sass-lint', \ 'executable': 'sass-lint',
\ 'command': g:ale#util#stdin_wrapper . ' .sass sass-lint -v -q -f compact', \ 'command': g:ale#util#stdin_wrapper . ' .sass sass-lint -v -q -f compact',

View File

@ -49,7 +49,7 @@ function! ale_linters#scala#scalac#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('scala', { call ale#linter#Define('scala', {
\ 'name': 'scalac', \ 'name': 'scalac',
\ 'executable': 'scalac', \ 'executable': 'scalac',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',

View File

@ -6,7 +6,7 @@ endif
let g:loaded_ale_linters_scss_sasslint = 1 let g:loaded_ale_linters_scss_sasslint = 1
call ALEAddLinter('scss', { call ale#linter#Define('scss', {
\ 'name': 'sasslint', \ 'name': 'sasslint',
\ 'executable': 'sass-lint', \ 'executable': 'sass-lint',
\ 'command': g:ale#util#stdin_wrapper . ' .scss sass-lint -v -q -f compact', \ 'command': g:ale#util#stdin_wrapper . ' .scss sass-lint -v -q -f compact',

View File

@ -41,7 +41,7 @@ function! ale_linters#scss#scsslint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('scss', { call ale#linter#Define('scss', {
\ 'name': 'scsslint', \ 'name': 'scsslint',
\ 'executable': 'scss-lint', \ 'executable': 'scss-lint',
\ 'command': 'scss-lint --stdin-file-path=%s', \ 'command': 'scss-lint --stdin-file-path=%s',

View File

@ -74,7 +74,7 @@ function! ale_linters#sh#shell#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('sh', { call ale#linter#Define('sh', {
\ 'name': 'shell', \ 'name': 'shell',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable_callback': 'ale_linters#sh#shell#GetExecutable', \ 'executable_callback': 'ale_linters#sh#shell#GetExecutable',

View File

@ -22,7 +22,7 @@ else
let s:exclude_option = '' let s:exclude_option = ''
endif endif
call ALEAddLinter('sh', { call ale#linter#Define('sh', {
\ 'name': 'shellcheck', \ 'name': 'shellcheck',
\ 'executable': 'shellcheck', \ 'executable': 'shellcheck',
\ 'command': 'shellcheck ' . s:exclude_option . ' -f gcc -', \ 'command': 'shellcheck ' . s:exclude_option . ' -f gcc -',

View File

@ -43,7 +43,7 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('typescript', { call ale#linter#Define('typescript', {
\ 'name': 'tslint', \ 'name': 'tslint',
\ 'executable': 'tslint', \ 'executable': 'tslint',
\ 'command': g:ale#util#stdin_wrapper . ' .ts tslint', \ 'command': g:ale#util#stdin_wrapper . ' .ts tslint',

View File

@ -42,7 +42,7 @@ function! ale_linters#verilog#iverilog#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('verilog', { call ale#linter#Define('verilog', {
\ 'name': 'iverilog', \ 'name': 'iverilog',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'iverilog', \ 'executable': 'iverilog',

View File

@ -44,7 +44,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('verilog', { call ale#linter#Define('verilog', {
\ 'name': 'verilator', \ 'name': 'verilator',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'verilator', \ 'executable': 'verilator',

View File

@ -9,7 +9,7 @@ let g:loaded_ale_linters_vim_vint = 1
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})' let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})'
call ALEAddLinter('vim', { call ale#linter#Define('vim', {
\ 'name': 'vint', \ 'name': 'vint',
\ 'executable': 'vint', \ 'executable': 'vint',
\ 'command': g:ale#util#stdin_wrapper . ' .vim vint -w --no-color ' . s:format, \ 'command': g:ale#util#stdin_wrapper . ' .vim vint -w --no-color ' . s:format,

View File

@ -40,7 +40,7 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines)
return output return output
endfunction endfunction
call ALEAddLinter('yaml', { call ale#linter#Define('yaml', {
\ 'name': 'yamllint', \ 'name': 'yamllint',
\ 'executable': 'yamllint', \ 'executable': 'yamllint',
\ 'command': g:ale#util#stdin_wrapper . ' .yml yamllint -f parsable', \ 'command': g:ale#util#stdin_wrapper . ' .yml yamllint -f parsable',

48
autoload/ale.vim Normal file
View File

@ -0,0 +1,48 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Primary code path for the plugin
" Manages execution of linters when requested by autocommands
let s:lint_timer = -1
function! ale#Queue(delay) abort
if s:lint_timer != -1
call timer_stop(s:lint_timer)
let s:lint_timer = -1
endif
let linters = ale#linter#Get(&filetype)
if len(linters) == 0
" There are no linters to lint with, so stop here.
return
endif
if a:delay > 0
let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
else
call ale#Lint()
endif
endfunction
function! ale#Lint(...) abort
let buffer = bufnr('%')
let linters = ale#linter#Get(&filetype)
" Set a variable telling us to clear the loclist later.
let g:ale_buffer_should_reset_map[buffer] = 1
for linter in linters
" Check if a given linter has a program which can be executed.
if has_key(linter, 'executable_callback')
let l:executable = ale#util#GetFunction(linter.executable_callback)(buffer)
else
let l:executable = linter.executable
endif
if !executable(l:executable)
" The linter's program cannot be executed, so skip it.
continue
endif
call ale#engine#Invoke(buffer, linter)
endfor
endfunction

16
autoload/ale/cleanup.vim Normal file
View File

@ -0,0 +1,16 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Utility functions related to cleaning state.
function! ale#cleanup#Buffer(buffer) abort
if has_key(g:ale_buffer_should_reset_map, a:buffer)
call remove(g:ale_buffer_should_reset_map, a:buffer)
endif
if has_key(g:ale_buffer_loclist_map, a:buffer)
call remove(g:ale_buffer_loclist_map, a:buffer)
endif
if has_key(g:ale_buffer_sign_dummy_map, a:buffer)
call remove(g:ale_buffer_sign_dummy_map, a:buffer)
endif
endfunction

View File

@ -1,12 +1,6 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Echoes lint message for the current line, if any " Description: Echoes lint message for the current line, if any
if exists('g:loaded_ale_cursor')
finish
endif
let g:loaded_ale_cursor = 1
" Return a formatted message according to g:ale_echo_msg_format variable " Return a formatted message according to g:ale_echo_msg_format variable
function! s:GetMessage(linter, type, text) abort function! s:GetMessage(linter, type, text) abort
let msg = g:ale_echo_msg_format let msg = g:ale_echo_msg_format
@ -26,7 +20,7 @@ endfunction
" This function will perform a binary search to find a message from the " This function will perform a binary search to find a message from the
" loclist to echo when the cursor moves. " loclist to echo when the cursor moves.
function! s:BinarySearch(loclist, line, column) function! s:BinarySearch(loclist, line, column) abort
let min = 0 let min = 0
let max = len(a:loclist) - 1 let max = len(a:loclist) - 1
let last_column_match = -1 let last_column_match = -1
@ -59,7 +53,7 @@ function! s:BinarySearch(loclist, line, column)
endwhile endwhile
endfunction endfunction
function! ale#cursor#TruncatedEcho(message) function! ale#cursor#TruncatedEcho(message) abort
let message = a:message let message = a:message
" Change tabs to spaces. " Change tabs to spaces.
let message = substitute(message, "\t", ' ', 'g') let message = substitute(message, "\t", ' ', 'g')
@ -79,7 +73,7 @@ function! ale#cursor#TruncatedEcho(message)
endtry endtry
endfunction endfunction
function! ale#cursor#EchoCursorWarning(...) function! ale#cursor#EchoCursorWarning(...) abort
" Only echo the warnings in normal mode, otherwise we will get problems. " Only echo the warnings in normal mode, otherwise we will get problems.
if mode() !=# 'n' if mode() !=# 'n'
return return
@ -108,7 +102,7 @@ endfunction
let s:cursor_timer = -1 let s:cursor_timer = -1
function! ale#cursor#EchoCursorWarningWithDelay() function! ale#cursor#EchoCursorWarningWithDelay() abort
if s:cursor_timer != -1 if s:cursor_timer != -1
call timer_stop(s:cursor_timer) call timer_stop(s:cursor_timer)
let s:cursor_timer = -1 let s:cursor_timer = -1

View File

@ -1,19 +1,6 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Main entry point for this plugin " Description: Backend execution and job management
" Loads linters and manages lint jobs " Executes linters in the background, using NeoVim or Vim 8 jobs
if exists('g:loaded_ale_zmain')
finish
endif
let g:loaded_ale_zmain = 1
let s:lint_timer = -1
let s:linters = {}
if !exists('g:ale_linters')
let g:ale_linters = {}
endif
" Stores information for each job including: " Stores information for each job including:
" "
@ -22,20 +9,18 @@ endif
" output: The array of lines for the output of the job. " output: The array of lines for the output of the job.
let s:job_info_map = {} let s:job_info_map = {}
" Globals which each part of the plugin should use. function! s:GetJobID(job) abort
let g:ale_buffer_loclist_map = {} if has('nvim')
let g:ale_buffer_should_reset_map = {} "In NeoVim, job values are just IDs.
let g:ale_buffer_sign_dummy_map = {} return a:job
function! s:GetFunction(string_or_ref)
if type(a:string_or_ref) == type('')
return function(a:string_or_ref)
endif endif
return a:string_or_ref " 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.
return ch_info(job_getchannel(a:job)).id
endfunction endfunction
function! s:ClearJob(job) function! s:ClearJob(job) abort
let job_id = s:GetJobID(a:job) let job_id = s:GetJobID(a:job)
let linter = s:job_info_map[job_id].linter let linter = s:job_info_map[job_id].linter
@ -55,7 +40,7 @@ function! s:ClearJob(job)
call remove(linter, 'job') call remove(linter, 'job')
endfunction endfunction
function! s:GatherOutput(job, data) function! s:GatherOutput(job, data) abort
let job_id = s:GetJobID(a:job) let job_id = s:GetJobID(a:job)
if !has_key(s:job_info_map, job_id) if !has_key(s:job_info_map, job_id)
@ -65,51 +50,15 @@ function! s:GatherOutput(job, data)
call extend(s:job_info_map[job_id].output, a:data) call extend(s:job_info_map[job_id].output, a:data)
endfunction endfunction
function! s:GatherOutputNeoVim(job, data, event) function! s:GatherOutputVim(channel, data) abort
call s:GatherOutput(a:job, a:data)
endfunction
function! s:GatherOutputVim(channel, data)
call s:GatherOutput(ch_getjob(a:channel), [a:data]) call s:GatherOutput(ch_getjob(a:channel), [a:data])
endfunction endfunction
function! s:LocItemCompare(left, right) function! s:GatherOutputNeoVim(job, data, event) abort
if a:left['lnum'] < a:right['lnum'] call s:GatherOutput(a:job, a:data)
return -1
endif
if a:left['lnum'] > a:right['lnum']
return 1
endif
if a:left['col'] < a:right['col']
return -1
endif
if a:left['col'] > a:right['col']
return 1
endif
return 0
endfunction endfunction
function! s:FixLoclist(buffer, loclist) function! s:HandleExit(job) 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
" of the file instead.
let last_line_number = ale#util#GetLineCount(a:buffer)
for item in a:loclist
if item.lnum == 0
" When errors appear at line 0, put them at line 1 instead.
let item.lnum = 1
elseif item.lnum > last_line_number
let item.lnum = last_line_number
endif
endfor
endfunction
function! s:HandleExit(job)
if a:job ==# 'no process' if a:job ==# 'no process'
" Stop right away when the job is not valid in Vim 8. " Stop right away when the job is not valid in Vim 8.
return return
@ -129,15 +78,10 @@ function! s:HandleExit(job)
let output = job_info.output let output = job_info.output
let buffer = job_info.buffer let buffer = job_info.buffer
let linter_loclist = s:GetFunction(linter.callback)(buffer, output) let linter_loclist = ale#util#GetFunction(linter.callback)(buffer, output)
" Make some adjustments to the loclists to fix common problems. " Make some adjustments to the loclists to fix common problems.
call s:FixLoclist(buffer, linter_loclist) call s:FixLocList(buffer, linter_loclist)
" Remember which linter returned these items for later use.
for obj in linter_loclist
let obj.linter_name = linter.name
endfor
if g:ale_buffer_should_reset_map[buffer] if g:ale_buffer_should_reset_map[buffer]
let g:ale_buffer_should_reset_map[buffer] = 0 let g:ale_buffer_should_reset_map[buffer] = 0
@ -150,7 +94,7 @@ function! s:HandleExit(job)
" Sort the loclist again. " Sort the loclist again.
" We need a sorted list so we can run a binary search against it " We need a sorted list so we can run a binary search against it
" for efficient lookup of the messages in the cursor handler. " for efficient lookup of the messages in the cursor handler.
call sort(g:ale_buffer_loclist_map[buffer], 's:LocItemCompare') call sort(g:ale_buffer_loclist_map[buffer], 'ale#util#LocItemCompare')
if g:ale_set_loclist if g:ale_set_loclist
call setloclist(0, g:ale_buffer_loclist_map[buffer]) call setloclist(0, g:ale_buffer_loclist_map[buffer])
@ -164,26 +108,31 @@ function! s:HandleExit(job)
" matchadd('ALEError', '\%200l\%17v') " matchadd('ALEError', '\%200l\%17v')
endfunction endfunction
function! s:GetJobID(job) function! s:HandleExitNeoVim(job, data, event) 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.
return ch_info(job_getchannel(a:job)).id
endfunction
function! s:HandleExitNeoVim(job, data, event)
call s:HandleExit(a:job) call s:HandleExit(a:job)
endfunction endfunction
function! s:HandleExitVim(channel) function! s:HandleExitVim(channel) abort
call s:HandleExit(ch_getjob(a:channel)) call s:HandleExit(ch_getjob(a:channel))
endfunction endfunction
function! s:ApplyLinter(buffer, linter) 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
" of the file instead.
let last_line_number = ale#util#GetLineCount(a:buffer)
for item in a:loclist
if item.lnum == 0
" When errors appear at line 0, put them at line 1 instead.
let item.lnum = 1
elseif item.lnum > last_line_number
let item.lnum = last_line_number
endif
endfor
endfunction
function! ale#engine#Invoke(buffer, linter) abort
if has_key(a:linter, 'job') if has_key(a:linter, 'job')
" Stop previous jobs for the same linter. " Stop previous jobs for the same linter.
call s:ClearJob(a:linter.job) call s:ClearJob(a:linter.job)
@ -191,7 +140,7 @@ function! s:ApplyLinter(buffer, linter)
if has_key(a:linter, 'command_callback') if has_key(a:linter, 'command_callback')
" If there is a callback for generating a command, call that instead. " If there is a callback for generating a command, call that instead.
let command = s:GetFunction(a:linter.command_callback)(a:buffer) let command = ale#util#GetFunction(a:linter.command_callback)(a:buffer)
else else
let command = a:linter.command let command = a:linter.command
endif endif
@ -274,8 +223,7 @@ function! s:ApplyLinter(buffer, linter)
call jobsend(job, input) call jobsend(job, input)
call jobclose(job, 'stdin') call jobclose(job, 'stdin')
elseif has('win32') elseif has('win32')
" On Windows, we have to send the buffer lines ourselves, " On some Vim versions, we have to send the buffer data ourselves.
" as there are issues with Windows and 'in_buf'
let input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n" let input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n"
let channel = job_getchannel(job) let channel = job_getchannel(job)
@ -286,152 +234,3 @@ function! s:ApplyLinter(buffer, linter)
endif endif
endif endif
endfunction endfunction
function! s:TimerHandler(...)
let filetype = &filetype
let linters = ALEGetLinters(filetype)
let buffer = bufnr('%')
" Set a variable telling us to clear the loclist later.
let g:ale_buffer_should_reset_map[buffer] = 1
for linter in linters
" Check if a given linter has a program which can be executed.
if has_key(linter, 'executable_callback')
let l:executable = s:GetFunction(linter.executable_callback)(buffer)
else
let l:executable = linter.executable
endif
if !executable(l:executable)
" The linter's program cannot be executed, so skip it.
continue
endif
call s:ApplyLinter(buffer, linter)
endfor
endfunction
function s:BufferCleanup(buffer)
if has_key(g:ale_buffer_should_reset_map, a:buffer)
call remove(g:ale_buffer_should_reset_map, a:buffer)
endif
if has_key(g:ale_buffer_loclist_map, a:buffer)
call remove(g:ale_buffer_loclist_map, a:buffer)
endif
if has_key(g:ale_buffer_sign_dummy_map, a:buffer)
call remove(g:ale_buffer_sign_dummy_map, a:buffer)
endif
endfunction
function! ALEAddLinter(filetype, linter)
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
endif
let new_linter = {
\ 'name': a:linter.name,
\ 'callback': a:linter.callback,
\}
if has_key(a:linter, 'executable_callback')
let new_linter.executable_callback = a:linter.executable_callback
else
let new_linter.executable = a:linter.executable
endif
if has_key(a:linter, 'command_callback')
let new_linter.command_callback = a:linter.command_callback
else
let new_linter.command = a:linter.command
endif
if has_key(a:linter, 'output_stream')
let new_linter.output_stream = a:linter.output_stream
else
let new_linter.output_stream = 'stdout'
endif
" TODO: Assert the value of the output_stream to be something sensible.
call add(s:linters[a:filetype], new_linter)
endfunction
function! ALEGetLinters(filetype)
if !has_key(s:linters, a:filetype)
return []
endif
if has_key(g:ale_linters, a:filetype)
let linters = []
" Filter loaded linters according to list of linters specified in option
for linter in s:linters[a:filetype]
if index(g:ale_linters[a:filetype], linter.name) != -1
call add(linters, linter)
endif
endfor
return linters
endif
return s:linters[a:filetype]
endfunction
function! ALELint(delay)
let filetype = &filetype
let linters = ALEGetLinters(filetype)
if s:lint_timer != -1
call timer_stop(s:lint_timer)
let s:lint_timer = -1
endif
if len(linters) == 0
" There are no linters to lint with, so stop here.
return
endif
if a:delay > 0
let s:lint_timer = timer_start(a:delay, function('s:TimerHandler'))
else
call s:TimerHandler()
endif
endfunction
" Load all of the linters for each filetype.
runtime! ale_linters/*/*.vim
if !g:ale_has_required_features
echoerr 'ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'
echoerr 'Please update your editor appropriately.'
finish
endif
if g:ale_lint_on_text_changed
augroup ALERunOnTextChangedGroup
autocmd!
autocmd TextChanged,TextChangedI * call ALELint(g:ale_lint_delay)
augroup END
endif
if g:ale_lint_on_enter
augroup ALERunOnEnterGroup
autocmd!
autocmd BufEnter,BufRead * call ALELint(100)
augroup END
endif
if g:ale_lint_on_save
augroup ALERunOnSaveGroup
autocmd!
autocmd BufWrite * call ALELint(0)
augroup END
endif
" Clean up buffers automatically when they are unloaded.
augroup ALEBuffferCleanup
autocmd!
autocmd BufUnload * call s:BufferCleanup('<abuf>')
augroup END

View File

@ -4,13 +4,7 @@ scriptencoding utf-8
" linter which outputs warnings and errors in a format accepted by one of " linter which outputs warnings and errors in a format accepted by one of
" these functions can simply use one of these pre-defined error handlers. " these functions can simply use one of these pre-defined error handlers.
if exists('g:loaded_ale_handlers') function! ale#handlers#HandleGCCFormat(buffer, lines) abort
finish
endif
let g:loaded_ale_handlers = 1
function! ale#handlers#HandleGCCFormat(buffer, lines)
" Look for lines like the following. " Look for lines like the following.
" "
" <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=] " <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]
@ -40,7 +34,7 @@ function! ale#handlers#HandleGCCFormat(buffer, lines)
return output return output
endfunction endfunction
function! ale#handlers#HandleCSSLintFormat(buffer, lines) function! ale#handlers#HandleCSSLintFormat(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" "
" something.css: line 2, col 1, Error - Expected RBRACE at line 2, col 1. (errors) " something.css: line 2, col 1, Error - Expected RBRACE at line 2, col 1. (errors)

66
autoload/ale/linter.vim Normal file
View File

@ -0,0 +1,66 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Linter registration and lazy-loading
" Retrieves linters as requested by the engine, loading them if needed.
let s:linters = {}
function! ale#linter#Define(filetype, linter) abort
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
endif
let new_linter = {
\ 'name': a:linter.name,
\ 'callback': a:linter.callback,
\}
if has_key(a:linter, 'executable_callback')
let new_linter.executable_callback = a:linter.executable_callback
else
let new_linter.executable = a:linter.executable
endif
if has_key(a:linter, 'command_callback')
let new_linter.command_callback = a:linter.command_callback
else
let new_linter.command = a:linter.command
endif
if has_key(a:linter, 'output_stream')
let new_linter.output_stream = a:linter.output_stream
else
let new_linter.output_stream = 'stdout'
endif
" TODO: Assert the value of the output_stream to be something sensible.
call add(s:linters[a:filetype], new_linter)
endfunction
function! ale#linter#Get(filetype) abort
if a:filetype ==# ''
" Empty filetype? Nothing to be done about that.
return []
endif
if has_key(s:linters, a:filetype)
" We already loaded a linter, great!
return s:linters[a:filetype]
endif
if has_key(g:ale_linters, a:filetype)
" Filter loaded linters according to list of linters specified in option.
for linter in g:ale_linters[a:filetype]
execute 'runtime! ale_linters/' . a:filetype . '/' . linter . '.vim'
endfor
else
execute 'runtime! ale_linters/' . a:filetype . '/*.vim'
endif
if !has_key(s:linters, a:filetype)
" If we couldn't load any linters, let everyone know.
let s:linters[a:filetype] = []
endif
return s:linters[a:filetype]
endfunction

View File

@ -1,12 +1,7 @@
scriptencoding utf-8 scriptencoding utf8
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Draws error and warning signs into signcolumn " Description: Draws error and warning signs into signcolumn
if exists('g:loaded_ale_sign')
finish
endif
let g:loaded_ale_sign = 1
let b:dummy_sign_set_map = {} let b:dummy_sign_set_map = {}
if !hlexists('ALEErrorSign') if !hlexists('ALEErrorSign')
@ -40,7 +35,7 @@ execute 'sign define ALEWarningSign text=' . g:ale_sign_warning
\ . ' texthl=ALEWarningSign' \ . ' texthl=ALEWarningSign'
sign define ALEDummySign sign define ALEDummySign
function! ale#sign#FindCurrentSigns(buffer) function! ale#sign#FindCurrentSigns(buffer) abort
" Matches output like : " Matches output like :
" line=4 id=1 name=ALEErrorSign " line=4 id=1 name=ALEErrorSign
" строка=1 id=1000001 имя=ALEErrorSign " строка=1 id=1000001 имя=ALEErrorSign
@ -66,7 +61,7 @@ endfunction
" Given a loclist, combine the loclist into a list of signs such that only " Given a loclist, combine the loclist into a list of signs such that only
" one sign appears per line. Error lines will take precedence. " one sign appears per line. Error lines will take precedence.
" The loclist will have been previously sorted. " The loclist will have been previously sorted.
function! ale#sign#CombineSigns(loclist) function! ale#sign#CombineSigns(loclist) abort
let signlist = [] let signlist = []
for obj in a:loclist for obj in a:loclist
@ -98,7 +93,7 @@ function! ale#sign#CombineSigns(loclist)
endfunction endfunction
" This function will set the signs which show up on the left. " This function will set the signs which show up on the left.
function! ale#sign#SetSigns(buffer, loclist) function! ale#sign#SetSigns(buffer, loclist) abort
let signlist = ale#sign#CombineSigns(a:loclist) let signlist = ale#sign#CombineSigns(a:loclist)
if len(signlist) > 0 || g:ale_sign_column_always if len(signlist) > 0 || g:ale_sign_column_always

View File

@ -1,7 +1,7 @@
" Author: KabbAmine <amine.kabb@gmail.com> " Author: KabbAmine <amine.kabb@gmail.com>
" Description: Statusline related function(s) " Description: Statusline related function(s)
function! ALEGetStatusLine() abort function! ale#statusline#Status() abort
" Returns a formatted string that can be integrated in the " Returns a formatted string that can be integrated in the
" statusline " statusline

View File

@ -1,13 +1,7 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Contains miscellaneous functions " Description: Contains miscellaneous functions
if exists('g:loaded_ale_util') function! s:FindWrapperScript() abort
finish
endif
let g:loaded_ale_util = 1
function! s:FindWrapperScript()
for parent in split(&runtimepath, ',') for parent in split(&runtimepath, ',')
" Expand the path to deal with ~ issues. " Expand the path to deal with ~ issues.
let path = expand(parent . '/' . 'stdin-wrapper') let path = expand(parent . '/' . 'stdin-wrapper')
@ -24,20 +18,48 @@ endfunction
let g:ale#util#stdin_wrapper = s:FindWrapperScript() let g:ale#util#stdin_wrapper = s:FindWrapperScript()
" Return the number of lines for a given buffer.
function! ale#util#GetLineCount(buffer)
return len(getbufline(a:buffer, 1, '$'))
endfunction
" Given a buffer and a filename, find the nearest file by searching upwards
" through the paths relative to the given buffer.
function! ale#util#FindNearestFile(buffer, filename)
return findfile(a:filename, fnamemodify(bufname(a:buffer), ':p') . ';')
endfunction
" A null file for sending output to nothing. " A null file for sending output to nothing.
let g:ale#util#nul_file = '/dev/null' let g:ale#util#nul_file = '/dev/null'
if has('win32') if has('win32')
let g:ale#util#nul_file = 'nul' let g:ale#util#nul_file = 'nul'
endif endif
" Return the number of lines for a given buffer.
function! ale#util#GetLineCount(buffer) abort
return len(getbufline(a:buffer, 1, '$'))
endfunction
" Given a buffer and a filename, find the nearest file by searching upwards
" through the paths relative to the given buffer.
function! ale#util#FindNearestFile(buffer, filename) abort
return findfile(a:filename, fnamemodify(bufname(a:buffer), ':p') . ';')
endfunction
function! ale#util#GetFunction(string_or_ref) abort
if type(a:string_or_ref) == type('')
return function(a:string_or_ref)
endif
return a:string_or_ref
endfunction
function! ale#util#LocItemCompare(left, right) abort
if a:left['lnum'] < a:right['lnum']
return -1
endif
if a:left['lnum'] > a:right['lnum']
return 1
endif
if a:left['col'] < a:right['col']
return -1
endif
if a:left['col'] > a:right['col']
return 1
endif
return 0
endfunction

View File

@ -289,11 +289,30 @@ g:ale_statusline_format *g:ale_statusline_format*
Type: |List| Type: |List|
Default: `['%d error(s)', '%d warning(s)', 'OK']` Default: `['%d error(s)', '%d warning(s)', 'OK']`
This variable defines the format of |`ALEGetStatusLine()`| output. This variable defines the format of |`ale#statusline#status()`| output.
- The 1st element is for errors - The 1st element is for errors
- The 2nd element is for warnings - The 2nd element is for warnings
- The 3rd element is for when no errors are detected - The 3rd element is for when no errors are detected
g:airline#extensions#ale#enabled *g:airline#extensions#ale#enabled*
Type: |Number|
Default: `1`
Enables or disables the |airline|'s native extension for ale, which displays
warnings and errors in the status line, prefixed by
|airline#extensions#ale#error_symbol| and
|airline#extensions#ale#warning_symbol|.
g:airline#extensions#ale#enabled *g:airline#extensions#ale#enabled*
Type: |Number|
Default: `1`
Enables or disables the |airline|'s native extension for ale, which displays
warnings and errors in the status line, prefixed by
|airline#extensions#ale#error_symbol| and
|airline#extensions#ale#warning_symbol|.
=============================================================================== ===============================================================================
4. Linter Specific Options *ale-linter-options* 4. Linter Specific Options *ale-linter-options*
@ -413,14 +432,14 @@ g:ale_javascript_jshint_executable *g:ale_javascript_jshint_executable*
=============================================================================== ===============================================================================
5. API *ale-api* 5. API *ale-api*
ALELint(delay) *ALELint()* ale#Queue(delay) *ale#Queue()*
Run linters for the current buffer, based on the filetype of the buffer, Run linters for the current buffer, based on the filetype of the buffer,
with a given `delay`. A `delay` of `0` will run the linters immediately. with a given `delay`. A `delay` of `0` will run the linters immediately.
The linters will always be run in the background. Calling this function The linters will always be run in the background. Calling this function
again from the same buffer again from the same buffer
ALEAddLinter(filetype, linter) *ALEAddLinter()* ale#linter#Define(filetype, linter) *ale#linter#Define()*
Given a |String| for a filetype and a |Dictionary| Describing a linter Given a |String| for a filetype and a |Dictionary| Describing a linter
configuration, add a linter for the given filetype. The dictionaries each configuration, add a linter for the given filetype. The dictionaries each
offer the following options: offer the following options:
@ -492,21 +511,21 @@ ALEAddLinter(filetype, linter) *ALEAddLinter()*
'command': g:ale#util#stdin_wrapper . ' .hs ghc -fno-code -v0', 'command': g:ale#util#stdin_wrapper . ' .hs ghc -fno-code -v0',
< <
ALEGetLinters(filetype) *ALEGetLinters()* ale#linter#Get(filetype) *ale#linter#Get()*
Return all of linters configured for a given filetype as a |List| of Return all of linters configured for a given filetype as a |List| of
|Dictionary| values in the format specified by |ALEAddLinter()|. |Dictionary| values in the format specified by |ale#linter#Define()|.
ALEGetStatusLine() *ALEGetStatusLine()* ale#statusline#Status() *ale#statusline#Status()*
Return a formatted string that can be added to the statusline. Return a formatted string that can be added to the statusline.
The output's format is defined in |`g:ale_statusline_format`|. The output's format is defined in |`g:ale_statusline_format`|.
To enable it, the following should be present in your |statusline| settings: > To enable it, the following should be present in your |statusline| settings: >
%{ALEGetStatusLine()} %{ale#statusline#status()}
g:ale#util#stdin_wrapper *g:ale#util#stdin_wrapper* g:ale#util#stdin_wrapper *g:ale#util#stdin_wrapper*
This variable names a wrapper script for sending stdin input to programs This variable names a wrapper script for sending stdin input to programs
which cannot accept input via stdin. See |ALEAddLinter| for more. which cannot accept input via stdin. See |ale#linter#Define()| for more.
=============================================================================== ===============================================================================

View File

@ -1,12 +1,11 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: This file sets up configuration settings for the ALE plugin. " Description: Main entry point for the plugin: sets up prefs and autocommands
" Flags can be set in vimrc files and so on to disable particular features " Preferences can be set in vimrc files and so on to configure ale
if exists('g:loaded_ale_flags') if exists('g:loaded_ale')
finish finish
endif endif
let g:loaded_ale = 1
let g:loaded_ale_flags = 1
" A flag for detecting if the required features are set. " A flag for detecting if the required features are set.
if has('nvim') if has('nvim')
@ -15,6 +14,15 @@ else
let g:ale_has_required_features = has('timers') && has('job') && has('channel') let g:ale_has_required_features = has('timers') && has('job') && has('channel')
endif endif
if !g:ale_has_required_features
echoerr 'ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'
echoerr 'Please update your editor appropriately.'
finish
endif
" This list configures which linters are enabled for which languages.
let g:ale_linters = get(g:, 'ale_linters', {})
" This flag can be set to 0 to disable linting when text is changed. " This flag can be set to 0 to disable linting when text is changed.
let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 1) let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 1)
@ -64,3 +72,43 @@ let g:ale_echo_msg_format = get(g:, 'ale_echo_msg_format', '%s')
" Strings used for severity in the echoed message " Strings used for severity in the echoed message
let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error') let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error')
let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning') let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
if g:ale_lint_on_text_changed
augroup ALERunOnTextChangedGroup
autocmd!
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay)
augroup END
endif
if g:ale_lint_on_enter
augroup ALERunOnEnterGroup
autocmd!
autocmd BufEnter,BufRead * call ale#Queue(100)
augroup END
endif
if g:ale_lint_on_save
augroup ALERunOnSaveGroup
autocmd!
autocmd BufWrite * call ale#Queue(0)
augroup END
endif
" Clean up buffers automatically when they are unloaded.
augroup ALEBufferCleanup
autocmd!
autocmd BufUnload * call ale#cleanup#Buffer('<abuf>')
augroup END
" Globals which each part of the plugin should use.
let g:ale_buffer_loclist_map = {}
let g:ale_buffer_should_reset_map = {}
let g:ale_buffer_sign_dummy_map = {}
" Backwards compatibility
function! ALELint(delay)
call ale#Queue(a:delay)
endfunction
function! ALEGetStatusLine()
call ale#statusline#Status()
endfunction