diff options
author | Bjorn Neergaard <bjorn@neersighted.com> | 2016-10-10 13:51:29 -0500 |
---|---|---|
committer | w0rp <w0rp@users.noreply.github.com> | 2016-10-10 19:51:29 +0100 |
commit | 7f0ce89d2b574fd5bdd0c050eaad92deeb63086d (patch) | |
tree | c508480ff3ccbf36ef7283610fdcaefe476ae6e1 | |
parent | 0680f875fe9ef07daceb3e9a90224bee613730df (diff) | |
download | ale-7f0ce89d2b574fd5bdd0c050eaad92deeb63086d.zip |
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
44 files changed, 333 insertions, 332 deletions
diff --git a/ale_linters/c/gcc.vim b/ale_linters/c/gcc.vim index 500542d7..c22b5e88 100644 --- a/ale_linters/c/gcc.vim +++ b/ale_linters/c/gcc.vim @@ -12,7 +12,7 @@ if !exists('g:ale_c_gcc_options') let g:ale_c_gcc_options = '-Wall' endif -call ALEAddLinter('c', { +call ale#linter#Define('c', { \ 'name': 'gcc', \ 'output_stream': 'stderr', \ 'executable': 'gcc', diff --git a/ale_linters/coffee/coffee.vim b/ale_linters/coffee/coffee.vim index a19017c6..b2ad32b1 100644 --- a/ale_linters/coffee/coffee.vim +++ b/ale_linters/coffee/coffee.vim @@ -7,7 +7,7 @@ endif let g:loaded_ale_linters_coffee_coffee = 1 -call ALEAddLinter('coffee', { +call ale#linter#Define('coffee', { \ 'name': 'coffee', \ 'executable': 'coffee', \ 'command': 'coffee -cp -s', diff --git a/ale_linters/coffee/coffeelint.vim b/ale_linters/coffee/coffeelint.vim index 972fa25d..61f3dc81 100644 --- a/ale_linters/coffee/coffeelint.vim +++ b/ale_linters/coffee/coffeelint.vim @@ -44,7 +44,7 @@ function! ale_linters#coffee#coffeelint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('coffee', { +call ale#linter#Define('coffee', { \ 'name': 'coffeelint', \ 'executable': 'coffeelint', \ 'command': 'coffeelint --stdin --reporter csv', diff --git a/ale_linters/cpp/gcc.vim b/ale_linters/cpp/gcc.vim index 31c3c245..0936a82e 100644 --- a/ale_linters/cpp/gcc.vim +++ b/ale_linters/cpp/gcc.vim @@ -12,7 +12,7 @@ if !exists('g:ale_cpp_gcc_options') let g:ale_cpp_gcc_options = '-Wall' endif -call ALEAddLinter('cpp', { +call ale#linter#Define('cpp', { \ 'name': 'gcc', \ 'output_stream': 'stderr', \ 'executable': 'gcc', diff --git a/ale_linters/css/csslint.vim b/ale_linters/css/csslint.vim index e212aecc..dbaed15b 100644 --- a/ale_linters/css/csslint.vim +++ b/ale_linters/css/csslint.vim @@ -7,7 +7,7 @@ endif let g:loaded_ale_linters_css_csslint = 1 -call ALEAddLinter('css', { +call ale#linter#Define('css', { \ 'name': 'csslint', \ 'executable': 'csslint', \ 'command': g:ale#util#stdin_wrapper . ' .css csslint --format=compact', diff --git a/ale_linters/d/dmd.vim b/ale_linters/d/dmd.vim index 4c109e08..0fdf0bac 100644 --- a/ale_linters/d/dmd.vim +++ b/ale_linters/d/dmd.vim @@ -61,7 +61,7 @@ function! ale_linters#d#dmd#Handle(buffer, lines) return output endfunction -call ALEAddLinter('d', { +call ale#linter#Define('d', { \ 'name': 'dmd', \ 'output_stream': 'stderr', \ 'executable': 'dmd', diff --git a/ale_linters/fortran/gcc.vim b/ale_linters/fortran/gcc.vim index 3e97fea9..fecaf39a 100644 --- a/ale_linters/fortran/gcc.vim +++ b/ale_linters/fortran/gcc.vim @@ -60,7 +60,7 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) return output endfunction -call ALEAddLinter('fortran', { +call ale#linter#Define('fortran', { \ 'name': 'gcc', \ 'output_stream': 'stderr', \ 'executable': 'gcc', diff --git a/ale_linters/haskell/ghc.vim b/ale_linters/haskell/ghc.vim index 5af4bb3d..5c5dba10 100644 --- a/ale_linters/haskell/ghc.vim +++ b/ale_linters/haskell/ghc.vim @@ -58,7 +58,7 @@ function! ale_linters#haskell#ghc#Handle(buffer, lines) return output endfunction -call ALEAddLinter('haskell', { +call ale#linter#Define('haskell', { \ 'name': 'ghc', \ 'output_stream': 'stderr', \ 'executable': 'ghc', @@ -66,7 +66,7 @@ call ALEAddLinter('haskell', { \ 'callback': 'ale_linters#haskell#ghc#Handle', \}) -call ALEAddLinter('haskell', { +call ale#linter#Define('haskell', { \ 'name': 'stack-ghc', \ 'output_stream': 'stderr', \ 'executable': 'stack', diff --git a/ale_linters/html/htmlhint.vim b/ale_linters/html/htmlhint.vim index 8cfe1f28..57eff0ec 100644 --- a/ale_linters/html/htmlhint.vim +++ b/ale_linters/html/htmlhint.vim @@ -40,7 +40,7 @@ function! ale_linters#html#htmlhint#Handle(buffer, lines) abort return output endfunction -call ALEAddLinter('html', { +call ale#linter#Define('html', { \ 'name': 'htmlhint', \ 'executable': 'htmlhint', \ 'command': 'htmlhint --format=unix stdin', diff --git a/ale_linters/html/tidy.vim b/ale_linters/html/tidy.vim index b5621f91..c1aab8f3 100644 --- a/ale_linters/html/tidy.vim +++ b/ale_linters/html/tidy.vim @@ -71,7 +71,7 @@ function! ale_linters#html#tidy#Handle(buffer, lines) abort return output endfunction -call ALEAddLinter('html', { +call ale#linter#Define('html', { \ 'name': 'tidy', \ 'executable': g:ale_html_tidy_executable, \ 'output_stream': 'stderr', diff --git a/ale_linters/javascript/eslint.vim b/ale_linters/javascript/eslint.vim index 94d14e6b..d140a957 100644 --- a/ale_linters/javascript/eslint.vim +++ b/ale_linters/javascript/eslint.vim @@ -49,14 +49,14 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('javascript', { +call ale#linter#Define('javascript', { \ 'name': 'eslint', \ 'executable': g:ale_javascript_eslint_executable, \ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s', \ 'callback': 'ale_linters#javascript#eslint#Handle', \}) -call ALEAddLinter('javascript.jsx', { +call ale#linter#Define('javascript.jsx', { \ 'name': 'eslint', \ 'executable': g:ale_javascript_eslint_executable, \ 'command': g:ale_javascript_eslint_executable . ' -f unix --stdin --stdin-filename %s', diff --git a/ale_linters/javascript/jscs.vim b/ale_linters/javascript/jscs.vim index 263ea88d..9252eef3 100644 --- a/ale_linters/javascript/jscs.vim +++ b/ale_linters/javascript/jscs.vim @@ -43,14 +43,14 @@ function! ale_linters#javascript#jscs#Handle(buffer, lines) return output endfunction -call ALEAddLinter('javascript', { +call ale#linter#Define('javascript', { \ 'name': 'jscs', \ 'executable': 'jscs', \ 'command': 'jscs -r unix -n -', \ 'callback': 'ale_linters#javascript#jscs#Handle', \}) -call ALEAddLinter('javascript.jsx', { +call ale#linter#Define('javascript.jsx', { \ 'name': 'jscs', \ 'executable': 'jscs', \ 'command': 'jscs -r unix -n -', diff --git a/ale_linters/javascript/jshint.vim b/ale_linters/javascript/jshint.vim index a020ca0c..11c60409 100644 --- a/ale_linters/javascript/jshint.vim +++ b/ale_linters/javascript/jshint.vim @@ -70,14 +70,14 @@ function! ale_linters#javascript#jshint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('javascript', { +call ale#linter#Define('javascript', { \ 'name': 'jshint', \ 'executable': g:ale_javascript_jshint_executable, \ 'command_callback': 'ale_linters#javascript#jshint#GetCommand', \ 'callback': 'ale_linters#javascript#jshint#Handle', \}) -call ALEAddLinter('javascript.jsx', { +call ale#linter#Define('javascript.jsx', { \ 'name': 'jshint', \ 'executable': g:ale_javascript_jshint_executable, \ 'command_callback': 'ale_linters#javascript#jshint#GetCommand', diff --git a/ale_linters/json/jsonlint.vim b/ale_linters/json/jsonlint.vim index 77145bcd..aaf56b6e 100644 --- a/ale_linters/json/jsonlint.vim +++ b/ale_linters/json/jsonlint.vim @@ -35,7 +35,7 @@ function! ale_linters#json#jsonlint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('json', { +call ale#linter#Define('json', { \ 'name': 'jsonlint', \ 'executable': 'jsonlint', \ 'output_stream': 'stderr', diff --git a/ale_linters/perl/perl.vim b/ale_linters/perl/perl.vim index ad33b6dc..c5300ac8 100644 --- a/ale_linters/perl/perl.vim +++ b/ale_linters/perl/perl.vim @@ -37,7 +37,7 @@ function! ale_linters#perl#perl#Handle(buffer, lines) return output endfunction -call ALEAddLinter('perl', { +call ale#linter#Define('perl', { \ 'name': 'perl', \ 'executable': 'perl', \ 'output_stream': 'both', diff --git a/ale_linters/perl/perlcritic.vim b/ale_linters/perl/perlcritic.vim index 98ac83a8..64e1e3e4 100644 --- a/ale_linters/perl/perlcritic.vim +++ b/ale_linters/perl/perlcritic.vim @@ -37,7 +37,7 @@ function! ale_linters#perl#perlcritic#Handle(buffer, lines) return output endfunction -call ALEAddLinter('perl', { +call ale#linter#Define('perl', { \ 'name': 'perlcritic', \ 'executable': 'perlcritic', \ 'output_stream': 'sdtout', diff --git a/ale_linters/php/php.vim b/ale_linters/php/php.vim index 808a5ce6..57519a24 100644 --- a/ale_linters/php/php.vim +++ b/ale_linters/php/php.vim @@ -36,7 +36,7 @@ function! ale_linters#php#php#Handle(buffer, lines) return output endfunction -call ALEAddLinter('php', { +call ale#linter#Define('php', { \ 'name': 'php', \ 'executable': 'php', \ 'output_stream': 'both', diff --git a/ale_linters/php/phpcs.vim b/ale_linters/php/phpcs.vim index db7598fa..ed74b443 100644 --- a/ale_linters/php/phpcs.vim +++ b/ale_linters/php/phpcs.vim @@ -50,7 +50,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) return output endfunction -call ALEAddLinter('php', { +call ale#linter#Define('php', { \ 'name': 'phpcs', \ 'executable': 'phpcs', \ 'command_callback': 'ale_linters#php#phpcs#GetCommand', diff --git a/ale_linters/pug/puglint.vim b/ale_linters/pug/puglint.vim index d59c7f06..754c6bb4 100644 --- a/ale_linters/pug/puglint.vim +++ b/ale_linters/pug/puglint.vim @@ -35,7 +35,7 @@ function! ale_linters#pug#puglint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('pug', { +call ale#linter#Define('pug', { \ 'name': 'puglint', \ 'executable': 'pug-lint', \ 'output_stream': 'stderr', diff --git a/ale_linters/pyrex/cython.vim b/ale_linters/pyrex/cython.vim index a0175ab4..0c393f95 100644 --- a/ale_linters/pyrex/cython.vim +++ b/ale_linters/pyrex/cython.vim @@ -34,7 +34,7 @@ function! ale_linters#pyrex#cython#Handle(buffer, lines) return output endfunction -call ALEAddLinter('pyrex', { +call ale#linter#Define('pyrex', { \ 'name': 'cython', \ 'output_stream': 'stderr', \ 'executable': 'cython', diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim index 95ab2a28..aa114df6 100644 --- a/ale_linters/python/flake8.vim +++ b/ale_linters/python/flake8.vim @@ -47,7 +47,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines) return output endfunction -call ALEAddLinter('python', { +call ale#linter#Define('python', { \ 'name': 'flake8', \ 'executable': 'flake8', \ 'command': 'flake8 -', diff --git a/ale_linters/ruby/rubocop.vim b/ale_linters/ruby/rubocop.vim index 1acb2636..17326a7e 100644 --- a/ale_linters/ruby/rubocop.vim +++ b/ale_linters/ruby/rubocop.vim @@ -40,7 +40,7 @@ function! ale_linters#ruby#rubocop#Handle(buffer, lines) return output endfunction -call ALEAddLinter('ruby', { +call ale#linter#Define('ruby', { \ 'name': 'rubocop', \ 'executable': 'rubocop', \ 'command': 'rubocop --format emacs --stdin _', diff --git a/ale_linters/sass/sasslint.vim b/ale_linters/sass/sasslint.vim index 3d7fbfc4..eb14ba9c 100644 --- a/ale_linters/sass/sasslint.vim +++ b/ale_linters/sass/sasslint.vim @@ -6,7 +6,7 @@ endif let g:loaded_ale_linters_sass_sasslint = 1 -call ALEAddLinter('sass', { +call ale#linter#Define('sass', { \ 'name': 'sasslint', \ 'executable': 'sass-lint', \ 'command': g:ale#util#stdin_wrapper . ' .sass sass-lint -v -q -f compact', diff --git a/ale_linters/scala/scalac.vim b/ale_linters/scala/scalac.vim index 7d7d14ab..06508107 100644 --- a/ale_linters/scala/scalac.vim +++ b/ale_linters/scala/scalac.vim @@ -49,7 +49,7 @@ function! ale_linters#scala#scalac#Handle(buffer, lines) return output endfunction -call ALEAddLinter('scala', { +call ale#linter#Define('scala', { \ 'name': 'scalac', \ 'executable': 'scalac', \ 'output_stream': 'stderr', diff --git a/ale_linters/scss/sasslint.vim b/ale_linters/scss/sasslint.vim index baf860b6..c0dd09c8 100644 --- a/ale_linters/scss/sasslint.vim +++ b/ale_linters/scss/sasslint.vim @@ -6,7 +6,7 @@ endif let g:loaded_ale_linters_scss_sasslint = 1 -call ALEAddLinter('scss', { +call ale#linter#Define('scss', { \ 'name': 'sasslint', \ 'executable': 'sass-lint', \ 'command': g:ale#util#stdin_wrapper . ' .scss sass-lint -v -q -f compact', diff --git a/ale_linters/scss/scsslint.vim b/ale_linters/scss/scsslint.vim index 7f4c67ea..ac1c3796 100644 --- a/ale_linters/scss/scsslint.vim +++ b/ale_linters/scss/scsslint.vim @@ -41,7 +41,7 @@ function! ale_linters#scss#scsslint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('scss', { +call ale#linter#Define('scss', { \ 'name': 'scsslint', \ 'executable': 'scss-lint', \ 'command': 'scss-lint --stdin-file-path=%s', diff --git a/ale_linters/sh/shell.vim b/ale_linters/sh/shell.vim index 07c5650c..b17f331a 100644 --- a/ale_linters/sh/shell.vim +++ b/ale_linters/sh/shell.vim @@ -74,7 +74,7 @@ function! ale_linters#sh#shell#Handle(buffer, lines) return output endfunction -call ALEAddLinter('sh', { +call ale#linter#Define('sh', { \ 'name': 'shell', \ 'output_stream': 'stderr', \ 'executable_callback': 'ale_linters#sh#shell#GetExecutable', diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim index 3bc9abe4..82ca5947 100644 --- a/ale_linters/sh/shellcheck.vim +++ b/ale_linters/sh/shellcheck.vim @@ -22,7 +22,7 @@ else let s:exclude_option = '' endif -call ALEAddLinter('sh', { +call ale#linter#Define('sh', { \ 'name': 'shellcheck', \ 'executable': 'shellcheck', \ 'command': 'shellcheck ' . s:exclude_option . ' -f gcc -', diff --git a/ale_linters/typescript/tslint.vim b/ale_linters/typescript/tslint.vim index 16a6f352..ef147832 100644 --- a/ale_linters/typescript/tslint.vim +++ b/ale_linters/typescript/tslint.vim @@ -43,7 +43,7 @@ function! ale_linters#typescript#tslint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('typescript', { +call ale#linter#Define('typescript', { \ 'name': 'tslint', \ 'executable': 'tslint', \ 'command': g:ale#util#stdin_wrapper . ' .ts tslint', diff --git a/ale_linters/verilog/iverilog.vim b/ale_linters/verilog/iverilog.vim index d1eb51e3..02df6f84 100644 --- a/ale_linters/verilog/iverilog.vim +++ b/ale_linters/verilog/iverilog.vim @@ -42,7 +42,7 @@ function! ale_linters#verilog#iverilog#Handle(buffer, lines) return output endfunction -call ALEAddLinter('verilog', { +call ale#linter#Define('verilog', { \ 'name': 'iverilog', \ 'output_stream': 'stderr', \ 'executable': 'iverilog', diff --git a/ale_linters/verilog/verilator.vim b/ale_linters/verilog/verilator.vim index cc29f890..4878ad3e 100644 --- a/ale_linters/verilog/verilator.vim +++ b/ale_linters/verilog/verilator.vim @@ -44,7 +44,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) return output endfunction -call ALEAddLinter('verilog', { +call ale#linter#Define('verilog', { \ 'name': 'verilator', \ 'output_stream': 'stderr', \ 'executable': 'verilator', diff --git a/ale_linters/vim/vint.vim b/ale_linters/vim/vint.vim index 5d4b10eb..32e64041 100644 --- a/ale_linters/vim/vint.vim +++ b/ale_linters/vim/vint.vim @@ -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})' -call ALEAddLinter('vim', { +call ale#linter#Define('vim', { \ 'name': 'vint', \ 'executable': 'vint', \ 'command': g:ale#util#stdin_wrapper . ' .vim vint -w --no-color ' . s:format, diff --git a/ale_linters/yaml/yamllint.vim b/ale_linters/yaml/yamllint.vim index 92a4313d..db01ccc4 100644 --- a/ale_linters/yaml/yamllint.vim +++ b/ale_linters/yaml/yamllint.vim @@ -40,7 +40,7 @@ function! ale_linters#yaml#yamllint#Handle(buffer, lines) return output endfunction -call ALEAddLinter('yaml', { +call ale#linter#Define('yaml', { \ 'name': 'yamllint', \ 'executable': 'yamllint', \ 'command': g:ale#util#stdin_wrapper . ' .yml yamllint -f parsable', diff --git a/autoload/ale.vim b/autoload/ale.vim new file mode 100644 index 00000000..b25bcc99 --- /dev/null +++ b/autoload/ale.vim @@ -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 diff --git a/autoload/ale/cleanup.vim b/autoload/ale/cleanup.vim new file mode 100644 index 00000000..2f636eee --- /dev/null +++ b/autoload/ale/cleanup.vim @@ -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 diff --git a/plugin/ale/cursor.vim b/autoload/ale/cursor.vim index a6d23979..eaa466b2 100644 --- a/plugin/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -1,12 +1,6 @@ " Author: w0rp <devw0rp@gmail.com> " 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 function! s:GetMessage(linter, type, text) abort 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 " loclist to echo when the cursor moves. -function! s:BinarySearch(loclist, line, column) +function! s:BinarySearch(loclist, line, column) abort let min = 0 let max = len(a:loclist) - 1 let last_column_match = -1 @@ -59,7 +53,7 @@ function! s:BinarySearch(loclist, line, column) endwhile endfunction -function! ale#cursor#TruncatedEcho(message) +function! ale#cursor#TruncatedEcho(message) abort let message = a:message " Change tabs to spaces. let message = substitute(message, "\t", ' ', 'g') @@ -79,7 +73,7 @@ function! ale#cursor#TruncatedEcho(message) endtry endfunction -function! ale#cursor#EchoCursorWarning(...) +function! ale#cursor#EchoCursorWarning(...) abort " Only echo the warnings in normal mode, otherwise we will get problems. if mode() !=# 'n' return @@ -108,7 +102,7 @@ endfunction let s:cursor_timer = -1 -function! ale#cursor#EchoCursorWarningWithDelay() +function! ale#cursor#EchoCursorWarningWithDelay() abort if s:cursor_timer != -1 call timer_stop(s:cursor_timer) let s:cursor_timer = -1 diff --git a/plugin/ale/zmain.vim b/autoload/ale/engine.vim index 16b0a476..3d7374c6 100644 --- a/plugin/ale/zmain.vim +++ b/autoload/ale/engine.vim @@ -1,19 +1,6 @@ " Author: w0rp <devw0rp@gmail.com> -" Description: Main entry point for this plugin -" Loads linters and manages lint 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 +" Description: Backend execution and job management +" Executes linters in the background, using NeoVim or Vim 8 jobs " Stores information for each job including: " @@ -22,20 +9,18 @@ endif " output: The array of lines for the output of the job. let s:job_info_map = {} -" 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 = {} - -function! s:GetFunction(string_or_ref) - if type(a:string_or_ref) == type('') - return function(a:string_or_ref) +function! s:GetJobID(job) abort + if has('nvim') + "In NeoVim, job values are just IDs. + return a:job 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 -function! s:ClearJob(job) +function! s:ClearJob(job) abort let job_id = s:GetJobID(a:job) let linter = s:job_info_map[job_id].linter @@ -55,7 +40,7 @@ function! s:ClearJob(job) call remove(linter, 'job') endfunction -function! s:GatherOutput(job, data) +function! s:GatherOutput(job, data) abort let job_id = s:GetJobID(a:job) 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) endfunction -function! s:GatherOutputNeoVim(job, data, event) - call s:GatherOutput(a:job, a:data) -endfunction - -function! s:GatherOutputVim(channel, data) +function! s:GatherOutputVim(channel, data) abort call s:GatherOutput(ch_getjob(a:channel), [a:data]) endfunction -function! s:LocItemCompare(left, right) - 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 - -function! s:FixLoclist(buffer, loclist) - " 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 +function! s:GatherOutputNeoVim(job, data, event) abort + call s:GatherOutput(a:job, a:data) endfunction -function! s:HandleExit(job) +function! s:HandleExit(job) abort if a:job ==# 'no process' " Stop right away when the job is not valid in Vim 8. return @@ -129,15 +78,10 @@ function! s:HandleExit(job) let output = job_info.output 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. - 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 + call s:FixLocList(buffer, linter_loclist) if g:ale_buffer_should_reset_map[buffer] let g:ale_buffer_should_reset_map[buffer] = 0 @@ -150,7 +94,7 @@ function! s:HandleExit(job) " Sort the loclist again. " We need a sorted list so we can run a binary search against it " 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 call setloclist(0, g:ale_buffer_loclist_map[buffer]) @@ -164,26 +108,31 @@ function! s:HandleExit(job) " matchadd('ALEError', '\%200l\%17v') endfunction -function! s:GetJobID(job) - 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) +function! s:HandleExitNeoVim(job, data, event) abort call s:HandleExit(a:job) endfunction -function! s:HandleExitVim(channel) +function! s:HandleExitVim(channel) abort call s:HandleExit(ch_getjob(a:channel)) 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') " Stop previous jobs for the same linter. call s:ClearJob(a:linter.job) @@ -191,7 +140,7 @@ function! s:ApplyLinter(buffer, linter) if has_key(a:linter, 'command_callback') " 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 let command = a:linter.command endif @@ -274,8 +223,7 @@ function! s:ApplyLinter(buffer, linter) call jobsend(job, input) call jobclose(job, 'stdin') elseif has('win32') - " On Windows, we have to send the buffer lines ourselves, - " as there are issues with Windows and 'in_buf' + " On some Vim versions, we have to send the buffer data ourselves. let input = join(getbufline(a:buffer, 1, '$'), "\n") . "\n" let channel = job_getchannel(job) @@ -286,152 +234,3 @@ function! s:ApplyLinter(buffer, linter) endif endif 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 diff --git a/plugin/ale/handlers.vim b/autoload/ale/handlers.vim index a348ad30..6a8bd246 100644 --- a/plugin/ale/handlers.vim +++ b/autoload/ale/handlers.vim @@ -4,13 +4,7 @@ scriptencoding utf-8 " 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. -if exists('g:loaded_ale_handlers') - finish -endif - -let g:loaded_ale_handlers = 1 - -function! ale#handlers#HandleGCCFormat(buffer, lines) +function! ale#handlers#HandleGCCFormat(buffer, lines) abort " Look for lines like the following. " " <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=] @@ -40,7 +34,7 @@ function! ale#handlers#HandleGCCFormat(buffer, lines) return output endfunction -function! ale#handlers#HandleCSSLintFormat(buffer, lines) +function! ale#handlers#HandleCSSLintFormat(buffer, lines) abort " Matches patterns line the following: " " something.css: line 2, col 1, Error - Expected RBRACE at line 2, col 1. (errors) diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim new file mode 100644 index 00000000..c87fa8df --- /dev/null +++ b/autoload/ale/linter.vim @@ -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 diff --git a/plugin/ale/sign.vim b/autoload/ale/sign.vim index 5950ae99..5cdd97c1 100644 --- a/plugin/ale/sign.vim +++ b/autoload/ale/sign.vim @@ -1,12 +1,7 @@ -scriptencoding utf-8 +scriptencoding utf8 " Author: w0rp <devw0rp@gmail.com> " 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 = {} if !hlexists('ALEErrorSign') @@ -40,7 +35,7 @@ execute 'sign define ALEWarningSign text=' . g:ale_sign_warning \ . ' texthl=ALEWarningSign' sign define ALEDummySign -function! ale#sign#FindCurrentSigns(buffer) +function! ale#sign#FindCurrentSigns(buffer) abort " Matches output like : " line=4 id=1 name=ALEErrorSign " строка=1 id=1000001 имя=ALEErrorSign @@ -66,7 +61,7 @@ endfunction " Given a loclist, combine the loclist into a list of signs such that only " one sign appears per line. Error lines will take precedence. " The loclist will have been previously sorted. -function! ale#sign#CombineSigns(loclist) +function! ale#sign#CombineSigns(loclist) abort let signlist = [] for obj in a:loclist @@ -98,7 +93,7 @@ function! ale#sign#CombineSigns(loclist) endfunction " 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) if len(signlist) > 0 || g:ale_sign_column_always diff --git a/plugin/ale/statusline.vim b/autoload/ale/statusline.vim index baef418a..ded5283b 100644 --- a/plugin/ale/statusline.vim +++ b/autoload/ale/statusline.vim @@ -1,7 +1,7 @@ " Author: KabbAmine <amine.kabb@gmail.com> " Description: Statusline related function(s) -function! ALEGetStatusLine() abort +function! ale#statusline#Status() abort " Returns a formatted string that can be integrated in the " statusline diff --git a/plugin/ale/util.vim b/autoload/ale/util.vim index fd9bb356..e292c990 100644 --- a/plugin/ale/util.vim +++ b/autoload/ale/util.vim @@ -1,13 +1,7 @@ " Author: w0rp <devw0rp@gmail.com> " Description: Contains miscellaneous functions -if exists('g:loaded_ale_util') - finish -endif - -let g:loaded_ale_util = 1 - -function! s:FindWrapperScript() +function! s:FindWrapperScript() abort for parent in split(&runtimepath, ',') " Expand the path to deal with ~ issues. let path = expand(parent . '/' . 'stdin-wrapper') @@ -24,20 +18,48 @@ endfunction let g:ale#util#stdin_wrapper = s:FindWrapperScript() +" A null file for sending output to nothing. +let g:ale#util#nul_file = '/dev/null' + +if has('win32') + let g:ale#util#nul_file = 'nul' +endif + " Return the number of lines for a given buffer. -function! ale#util#GetLineCount(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) +function! ale#util#FindNearestFile(buffer, filename) abort return findfile(a:filename, fnamemodify(bufname(a:buffer), ':p') . ';') endfunction -" A null file for sending output to nothing. -let g:ale#util#nul_file = '/dev/null' +function! ale#util#GetFunction(string_or_ref) abort + if type(a:string_or_ref) == type('') + return function(a:string_or_ref) + endif -if has('win32') - let g:ale#util#nul_file = 'nul' -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 diff --git a/doc/ale.txt b/doc/ale.txt index bfe3cd8e..d7c5d25e 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -289,11 +289,30 @@ g:ale_statusline_format *g:ale_statusline_format* Type: |List| 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 2nd element is for warnings - 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* @@ -413,14 +432,14 @@ g:ale_javascript_jshint_executable *g:ale_javascript_jshint_executable* =============================================================================== 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, 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 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 configuration, add a linter for the given filetype. The dictionaries each offer the following options: @@ -492,21 +511,21 @@ ALEAddLinter(filetype, linter) *ALEAddLinter()* '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 - |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. The output's format is defined in |`g:ale_statusline_format`|. 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* 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. =============================================================================== diff --git a/plugin/ale/aaflags.vim b/plugin/ale.vim index 56ed4175..3982ee69 100644 --- a/plugin/ale/aaflags.vim +++ b/plugin/ale.vim @@ -1,12 +1,11 @@ " Author: w0rp <devw0rp@gmail.com> -" Description: This file sets up configuration settings for the ALE plugin. -" Flags can be set in vimrc files and so on to disable particular features +" Description: Main entry point for the plugin: sets up prefs and autocommands +" 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 endif - -let g:loaded_ale_flags = 1 +let g:loaded_ale = 1 " A flag for detecting if the required features are set. if has('nvim') @@ -15,6 +14,15 @@ else let g:ale_has_required_features = has('timers') && has('job') && has('channel') 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. 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 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') + +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 |