summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ale_linters/ada/gcc.vim4
-rw-r--r--ale_linters/ansible/ansible_lint.vim2
-rw-r--r--ale_linters/asciidoc/textlint.vim4
-rw-r--r--ale_linters/asm/gcc.vim4
-rw-r--r--ale_linters/awk/gawk.vim4
-rw-r--r--ale_linters/bib/bibclean.vim4
-rw-r--r--ale_linters/c/ccls.vim6
-rw-r--r--ale_linters/c/clang.vim2
-rw-r--r--ale_linters/c/clangd.vim6
-rw-r--r--ale_linters/c/clangtidy.vim4
-rw-r--r--ale_linters/c/cppcheck.vim4
-rw-r--r--ale_linters/c/cquery.vim6
-rw-r--r--ale_linters/c/flawfinder.vim4
-rw-r--r--ale_linters/c/gcc.vim2
-rw-r--r--ale_linters/chef/foodcritic.vim4
-rw-r--r--ale_linters/cmake/cmakelint.vim4
-rw-r--r--ale_linters/coffee/coffee.vim4
-rw-r--r--ale_linters/coffee/coffeelint.vim4
-rw-r--r--ale_linters/cpp/ccls.vim6
-rw-r--r--ale_linters/cpp/clang.vim2
-rw-r--r--ale_linters/cpp/clangcheck.vim4
-rw-r--r--ale_linters/cpp/clangd.vim6
-rw-r--r--ale_linters/cpp/clangtidy.vim4
-rw-r--r--ale_linters/cpp/clazy.vim4
-rw-r--r--ale_linters/cpp/cppcheck.vim4
-rw-r--r--ale_linters/cpp/cpplint.vim4
-rw-r--r--ale_linters/cpp/cquery.vim6
-rw-r--r--ale_linters/cpp/flawfinder.vim4
-rw-r--r--ale_linters/cpp/gcc.vim2
-rw-r--r--ale_linters/crystal/ameba.vim4
-rw-r--r--ale_linters/crystal/crystal.vim2
-rw-r--r--ale_linters/cs/mcs.vim2
-rw-r--r--ale_linters/cs/mcsc.vim2
-rw-r--r--ale_linters/css/csslint.vim2
-rw-r--r--ale_linters/css/stylelint.vim6
-rw-r--r--ale_linters/cucumber/cucumber.vim2
-rw-r--r--ale_linters/cuda/nvcc.vim4
-rw-r--r--ale_linters/d/dls.vim6
-rw-r--r--ale_linters/dart/dartanalyzer.vim4
-rw-r--r--ale_linters/dart/language_server.vim4
-rw-r--r--ale_linters/dockerfile/dockerfile_lint.vim4
-rw-r--r--ale_linters/dockerfile/hadolint.vim4
-rw-r--r--ale_linters/elixir/credo.vim2
-rw-r--r--ale_linters/elixir/dialyxir.vim2
-rw-r--r--ale_linters/elixir/dogma.vim2
-rw-r--r--ale_linters/elixir/elixir_ls.vim8
-rw-r--r--ale_linters/elixir/mix.vim2
-rw-r--r--ale_linters/elm/make.vim4
-rw-r--r--ale_linters/erlang/erlc.vim2
-rw-r--r--ale_linters/erlang/syntaxerl.vim2
-rw-r--r--ale_linters/eruby/erb.vim2
-rw-r--r--ale_linters/eruby/erubis.vim2
-rw-r--r--ale_linters/eruby/ruumba.vim4
-rw-r--r--ale_linters/fortran/gcc.vim4
-rw-r--r--ale_linters/fortran/language_server.vim4
-rw-r--r--ale_linters/fuse/fusionlint.vim4
-rw-r--r--ale_linters/gitcommit/gitlint.vim4
-rw-r--r--ale_linters/glsl/glslang.vim4
-rw-r--r--ale_linters/glsl/glslls.vim6
-rw-r--r--ale_linters/go/bingo.vim6
-rw-r--r--ale_linters/go/gobuild.vim4
-rw-r--r--ale_linters/go/golangci_lint.vim4
-rw-r--r--ale_linters/go/golint.vim4
-rw-r--r--ale_linters/go/gometalinter.vim4
-rw-r--r--ale_linters/go/gosimple.vim2
-rw-r--r--ale_linters/go/gotype.vim2
-rw-r--r--ale_linters/go/govet.vim4
-rw-r--r--ale_linters/go/langserver.vim6
-rw-r--r--ale_linters/go/staticcheck.vim2
-rw-r--r--ale_linters/graphql/eslint.vim4
-rw-r--r--ale_linters/graphql/gqlint.vim2
-rw-r--r--ale_linters/hack/hack.vim4
-rw-r--r--ale_linters/hack/hhast.vim6
-rw-r--r--ale_linters/haml/hamllint.vim4
-rw-r--r--ale_linters/handlebars/embertemplatelint.vim4
-rw-r--r--ale_linters/haskell/cabal_ghc.vim2
-rw-r--r--ale_linters/haskell/ghc.vim2
-rw-r--r--ale_linters/haskell/ghc_mod.vim4
-rw-r--r--ale_linters/haskell/hdevtools.vim4
-rw-r--r--ale_linters/haskell/hie.vim6
-rw-r--r--ale_linters/haskell/hlint.vim4
-rw-r--r--ale_linters/haskell/stack_build.vim4
-rw-r--r--ale_linters/haskell/stack_ghc.vim4
-rw-r--r--ale_linters/html/htmlhint.vim6
-rw-r--r--ale_linters/html/stylelint.vim4
-rw-r--r--ale_linters/html/tidy.vim4
-rw-r--r--ale_linters/idris/idris.vim4
-rw-r--r--ale_linters/ispc/ispc.vim4
-rw-r--r--ale_linters/java/checkstyle.vim2
-rw-r--r--ale_linters/java/javac.vim2
-rw-r--r--ale_linters/java/javalsp.vim6
-rw-r--r--ale_linters/java/pmd.vim2
-rw-r--r--ale_linters/javascript/eslint.vim4
-rwxr-xr-xale_linters/javascript/flow.vim2
-rw-r--r--ale_linters/javascript/flow_ls.vim6
-rw-r--r--ale_linters/javascript/jscs.vim6
-rw-r--r--ale_linters/javascript/jshint.vim6
-rw-r--r--ale_linters/javascript/standard.vim4
-rw-r--r--ale_linters/javascript/tsserver.vim6
-rw-r--r--ale_linters/javascript/xo.vim4
-rw-r--r--ale_linters/julia/languageserver.vim6
-rw-r--r--ale_linters/kotlin/ktlint.vim2
-rw-r--r--ale_linters/kotlin/languageserver.vim4
-rwxr-xr-xale_linters/less/lessc.vim6
-rw-r--r--ale_linters/less/stylelint.vim6
-rw-r--r--ale_linters/llvm/llc.vim4
-rw-r--r--ale_linters/lua/luac.vim2
-rw-r--r--ale_linters/lua/luacheck.vim4
-rw-r--r--ale_linters/markdown/mdl.vim4
-rw-r--r--ale_linters/markdown/remark_lint.vim6
-rw-r--r--ale_linters/markdown/textlint.vim4
-rw-r--r--ale_linters/matlab/mlint.vim2
-rw-r--r--ale_linters/mercury/mmc.vim4
-rw-r--r--ale_linters/nasm/nasm.vim4
-rw-r--r--ale_linters/nim/nimcheck.vim2
-rw-r--r--ale_linters/objc/ccls.vim6
-rw-r--r--ale_linters/objc/clang.vim2
-rw-r--r--ale_linters/objc/clangd.vim6
-rw-r--r--ale_linters/objcpp/clang.vim2
-rw-r--r--ale_linters/objcpp/clangd.vim6
-rw-r--r--ale_linters/ocaml/ols.vim6
-rw-r--r--ale_linters/perl/perl.vim4
-rw-r--r--ale_linters/perl/perlcritic.vim4
-rw-r--r--ale_linters/perl6/perl6.vim4
-rw-r--r--ale_linters/php/langserver.vim6
-rw-r--r--ale_linters/php/phan.vim4
-rw-r--r--ale_linters/php/php.vim2
-rw-r--r--ale_linters/php/phpcs.vim6
-rw-r--r--ale_linters/php/phpmd.vim4
-rw-r--r--ale_linters/php/phpstan.vim2
-rw-r--r--ale_linters/php/psalm.vim6
-rw-r--r--ale_linters/pony/ponyc.vim4
-rw-r--r--ale_linters/prolog/swipl.vim4
-rw-r--r--ale_linters/proto/protoc_gen_lint.vim2
-rw-r--r--ale_linters/pug/puglint.vim6
-rw-r--r--ale_linters/puppet/languageserver.vim4
-rw-r--r--ale_linters/puppet/puppet.vim4
-rw-r--r--ale_linters/puppet/puppetlint.vim4
-rw-r--r--ale_linters/pyrex/cython.vim4
-rw-r--r--ale_linters/python/bandit.vim13
-rw-r--r--ale_linters/python/flake8.vim2
-rw-r--r--ale_linters/python/mypy.vim4
-rw-r--r--ale_linters/python/prospector.vim4
-rw-r--r--ale_linters/python/pycodestyle.vim4
-rw-r--r--ale_linters/python/pydocstyle.vim4
-rw-r--r--ale_linters/python/pyflakes.vim4
-rw-r--r--ale_linters/python/pylama.vim4
-rw-r--r--ale_linters/python/pylint.vim18
-rw-r--r--ale_linters/python/pyls.vim8
-rw-r--r--ale_linters/python/pyre.vim6
-rw-r--r--ale_linters/python/vulture.vim4
-rw-r--r--ale_linters/qml/qmlfmt.vim2
-rw-r--r--ale_linters/r/lintr.vim2
-rw-r--r--ale_linters/reason/ols.vim6
-rw-r--r--ale_linters/rst/rstcheck.vim2
-rw-r--r--ale_linters/rst/textlint.vim4
-rw-r--r--ale_linters/ruby/brakeman.vim4
-rw-r--r--ale_linters/ruby/rails_best_practices.vim4
-rw-r--r--ale_linters/ruby/reek.vim2
-rw-r--r--ale_linters/ruby/rubocop.vim4
-rw-r--r--ale_linters/ruby/ruby.vim2
-rw-r--r--ale_linters/ruby/solargraph.vim8
-rw-r--r--ale_linters/ruby/standardrb.vim4
-rw-r--r--ale_linters/rust/cargo.vim2
-rw-r--r--ale_linters/rust/rls.vim8
-rw-r--r--ale_linters/rust/rustc.vim2
-rw-r--r--ale_linters/sass/sasslint.vim4
-rw-r--r--ale_linters/sass/stylelint.vim4
-rw-r--r--ale_linters/scala/fsc.vim2
-rw-r--r--ale_linters/scala/sbtserver.vim4
-rw-r--r--ale_linters/scala/scalac.vim2
-rw-r--r--ale_linters/scala/scalastyle.vim2
-rw-r--r--ale_linters/scss/sasslint.vim4
-rw-r--r--ale_linters/scss/stylelint.vim6
-rw-r--r--ale_linters/sh/language_server.vim6
-rw-r--r--ale_linters/sh/shell.vim4
-rw-r--r--ale_linters/sh/shellcheck.vim2
-rw-r--r--ale_linters/slim/slimlint.vim2
-rw-r--r--ale_linters/sml/smlnj.vim2
-rw-r--r--ale_linters/sml/smlnj_cm.vim4
-rw-r--r--ale_linters/spec/rpmlint.vim4
-rw-r--r--ale_linters/stylus/stylelint.vim6
-rw-r--r--ale_linters/sugarss/stylelint.vim6
-rw-r--r--ale_linters/swift/swiftlint.vim4
-rw-r--r--ale_linters/tcl/nagelfar.vim4
-rw-r--r--ale_linters/terraform/tflint.vim4
-rw-r--r--ale_linters/tex/chktex.vim2
-rw-r--r--ale_linters/tex/lacheck.vim2
-rw-r--r--ale_linters/tex/textlint.vim4
-rw-r--r--ale_linters/text/textlint.vim4
-rw-r--r--ale_linters/thrift/thrift.vim5
-rw-r--r--ale_linters/typescript/eslint.vim4
-rw-r--r--ale_linters/typescript/tslint.vim4
-rw-r--r--ale_linters/typescript/tsserver.vim6
-rw-r--r--ale_linters/verilog/iverilog.vim2
-rw-r--r--ale_linters/verilog/verilator.vim2
-rw-r--r--ale_linters/verilog/vlog.vim4
-rw-r--r--ale_linters/verilog/xvlog.vim4
-rw-r--r--ale_linters/vhdl/ghdl.vim4
-rw-r--r--ale_linters/vhdl/vcom.vim4
-rw-r--r--ale_linters/vhdl/xvhdl.vim4
-rw-r--r--ale_linters/vim/ale_custom_linting_rules.vim4
-rw-r--r--ale_linters/vim/vint.vim2
-rw-r--r--ale_linters/vue/vls.vim6
-rw-r--r--ale_linters/xml/xmllint.vim4
-rw-r--r--ale_linters/yaml/swaglint.vim4
-rw-r--r--ale_linters/yaml/yamllint.vim4
-rw-r--r--ale_linters/yang/yang_lsp.vim4
-rw-r--r--autoload/ale.vim5
-rw-r--r--autoload/ale/assert.vim28
-rw-r--r--autoload/ale/command.vim4
-rw-r--r--autoload/ale/engine.vim12
-rw-r--r--autoload/ale/fix.vim140
-rw-r--r--autoload/ale/fixers/generic.vim4
-rw-r--r--autoload/ale/fixers/generic_python.vim4
-rw-r--r--autoload/ale/fixers/help.vim2
-rw-r--r--autoload/ale/linter.vim76
-rw-r--r--autoload/ale/lsp.vim9
-rw-r--r--autoload/ale/lsp_linter.vim177
-rw-r--r--autoload/ale/node.vim5
-rw-r--r--autoload/ale/path.vim17
-rw-r--r--autoload/ale/python.vim2
-rw-r--r--autoload/ale/toggle.vim4
-rw-r--r--doc/ale-python.txt23
-rw-r--r--doc/ale-rust.txt14
-rw-r--r--doc/ale.txt299
-rw-r--r--test/command_callback/python_paths/with_bandit/.bandit0
-rw-r--r--test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py0
-rw-r--r--test/command_callback/python_paths/with_bandit/namespace/foo/bar.py0
-rw-r--r--test/command_callback/test_bandit_command_callback.vader22
-rw-r--r--test/command_callback/test_pylint_command_callback.vader6
-rw-r--r--test/command_callback/test_rust_rls_callbacks.vader5
-rw-r--r--test/fix/test_ale_fix.vader77
-rw-r--r--test/fixers/test_break_up_long_lines_python_fixer.vader4
-rw-r--r--test/fixers/test_trim_whitespace.vader18
-rw-r--r--test/lsp/test_lsp_root_detection.vader17
-rw-r--r--test/lsp/test_lsp_startup.vader364
-rw-r--r--test/test_deferred_command_string.vader46
-rw-r--r--test/test_deferred_executable_string.vader16
-rw-r--r--test/test_linter_defintion_processing.vader203
-rw-r--r--test/test_no_linting_on_write_quit.vader2
-rw-r--r--test/test_path_uri.vader14
242 files changed, 1654 insertions, 803 deletions
diff --git a/ale_linters/ada/gcc.vim b/ale_linters/ada/gcc.vim
index 7b0c4809..87496b81 100644
--- a/ale_linters/ada/gcc.vim
+++ b/ale_linters/ada/gcc.vim
@@ -48,7 +48,7 @@ endfunction
call ale#linter#Define('ada', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('ada_gcc_executable'),
-\ 'command_callback': 'ale_linters#ada#gcc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'ada_gcc_executable')},
+\ 'command': function('ale_linters#ada#gcc#GetCommand'),
\ 'callback': 'ale_linters#ada#gcc#Handle',
\})
diff --git a/ale_linters/ansible/ansible_lint.vim b/ale_linters/ansible/ansible_lint.vim
index 99fff6c3..c4affa31 100644
--- a/ale_linters/ansible/ansible_lint.vim
+++ b/ale_linters/ansible/ansible_lint.vim
@@ -50,7 +50,7 @@ endfunction
call ale#linter#Define('ansible', {
\ 'name': 'ansible_lint',
\ 'aliases': ['ansible', 'ansible-lint'],
-\ 'executable_callback': 'ale_linters#ansible#ansible_lint#GetExecutable',
+\ 'executable': function('ale_linters#ansible#ansible_lint#GetExecutable'),
\ 'command': '%e -p %t',
\ 'callback': 'ale_linters#ansible#ansible_lint#Handle',
\})
diff --git a/ale_linters/asciidoc/textlint.vim b/ale_linters/asciidoc/textlint.vim
index 757718b9..308a3a29 100644
--- a/ale_linters/asciidoc/textlint.vim
+++ b/ale_linters/asciidoc/textlint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('asciidoc', {
\ 'name': 'textlint',
-\ 'executable_callback': 'ale#handlers#textlint#GetExecutable',
-\ 'command_callback': 'ale#handlers#textlint#GetCommand',
+\ 'executable': function('ale#handlers#textlint#GetExecutable'),
+\ 'command': function('ale#handlers#textlint#GetCommand'),
\ 'callback': 'ale#handlers#textlint#HandleTextlintOutput',
\})
diff --git a/ale_linters/asm/gcc.vim b/ale_linters/asm/gcc.vim
index fdd0ee83..72b293c0 100644
--- a/ale_linters/asm/gcc.vim
+++ b/ale_linters/asm/gcc.vim
@@ -28,7 +28,7 @@ endfunction
call ale#linter#Define('asm', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('asm_gcc_executable'),
-\ 'command_callback': 'ale_linters#asm#gcc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'asm_gcc_executable')},
+\ 'command': function('ale_linters#asm#gcc#GetCommand'),
\ 'callback': 'ale_linters#asm#gcc#Handle',
\})
diff --git a/ale_linters/awk/gawk.vim b/ale_linters/awk/gawk.vim
index eb92e45e..f795c57d 100644
--- a/ale_linters/awk/gawk.vim
+++ b/ale_linters/awk/gawk.vim
@@ -15,8 +15,8 @@ endfunction
call ale#linter#Define('awk', {
\ 'name': 'gawk',
-\ 'executable_callback': ale#VarFunc('awk_gawk_executable'),
-\ 'command_callback': 'ale_linters#awk#gawk#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'awk_gawk_executable')},
+\ 'command': function('ale_linters#awk#gawk#GetCommand'),
\ 'callback': 'ale#handlers#gawk#HandleGawkFormat',
\ 'output_stream': 'both'
\})
diff --git a/ale_linters/bib/bibclean.vim b/ale_linters/bib/bibclean.vim
index 1c6b55d0..9056a9c3 100644
--- a/ale_linters/bib/bibclean.vim
+++ b/ale_linters/bib/bibclean.vim
@@ -68,8 +68,8 @@ endfunction
call ale#linter#Define('bib', {
\ 'name': 'bibclean',
-\ 'executable_callback': ale#VarFunc('bib_bibclean_executable'),
-\ 'command_callback': 'ale_linters#bib#bibclean#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'bib_bibclean_executable')},
+\ 'command': function('ale_linters#bib#bibclean#GetCommand'),
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#bib#bibclean#Handle',
\})
diff --git a/ale_linters/c/ccls.vim b/ale_linters/c/ccls.vim
index 5dc2339f..9e3dafe9 100644
--- a/ale_linters/c/ccls.vim
+++ b/ale_linters/c/ccls.vim
@@ -7,8 +7,8 @@ call ale#Set('c_ccls_init_options', {})
call ale#linter#Define('c', {
\ 'name': 'ccls',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('c_ccls_executable'),
+\ 'executable': {b -> ale#Var(b, 'c_ccls_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
-\ 'initialization_options_callback':ale#VarFunc('c_ccls_init_options'),
+\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
+\ 'initialization_options': {b -> ale#Var(b, 'c_ccls_init_options')},
\})
diff --git a/ale_linters/c/clang.vim b/ale_linters/c/clang.vim
index f1bd675b..5b243bfe 100644
--- a/ale_linters/c/clang.vim
+++ b/ale_linters/c/clang.vim
@@ -18,7 +18,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('c_clang_executable'),
+\ 'executable': {b -> ale#Var(b, 'c_clang_executable')},
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#c#clang#GetCommand'}
diff --git a/ale_linters/c/clangd.vim b/ale_linters/c/clangd.vim
index 6cad601a..918eadcc 100644
--- a/ale_linters/c/clangd.vim
+++ b/ale_linters/c/clangd.vim
@@ -17,7 +17,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'clangd',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('c_clangd_executable'),
-\ 'command_callback': 'ale_linters#c#clangd#GetCommand',
-\ 'project_root_callback': 'ale_linters#c#clangd#GetProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'c_clangd_executable')},
+\ 'command': function('ale_linters#c#clangd#GetCommand'),
+\ 'project_root': function('ale_linters#c#clangd#GetProjectRoot'),
\})
diff --git a/ale_linters/c/clangtidy.vim b/ale_linters/c/clangtidy.vim
index 4f334655..6484f8af 100644
--- a/ale_linters/c/clangtidy.vim
+++ b/ale_linters/c/clangtidy.vim
@@ -35,8 +35,8 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('c_clangtidy_executable'),
-\ 'command_callback': 'ale_linters#c#clangtidy#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'c_clangtidy_executable')},
+\ 'command': function('ale_linters#c#clangtidy#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/c/cppcheck.vim b/ale_linters/c/cppcheck.vim
index 5e8c7936..851f9f11 100644
--- a/ale_linters/c/cppcheck.vim
+++ b/ale_linters/c/cppcheck.vim
@@ -28,7 +28,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
-\ 'executable_callback': ale#VarFunc('c_cppcheck_executable'),
-\ 'command_callback': 'ale_linters#c#cppcheck#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'c_cppcheck_executable')},
+\ 'command': function('ale_linters#c#cppcheck#GetCommand'),
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\})
diff --git a/ale_linters/c/cquery.vim b/ale_linters/c/cquery.vim
index a20782a2..d2be9cd9 100644
--- a/ale_linters/c/cquery.vim
+++ b/ale_linters/c/cquery.vim
@@ -21,8 +21,8 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'cquery',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('c_cquery_executable'),
+\ 'executable': {b -> ale#Var(b, 'c_cquery_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale_linters#c#cquery#GetProjectRoot',
-\ 'initialization_options_callback': 'ale_linters#c#cquery#GetInitializationOptions',
+\ 'project_root': function('ale_linters#c#cquery#GetProjectRoot'),
+\ 'initialization_options': function('ale_linters#c#cquery#GetInitializationOptions'),
\})
diff --git a/ale_linters/c/flawfinder.vim b/ale_linters/c/flawfinder.vim
index 94104141..53c36716 100644
--- a/ale_linters/c/flawfinder.vim
+++ b/ale_linters/c/flawfinder.vim
@@ -19,7 +19,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'flawfinder',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('c_flawfinder_executable'),
-\ 'command_callback': 'ale_linters#c#flawfinder#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'c_flawfinder_executable')},
+\ 'command': function('ale_linters#c#flawfinder#GetCommand'),
\ 'callback': 'ale#handlers#flawfinder#HandleFlawfinderFormat',
\})
diff --git a/ale_linters/c/gcc.vim b/ale_linters/c/gcc.vim
index 60ecb712..ccb1912b 100644
--- a/ale_linters/c/gcc.vim
+++ b/ale_linters/c/gcc.vim
@@ -18,7 +18,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('c_gcc_executable'),
+\ 'executable': {b -> ale#Var(b, 'c_gcc_executable')},
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#c#gcc#GetCommand'}
diff --git a/ale_linters/chef/foodcritic.vim b/ale_linters/chef/foodcritic.vim
index c86336d6..48beba75 100644
--- a/ale_linters/chef/foodcritic.vim
+++ b/ale_linters/chef/foodcritic.vim
@@ -34,8 +34,8 @@ endfunction
call ale#linter#Define('chef', {
\ 'name': 'foodcritic',
-\ 'executable_callback': ale#VarFunc('chef_foodcritic_executable'),
-\ 'command_callback': 'ale_linters#chef#foodcritic#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'chef_foodcritic_executable')},
+\ 'command': function('ale_linters#chef#foodcritic#GetCommand'),
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/cmake/cmakelint.vim b/ale_linters/cmake/cmakelint.vim
index 78676518..d955a265 100644
--- a/ale_linters/cmake/cmakelint.vim
+++ b/ale_linters/cmake/cmakelint.vim
@@ -18,7 +18,7 @@ endfunction
call ale#linter#Define('cmake', {
\ 'name': 'cmakelint',
-\ 'executable_callback': 'ale_linters#cmake#cmakelint#Executable',
-\ 'command_callback': 'ale_linters#cmake#cmakelint#Command',
+\ 'executable': function('ale_linters#cmake#cmakelint#Executable'),
+\ 'command': function('ale_linters#cmake#cmakelint#Command'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
\})
diff --git a/ale_linters/coffee/coffee.vim b/ale_linters/coffee/coffee.vim
index f2539281..8e891639 100644
--- a/ale_linters/coffee/coffee.vim
+++ b/ale_linters/coffee/coffee.vim
@@ -16,8 +16,8 @@ endfunction
call ale#linter#Define('coffee', {
\ 'name': 'coffee',
-\ 'executable_callback': 'ale_linters#coffee#coffee#GetExecutable',
-\ 'command_callback': 'ale_linters#coffee#coffee#GetCommand',
+\ 'executable': function('ale_linters#coffee#coffee#GetExecutable'),
+\ 'command': function('ale_linters#coffee#coffee#GetCommand'),
\ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\})
diff --git a/ale_linters/coffee/coffeelint.vim b/ale_linters/coffee/coffeelint.vim
index 6d3df353..b7c85fa7 100644
--- a/ale_linters/coffee/coffeelint.vim
+++ b/ale_linters/coffee/coffeelint.vim
@@ -37,7 +37,7 @@ endfunction
call ale#linter#Define('coffee', {
\ 'name': 'coffeelint',
-\ 'executable_callback': 'ale_linters#coffee#coffeelint#GetExecutable',
-\ 'command_callback': 'ale_linters#coffee#coffeelint#GetCommand',
+\ 'executable': function('ale_linters#coffee#coffeelint#GetExecutable'),
+\ 'command': function('ale_linters#coffee#coffeelint#GetCommand'),
\ 'callback': 'ale_linters#coffee#coffeelint#Handle',
\})
diff --git a/ale_linters/cpp/ccls.vim b/ale_linters/cpp/ccls.vim
index 501fd685..b265ff70 100644
--- a/ale_linters/cpp/ccls.vim
+++ b/ale_linters/cpp/ccls.vim
@@ -7,8 +7,8 @@ call ale#Set('cpp_ccls_init_options', {})
call ale#linter#Define('cpp', {
\ 'name': 'ccls',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('cpp_ccls_executable'),
+\ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
-\ 'initialization_options_callback': ale#VarFunc('cpp_ccls_init_options'),
+\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
+\ 'initialization_options': {b -> ale#Var(b, 'cpp_ccls_init_options')},
\})
diff --git a/ale_linters/cpp/clang.vim b/ale_linters/cpp/clang.vim
index 649c5993..5a465812 100644
--- a/ale_linters/cpp/clang.vim
+++ b/ale_linters/cpp/clang.vim
@@ -18,7 +18,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('cpp_clang_executable'),
+\ 'executable': {b -> ale#Var(b, 'cpp_clang_executable')},
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#cpp#clang#GetCommand'},
diff --git a/ale_linters/cpp/clangcheck.vim b/ale_linters/cpp/clangcheck.vim
index c66d6702..b511a413 100644
--- a/ale_linters/cpp/clangcheck.vim
+++ b/ale_linters/cpp/clangcheck.vim
@@ -27,8 +27,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangcheck',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('cpp_clangcheck_executable'),
-\ 'command_callback': 'ale_linters#cpp#clangcheck#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cpp_clangcheck_executable')},
+\ 'command': function('ale_linters#cpp#clangcheck#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/cpp/clangd.vim b/ale_linters/cpp/clangd.vim
index 9139f054..4a8ff4f6 100644
--- a/ale_linters/cpp/clangd.vim
+++ b/ale_linters/cpp/clangd.vim
@@ -17,7 +17,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangd',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('cpp_clangd_executable'),
-\ 'command_callback': 'ale_linters#cpp#clangd#GetCommand',
-\ 'project_root_callback': 'ale_linters#cpp#clangd#GetProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')},
+\ 'command': function('ale_linters#cpp#clangd#GetCommand'),
+\ 'project_root': function('ale_linters#cpp#clangd#GetProjectRoot'),
\})
diff --git a/ale_linters/cpp/clangtidy.vim b/ale_linters/cpp/clangtidy.vim
index 9c3da8db..841b795f 100644
--- a/ale_linters/cpp/clangtidy.vim
+++ b/ale_linters/cpp/clangtidy.vim
@@ -29,8 +29,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('cpp_clangtidy_executable'),
-\ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cpp_clangtidy_executable')},
+\ 'command': function('ale_linters#cpp#clangtidy#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/cpp/clazy.vim b/ale_linters/cpp/clazy.vim
index cbbd0ccf..9b29ac9a 100644
--- a/ale_linters/cpp/clazy.vim
+++ b/ale_linters/cpp/clazy.vim
@@ -25,8 +25,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clazy',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('cpp_clazy_executable'),
-\ 'command_callback': 'ale_linters#cpp#clazy#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cpp_clazy_executable')},
+\ 'command': function('ale_linters#cpp#clazy#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/cpp/cppcheck.vim b/ale_linters/cpp/cppcheck.vim
index 229d6133..5173d698 100644
--- a/ale_linters/cpp/cppcheck.vim
+++ b/ale_linters/cpp/cppcheck.vim
@@ -28,7 +28,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
-\ 'executable_callback': ale#VarFunc('cpp_cppcheck_executable'),
-\ 'command_callback': 'ale_linters#cpp#cppcheck#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cpp_cppcheck_executable')},
+\ 'command': function('ale_linters#cpp#cppcheck#GetCommand'),
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\})
diff --git a/ale_linters/cpp/cpplint.vim b/ale_linters/cpp/cpplint.vim
index d135fa79..f1f6ce7f 100644
--- a/ale_linters/cpp/cpplint.vim
+++ b/ale_linters/cpp/cpplint.vim
@@ -13,8 +13,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cpplint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('cpp_cpplint_executable'),
-\ 'command_callback': 'ale_linters#cpp#cpplint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cpp_cpplint_executable')},
+\ 'command': function('ale_linters#cpp#cpplint#GetCommand'),
\ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/cpp/cquery.vim b/ale_linters/cpp/cquery.vim
index b1c81989..0dd9f6ad 100644
--- a/ale_linters/cpp/cquery.vim
+++ b/ale_linters/cpp/cquery.vim
@@ -21,8 +21,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cquery',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('cpp_cquery_executable'),
+\ 'executable': {b -> ale#Var(b, 'cpp_cquery_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale_linters#cpp#cquery#GetProjectRoot',
-\ 'initialization_options_callback': 'ale_linters#cpp#cquery#GetInitializationOptions',
+\ 'project_root': function('ale_linters#cpp#cquery#GetProjectRoot'),
+\ 'initialization_options': function('ale_linters#cpp#cquery#GetInitializationOptions'),
\})
diff --git a/ale_linters/cpp/flawfinder.vim b/ale_linters/cpp/flawfinder.vim
index 0a966604..5bfdea22 100644
--- a/ale_linters/cpp/flawfinder.vim
+++ b/ale_linters/cpp/flawfinder.vim
@@ -19,7 +19,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'flawfinder',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('cpp_flawfinder_executable'),
-\ 'command_callback': 'ale_linters#cpp#flawfinder#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cpp_flawfinder_executable')},
+\ 'command': function('ale_linters#cpp#flawfinder#GetCommand'),
\ 'callback': 'ale#handlers#flawfinder#HandleFlawfinderFormat',
\})
diff --git a/ale_linters/cpp/gcc.vim b/ale_linters/cpp/gcc.vim
index 9935b0bb..831620d5 100644
--- a/ale_linters/cpp/gcc.vim
+++ b/ale_linters/cpp/gcc.vim
@@ -19,7 +19,7 @@ call ale#linter#Define('cpp', {
\ 'name': 'gcc',
\ 'aliases': ['g++'],
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('cpp_gcc_executable'),
+\ 'executable': {b -> ale#Var(b, 'cpp_gcc_executable')},
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#cpp#gcc#GetCommand'},
diff --git a/ale_linters/crystal/ameba.vim b/ale_linters/crystal/ameba.vim
index a1bf9c1d..5dfc7f45 100644
--- a/ale_linters/crystal/ameba.vim
+++ b/ale_linters/crystal/ameba.vim
@@ -50,8 +50,8 @@ endfunction
call ale#linter#Define('crystal', {
\ 'name': 'ameba',
-\ 'executable_callback': ale#VarFunc('crystal_ameba_executable'),
-\ 'command_callback': 'ale_linters#crystal#ameba#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'crystal_ameba_executable')},
+\ 'command': function('ale_linters#crystal#ameba#GetCommand'),
\ 'callback': 'ale_linters#crystal#ameba#HandleAmebaOutput',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/crystal/crystal.vim b/ale_linters/crystal/crystal.vim
index 81579d63..3c2fefb7 100644
--- a/ale_linters/crystal/crystal.vim
+++ b/ale_linters/crystal/crystal.vim
@@ -26,6 +26,6 @@ call ale#linter#Define('crystal', {
\ 'executable': 'crystal',
\ 'output_stream': 'both',
\ 'lint_file': 1,
-\ 'command_callback': 'ale_linters#crystal#crystal#GetCommand',
+\ 'command': function('ale_linters#crystal#crystal#GetCommand'),
\ 'callback': 'ale_linters#crystal#crystal#Handle',
\})
diff --git a/ale_linters/cs/mcs.vim b/ale_linters/cs/mcs.vim
index 8738026d..1b373e73 100644
--- a/ale_linters/cs/mcs.vim
+++ b/ale_linters/cs/mcs.vim
@@ -32,6 +32,6 @@ call ale#linter#Define('cs',{
\ 'name': 'mcs',
\ 'output_stream': 'stderr',
\ 'executable': 'mcs',
-\ 'command_callback': 'ale_linters#cs#mcs#GetCommand',
+\ 'command': function('ale_linters#cs#mcs#GetCommand'),
\ 'callback': 'ale_linters#cs#mcs#Handle',
\})
diff --git a/ale_linters/cs/mcsc.vim b/ale_linters/cs/mcsc.vim
index a169297c..dd067eba 100644
--- a/ale_linters/cs/mcsc.vim
+++ b/ale_linters/cs/mcsc.vim
@@ -75,7 +75,7 @@ call ale#linter#Define('cs',{
\ 'name': 'mcsc',
\ 'output_stream': 'stderr',
\ 'executable': 'mcs',
-\ 'command_callback': 'ale_linters#cs#mcsc#GetCommand',
+\ 'command': function('ale_linters#cs#mcsc#GetCommand'),
\ 'callback': 'ale_linters#cs#mcsc#Handle',
\ 'lint_file': 1
\})
diff --git a/ale_linters/css/csslint.vim b/ale_linters/css/csslint.vim
index 98b7fdd4..50c21ce2 100644
--- a/ale_linters/css/csslint.vim
+++ b/ale_linters/css/csslint.vim
@@ -13,6 +13,6 @@ endfunction
call ale#linter#Define('css', {
\ 'name': 'csslint',
\ 'executable': 'csslint',
-\ 'command_callback': 'ale_linters#css#csslint#GetCommand',
+\ 'command': function('ale_linters#css#csslint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleCSSLintFormat',
\})
diff --git a/ale_linters/css/stylelint.vim b/ale_linters/css/stylelint.vim
index 6f8bef68..38cb0e0b 100644
--- a/ale_linters/css/stylelint.vim
+++ b/ale_linters/css/stylelint.vim
@@ -11,9 +11,9 @@ endfunction
call ale#linter#Define('css', {
\ 'name': 'stylelint',
-\ 'executable_callback': ale#node#FindExecutableFunc('css_stylelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'css_stylelint', [
\ 'node_modules/.bin/stylelint',
-\ ]),
-\ 'command_callback': 'ale_linters#css#stylelint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#css#stylelint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/cucumber/cucumber.vim b/ale_linters/cucumber/cucumber.vim
index e8ae09ff..0cfd815e 100644
--- a/ale_linters/cucumber/cucumber.vim
+++ b/ale_linters/cucumber/cucumber.vim
@@ -41,6 +41,6 @@ endfunction
call ale#linter#Define('cucumber', {
\ 'name': 'cucumber',
\ 'executable': 'cucumber',
-\ 'command_callback': 'ale_linters#cucumber#cucumber#GetCommand',
+\ 'command': function('ale_linters#cucumber#cucumber#GetCommand'),
\ 'callback': 'ale_linters#cucumber#cucumber#Handle'
\})
diff --git a/ale_linters/cuda/nvcc.vim b/ale_linters/cuda/nvcc.vim
index db789ff1..f3af07b6 100644
--- a/ale_linters/cuda/nvcc.vim
+++ b/ale_linters/cuda/nvcc.vim
@@ -42,8 +42,8 @@ endfunction
call ale#linter#Define('cuda', {
\ 'name': 'nvcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('cuda_nvcc_executable'),
-\ 'command_callback': 'ale_linters#cuda#nvcc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'cuda_nvcc_executable')},
+\ 'command': function('ale_linters#cuda#nvcc#GetCommand'),
\ 'callback': 'ale_linters#cuda#nvcc#HandleNVCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/d/dls.vim b/ale_linters/d/dls.vim
index 7210d21e..78d1c152 100644
--- a/ale_linters/d/dls.vim
+++ b/ale_linters/d/dls.vim
@@ -16,7 +16,7 @@ endfunction
call ale#linter#Define('d', {
\ 'name': 'dls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#d#dls#GetExecutable',
-\ 'command_callback': 'ale_linters#d#dls#GetExecutable',
-\ 'project_root_callback': 'ale_linters#d#dls#FindProjectRoot',
+\ 'executable': function('ale_linters#d#dls#GetExecutable'),
+\ 'command': function('ale_linters#d#dls#GetExecutable'),
+\ 'project_root': function('ale_linters#d#dls#FindProjectRoot'),
\})
diff --git a/ale_linters/dart/dartanalyzer.vim b/ale_linters/dart/dartanalyzer.vim
index 26817df5..0a4d9742 100644
--- a/ale_linters/dart/dartanalyzer.vim
+++ b/ale_linters/dart/dartanalyzer.vim
@@ -29,8 +29,8 @@ endfunction
call ale#linter#Define('dart', {
\ 'name': 'dartanalyzer',
-\ 'executable_callback': ale#VarFunc('dart_dartanalyzer_executable'),
-\ 'command_callback': 'ale_linters#dart#dartanalyzer#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'dart_dartanalyzer_executable')},
+\ 'command': function('ale_linters#dart#dartanalyzer#GetCommand'),
\ 'callback': 'ale_linters#dart#dartanalyzer#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/dart/language_server.vim b/ale_linters/dart/language_server.vim
index 8e0c139b..d0e639c8 100644
--- a/ale_linters/dart/language_server.vim
+++ b/ale_linters/dart/language_server.vim
@@ -14,7 +14,7 @@ endfunction
call ale#linter#Define('dart', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('dart_language_server_executable'),
+\ 'executable': {b -> ale#Var(b, 'dart_language_server_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale_linters#dart#language_server#GetProjectRoot',
+\ 'project_root': function('ale_linters#dart#language_server#GetProjectRoot'),
\})
diff --git a/ale_linters/dockerfile/dockerfile_lint.vim b/ale_linters/dockerfile/dockerfile_lint.vim
index a5a846f2..95768b12 100644
--- a/ale_linters/dockerfile/dockerfile_lint.vim
+++ b/ale_linters/dockerfile/dockerfile_lint.vim
@@ -55,7 +55,7 @@ endfunction
call ale#linter#Define('dockerfile', {
\ 'name': 'dockerfile_lint',
-\ 'executable_callback': ale#VarFunc('dockerfile_dockerfile_lint_executable'),
-\ 'command_callback': 'ale_linters#dockerfile#dockerfile_lint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'dockerfile_dockerfile_lint_executable')},
+\ 'command': function('ale_linters#dockerfile#dockerfile_lint#GetCommand'),
\ 'callback': 'ale_linters#dockerfile#dockerfile_lint#Handle',
\})
diff --git a/ale_linters/dockerfile/hadolint.vim b/ale_linters/dockerfile/hadolint.vim
index dc0f5b9e..e57cd76d 100644
--- a/ale_linters/dockerfile/hadolint.vim
+++ b/ale_linters/dockerfile/hadolint.vim
@@ -93,7 +93,7 @@ endfunction
call ale#linter#Define('dockerfile', {
\ 'name': 'hadolint',
-\ 'executable_callback': 'ale_linters#dockerfile#hadolint#GetExecutable',
-\ 'command_callback': 'ale_linters#dockerfile#hadolint#GetCommand',
+\ 'executable': function('ale_linters#dockerfile#hadolint#GetExecutable'),
+\ 'command': function('ale_linters#dockerfile#hadolint#GetCommand'),
\ 'callback': 'ale_linters#dockerfile#hadolint#Handle',
\})
diff --git a/ale_linters/elixir/credo.vim b/ale_linters/elixir/credo.vim
index d778471c..8431c0df 100644
--- a/ale_linters/elixir/credo.vim
+++ b/ale_linters/elixir/credo.vim
@@ -47,6 +47,6 @@ endfunction
call ale#linter#Define('elixir', {
\ 'name': 'credo',
\ 'executable': 'mix',
-\ 'command_callback': 'ale_linters#elixir#credo#GetCommand',
+\ 'command': function('ale_linters#elixir#credo#GetCommand'),
\ 'callback': 'ale_linters#elixir#credo#Handle',
\})
diff --git a/ale_linters/elixir/dialyxir.vim b/ale_linters/elixir/dialyxir.vim
index d28d3c70..c7da7757 100644
--- a/ale_linters/elixir/dialyxir.vim
+++ b/ale_linters/elixir/dialyxir.vim
@@ -35,7 +35,7 @@ endfunction
call ale#linter#Define('elixir', {
\ 'name': 'dialyxir',
\ 'executable': 'mix',
-\ 'command_callback': 'ale_linters#elixir#dialyxir#GetCommand',
+\ 'command': function('ale_linters#elixir#dialyxir#GetCommand'),
\ 'callback': 'ale_linters#elixir#dialyxir#Handle',
\})
diff --git a/ale_linters/elixir/dogma.vim b/ale_linters/elixir/dogma.vim
index dcfb6f28..1c721158 100644
--- a/ale_linters/elixir/dogma.vim
+++ b/ale_linters/elixir/dogma.vim
@@ -39,7 +39,7 @@ endfunction
call ale#linter#Define('elixir', {
\ 'name': 'dogma',
\ 'executable': 'mix',
-\ 'command_callback': 'ale_linters#elixir#dogma#GetCommand',
+\ 'command': function('ale_linters#elixir#dogma#GetCommand'),
\ 'lint_file': 1,
\ 'callback': 'ale_linters#elixir#dogma#Handle',
\})
diff --git a/ale_linters/elixir/elixir_ls.vim b/ale_linters/elixir/elixir_ls.vim
index 3b299ec6..d5db7cd0 100644
--- a/ale_linters/elixir/elixir_ls.vim
+++ b/ale_linters/elixir/elixir_ls.vim
@@ -14,8 +14,8 @@ endfunction
call ale#linter#Define('elixir', {
\ 'name': 'elixir-ls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#elixir#elixir_ls#GetExecutable',
-\ 'command_callback': 'ale_linters#elixir#elixir_ls#GetExecutable',
-\ 'project_root_callback': 'ale#handlers#elixir#FindMixUmbrellaRoot',
-\ 'lsp_config_callback': ale#VarFunc('elixir_elixir_ls_config'),
+\ 'executable': function('ale_linters#elixir#elixir_ls#GetExecutable'),
+\ 'command': function('ale_linters#elixir#elixir_ls#GetExecutable'),
+\ 'project_root': function('ale#handlers#elixir#FindMixUmbrellaRoot'),
+\ 'lsp_config': {b -> ale#Var(b, 'elixir_elixir_ls_config')},
\})
diff --git a/ale_linters/elixir/mix.vim b/ale_linters/elixir/mix.vim
index 59cfe505..abf5d0aa 100644
--- a/ale_linters/elixir/mix.vim
+++ b/ale_linters/elixir/mix.vim
@@ -46,7 +46,7 @@ endfunction
call ale#linter#Define('elixir', {
\ 'name': 'mix',
\ 'executable': 'mix',
-\ 'command_callback': 'ale_linters#elixir#mix#GetCommand',
+\ 'command': function('ale_linters#elixir#mix#GetCommand'),
\ 'callback': 'ale_linters#elixir#mix#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/elm/make.vim b/ale_linters/elm/make.vim
index 190f7541..6b93257f 100644
--- a/ale_linters/elm/make.vim
+++ b/ale_linters/elm/make.vim
@@ -233,8 +233,8 @@ endfunction
call ale#linter#Define('elm', {
\ 'name': 'make',
-\ 'executable_callback': 'ale_linters#elm#make#GetExecutable',
+\ 'executable': function('ale_linters#elm#make#GetExecutable'),
\ 'output_stream': 'both',
-\ 'command_callback': 'ale_linters#elm#make#GetCommand',
+\ 'command': function('ale_linters#elm#make#GetCommand'),
\ 'callback': 'ale_linters#elm#make#Handle'
\})
diff --git a/ale_linters/erlang/erlc.vim b/ale_linters/erlang/erlc.vim
index 81ba128b..a83bacc3 100644
--- a/ale_linters/erlang/erlc.vim
+++ b/ale_linters/erlang/erlc.vim
@@ -91,6 +91,6 @@ endfunction
call ale#linter#Define('erlang', {
\ 'name': 'erlc',
\ 'executable': 'erlc',
-\ 'command_callback': 'ale_linters#erlang#erlc#GetCommand',
+\ 'command': function('ale_linters#erlang#erlc#GetCommand'),
\ 'callback': 'ale_linters#erlang#erlc#Handle',
\})
diff --git a/ale_linters/erlang/syntaxerl.vim b/ale_linters/erlang/syntaxerl.vim
index 5b679743..2b7276a1 100644
--- a/ale_linters/erlang/syntaxerl.vim
+++ b/ale_linters/erlang/syntaxerl.vim
@@ -26,7 +26,7 @@ endfunction
call ale#linter#Define('erlang', {
\ 'name': 'syntaxerl',
-\ 'executable_callback': ale#VarFunc('erlang_syntaxerl_executable'),
+\ 'executable': {b -> ale#Var(b, 'erlang_syntaxerl_executable')},
\ 'command_chain': [
\ {'callback': {-> '%e -h'}},
\ {'callback': 'ale_linters#erlang#syntaxerl#GetCommand'},
diff --git a/ale_linters/eruby/erb.vim b/ale_linters/eruby/erb.vim
index 61d97032..f3438320 100644
--- a/ale_linters/eruby/erb.vim
+++ b/ale_linters/eruby/erb.vim
@@ -19,7 +19,7 @@ call ale#linter#Define('eruby', {
\ 'aliases': ['erubylint'],
\ 'executable': 'erb',
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#eruby#erb#GetCommand',
+\ 'command': function('ale_linters#eruby#erb#GetCommand'),
\ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors',
\})
diff --git a/ale_linters/eruby/erubis.vim b/ale_linters/eruby/erubis.vim
index 1ebd4a05..755c5803 100644
--- a/ale_linters/eruby/erubis.vim
+++ b/ale_linters/eruby/erubis.vim
@@ -18,6 +18,6 @@ call ale#linter#Define('eruby', {
\ 'name': 'erubis',
\ 'executable': 'erubis',
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#eruby#erubis#GetCommand',
+\ 'command': function('ale_linters#eruby#erubis#GetCommand'),
\ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors',
\})
diff --git a/ale_linters/eruby/ruumba.vim b/ale_linters/eruby/ruumba.vim
index 24f112e4..e68bb51d 100644
--- a/ale_linters/eruby/ruumba.vim
+++ b/ale_linters/eruby/ruumba.vim
@@ -56,7 +56,7 @@ endfunction
call ale#linter#Define('eruby', {
\ 'name': 'ruumba',
-\ 'executable_callback': ale#VarFunc('eruby_ruumba_executable'),
-\ 'command_callback': 'ale_linters#eruby#ruumba#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'eruby_ruumba_executable')},
+\ 'command': function('ale_linters#eruby#ruumba#GetCommand'),
\ 'callback': 'ale_linters#eruby#ruumba#Handle',
\})
diff --git a/ale_linters/fortran/gcc.vim b/ale_linters/fortran/gcc.vim
index f1595789..6e97d6fd 100644
--- a/ale_linters/fortran/gcc.vim
+++ b/ale_linters/fortran/gcc.vim
@@ -66,7 +66,7 @@ endfunction
call ale#linter#Define('fortran', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('fortran_gcc_executable'),
-\ 'command_callback': 'ale_linters#fortran#gcc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'fortran_gcc_executable')},
+\ 'command': function('ale_linters#fortran#gcc#GetCommand'),
\ 'callback': 'ale_linters#fortran#gcc#Handle',
\})
diff --git a/ale_linters/fortran/language_server.vim b/ale_linters/fortran/language_server.vim
index 4e5f5dc4..00aa0577 100644
--- a/ale_linters/fortran/language_server.vim
+++ b/ale_linters/fortran/language_server.vim
@@ -13,7 +13,7 @@ endfunction
call ale#linter#Define('fortran', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('fortran_language_server_executable'),
+\ 'executable': {b -> ale#Var(b, 'fortran_language_server_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale_linters#fortran#language_server#GetProjectRoot',
+\ 'project_root': function('ale_linters#fortran#language_server#GetProjectRoot'),
\})
diff --git a/ale_linters/fuse/fusionlint.vim b/ale_linters/fuse/fusionlint.vim
index ab8f143b..ffb25d33 100644
--- a/ale_linters/fuse/fusionlint.vim
+++ b/ale_linters/fuse/fusionlint.vim
@@ -27,7 +27,7 @@ endfunction
call ale#linter#Define('fuse', {
\ 'name': 'fusionlint',
-\ 'executable_callback': ale#VarFunc('fuse_fusionlint_executable'),
-\ 'command_callback': 'ale_linters#fuse#fusionlint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'fuse_fusionlint_executable')},
+\ 'command': function('ale_linters#fuse#fusionlint#GetCommand'),
\ 'callback': 'ale_linters#fuse#fusionlint#Handle',
\})
diff --git a/ale_linters/gitcommit/gitlint.vim b/ale_linters/gitcommit/gitlint.vim
index a9c4822d..4b9cec63 100644
--- a/ale_linters/gitcommit/gitlint.vim
+++ b/ale_linters/gitcommit/gitlint.vim
@@ -45,7 +45,7 @@ endfunction
call ale#linter#Define('gitcommit', {
\ 'name': 'gitlint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#gitcommit#gitlint#GetExecutable',
-\ 'command_callback': 'ale_linters#gitcommit#gitlint#GetCommand',
+\ 'executable': function('ale_linters#gitcommit#gitlint#GetExecutable'),
+\ 'command': function('ale_linters#gitcommit#gitlint#GetCommand'),
\ 'callback': 'ale_linters#gitcommit#gitlint#Handle',
\})
diff --git a/ale_linters/glsl/glslang.vim b/ale_linters/glsl/glslang.vim
index d55a5e7c..bbddce90 100644
--- a/ale_linters/glsl/glslang.vim
+++ b/ale_linters/glsl/glslang.vim
@@ -34,7 +34,7 @@ endfunction
call ale#linter#Define('glsl', {
\ 'name': 'glslang',
-\ 'executable_callback': ale#VarFunc('glsl_glslang_executable'),
-\ 'command_callback': 'ale_linters#glsl#glslang#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'glsl_glslang_executable')},
+\ 'command': function('ale_linters#glsl#glslang#GetCommand'),
\ 'callback': 'ale_linters#glsl#glslang#Handle',
\})
diff --git a/ale_linters/glsl/glslls.vim b/ale_linters/glsl/glslls.vim
index 8c6d9bd9..b62844c7 100644
--- a/ale_linters/glsl/glslls.vim
+++ b/ale_linters/glsl/glslls.vim
@@ -24,7 +24,7 @@ endfunction
call ale#linter#Define('glsl', {
\ 'name': 'glslls',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('glsl_glslls_executable'),
-\ 'command_callback': 'ale_linters#glsl#glslls#GetCommand',
-\ 'project_root_callback': 'ale_linters#glsl#glslls#GetProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'glsl_glslls_executable')},
+\ 'command': function('ale_linters#glsl#glslls#GetCommand'),
+\ 'project_root': function('ale_linters#glsl#glslls#GetProjectRoot'),
\})
diff --git a/ale_linters/go/bingo.vim b/ale_linters/go/bingo.vim
index ba80fbe8..e446bdcc 100644
--- a/ale_linters/go/bingo.vim
+++ b/ale_linters/go/bingo.vim
@@ -23,7 +23,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'bingo',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('go_bingo_executable'),
-\ 'command_callback': 'ale_linters#go#bingo#GetCommand',
-\ 'project_root_callback': 'ale_linters#go#bingo#FindProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'go_bingo_executable')},
+\ 'command': function('ale_linters#go#bingo#GetCommand'),
+\ 'project_root': function('ale_linters#go#bingo#FindProjectRoot'),
\})
diff --git a/ale_linters/go/gobuild.vim b/ale_linters/go/gobuild.vim
index cef1ff88..374ded35 100644
--- a/ale_linters/go/gobuild.vim
+++ b/ale_linters/go/gobuild.vim
@@ -48,8 +48,8 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gobuild',
\ 'aliases': ['go build'],
-\ 'executable_callback': ale#VarFunc('go_go_executable'),
-\ 'command_callback': 'ale_linters#go#gobuild#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'go_go_executable')},
+\ 'command': function('ale_linters#go#gobuild#GetCommand'),
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#go#gobuild#Handler',
\ 'lint_file': 1,
diff --git a/ale_linters/go/golangci_lint.vim b/ale_linters/go/golangci_lint.vim
index dd9a3c64..357f7949 100644
--- a/ale_linters/go/golangci_lint.vim
+++ b/ale_linters/go/golangci_lint.vim
@@ -49,8 +49,8 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'golangci-lint',
-\ 'executable_callback': ale#VarFunc('go_golangci_lint_executable'),
-\ 'command_callback': 'ale_linters#go#golangci_lint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'go_golangci_lint_executable')},
+\ 'command': function('ale_linters#go#golangci_lint#GetCommand'),
\ 'callback': 'ale_linters#go#golangci_lint#Handler',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/go/golint.vim b/ale_linters/go/golint.vim
index 4bf14fcc..765e1477 100644
--- a/ale_linters/go/golint.vim
+++ b/ale_linters/go/golint.vim
@@ -15,7 +15,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'golint',
\ 'output_stream': 'both',
-\ 'executable_callback': ale#VarFunc('go_golint_executable'),
-\ 'command_callback': 'ale_linters#go#golint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'go_golint_executable')},
+\ 'command': function('ale_linters#go#golint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
\})
diff --git a/ale_linters/go/gometalinter.vim b/ale_linters/go/gometalinter.vim
index d005e1d2..19d70a81 100644
--- a/ale_linters/go/gometalinter.vim
+++ b/ale_linters/go/gometalinter.vim
@@ -50,8 +50,8 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gometalinter',
-\ 'executable_callback': ale#VarFunc('go_gometalinter_executable'),
-\ 'command_callback': 'ale_linters#go#gometalinter#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'go_gometalinter_executable')},
+\ 'command': function('ale_linters#go#gometalinter#GetCommand'),
\ 'callback': 'ale_linters#go#gometalinter#Handler',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/go/gosimple.vim b/ale_linters/go/gosimple.vim
index dbdc3fcf..281a0e53 100644
--- a/ale_linters/go/gosimple.vim
+++ b/ale_linters/go/gosimple.vim
@@ -8,7 +8,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gosimple',
\ 'executable': 'gosimple',
-\ 'command_callback': 'ale_linters#go#gosimple#GetCommand',
+\ 'command': function('ale_linters#go#gosimple#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler',
\ 'output_stream': 'both',
\ 'lint_file': 1,
diff --git a/ale_linters/go/gotype.vim b/ale_linters/go/gotype.vim
index a678e0f3..159df892 100644
--- a/ale_linters/go/gotype.vim
+++ b/ale_linters/go/gotype.vim
@@ -13,7 +13,7 @@ call ale#linter#Define('go', {
\ 'name': 'gotype',
\ 'output_stream': 'stderr',
\ 'executable': 'gotype',
-\ 'command_callback': 'ale_linters#go#gotype#GetCommand',
+\ 'command': function('ale_linters#go#gotype#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/go/govet.vim b/ale_linters/go/govet.vim
index 3d0d2adf..bb81d5d0 100644
--- a/ale_linters/go/govet.vim
+++ b/ale_linters/go/govet.vim
@@ -20,8 +20,8 @@ call ale#linter#Define('go', {
\ 'name': 'govet',
\ 'aliases': ['go vet'],
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('go_go_executable'),
-\ 'command_callback': 'ale_linters#go#govet#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'go_go_executable')},
+\ 'command': function('ale_linters#go#govet#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/go/langserver.vim b/ale_linters/go/langserver.vim
index e049be7b..776186c7 100644
--- a/ale_linters/go/langserver.vim
+++ b/ale_linters/go/langserver.vim
@@ -22,7 +22,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'golangserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('go_langserver_executable'),
-\ 'command_callback': 'ale_linters#go#langserver#GetCommand',
-\ 'project_root_callback': 'ale#go#FindProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'go_langserver_executable')},
+\ 'command': function('ale_linters#go#langserver#GetCommand'),
+\ 'project_root': function('ale#go#FindProjectRoot'),
\})
diff --git a/ale_linters/go/staticcheck.vim b/ale_linters/go/staticcheck.vim
index a3464015..26fe0193 100644
--- a/ale_linters/go/staticcheck.vim
+++ b/ale_linters/go/staticcheck.vim
@@ -26,7 +26,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'staticcheck',
\ 'executable': 'staticcheck',
-\ 'command_callback': 'ale_linters#go#staticcheck#GetCommand',
+\ 'command': function('ale_linters#go#staticcheck#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler',
\ 'output_stream': 'both',
\ 'lint_file': 1,
diff --git a/ale_linters/graphql/eslint.vim b/ale_linters/graphql/eslint.vim
index dfcbf9d9..654b8c17 100644
--- a/ale_linters/graphql/eslint.vim
+++ b/ale_linters/graphql/eslint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('graphql', {
\ 'name': 'eslint',
-\ 'executable_callback': 'ale#handlers#eslint#GetExecutable',
-\ 'command_callback': 'ale#handlers#eslint#GetCommand',
+\ 'executable': function('ale#handlers#eslint#GetExecutable'),
+\ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle',
\})
diff --git a/ale_linters/graphql/gqlint.vim b/ale_linters/graphql/gqlint.vim
index e45bf4c8..d5029de1 100644
--- a/ale_linters/graphql/gqlint.vim
+++ b/ale_linters/graphql/gqlint.vim
@@ -10,6 +10,6 @@ endfunction
call ale#linter#Define('graphql', {
\ 'name': 'gqlint',
\ 'executable': 'gqlint',
-\ 'command_callback': 'ale_linters#graphql#gqlint#GetCommand',
+\ 'command': function('ale_linters#graphql#gqlint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
\})
diff --git a/ale_linters/hack/hack.vim b/ale_linters/hack/hack.vim
index aea428cc..822b5c87 100644
--- a/ale_linters/hack/hack.vim
+++ b/ale_linters/hack/hack.vim
@@ -16,7 +16,7 @@ endfunction
call ale#linter#Define('hack', {
\ 'name': 'hack',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#hack#hack#GetExecutable',
+\ 'executable': function('ale_linters#hack#hack#GetExecutable'),
\ 'command': '%e lsp --from vim-ale',
-\ 'project_root_callback': 'ale_linters#hack#hack#GetProjectRoot',
+\ 'project_root': function('ale_linters#hack#hack#GetProjectRoot'),
\})
diff --git a/ale_linters/hack/hhast.vim b/ale_linters/hack/hhast.vim
index f6870b59..5e6d4dec 100644
--- a/ale_linters/hack/hhast.vim
+++ b/ale_linters/hack/hhast.vim
@@ -33,8 +33,8 @@ endfunction
call ale#linter#Define('hack', {
\ 'name': 'hhast',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#hack#hhast#GetExecutable',
+\ 'executable': function('ale_linters#hack#hhast#GetExecutable'),
\ 'command': '%e --mode lsp --from vim-ale',
-\ 'project_root_callback': 'ale_linters#hack#hhast#GetProjectRoot',
-\ 'initialization_options_callback': 'ale_linters#hack#hhast#GetInitializationOptions',
+\ 'project_root': function('ale_linters#hack#hhast#GetProjectRoot'),
+\ 'initialization_options': function('ale_linters#hack#hhast#GetInitializationOptions'),
\})
diff --git a/ale_linters/haml/hamllint.vim b/ale_linters/haml/hamllint.vim
index 6598f81a..7d7278aa 100644
--- a/ale_linters/haml/hamllint.vim
+++ b/ale_linters/haml/hamllint.vim
@@ -51,7 +51,7 @@ endfunction
call ale#linter#Define('haml', {
\ 'name': 'hamllint',
-\ 'executable_callback': 'ale_linters#haml#hamllint#GetExecutable',
-\ 'command_callback': 'ale_linters#haml#hamllint#GetCommand',
+\ 'executable': function('ale_linters#haml#hamllint#GetExecutable'),
+\ 'command': function('ale_linters#haml#hamllint#GetCommand'),
\ 'callback': 'ale_linters#haml#hamllint#Handle'
\})
diff --git a/ale_linters/handlebars/embertemplatelint.vim b/ale_linters/handlebars/embertemplatelint.vim
index 4fc0f20d..74bd6a99 100644
--- a/ale_linters/handlebars/embertemplatelint.vim
+++ b/ale_linters/handlebars/embertemplatelint.vim
@@ -31,9 +31,9 @@ endfunction
call ale#linter#Define('handlebars', {
\ 'name': 'ember-template-lint',
-\ 'executable_callback': ale#node#FindExecutableFunc('handlebars_embertemplatelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [
\ 'node_modules/.bin/ember-template-lint',
-\ ]),
+\ ])},
\ 'command': '%e --json %t',
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\})
diff --git a/ale_linters/haskell/cabal_ghc.vim b/ale_linters/haskell/cabal_ghc.vim
index 003adf5d..59978e7e 100644
--- a/ale_linters/haskell/cabal_ghc.vim
+++ b/ale_linters/haskell/cabal_ghc.vim
@@ -14,6 +14,6 @@ call ale#linter#Define('haskell', {
\ 'aliases': ['cabal-ghc'],
\ 'output_stream': 'stderr',
\ 'executable': 'cabal',
-\ 'command_callback': 'ale_linters#haskell#cabal_ghc#GetCommand',
+\ 'command': function('ale_linters#haskell#cabal_ghc#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/ghc.vim b/ale_linters/haskell/ghc.vim
index daf91c8f..9c3906b2 100644
--- a/ale_linters/haskell/ghc.vim
+++ b/ale_linters/haskell/ghc.vim
@@ -13,6 +13,6 @@ call ale#linter#Define('haskell', {
\ 'name': 'ghc',
\ 'output_stream': 'stderr',
\ 'executable': 'ghc',
-\ 'command_callback': 'ale_linters#haskell#ghc#GetCommand',
+\ 'command': function('ale_linters#haskell#ghc#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/ghc_mod.vim b/ale_linters/haskell/ghc_mod.vim
index 9762be7a..30e96b40 100644
--- a/ale_linters/haskell/ghc_mod.vim
+++ b/ale_linters/haskell/ghc_mod.vim
@@ -13,7 +13,7 @@ endfunction
call ale#linter#Define('haskell', {
\ 'name': 'ghc_mod',
\ 'aliases': ['ghc-mod'],
-\ 'executable_callback': ale#VarFunc('haskell_ghc_mod_executable'),
-\ 'command_callback': 'ale_linters#haskell#ghc_mod#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'haskell_ghc_mod_executable')},
+\ 'command': function('ale_linters#haskell#ghc_mod#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/hdevtools.vim b/ale_linters/haskell/hdevtools.vim
index cc5ce56f..3e55e4f0 100644
--- a/ale_linters/haskell/hdevtools.vim
+++ b/ale_linters/haskell/hdevtools.vim
@@ -14,7 +14,7 @@ endfunction
call ale#linter#Define('haskell', {
\ 'name': 'hdevtools',
-\ 'executable_callback': ale#VarFunc('haskell_hdevtools_executable'),
-\ 'command_callback': 'ale_linters#haskell#hdevtools#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'haskell_hdevtools_executable')},
+\ 'command': function('ale_linters#haskell#hdevtools#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/hie.vim b/ale_linters/haskell/hie.vim
index cc85fbed..c4b5f1df 100644
--- a/ale_linters/haskell/hie.vim
+++ b/ale_linters/haskell/hie.vim
@@ -35,7 +35,7 @@ endfunction
call ale#linter#Define('haskell', {
\ 'name': 'hie',
\ 'lsp': 'stdio',
-\ 'command_callback': 'ale_linters#haskell#hie#GetCommand',
-\ 'executable_callback': ale#VarFunc('haskell_hie_executable'),
-\ 'project_root_callback': 'ale_linters#haskell#hie#GetProjectRoot',
+\ 'command': function('ale_linters#haskell#hie#GetCommand'),
+\ 'executable': {b -> ale#Var(b, 'haskell_hie_executable')},
+\ 'project_root': function('ale_linters#haskell#hie#GetProjectRoot'),
\})
diff --git a/ale_linters/haskell/hlint.vim b/ale_linters/haskell/hlint.vim
index 0cc7437f..1425251a 100644
--- a/ale_linters/haskell/hlint.vim
+++ b/ale_linters/haskell/hlint.vim
@@ -40,7 +40,7 @@ endfunction
call ale#linter#Define('haskell', {
\ 'name': 'hlint',
-\ 'executable_callback': ale#VarFunc('haskell_hlint_executable'),
-\ 'command_callback': 'ale_linters#haskell#hlint#GetCommand' ,
+\ 'executable': {b -> ale#Var(b, 'haskell_hlint_executable')},
+\ 'command': function('ale_linters#haskell#hlint#GetCommand') ,
\ 'callback': 'ale_linters#haskell#hlint#Handle',
\})
diff --git a/ale_linters/haskell/stack_build.vim b/ale_linters/haskell/stack_build.vim
index 95a54587..8f2d9fd9 100644
--- a/ale_linters/haskell/stack_build.vim
+++ b/ale_linters/haskell/stack_build.vim
@@ -16,8 +16,8 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_build',
\ 'aliases': ['stack-build'],
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
-\ 'command_callback': 'ale_linters#haskell#stack_build#GetCommand',
+\ 'executable': function('ale#handlers#haskell#GetStackExecutable'),
+\ 'command': function('ale_linters#haskell#stack_build#GetCommand'),
\ 'lint_file': 1,
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/stack_ghc.vim b/ale_linters/haskell/stack_ghc.vim
index 99aa2540..06af7f6d 100644
--- a/ale_linters/haskell/stack_ghc.vim
+++ b/ale_linters/haskell/stack_ghc.vim
@@ -14,7 +14,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_ghc',
\ 'aliases': ['stack-ghc'],
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
-\ 'command_callback': 'ale_linters#haskell#stack_ghc#GetCommand',
+\ 'executable': function('ale#handlers#haskell#GetStackExecutable'),
+\ 'command': function('ale_linters#haskell#stack_ghc#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/html/htmlhint.vim b/ale_linters/html/htmlhint.vim
index 234c1176..3e01f51a 100644
--- a/ale_linters/html/htmlhint.vim
+++ b/ale_linters/html/htmlhint.vim
@@ -24,9 +24,9 @@ endfunction
call ale#linter#Define('html', {
\ 'name': 'htmlhint',
-\ 'executable_callback': ale#node#FindExecutableFunc('html_htmlhint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'html_htmlhint', [
\ 'node_modules/.bin/htmlhint',
-\ ]),
-\ 'command_callback': 'ale_linters#html#htmlhint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#html#htmlhint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/html/stylelint.vim b/ale_linters/html/stylelint.vim
index 908c4b02..ae8955f3 100644
--- a/ale_linters/html/stylelint.vim
+++ b/ale_linters/html/stylelint.vim
@@ -21,7 +21,7 @@ endfunction
call ale#linter#Define('html', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#html#stylelint#GetExecutable',
-\ 'command_callback': 'ale_linters#html#stylelint#GetCommand',
+\ 'executable': function('ale_linters#html#stylelint#GetExecutable'),
+\ 'command': function('ale_linters#html#stylelint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/html/tidy.vim b/ale_linters/html/tidy.vim
index 4ec29091..1e476d40 100644
--- a/ale_linters/html/tidy.vim
+++ b/ale_linters/html/tidy.vim
@@ -63,8 +63,8 @@ endfunction
call ale#linter#Define('html', {
\ 'name': 'tidy',
-\ 'executable_callback': ale#VarFunc('html_tidy_executable'),
+\ 'executable': {b -> ale#Var(b, 'html_tidy_executable')},
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#html#tidy#GetCommand',
+\ 'command': function('ale_linters#html#tidy#GetCommand'),
\ 'callback': 'ale_linters#html#tidy#Handle',
\ })
diff --git a/ale_linters/idris/idris.vim b/ale_linters/idris/idris.vim
index 42b88158..879e92f2 100644
--- a/ale_linters/idris/idris.vim
+++ b/ale_linters/idris/idris.vim
@@ -75,7 +75,7 @@ endfunction
call ale#linter#Define('idris', {
\ 'name': 'idris',
-\ 'executable_callback': ale#VarFunc('idris_idris_executable'),
-\ 'command_callback': 'ale_linters#idris#idris#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'idris_idris_executable')},
+\ 'command': function('ale_linters#idris#idris#GetCommand'),
\ 'callback': 'ale_linters#idris#idris#Handle',
\})
diff --git a/ale_linters/ispc/ispc.vim b/ale_linters/ispc/ispc.vim
index de7ceafa..eb365117 100644
--- a/ale_linters/ispc/ispc.vim
+++ b/ale_linters/ispc/ispc.vim
@@ -38,8 +38,8 @@ endfunction
call ale#linter#Define('ispc', {
\ 'name': 'ispc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('ispc_ispc_executable'),
-\ 'command_callback': 'ale_linters#ispc#ispc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'ispc_ispc_executable')},
+\ 'command': function('ale_linters#ispc#ispc#GetCommand'),
\ 'callback': 'ale_linters#ispc#ispc#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/java/checkstyle.vim b/ale_linters/java/checkstyle.vim
index c07b65d0..3159cd55 100644
--- a/ale_linters/java/checkstyle.vim
+++ b/ale_linters/java/checkstyle.vim
@@ -44,7 +44,7 @@ endif
call ale#linter#Define('java', {
\ 'name': 'checkstyle',
\ 'executable': 'checkstyle',
-\ 'command_callback': 'ale_linters#java#checkstyle#GetCommand',
+\ 'command': function('ale_linters#java#checkstyle#GetCommand'),
\ 'callback': 'ale_linters#java#checkstyle#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/java/javac.vim b/ale_linters/java/javac.vim
index 18a26b77..50cabacd 100644
--- a/ale_linters/java/javac.vim
+++ b/ale_linters/java/javac.vim
@@ -119,7 +119,7 @@ endfunction
call ale#linter#Define('java', {
\ 'name': 'javac',
-\ 'executable_callback': ale#VarFunc('java_javac_executable'),
+\ 'executable': {b -> ale#Var(b, 'java_javac_executable')},
\ 'command_chain': [
\ {'callback': 'ale_linters#java#javac#GetImportPaths', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#java#javac#GetCommand', 'output_stream': 'stderr'},
diff --git a/ale_linters/java/javalsp.vim b/ale_linters/java/javalsp.vim
index 6329ab3c..a327363d 100644
--- a/ale_linters/java/javalsp.vim
+++ b/ale_linters/java/javalsp.vim
@@ -16,8 +16,8 @@ endfunction
call ale#linter#Define('java', {
\ 'name': 'javalsp',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#java#javalsp#Executable',
-\ 'command_callback': 'ale_linters#java#javalsp#Command',
+\ 'executable': function('ale_linters#java#javalsp#Executable'),
+\ 'command': function('ale_linters#java#javalsp#Command'),
\ 'language': 'java',
-\ 'project_root_callback': 'ale#java#FindProjectRoot',
+\ 'project_root': function('ale#java#FindProjectRoot'),
\})
diff --git a/ale_linters/java/pmd.vim b/ale_linters/java/pmd.vim
index b530ad09..a1f4c93c 100644
--- a/ale_linters/java/pmd.vim
+++ b/ale_linters/java/pmd.vim
@@ -31,6 +31,6 @@ endif
call ale#linter#Define('java', {
\ 'name': 'pmd',
\ 'executable': 'pmd',
-\ 'command_callback': 'ale_linters#java#pmd#GetCommand',
+\ 'command': function('ale_linters#java#pmd#GetCommand'),
\ 'callback': 'ale_linters#java#pmd#Handle',
\})
diff --git a/ale_linters/javascript/eslint.vim b/ale_linters/javascript/eslint.vim
index 23e16949..8aeac2d8 100644
--- a/ale_linters/javascript/eslint.vim
+++ b/ale_linters/javascript/eslint.vim
@@ -4,7 +4,7 @@
call ale#linter#Define('javascript', {
\ 'name': 'eslint',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale#handlers#eslint#GetExecutable',
-\ 'command_callback': 'ale#handlers#eslint#GetCommand',
+\ 'executable': function('ale#handlers#eslint#GetExecutable'),
+\ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle',
\})
diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim
index 0561ab74..05aae030 100755
--- a/ale_linters/javascript/flow.vim
+++ b/ale_linters/javascript/flow.vim
@@ -168,7 +168,7 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'flow',
-\ 'executable_callback': 'ale_linters#javascript#flow#GetExecutable',
+\ 'executable': function('ale_linters#javascript#flow#GetExecutable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#javascript#flow#VersionCheck'},
\ {'callback': 'ale_linters#javascript#flow#GetCommand'},
diff --git a/ale_linters/javascript/flow_ls.vim b/ale_linters/javascript/flow_ls.vim
index 75377183..accaaa73 100644
--- a/ale_linters/javascript/flow_ls.vim
+++ b/ale_linters/javascript/flow_ls.vim
@@ -19,10 +19,10 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'flow-language-server',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#node#FindExecutableFunc('javascript_flow_ls', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'javascript_flow_ls', [
\ 'node_modules/.bin/flow',
-\ ]),
+\ ])},
\ 'command': '%e lsp --from ale-lsp',
-\ 'project_root_callback': 'ale_linters#javascript#flow_ls#FindProjectRoot',
+\ 'project_root': function('ale_linters#javascript#flow_ls#FindProjectRoot'),
\ 'language': 'javascript',
\})
diff --git a/ale_linters/javascript/jscs.vim b/ale_linters/javascript/jscs.vim
index a38766a6..8905b3a1 100644
--- a/ale_linters/javascript/jscs.vim
+++ b/ale_linters/javascript/jscs.vim
@@ -53,9 +53,9 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jscs',
-\ 'executable_callback': ale#node#FindExecutableFunc('javascript_jscs', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'javascript_jscs', [
\ 'node_modules/.bin/jscs',
-\ ]),
-\ 'command_callback': 'ale_linters#javascript#jscs#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#javascript#jscs#GetCommand'),
\ 'callback': 'ale_linters#javascript#jscs#Handle',
\})
diff --git a/ale_linters/javascript/jshint.vim b/ale_linters/javascript/jshint.vim
index cb7f66fc..d80a2250 100644
--- a/ale_linters/javascript/jshint.vim
+++ b/ale_linters/javascript/jshint.vim
@@ -25,9 +25,9 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jshint',
-\ 'executable_callback': ale#node#FindExecutableFunc('javascript_jshint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'javascript_jshint', [
\ 'node_modules/.bin/jshint',
-\ ]),
-\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#javascript#jshint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/javascript/standard.vim b/ale_linters/javascript/standard.vim
index f16b837a..4cd2c303 100644
--- a/ale_linters/javascript/standard.vim
+++ b/ale_linters/javascript/standard.vim
@@ -24,7 +24,7 @@ endfunction
" standard uses eslint and the output format is the same
call ale#linter#Define('javascript', {
\ 'name': 'standard',
-\ 'executable_callback': 'ale_linters#javascript#standard#GetExecutable',
-\ 'command_callback': 'ale_linters#javascript#standard#GetCommand',
+\ 'executable': function('ale_linters#javascript#standard#GetExecutable'),
+\ 'command': function('ale_linters#javascript#standard#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle',
\})
diff --git a/ale_linters/javascript/tsserver.vim b/ale_linters/javascript/tsserver.vim
index 63509022..68c252c5 100644
--- a/ale_linters/javascript/tsserver.vim
+++ b/ale_linters/javascript/tsserver.vim
@@ -8,10 +8,10 @@ call ale#Set('javascript_tsserver_use_global', get(g:, 'ale_use_global_executabl
call ale#linter#Define('javascript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
-\ 'executable_callback': ale#node#FindExecutableFunc('javascript_tsserver', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'javascript_tsserver', [
\ 'node_modules/.bin/tsserver',
-\ ]),
+\ ])},
\ 'command': '%e',
-\ 'project_root_callback': 'ale#handlers#tsserver#GetProjectRoot',
+\ 'project_root': function('ale#handlers#tsserver#GetProjectRoot'),
\ 'language': '',
\})
diff --git a/ale_linters/javascript/xo.vim b/ale_linters/javascript/xo.vim
index bc8657ed..4ba39101 100644
--- a/ale_linters/javascript/xo.vim
+++ b/ale_linters/javascript/xo.vim
@@ -20,7 +20,7 @@ endfunction
" xo uses eslint and the output format is the same
call ale#linter#Define('javascript', {
\ 'name': 'xo',
-\ 'executable_callback': 'ale_linters#javascript#xo#GetExecutable',
-\ 'command_callback': 'ale_linters#javascript#xo#GetCommand',
+\ 'executable': function('ale_linters#javascript#xo#GetExecutable'),
+\ 'command': function('ale_linters#javascript#xo#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle',
\})
diff --git a/ale_linters/julia/languageserver.vim b/ale_linters/julia/languageserver.vim
index cd2000de..564bec39 100644
--- a/ale_linters/julia/languageserver.vim
+++ b/ale_linters/julia/languageserver.vim
@@ -14,8 +14,8 @@ endfunction
call ale#linter#Define('julia', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('julia_executable'),
-\ 'command_callback': 'ale_linters#julia#languageserver#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'julia_executable')},
+\ 'command': function('ale_linters#julia#languageserver#GetCommand'),
\ 'language': 'julia',
-\ 'project_root_callback': 'ale#julia#FindProjectRoot',
+\ 'project_root': function('ale#julia#FindProjectRoot'),
\})
diff --git a/ale_linters/kotlin/ktlint.vim b/ale_linters/kotlin/ktlint.vim
index b8920aa7..f0384005 100644
--- a/ale_linters/kotlin/ktlint.vim
+++ b/ale_linters/kotlin/ktlint.vim
@@ -4,7 +4,7 @@
call ale#linter#Define('kotlin', {
\ 'name': 'ktlint',
\ 'executable': 'ktlint',
-\ 'command_callback': 'ale#handlers#ktlint#GetCommand',
+\ 'command': function('ale#handlers#ktlint#GetCommand'),
\ 'callback': 'ale#handlers#ktlint#Handle',
\ 'lint_file': 1
\})
diff --git a/ale_linters/kotlin/languageserver.vim b/ale_linters/kotlin/languageserver.vim
index aea817ba..af78c0e0 100644
--- a/ale_linters/kotlin/languageserver.vim
+++ b/ale_linters/kotlin/languageserver.vim
@@ -22,8 +22,8 @@ endfunction
call ale#linter#Define('kotlin', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('kotlin_languageserver_executable'),
+\ 'executable': {b -> ale#Var(b, 'kotlin_languageserver_executable')},
\ 'command': '%e',
\ 'language': 'kotlin',
-\ 'project_root_callback': 'ale_linters#kotlin#languageserver#GetProjectRoot',
+\ 'project_root': function('ale_linters#kotlin#languageserver#GetProjectRoot'),
\})
diff --git a/ale_linters/less/lessc.vim b/ale_linters/less/lessc.vim
index 37600649..4ec8b00e 100755
--- a/ale_linters/less/lessc.vim
+++ b/ale_linters/less/lessc.vim
@@ -38,10 +38,10 @@ endfunction
call ale#linter#Define('less', {
\ 'name': 'lessc',
-\ 'executable_callback': ale#node#FindExecutableFunc('less_lessc', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'less_lessc', [
\ 'node_modules/.bin/lessc',
-\ ]),
-\ 'command_callback': 'ale_linters#less#lessc#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#less#lessc#GetCommand'),
\ 'callback': 'ale_linters#less#lessc#Handle',
\ 'output_stream': 'stderr',
\})
diff --git a/ale_linters/less/stylelint.vim b/ale_linters/less/stylelint.vim
index 479808c2..efb036c2 100644
--- a/ale_linters/less/stylelint.vim
+++ b/ale_linters/less/stylelint.vim
@@ -12,9 +12,9 @@ endfunction
call ale#linter#Define('less', {
\ 'name': 'stylelint',
-\ 'executable_callback': ale#node#FindExecutableFunc('less_stylelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'less_stylelint', [
\ 'node_modules/.bin/stylelint',
-\ ]),
-\ 'command_callback': 'ale_linters#less#stylelint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#less#stylelint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/llvm/llc.vim b/ale_linters/llvm/llc.vim
index 044f8c44..594be063 100644
--- a/ale_linters/llvm/llc.vim
+++ b/ale_linters/llvm/llc.vim
@@ -17,8 +17,8 @@ endfunction
call ale#linter#Define('llvm', {
\ 'name': 'llc',
-\ 'executable_callback': ale#VarFunc('llvm_llc_executable'),
+\ 'executable': {b -> ale#Var(b, 'llvm_llc_executable')},
\ 'output_stream': 'stderr',
-\ 'command_callback': {-> '%e -filetype=null -o=' . g:ale#util#nul_file},
+\ 'command': {-> '%e -filetype=null -o=' . g:ale#util#nul_file},
\ 'callback': 'ale_linters#llvm#llc#HandleErrors',
\})
diff --git a/ale_linters/lua/luac.vim b/ale_linters/lua/luac.vim
index bca2cd8d..41674a43 100644
--- a/ale_linters/lua/luac.vim
+++ b/ale_linters/lua/luac.vim
@@ -24,7 +24,7 @@ endfunction
call ale#linter#Define('lua', {
\ 'name': 'luac',
-\ 'executable_callback': ale#VarFunc('lua_luac_executable'),
+\ 'executable': {b -> ale#Var(b, 'lua_luac_executable')},
\ 'command': '%e -p -',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#lua#luac#Handle',
diff --git a/ale_linters/lua/luacheck.vim b/ale_linters/lua/luacheck.vim
index 669103b8..34be2b5a 100644
--- a/ale_linters/lua/luacheck.vim
+++ b/ale_linters/lua/luacheck.vim
@@ -38,7 +38,7 @@ endfunction
call ale#linter#Define('lua', {
\ 'name': 'luacheck',
-\ 'executable_callback': ale#VarFunc('lua_luacheck_executable'),
-\ 'command_callback': 'ale_linters#lua#luacheck#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'lua_luacheck_executable')},
+\ 'command': function('ale_linters#lua#luacheck#GetCommand'),
\ 'callback': 'ale_linters#lua#luacheck#Handle',
\})
diff --git a/ale_linters/markdown/mdl.vim b/ale_linters/markdown/mdl.vim
index 0953144b..305f5359 100644
--- a/ale_linters/markdown/mdl.vim
+++ b/ale_linters/markdown/mdl.vim
@@ -38,7 +38,7 @@ endfunction
call ale#linter#Define('markdown', {
\ 'name': 'mdl',
-\ 'executable_callback': 'ale_linters#markdown#mdl#GetExecutable',
-\ 'command_callback': 'ale_linters#markdown#mdl#GetCommand',
+\ 'executable': function('ale_linters#markdown#mdl#GetExecutable'),
+\ 'command': function('ale_linters#markdown#mdl#GetCommand'),
\ 'callback': 'ale_linters#markdown#mdl#Handle'
\})
diff --git a/ale_linters/markdown/remark_lint.vim b/ale_linters/markdown/remark_lint.vim
index 4f8d48fa..ed87d1ad 100644
--- a/ale_linters/markdown/remark_lint.vim
+++ b/ale_linters/markdown/remark_lint.vim
@@ -39,10 +39,10 @@ endfunction
call ale#linter#Define('markdown', {
\ 'name': 'remark_lint',
\ 'aliases': ['remark-lint'],
-\ 'executable_callback': ale#node#FindExecutableFunc('markdown_remark_lint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'markdown_remark_lint', [
\ 'node_modules/.bin/remark',
-\ ]),
-\ 'command_callback': 'ale_linters#markdown#remark_lint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#markdown#remark_lint#GetCommand'),
\ 'callback': 'ale_linters#markdown#remark_lint#Handle',
\ 'output_stream': 'stderr',
\})
diff --git a/ale_linters/markdown/textlint.vim b/ale_linters/markdown/textlint.vim
index 26458506..613c8411 100644
--- a/ale_linters/markdown/textlint.vim
+++ b/ale_linters/markdown/textlint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('markdown', {
\ 'name': 'textlint',
-\ 'executable_callback': 'ale#handlers#textlint#GetExecutable',
-\ 'command_callback': 'ale#handlers#textlint#GetCommand',
+\ 'executable': function('ale#handlers#textlint#GetExecutable'),
+\ 'command': function('ale#handlers#textlint#GetCommand'),
\ 'callback': 'ale#handlers#textlint#HandleTextlintOutput',
\})
diff --git a/ale_linters/matlab/mlint.vim b/ale_linters/matlab/mlint.vim
index 3435045e..f58f8b6d 100644
--- a/ale_linters/matlab/mlint.vim
+++ b/ale_linters/matlab/mlint.vim
@@ -37,7 +37,7 @@ endfunction
call ale#linter#Define('matlab', {
\ 'name': 'mlint',
-\ 'executable_callback': ale#VarFunc('matlab_mlint_executable'),
+\ 'executable': {b -> ale#Var(b, 'matlab_mlint_executable')},
\ 'command': '%e -id %t',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#matlab#mlint#Handle',
diff --git a/ale_linters/mercury/mmc.vim b/ale_linters/mercury/mmc.vim
index 76d357f0..8a9ccc0e 100644
--- a/ale_linters/mercury/mmc.vim
+++ b/ale_linters/mercury/mmc.vim
@@ -33,8 +33,8 @@ endfunction
call ale#linter#Define('mercury', {
\ 'name': 'mmc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('mercury_mmc_executable'),
-\ 'command_callback': 'ale_linters#mercury#mmc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'mercury_mmc_executable')},
+\ 'command': function('ale_linters#mercury#mmc#GetCommand'),
\ 'callback': 'ale_linters#mercury#mmc#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/nasm/nasm.vim b/ale_linters/nasm/nasm.vim
index cb2119a6..347abc1b 100644
--- a/ale_linters/nasm/nasm.vim
+++ b/ale_linters/nasm/nasm.vim
@@ -36,7 +36,7 @@ call ale#linter#Define('nasm', {
\ 'name': 'nasm',
\ 'output_stream': 'stderr',
\ 'lint_file': 1,
-\ 'executable_callback': ale#VarFunc('nasm_nasm_executable'),
-\ 'command_callback': 'ale_linters#nasm#nasm#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'nasm_nasm_executable')},
+\ 'command': function('ale_linters#nasm#nasm#GetCommand'),
\ 'callback': 'ale_linters#nasm#nasm#Handle',
\})
diff --git a/ale_linters/nim/nimcheck.vim b/ale_linters/nim/nimcheck.vim
index bff45f7d..b5796dcd 100644
--- a/ale_linters/nim/nimcheck.vim
+++ b/ale_linters/nim/nimcheck.vim
@@ -59,7 +59,7 @@ call ale#linter#Define('nim', {
\ 'name': 'nimcheck',
\ 'executable': 'nim',
\ 'output_stream': 'both',
-\ 'command_callback': 'ale_linters#nim#nimcheck#GetCommand',
+\ 'command': function('ale_linters#nim#nimcheck#GetCommand'),
\ 'callback': 'ale_linters#nim#nimcheck#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/objc/ccls.vim b/ale_linters/objc/ccls.vim
index 0aa6a5e5..51ecf056 100644
--- a/ale_linters/objc/ccls.vim
+++ b/ale_linters/objc/ccls.vim
@@ -7,8 +7,8 @@ call ale#Set('objc_ccls_init_options', {})
call ale#linter#Define('objc', {
\ 'name': 'ccls',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('objc_ccls_executable'),
+\ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')},
\ 'command': '%e',
-\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
-\ 'initialization_options_callback': ale#VarFunc('objc_ccls_init_options'),
+\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
+\ 'initialization_options': {b -> ale#Var(b, 'objc_ccls_init_options')},
\})
diff --git a/ale_linters/objc/clang.vim b/ale_linters/objc/clang.vim
index 4e80ac5c..7873dccd 100644
--- a/ale_linters/objc/clang.vim
+++ b/ale_linters/objc/clang.vim
@@ -18,6 +18,6 @@ call ale#linter#Define('objc', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': 'clang',
-\ 'command_callback': 'ale_linters#objc#clang#GetCommand',
+\ 'command': function('ale_linters#objc#clang#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/objc/clangd.vim b/ale_linters/objc/clangd.vim
index f090e6ce..ab52fec3 100644
--- a/ale_linters/objc/clangd.vim
+++ b/ale_linters/objc/clangd.vim
@@ -17,7 +17,7 @@ endfunction
call ale#linter#Define('objc', {
\ 'name': 'clangd',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('objc_clangd_executable'),
-\ 'command_callback': 'ale_linters#objc#clangd#GetCommand',
-\ 'project_root_callback': 'ale_linters#objc#clangd#GetProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')},
+\ 'command': function('ale_linters#objc#clangd#GetCommand'),
+\ 'project_root': function('ale_linters#objc#clangd#GetProjectRoot'),
\})
diff --git a/ale_linters/objcpp/clang.vim b/ale_linters/objcpp/clang.vim
index d1474f17..4dbe55b3 100644
--- a/ale_linters/objcpp/clang.vim
+++ b/ale_linters/objcpp/clang.vim
@@ -18,6 +18,6 @@ call ale#linter#Define('objcpp', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': 'clang++',
-\ 'command_callback': 'ale_linters#objcpp#clang#GetCommand',
+\ 'command': function('ale_linters#objcpp#clang#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/objcpp/clangd.vim b/ale_linters/objcpp/clangd.vim
index a09753be..3991d2ac 100644
--- a/ale_linters/objcpp/clangd.vim
+++ b/ale_linters/objcpp/clangd.vim
@@ -17,7 +17,7 @@ endfunction
call ale#linter#Define('objcpp', {
\ 'name': 'clangd',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('objcpp_clangd_executable'),
-\ 'command_callback': 'ale_linters#objcpp#clangd#GetCommand',
-\ 'project_root_callback': 'ale_linters#objcpp#clangd#GetProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')},
+\ 'command': function('ale_linters#objcpp#clangd#GetCommand'),
+\ 'project_root': function('ale_linters#objcpp#clangd#GetProjectRoot'),
\})
diff --git a/ale_linters/ocaml/ols.vim b/ale_linters/ocaml/ols.vim
index 077862fc..d8208c52 100644
--- a/ale_linters/ocaml/ols.vim
+++ b/ale_linters/ocaml/ols.vim
@@ -7,8 +7,8 @@ call ale#Set('ocaml_ols_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#linter#Define('ocaml', {
\ 'name': 'ols',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale#handlers#ols#GetExecutable',
-\ 'command_callback': 'ale#handlers#ols#GetCommand',
+\ 'executable': function('ale#handlers#ols#GetExecutable'),
+\ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
-\ 'project_root_callback': 'ale#handlers#ols#GetProjectRoot',
+\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\})
diff --git a/ale_linters/perl/perl.vim b/ale_linters/perl/perl.vim
index 4b954f0d..0f06528a 100644
--- a/ale_linters/perl/perl.vim
+++ b/ale_linters/perl/perl.vim
@@ -57,8 +57,8 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perl',
-\ 'executable_callback': ale#VarFunc('perl_perl_executable'),
+\ 'executable': {b -> ale#Var(b, 'perl_perl_executable')},
\ 'output_stream': 'both',
-\ 'command_callback': 'ale_linters#perl#perl#GetCommand',
+\ 'command': function('ale_linters#perl#perl#GetCommand'),
\ 'callback': 'ale_linters#perl#perl#Handle',
\})
diff --git a/ale_linters/perl/perlcritic.vim b/ale_linters/perl/perlcritic.vim
index 8619a404..f3154c09 100644
--- a/ale_linters/perl/perlcritic.vim
+++ b/ale_linters/perl/perlcritic.vim
@@ -55,7 +55,7 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perlcritic',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('perl_perlcritic_executable'),
-\ 'command_callback': 'ale_linters#perl#perlcritic#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'perl_perlcritic_executable')},
+\ 'command': function('ale_linters#perl#perlcritic#GetCommand'),
\ 'callback': 'ale_linters#perl#perlcritic#Handle',
\})
diff --git a/ale_linters/perl6/perl6.vim b/ale_linters/perl6/perl6.vim
index 39406ac4..68ef4769 100644
--- a/ale_linters/perl6/perl6.vim
+++ b/ale_linters/perl6/perl6.vim
@@ -158,9 +158,9 @@ endfunction
call ale#linter#Define('perl6', {
\ 'name': 'perl6',
-\ 'executable_callback': 'ale_linters#perl6#perl6#GetExecutable',
+\ 'executable': function('ale_linters#perl6#perl6#GetExecutable'),
\ 'output_stream': 'both',
-\ 'command_callback': 'ale_linters#perl6#perl6#GetCommand',
+\ 'command': function('ale_linters#perl6#perl6#GetCommand'),
\ 'callback': 'ale_linters#perl6#perl6#Handle',
\})
diff --git a/ale_linters/php/langserver.vim b/ale_linters/php/langserver.vim
index ca91db4c..c88281c4 100644
--- a/ale_linters/php/langserver.vim
+++ b/ale_linters/php/langserver.vim
@@ -13,9 +13,9 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'langserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#node#FindExecutableFunc('php_langserver', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'php_langserver', [
\ 'vendor/bin/php-language-server.php',
-\ ]),
+\ ])},
\ 'command': 'php %e',
-\ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot',
+\ 'project_root': function('ale_linters#php#langserver#GetProjectRoot'),
\})
diff --git a/ale_linters/php/phan.vim b/ale_linters/php/phan.vim
index c6f16356..53cb1ea9 100644
--- a/ale_linters/php/phan.vim
+++ b/ale_linters/php/phan.vim
@@ -67,7 +67,7 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phan',
-\ 'executable_callback': 'ale_linters#php#phan#GetExecutable',
-\ 'command_callback': 'ale_linters#php#phan#GetCommand',
+\ 'executable': function('ale_linters#php#phan#GetExecutable'),
+\ 'command': function('ale_linters#php#phan#GetCommand'),
\ 'callback': 'ale_linters#php#phan#Handle',
\})
diff --git a/ale_linters/php/php.vim b/ale_linters/php/php.vim
index 5d87196c..51a109b9 100644
--- a/ale_linters/php/php.vim
+++ b/ale_linters/php/php.vim
@@ -32,7 +32,7 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'php',
-\ 'executable_callback': ale#VarFunc('php_php_executable'),
+\ 'executable': {b -> ale#Var(b, 'php_php_executable')},
\ 'output_stream': 'stdout',
\ 'command': '%e -l -d error_reporting=E_ALL -d display_errors=1 -d log_errors=0 --',
\ 'callback': 'ale_linters#php#php#Handle',
diff --git a/ale_linters/php/phpcs.vim b/ale_linters/php/phpcs.vim
index 408c2652..1c92bbb2 100644
--- a/ale_linters/php/phpcs.vim
+++ b/ale_linters/php/phpcs.vim
@@ -44,10 +44,10 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpcs',
-\ 'executable_callback': ale#node#FindExecutableFunc('php_phpcs', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'php_phpcs', [
\ 'vendor/bin/phpcs',
\ 'phpcs'
-\ ]),
-\ 'command_callback': 'ale_linters#php#phpcs#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#php#phpcs#GetCommand'),
\ 'callback': 'ale_linters#php#phpcs#Handle',
\})
diff --git a/ale_linters/php/phpmd.vim b/ale_linters/php/phpmd.vim
index 65f1cc3c..9b1d1e44 100644
--- a/ale_linters/php/phpmd.vim
+++ b/ale_linters/php/phpmd.vim
@@ -32,7 +32,7 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpmd',
-\ 'executable_callback': ale#VarFunc('php_phpmd_executable'),
-\ 'command_callback': 'ale_linters#php#phpmd#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'php_phpmd_executable')},
+\ 'command': function('ale_linters#php#phpmd#GetCommand'),
\ 'callback': 'ale_linters#php#phpmd#Handle',
\})
diff --git a/ale_linters/php/phpstan.vim b/ale_linters/php/phpstan.vim
index 1c831e1b..34d4e799 100644
--- a/ale_linters/php/phpstan.vim
+++ b/ale_linters/php/phpstan.vim
@@ -65,7 +65,7 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpstan',
-\ 'executable_callback': 'ale_linters#php#phpstan#GetExecutable',
+\ 'executable': function('ale_linters#php#phpstan#GetExecutable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#php#phpstan#VersionCheck'},
\ {'callback': 'ale_linters#php#phpstan#GetCommand'},
diff --git a/ale_linters/php/psalm.vim b/ale_linters/php/psalm.vim
index dce59178..3cdb026a 100644
--- a/ale_linters/php/psalm.vim
+++ b/ale_linters/php/psalm.vim
@@ -13,9 +13,9 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'psalm',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#node#FindExecutableFunc('psalm_langserver', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
\ 'vendor/bin/psalm-language-server',
-\ ]),
+\ ])},
\ 'command': '%e',
-\ 'project_root_callback': 'ale_linters#php#psalm#GetProjectRoot',
+\ 'project_root': function('ale_linters#php#psalm#GetProjectRoot'),
\})
diff --git a/ale_linters/pony/ponyc.vim b/ale_linters/pony/ponyc.vim
index 19e7e828..6d4594f9 100644
--- a/ale_linters/pony/ponyc.vim
+++ b/ale_linters/pony/ponyc.vim
@@ -10,7 +10,7 @@ endfunction
call ale#linter#Define('pony', {
\ 'name': 'ponyc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('pony_ponyc_executable'),
-\ 'command_callback': 'ale_linters#pony#ponyc#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'pony_ponyc_executable')},
+\ 'command': function('ale_linters#pony#ponyc#GetCommand'),
\ 'callback': 'ale#handlers#pony#HandlePonycFormat',
\})
diff --git a/ale_linters/prolog/swipl.vim b/ale_linters/prolog/swipl.vim
index 77261ede..5c601c40 100644
--- a/ale_linters/prolog/swipl.vim
+++ b/ale_linters/prolog/swipl.vim
@@ -94,7 +94,7 @@ endfunction
call ale#linter#Define('prolog', {
\ 'name': 'swipl',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('prolog_swipl_executable'),
-\ 'command_callback': 'ale_linters#prolog#swipl#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'prolog_swipl_executable')},
+\ 'command': function('ale_linters#prolog#swipl#GetCommand'),
\ 'callback': 'ale_linters#prolog#swipl#Handle',
\})
diff --git a/ale_linters/proto/protoc_gen_lint.vim b/ale_linters/proto/protoc_gen_lint.vim
index c8b5c331..c3d10935 100644
--- a/ale_linters/proto/protoc_gen_lint.vim
+++ b/ale_linters/proto/protoc_gen_lint.vim
@@ -22,6 +22,6 @@ call ale#linter#Define('proto', {
\ 'lint_file': 1,
\ 'output_stream': 'stderr',
\ 'executable': 'protoc',
-\ 'command_callback': 'ale_linters#proto#protoc_gen_lint#GetCommand',
+\ 'command': function('ale_linters#proto#protoc_gen_lint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/pug/puglint.vim b/ale_linters/pug/puglint.vim
index 63208986..c4e0e233 100644
--- a/ale_linters/pug/puglint.vim
+++ b/ale_linters/pug/puglint.vim
@@ -33,10 +33,10 @@ endfunction
call ale#linter#Define('pug', {
\ 'name': 'puglint',
-\ 'executable_callback': ale#node#FindExecutableFunc('pug_puglint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'pug_puglint', [
\ 'node_modules/.bin/pug-lint',
-\ ]),
+\ ])},
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#pug#puglint#GetCommand',
+\ 'command': function('ale_linters#pug#puglint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/puppet/languageserver.vim b/ale_linters/puppet/languageserver.vim
index a3060e65..2078695f 100644
--- a/ale_linters/puppet/languageserver.vim
+++ b/ale_linters/puppet/languageserver.vim
@@ -30,8 +30,8 @@ endfunction
call ale#linter#Define('puppet', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('puppet_languageserver_executable'),
+\ 'executable': {b -> ale#Var(b, 'puppet_languageserver_executable')},
\ 'command': '%e --stdio',
\ 'language': 'puppet',
-\ 'project_root_callback': 'ale_linters#puppet#languageserver#GetProjectRoot',
+\ 'project_root': function('ale_linters#puppet#languageserver#GetProjectRoot'),
\})
diff --git a/ale_linters/puppet/puppet.vim b/ale_linters/puppet/puppet.vim
index 0e37bdbd..ae648615 100644
--- a/ale_linters/puppet/puppet.vim
+++ b/ale_linters/puppet/puppet.vim
@@ -30,8 +30,8 @@ endfunction
call ale#linter#Define('puppet', {
\ 'name': 'puppet',
-\ 'executable_callback': ale#VarFunc('puppet_puppet_executable'),
+\ 'executable': {b -> ale#Var(b, 'puppet_puppet_executable')},
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#puppet#puppet#GetCommand',
+\ 'command': function('ale_linters#puppet#puppet#GetCommand'),
\ 'callback': 'ale_linters#puppet#puppet#Handle',
\})
diff --git a/ale_linters/puppet/puppetlint.vim b/ale_linters/puppet/puppetlint.vim
index c9c16f5e..985d6a4d 100644
--- a/ale_linters/puppet/puppetlint.vim
+++ b/ale_linters/puppet/puppetlint.vim
@@ -12,7 +12,7 @@ endfunction
call ale#linter#Define('puppet', {
\ 'name': 'puppetlint',
-\ 'executable_callback': ale#VarFunc('puppet_puppetlint_executable'),
-\ 'command_callback': 'ale_linters#puppet#puppetlint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'puppet_puppetlint_executable')},
+\ 'command': function('ale_linters#puppet#puppetlint#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\})
diff --git a/ale_linters/pyrex/cython.vim b/ale_linters/pyrex/cython.vim
index d260698c..84382ba1 100644
--- a/ale_linters/pyrex/cython.vim
+++ b/ale_linters/pyrex/cython.vim
@@ -32,7 +32,7 @@ endfunction
call ale#linter#Define('pyrex', {
\ 'name': 'cython',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('pyrex_cython_executable'),
-\ 'command_callback': 'ale_linters#pyrex#cython#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'pyrex_cython_executable')},
+\ 'command': function('ale_linters#pyrex#cython#GetCommand'),
\ 'callback': 'ale_linters#pyrex#cython#Handle',
\})
diff --git a/ale_linters/python/bandit.vim b/ale_linters/python/bandit.vim
index 819c83aa..554f5000 100644
--- a/ale_linters/python/bandit.vim
+++ b/ale_linters/python/bandit.vim
@@ -3,6 +3,7 @@
call ale#Set('python_bandit_executable', 'bandit')
call ale#Set('python_bandit_options', '')
+call ale#Set('python_bandit_use_config', 1)
call ale#Set('python_bandit_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_bandit_auto_pipenv', 0)
@@ -22,6 +23,14 @@ function! ale_linters#python#bandit#GetCommand(buffer) abort
let l:flags = ' --format custom'
\ . ' --msg-template "{line}:{test_id}:{severity}:{msg}" '
+ if ale#Var(a:buffer, 'python_bandit_use_config')
+ let l:config_path = ale#path#FindNearestFile(a:buffer, '.bandit')
+
+ if !empty(l:config_path)
+ let l:flags = ' --ini ' . ale#Escape(l:config_path) . l:flags
+ endif
+ endif
+
let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run bandit'
\ : ''
@@ -53,7 +62,7 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'bandit',
-\ 'executable_callback': 'ale_linters#python#bandit#GetExecutable',
-\ 'command_callback': 'ale_linters#python#bandit#GetCommand',
+\ 'executable': function('ale_linters#python#bandit#GetExecutable'),
+\ 'command': function('ale_linters#python#bandit#GetCommand'),
\ 'callback': 'ale_linters#python#bandit#Handle',
\})
diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim
index 076bd9c4..993d7adb 100644
--- a/ale_linters/python/flake8.vim
+++ b/ale_linters/python/flake8.vim
@@ -143,7 +143,7 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'flake8',
-\ 'executable_callback': 'ale_linters#python#flake8#GetExecutable',
+\ 'executable': function('ale_linters#python#flake8#GetExecutable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#python#flake8#VersionCheck'},
\ {'callback': 'ale_linters#python#flake8#GetCommand', 'output_stream': 'both'},
diff --git a/ale_linters/python/mypy.vim b/ale_linters/python/mypy.vim
index 0c90a3c7..c4c6507f 100644
--- a/ale_linters/python/mypy.vim
+++ b/ale_linters/python/mypy.vim
@@ -75,7 +75,7 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'mypy',
-\ 'executable_callback': 'ale_linters#python#mypy#GetExecutable',
-\ 'command_callback': 'ale_linters#python#mypy#GetCommand',
+\ 'executable': function('ale_linters#python#mypy#GetExecutable'),
+\ 'command': function('ale_linters#python#mypy#GetCommand'),
\ 'callback': 'ale_linters#python#mypy#Handle',
\})
diff --git a/ale_linters/python/prospector.vim b/ale_linters/python/prospector.vim
index b01cec87..ee47012f 100644
--- a/ale_linters/python/prospector.vim
+++ b/ale_linters/python/prospector.vim
@@ -93,8 +93,8 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'prospector',
-\ 'executable_callback': 'ale_linters#python#prospector#GetExecutable',
-\ 'command_callback': 'ale_linters#python#prospector#GetCommand',
+\ 'executable': function('ale_linters#python#prospector#GetExecutable'),
+\ 'command': function('ale_linters#python#prospector#GetCommand'),
\ 'callback': 'ale_linters#python#prospector#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/python/pycodestyle.vim b/ale_linters/python/pycodestyle.vim
index f0269585..fb521bc1 100644
--- a/ale_linters/python/pycodestyle.vim
+++ b/ale_linters/python/pycodestyle.vim
@@ -69,7 +69,7 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pycodestyle',
-\ 'executable_callback': 'ale_linters#python#pycodestyle#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pycodestyle#GetCommand',
+\ 'executable': function('ale_linters#python#pycodestyle#GetExecutable'),
+\ 'command': function('ale_linters#python#pycodestyle#GetCommand'),
\ 'callback': 'ale_linters#python#pycodestyle#Handle',
\})
diff --git a/ale_linters/python/pydocstyle.vim b/ale_linters/python/pydocstyle.vim
index 177f5e0f..3901db4d 100644
--- a/ale_linters/python/pydocstyle.vim
+++ b/ale_linters/python/pydocstyle.vim
@@ -67,7 +67,7 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pydocstyle',
-\ 'executable_callback': 'ale_linters#python#pydocstyle#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pydocstyle#GetCommand',
+\ 'executable': function('ale_linters#python#pydocstyle#GetExecutable'),
+\ 'command': function('ale_linters#python#pydocstyle#GetCommand'),
\ 'callback': 'ale_linters#python#pydocstyle#Handle',
\})
diff --git a/ale_linters/python/pyflakes.vim b/ale_linters/python/pyflakes.vim
index 091408d5..b5127022 100644
--- a/ale_linters/python/pyflakes.vim
+++ b/ale_linters/python/pyflakes.vim
@@ -43,8 +43,8 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pyflakes',
-\ 'executable_callback': 'ale_linters#python#pyflakes#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pyflakes#GetCommand',
+\ 'executable': function('ale_linters#python#pyflakes#GetExecutable'),
+\ 'command': function('ale_linters#python#pyflakes#GetCommand'),
\ 'callback': 'ale_linters#python#pyflakes#Handle',
\ 'output_stream': 'both',
\})
diff --git a/ale_linters/python/pylama.vim b/ale_linters/python/pylama.vim
index 4ad25c0f..38dd2836 100644
--- a/ale_linters/python/pylama.vim
+++ b/ale_linters/python/pylama.vim
@@ -85,8 +85,8 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pylama',
-\ 'executable_callback': 'ale_linters#python#pylama#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pylama#GetCommand',
+\ 'executable': function('ale_linters#python#pylama#GetExecutable'),
+\ 'command': function('ale_linters#python#pylama#GetCommand'),
\ 'callback': 'ale_linters#python#pylama#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/python/pylint.vim b/ale_linters/python/pylint.vim
index da845b7a..57e82691 100644
--- a/ale_linters/python/pylint.vim
+++ b/ale_linters/python/pylint.vim
@@ -17,9 +17,17 @@ function! ale_linters#python#pylint#GetExecutable(buffer) abort
endfunction
function! ale_linters#python#pylint#GetCommand(buffer) abort
- let l:cd_string = ale#Var(a:buffer, 'python_pylint_change_directory')
- \ ? ale#path#BufferCdString(a:buffer)
- \ : ''
+ let l:cd_string = ''
+
+ if ale#Var(a:buffer, 'python_pylint_change_directory')
+ " pylint only checks for pylintrc in the packages above its current
+ " directory before falling back to user and global pylintrc.
+ " Run from project root, if found, otherwise buffer dir.
+ let l:project_root = ale#python#FindProjectRoot(a:buffer)
+ let l:cd_string = l:project_root isnot# ''
+ \ ? ale#path#CdString(l:project_root)
+ \ : ale#path#BufferCdString(a:buffer)
+ endif
let l:executable = ale_linters#python#pylint#GetExecutable(a:buffer)
@@ -70,8 +78,8 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pylint',
-\ 'executable_callback': 'ale_linters#python#pylint#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pylint#GetCommand',
+\ 'executable': function('ale_linters#python#pylint#GetExecutable'),
+\ 'command': function('ale_linters#python#pylint#GetCommand'),
\ 'callback': 'ale_linters#python#pylint#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/python/pyls.vim b/ale_linters/python/pyls.vim
index 2c2ed94c..c7f91430 100644
--- a/ale_linters/python/pyls.vim
+++ b/ale_linters/python/pyls.vim
@@ -28,9 +28,9 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pyls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#python#pyls#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pyls#GetCommand',
-\ 'project_root_callback': 'ale#python#FindProjectRoot',
+\ 'executable': function('ale_linters#python#pyls#GetExecutable'),
+\ 'command': function('ale_linters#python#pyls#GetCommand'),
+\ 'project_root': function('ale#python#FindProjectRoot'),
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
-\ 'lsp_config_callback': ale#VarFunc('python_pyls_config'),
+\ 'lsp_config': {b -> ale#Var(b, 'python_pyls_config')},
\})
diff --git a/ale_linters/python/pyre.vim b/ale_linters/python/pyre.vim
index adc185f2..4edd80f7 100644
--- a/ale_linters/python/pyre.vim
+++ b/ale_linters/python/pyre.vim
@@ -27,8 +27,8 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'pyre',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#python#pyre#GetExecutable',
-\ 'command_callback': 'ale_linters#python#pyre#GetCommand',
-\ 'project_root_callback': 'ale#python#FindProjectRoot',
+\ 'executable': function('ale_linters#python#pyre#GetExecutable'),
+\ 'command': function('ale_linters#python#pyre#GetCommand'),
+\ 'project_root': function('ale#python#FindProjectRoot'),
\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
\})
diff --git a/ale_linters/python/vulture.vim b/ale_linters/python/vulture.vim
index b3908b80..d328d262 100644
--- a/ale_linters/python/vulture.vim
+++ b/ale_linters/python/vulture.vim
@@ -73,8 +73,8 @@ endfunction
call ale#linter#Define('python', {
\ 'name': 'vulture',
-\ 'executable_callback': 'ale_linters#python#vulture#GetExecutable',
-\ 'command_callback': 'ale_linters#python#vulture#GetCommand',
+\ 'executable': function('ale_linters#python#vulture#GetExecutable'),
+\ 'command': function('ale_linters#python#vulture#GetCommand'),
\ 'callback': 'ale_linters#python#vulture#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/qml/qmlfmt.vim b/ale_linters/qml/qmlfmt.vim
index 12f3e97b..11cc9413 100644
--- a/ale_linters/qml/qmlfmt.vim
+++ b/ale_linters/qml/qmlfmt.vim
@@ -19,7 +19,7 @@ endfunction
call ale#linter#Define('qml', {
\ 'name': 'qmlfmt',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('qml_qmlfmt_executable'),
+\ 'executable': {b -> ale#Var(b, 'qml_qmlfmt_executable')},
\ 'command': '%e -e',
\ 'callback': 'ale_linters#qml#qmlfmt#Handle',
\})
diff --git a/ale_linters/r/lintr.vim b/ale_linters/r/lintr.vim
index 8f74c9b8..3164c06f 100644
--- a/ale_linters/r/lintr.vim
+++ b/ale_linters/r/lintr.vim
@@ -29,7 +29,7 @@ endfunction
call ale#linter#Define('r', {
\ 'name': 'lintr',
\ 'executable': 'Rscript',
-\ 'command_callback': 'ale_linters#r#lintr#GetCommand',
+\ 'command': function('ale_linters#r#lintr#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'output_stream': 'both',
\})
diff --git a/ale_linters/reason/ols.vim b/ale_linters/reason/ols.vim
index 4e5bd395..66137e1b 100644
--- a/ale_linters/reason/ols.vim
+++ b/ale_linters/reason/ols.vim
@@ -7,8 +7,8 @@ call ale#Set('reason_ols_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#linter#Define('reason', {
\ 'name': 'ols',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale#handlers#ols#GetExecutable',
-\ 'command_callback': 'ale#handlers#ols#GetCommand',
+\ 'executable': function('ale#handlers#ols#GetExecutable'),
+\ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
-\ 'project_root_callback': 'ale#handlers#ols#GetProjectRoot',
+\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\})
diff --git a/ale_linters/rst/rstcheck.vim b/ale_linters/rst/rstcheck.vim
index 8504738b..39e11d6e 100644
--- a/ale_linters/rst/rstcheck.vim
+++ b/ale_linters/rst/rstcheck.vim
@@ -32,7 +32,7 @@ endfunction
call ale#linter#Define('rst', {
\ 'name': 'rstcheck',
\ 'executable': 'rstcheck',
-\ 'command_callback': 'ale_linters#rst#rstcheck#GetCommand',
+\ 'command': function('ale_linters#rst#rstcheck#GetCommand'),
\ 'callback': 'ale_linters#rst#rstcheck#Handle',
\ 'output_stream': 'both',
\})
diff --git a/ale_linters/rst/textlint.vim b/ale_linters/rst/textlint.vim
index a14411cf..56dd8db8 100644
--- a/ale_linters/rst/textlint.vim
+++ b/ale_linters/rst/textlint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('rst', {
\ 'name': 'textlint',
-\ 'executable_callback': 'ale#handlers#textlint#GetExecutable',
-\ 'command_callback': 'ale#handlers#textlint#GetCommand',
+\ 'executable': function('ale#handlers#textlint#GetExecutable'),
+\ 'command': function('ale#handlers#textlint#GetCommand'),
\ 'callback': 'ale#handlers#textlint#HandleTextlintOutput',
\})
diff --git a/ale_linters/ruby/brakeman.vim b/ale_linters/ruby/brakeman.vim
index 122e0b5b..a8088080 100644
--- a/ale_linters/ruby/brakeman.vim
+++ b/ale_linters/ruby/brakeman.vim
@@ -44,8 +44,8 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'brakeman',
-\ 'executable_callback': ale#VarFunc('ruby_brakeman_executable'),
-\ 'command_callback': 'ale_linters#ruby#brakeman#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'ruby_brakeman_executable')},
+\ 'command': function('ale_linters#ruby#brakeman#GetCommand'),
\ 'callback': 'ale_linters#ruby#brakeman#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/ruby/rails_best_practices.vim b/ale_linters/ruby/rails_best_practices.vim
index 20cadca8..680cc364 100644
--- a/ale_linters/ruby/rails_best_practices.vim
+++ b/ale_linters/ruby/rails_best_practices.vim
@@ -42,8 +42,8 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rails_best_practices',
-\ 'executable_callback': ale#VarFunc('ruby_rails_best_practices_executable'),
-\ 'command_callback': 'ale_linters#ruby#rails_best_practices#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'ruby_rails_best_practices_executable')},
+\ 'command': function('ale_linters#ruby#rails_best_practices#GetCommand'),
\ 'callback': 'ale_linters#ruby#rails_best_practices#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/ruby/reek.vim b/ale_linters/ruby/reek.vim
index 53363d31..26f6e36c 100644
--- a/ale_linters/ruby/reek.vim
+++ b/ale_linters/ruby/reek.vim
@@ -69,7 +69,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'reek',
-\ 'executable_callback': ale#VarFunc('ruby_reek_executable'),
+\ 'executable': {b -> ale#Var(b, 'ruby_reek_executable')},
\ 'command_chain': [
\ {'callback': 'ale_linters#ruby#reek#VersionCheck'},
\ {'callback': 'ale_linters#ruby#reek#GetCommand'},
diff --git a/ale_linters/ruby/rubocop.vim b/ale_linters/ruby/rubocop.vim
index 790ca82c..8b9e9c84 100644
--- a/ale_linters/ruby/rubocop.vim
+++ b/ale_linters/ruby/rubocop.vim
@@ -25,7 +25,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rubocop',
-\ 'executable_callback': ale#VarFunc('ruby_rubocop_executable'),
-\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'ruby_rubocop_executable')},
+\ 'command': function('ale_linters#ruby#rubocop#GetCommand'),
\ 'callback': 'ale#ruby#HandleRubocopOutput',
\})
diff --git a/ale_linters/ruby/ruby.vim b/ale_linters/ruby/ruby.vim
index 2bc4ec4b..2dc55eb0 100644
--- a/ale_linters/ruby/ruby.vim
+++ b/ale_linters/ruby/ruby.vim
@@ -5,7 +5,7 @@ call ale#Set('ruby_ruby_executable', 'ruby')
call ale#linter#Define('ruby', {
\ 'name': 'ruby',
-\ 'executable_callback': ale#VarFunc('ruby_ruby_executable'),
+\ 'executable': {b -> ale#Var(b, 'ruby_ruby_executable')},
\ 'command': '%e -w -c -T1 %t',
\ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors',
diff --git a/ale_linters/ruby/solargraph.vim b/ale_linters/ruby/solargraph.vim
index 5ff0a759..bf54a55c 100644
--- a/ale_linters/ruby/solargraph.vim
+++ b/ale_linters/ruby/solargraph.vim
@@ -15,8 +15,8 @@ call ale#linter#Define('ruby', {
\ 'name': 'solargraph',
\ 'lsp': 'stdio',
\ 'language': 'ruby',
-\ 'executable_callback': ale#VarFunc('ruby_solargraph_executable'),
-\ 'command_callback': 'ale_linters#ruby#solargraph#GetCommand',
-\ 'project_root_callback': 'ale#ruby#FindProjectRoot',
-\ 'initialization_options_callback': ale#VarFunc('ruby_solargraph_options'),
+\ 'executable': {b -> ale#Var(b, 'ruby_solargraph_executable')},
+\ 'command': function('ale_linters#ruby#solargraph#GetCommand'),
+\ 'project_root': function('ale#ruby#FindProjectRoot'),
+\ 'initialization_options': {b -> ale#Var(b, 'ruby_solargraph_options')},
\})
diff --git a/ale_linters/ruby/standardrb.vim b/ale_linters/ruby/standardrb.vim
index 95e10934..f075a7d5 100644
--- a/ale_linters/ruby/standardrb.vim
+++ b/ale_linters/ruby/standardrb.vim
@@ -17,7 +17,7 @@ endfunction
" standardrb is based on RuboCop so the callback is the same
call ale#linter#Define('ruby', {
\ 'name': 'standardrb',
-\ 'executable_callback': ale#VarFunc('ruby_standardrb_executable'),
-\ 'command_callback': 'ale_linters#ruby#standardrb#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'ruby_standardrb_executable')},
+\ 'command': function('ale_linters#ruby#standardrb#GetCommand'),
\ 'callback': 'ale#ruby#HandleRubocopOutput',
\})
diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim
index cf6187f8..b4eabfae 100644
--- a/ale_linters/rust/cargo.vim
+++ b/ale_linters/rust/cargo.vim
@@ -93,7 +93,7 @@ endfunction
call ale#linter#Define('rust', {
\ 'name': 'cargo',
-\ 'executable_callback': 'ale_linters#rust#cargo#GetCargoExecutable',
+\ 'executable': function('ale_linters#rust#cargo#GetCargoExecutable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#rust#cargo#VersionCheck'},
\ {'callback': 'ale_linters#rust#cargo#GetCommand'},
diff --git a/ale_linters/rust/rls.vim b/ale_linters/rust/rls.vim
index 60dd3667..0e5c326c 100644
--- a/ale_linters/rust/rls.vim
+++ b/ale_linters/rust/rls.vim
@@ -3,6 +3,7 @@
call ale#Set('rust_rls_executable', 'rls')
call ale#Set('rust_rls_toolchain', 'nightly')
+call ale#Set('rust_rls_config', {})
function! ale_linters#rust#rls#GetCommand(buffer) abort
let l:toolchain = ale#Var(a:buffer, 'rust_rls_toolchain')
@@ -19,7 +20,8 @@ endfunction
call ale#linter#Define('rust', {
\ 'name': 'rls',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('rust_rls_executable'),
-\ 'command_callback': 'ale_linters#rust#rls#GetCommand',
-\ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot',
+\ 'lsp_config': {b -> ale#Var(b, 'rust_rls_config')},
+\ 'executable': {b -> ale#Var(b, 'rust_rls_executable')},
+\ 'command': function('ale_linters#rust#rls#GetCommand'),
+\ 'project_root': function('ale_linters#rust#rls#GetProjectRoot'),
\})
diff --git a/ale_linters/rust/rustc.vim b/ale_linters/rust/rustc.vim
index 33fb72f4..f140b58b 100644
--- a/ale_linters/rust/rustc.vim
+++ b/ale_linters/rust/rustc.vim
@@ -27,7 +27,7 @@ endfunction
call ale#linter#Define('rust', {
\ 'name': 'rustc',
\ 'executable': 'rustc',
-\ 'command_callback': 'ale_linters#rust#rustc#RustcCommand',
+\ 'command': function('ale_linters#rust#rustc#RustcCommand'),
\ 'callback': 'ale#handlers#rust#HandleRustErrors',
\ 'output_stream': 'stderr',
\})
diff --git a/ale_linters/sass/sasslint.vim b/ale_linters/sass/sasslint.vim
index 8d24185d..17cd3667 100644
--- a/ale_linters/sass/sasslint.vim
+++ b/ale_linters/sass/sasslint.vim
@@ -22,7 +22,7 @@ endfunction
call ale#linter#Define('sass', {
\ 'name': 'sasslint',
-\ 'executable_callback': 'ale_linters#sass#sasslint#GetExecutable',
-\ 'command_callback': 'ale_linters#sass#sasslint#GetCommand',
+\ 'executable': function('ale_linters#sass#sasslint#GetExecutable'),
+\ 'command': function('ale_linters#sass#sasslint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleCSSLintFormat',
\})
diff --git a/ale_linters/sass/stylelint.vim b/ale_linters/sass/stylelint.vim
index b6286f18..7b14c6b4 100644
--- a/ale_linters/sass/stylelint.vim
+++ b/ale_linters/sass/stylelint.vim
@@ -5,9 +5,9 @@ call ale#Set('sass_stylelint_use_global', get(g:, 'ale_use_global_executables',
call ale#linter#Define('sass', {
\ 'name': 'stylelint',
-\ 'executable_callback': ale#node#FindExecutableFunc('sass_stylelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'sass_stylelint', [
\ 'node_modules/.bin/stylelint',
-\ ]),
+\ ])},
\ 'command': '%e --stdin-filename %s',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/scala/fsc.vim b/ale_linters/scala/fsc.vim
index fbdce20e..94135235 100644
--- a/ale_linters/scala/fsc.vim
+++ b/ale_linters/scala/fsc.vim
@@ -7,7 +7,7 @@ endfunction
call ale#linter#Define('scala', {
\ 'name': 'fsc',
-\ 'executable_callback': {buf -> s:IsSbt(buf) ? '' : 'fsc'},
+\ 'executable': {buf -> s:IsSbt(buf) ? '' : 'fsc'},
\ 'command': '%e -Ystop-after:parser %t',
\ 'callback': 'ale#handlers#scala#HandleScalacLintFormat',
\ 'output_stream': 'stderr',
diff --git a/ale_linters/scala/sbtserver.vim b/ale_linters/scala/sbtserver.vim
index 694241d7..d4f137c2 100644
--- a/ale_linters/scala/sbtserver.vim
+++ b/ale_linters/scala/sbtserver.vim
@@ -25,7 +25,7 @@ endfunction
call ale#linter#Define('scala', {
\ 'name': 'sbtserver',
\ 'lsp': 'socket',
-\ 'address_callback': 'ale_linters#scala#sbtserver#GetAddress',
+\ 'address': function('ale_linters#scala#sbtserver#GetAddress'),
\ 'language': 'scala',
-\ 'project_root_callback': 'ale_linters#scala#sbtserver#GetProjectRoot',
+\ 'project_root': function('ale_linters#scala#sbtserver#GetProjectRoot'),
\})
diff --git a/ale_linters/scala/scalac.vim b/ale_linters/scala/scalac.vim
index 3dbdd925..1dd579b4 100644
--- a/ale_linters/scala/scalac.vim
+++ b/ale_linters/scala/scalac.vim
@@ -8,7 +8,7 @@ endfunction
call ale#linter#Define('scala', {
\ 'name': 'scalac',
-\ 'executable_callback': {buf -> s:IsSbt(buf) ? '' : 'scalac'},
+\ 'executable': {buf -> s:IsSbt(buf) ? '' : 'scalac'},
\ 'command': '%e -Ystop-after:parser %t',
\ 'callback': 'ale#handlers#scala#HandleScalacLintFormat',
\ 'output_stream': 'stderr',
diff --git a/ale_linters/scala/scalastyle.vim b/ale_linters/scala/scalastyle.vim
index 42228cf6..6e9e4c13 100644
--- a/ale_linters/scala/scalastyle.vim
+++ b/ale_linters/scala/scalastyle.vim
@@ -81,6 +81,6 @@ call ale#linter#Define('scala', {
\ 'name': 'scalastyle',
\ 'executable': 'scalastyle',
\ 'output_stream': 'stdout',
-\ 'command_callback': 'ale_linters#scala#scalastyle#GetCommand',
+\ 'command': function('ale_linters#scala#scalastyle#GetCommand'),
\ 'callback': 'ale_linters#scala#scalastyle#Handle',
\})
diff --git a/ale_linters/scss/sasslint.vim b/ale_linters/scss/sasslint.vim
index 8b725ba6..cf13546e 100644
--- a/ale_linters/scss/sasslint.vim
+++ b/ale_linters/scss/sasslint.vim
@@ -22,7 +22,7 @@ endfunction
call ale#linter#Define('scss', {
\ 'name': 'sasslint',
-\ 'executable_callback': 'ale_linters#scss#sasslint#GetExecutable',
-\ 'command_callback': 'ale_linters#scss#sasslint#GetCommand',
+\ 'executable': function('ale_linters#scss#sasslint#GetExecutable'),
+\ 'command': function('ale_linters#scss#sasslint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleCSSLintFormat',
\})
diff --git a/ale_linters/scss/stylelint.vim b/ale_linters/scss/stylelint.vim
index 2bffa8e1..b5b21536 100644
--- a/ale_linters/scss/stylelint.vim
+++ b/ale_linters/scss/stylelint.vim
@@ -11,9 +11,9 @@ endfunction
call ale#linter#Define('scss', {
\ 'name': 'stylelint',
-\ 'executable_callback': ale#node#FindExecutableFunc('scss_stylelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'scss_stylelint', [
\ 'node_modules/.bin/stylelint',
-\ ]),
-\ 'command_callback': 'ale_linters#scss#stylelint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#scss#stylelint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/sh/language_server.vim b/ale_linters/sh/language_server.vim
index 385d1119..5a3b0e9a 100644
--- a/ale_linters/sh/language_server.vim
+++ b/ale_linters/sh/language_server.vim
@@ -26,7 +26,7 @@ endfunction
call ale#linter#Define('sh', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#sh#language_server#GetExecutable',
-\ 'command_callback': 'ale_linters#sh#language_server#GetCommand',
-\ 'project_root_callback': 'ale_linters#sh#language_server#GetProjectRoot',
+\ 'executable': function('ale_linters#sh#language_server#GetExecutable'),
+\ 'command': function('ale_linters#sh#language_server#GetCommand'),
+\ 'project_root': function('ale_linters#sh#language_server#GetProjectRoot'),
\})
diff --git a/ale_linters/sh/shell.vim b/ale_linters/sh/shell.vim
index cf5e4e6c..189dc21d 100644
--- a/ale_linters/sh/shell.vim
+++ b/ale_linters/sh/shell.vim
@@ -51,7 +51,7 @@ endfunction
call ale#linter#Define('sh', {
\ 'name': 'shell',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#sh#shell#GetExecutable',
-\ 'command_callback': 'ale_linters#sh#shell#GetCommand',
+\ 'executable': function('ale_linters#sh#shell#GetExecutable'),
+\ 'command': function('ale_linters#sh#shell#GetCommand'),
\ 'callback': 'ale_linters#sh#shell#Handle',
\})
diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim
index 12864722..bb7048cd 100644
--- a/ale_linters/sh/shellcheck.vim
+++ b/ale_linters/sh/shellcheck.vim
@@ -108,7 +108,7 @@ endfunction
call ale#linter#Define('sh', {
\ 'name': 'shellcheck',
-\ 'executable_callback': 'ale_linters#sh#shellcheck#GetExecutable',
+\ 'executable': function('ale_linters#sh#shellcheck#GetExecutable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#sh#shellcheck#VersionCheck'},
\ {'callback': 'ale_linters#sh#shellcheck#GetCommand'},
diff --git a/ale_linters/slim/slimlint.vim b/ale_linters/slim/slimlint.vim
index a27736f8..1a4008ae 100644
--- a/ale_linters/slim/slimlint.vim
+++ b/ale_linters/slim/slimlint.vim
@@ -50,6 +50,6 @@ endfunction
call ale#linter#Define('slim', {
\ 'name': 'slimlint',
\ 'executable': 'slim-lint',
-\ 'command_callback': 'ale_linters#slim#slimlint#GetCommand',
+\ 'command': function('ale_linters#slim#slimlint#GetCommand'),
\ 'callback': 'ale_linters#slim#slimlint#Handle'
\})
diff --git a/ale_linters/sml/smlnj.vim b/ale_linters/sml/smlnj.vim
index f15579ea..852ea170 100644
--- a/ale_linters/sml/smlnj.vim
+++ b/ale_linters/sml/smlnj.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('sml', {
\ 'name': 'smlnj',
-\ 'executable_callback': 'ale#handlers#sml#GetExecutableSmlnjFile',
+\ 'executable': function('ale#handlers#sml#GetExecutableSmlnjFile'),
\ 'command': 'sml',
\ 'callback': 'ale#handlers#sml#Handle',
\})
diff --git a/ale_linters/sml/smlnj_cm.vim b/ale_linters/sml/smlnj_cm.vim
index bfa4bc05..9ad24af4 100644
--- a/ale_linters/sml/smlnj_cm.vim
+++ b/ale_linters/sml/smlnj_cm.vim
@@ -12,9 +12,9 @@ endfunction
call ale#linter#Define('sml', {
\ 'name': 'smlnj_cm',
\ 'aliases': ['smlnj-cm'],
-\ 'executable_callback': 'ale#handlers#sml#GetExecutableSmlnjCm',
+\ 'executable': function('ale#handlers#sml#GetExecutableSmlnjCm'),
\ 'lint_file': 1,
-\ 'command_callback': 'ale_linters#sml#smlnj_cm#GetCommand',
+\ 'command': function('ale_linters#sml#smlnj_cm#GetCommand'),
\ 'callback': 'ale#handlers#sml#Handle',
\})
diff --git a/ale_linters/spec/rpmlint.vim b/ale_linters/spec/rpmlint.vim
index 486bef1e..92ef4d63 100644
--- a/ale_linters/spec/rpmlint.vim
+++ b/ale_linters/spec/rpmlint.vim
@@ -72,7 +72,7 @@ endfunction
call ale#linter#Define('spec', {
\ 'name': 'rpmlint',
-\ 'executable_callback': ale#VarFunc('spec_rpmlint_executable'),
-\ 'command_callback': 'ale_linters#spec#rpmlint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'spec_rpmlint_executable')},
+\ 'command': function('ale_linters#spec#rpmlint#GetCommand'),
\ 'callback': 'ale_linters#spec#rpmlint#Handle',
\})
diff --git a/ale_linters/stylus/stylelint.vim b/ale_linters/stylus/stylelint.vim
index 2256f3c0..ce6f9426 100644
--- a/ale_linters/stylus/stylelint.vim
+++ b/ale_linters/stylus/stylelint.vim
@@ -12,9 +12,9 @@ endfunction
call ale#linter#Define('stylus', {
\ 'name': 'stylelint',
-\ 'executable_callback': ale#node#FindExecutableFunc('stylus_stylelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'stylus_stylelint', [
\ 'node_modules/.bin/stylelint',
-\ ]),
-\ 'command_callback': 'ale_linters#stylus#stylelint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#stylus#stylelint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/sugarss/stylelint.vim b/ale_linters/sugarss/stylelint.vim
index 6b0adf5a..6c705e46 100644
--- a/ale_linters/sugarss/stylelint.vim
+++ b/ale_linters/sugarss/stylelint.vim
@@ -13,9 +13,9 @@ endfunction
call ale#linter#Define('sugarss', {
\ 'name': 'stylelint',
-\ 'executable_callback': ale#node#FindExecutableFunc('sugarss_stylelint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'sugarss_stylelint', [
\ 'node_modules/.bin/stylelint',
-\ ]),
-\ 'command_callback': 'ale_linters#sugarss#stylelint#GetCommand',
+\ ])},
+\ 'command': function('ale_linters#sugarss#stylelint#GetCommand'),
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/swift/swiftlint.vim b/ale_linters/swift/swiftlint.vim
index 0f2ea8de..237c45d3 100644
--- a/ale_linters/swift/swiftlint.vim
+++ b/ale_linters/swift/swiftlint.vim
@@ -63,7 +63,7 @@ endfunction
call ale#linter#Define('swift', {
\ 'name': 'swiftlint',
-\ 'executable_callback': 'ale_linters#swift#swiftlint#GetExecutable',
-\ 'command_callback': 'ale_linters#swift#swiftlint#GetCommand',
+\ 'executable': function('ale_linters#swift#swiftlint#GetExecutable'),
+\ 'command': function('ale_linters#swift#swiftlint#GetCommand'),
\ 'callback': 'ale_linters#swift#swiftlint#Handle',
\})
diff --git a/ale_linters/tcl/nagelfar.vim b/ale_linters/tcl/nagelfar.vim
index 05fe581b..5a4940e1 100644
--- a/ale_linters/tcl/nagelfar.vim
+++ b/ale_linters/tcl/nagelfar.vim
@@ -32,8 +32,8 @@ endfunction
call ale#linter#Define('tcl', {
\ 'name': 'nagelfar',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('tcl_nagelfar_executable'),
-\ 'command_callback': 'ale_linters#tcl#nagelfar#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'tcl_nagelfar_executable')},
+\ 'command': function('ale_linters#tcl#nagelfar#GetCommand'),
\ 'callback': 'ale_linters#tcl#nagelfar#Handle',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/terraform/tflint.vim b/ale_linters/terraform/tflint.vim
index 0d77835a..6d54a8b1 100644
--- a/ale_linters/terraform/tflint.vim
+++ b/ale_linters/terraform/tflint.vim
@@ -52,7 +52,7 @@ endfunction
call ale#linter#Define('terraform', {
\ 'name': 'tflint',
-\ 'executable_callback': ale#VarFunc('terraform_tflint_executable'),
-\ 'command_callback': 'ale_linters#terraform#tflint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'terraform_tflint_executable')},
+\ 'command': function('ale_linters#terraform#tflint#GetCommand'),
\ 'callback': 'ale_linters#terraform#tflint#Handle',
\})
diff --git a/ale_linters/tex/chktex.vim b/ale_linters/tex/chktex.vim
index 7f1b0c72..160baf0d 100644
--- a/ale_linters/tex/chktex.vim
+++ b/ale_linters/tex/chktex.vim
@@ -49,6 +49,6 @@ endfunction
call ale#linter#Define('tex', {
\ 'name': 'chktex',
\ 'executable': 'chktex',
-\ 'command_callback': 'ale_linters#tex#chktex#GetCommand',
+\ 'command': function('ale_linters#tex#chktex#GetCommand'),
\ 'callback': 'ale_linters#tex#chktex#Handle'
\})
diff --git a/ale_linters/tex/lacheck.vim b/ale_linters/tex/lacheck.vim
index ee09fb41..19d69403 100644
--- a/ale_linters/tex/lacheck.vim
+++ b/ale_linters/tex/lacheck.vim
@@ -37,7 +37,7 @@ endfunction
call ale#linter#Define('tex', {
\ 'name': 'lacheck',
-\ 'executable_callback': ale#VarFunc('tex_lacheck_executable'),
+\ 'executable': {b -> ale#Var(b, 'tex_lacheck_executable')},
\ 'command': '%e %t',
\ 'callback': 'ale_linters#tex#lacheck#Handle'
\})
diff --git a/ale_linters/tex/textlint.vim b/ale_linters/tex/textlint.vim
index 0266ed85..5edac46d 100644
--- a/ale_linters/tex/textlint.vim
+++ b/ale_linters/tex/textlint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('tex', {
\ 'name': 'textlint',
-\ 'executable_callback': 'ale#handlers#textlint#GetExecutable',
-\ 'command_callback': 'ale#handlers#textlint#GetCommand',
+\ 'executable': function('ale#handlers#textlint#GetExecutable'),
+\ 'command': function('ale#handlers#textlint#GetCommand'),
\ 'callback': 'ale#handlers#textlint#HandleTextlintOutput',
\})
diff --git a/ale_linters/text/textlint.vim b/ale_linters/text/textlint.vim
index 8fafdd7d..67c4e378 100644
--- a/ale_linters/text/textlint.vim
+++ b/ale_linters/text/textlint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('text', {
\ 'name': 'textlint',
-\ 'executable_callback': 'ale#handlers#textlint#GetExecutable',
-\ 'command_callback': 'ale#handlers#textlint#GetCommand',
+\ 'executable': function('ale#handlers#textlint#GetExecutable'),
+\ 'command': function('ale#handlers#textlint#GetCommand'),
\ 'callback': 'ale#handlers#textlint#HandleTextlintOutput',
\})
diff --git a/ale_linters/thrift/thrift.vim b/ale_linters/thrift/thrift.vim
index 2f2086c9..345c7abe 100644
--- a/ale_linters/thrift/thrift.vim
+++ b/ale_linters/thrift/thrift.vim
@@ -80,9 +80,8 @@ endfunction
call ale#linter#Define('thrift', {
\ 'name': 'thrift',
-\ 'executable': 'thrift',
\ 'output_stream': 'both',
-\ 'executable_callback': ale#VarFunc('thrift_thrift_executable'),
-\ 'command_callback': 'ale_linters#thrift#thrift#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'thrift_thrift_executable')},
+\ 'command': function('ale_linters#thrift#thrift#GetCommand'),
\ 'callback': 'ale_linters#thrift#thrift#Handle',
\})
diff --git a/ale_linters/typescript/eslint.vim b/ale_linters/typescript/eslint.vim
index f1ae54e7..bf849337 100644
--- a/ale_linters/typescript/eslint.vim
+++ b/ale_linters/typescript/eslint.vim
@@ -3,7 +3,7 @@
call ale#linter#Define('typescript', {
\ 'name': 'eslint',
-\ 'executable_callback': 'ale#handlers#eslint#GetExecutable',
-\ 'command_callback': 'ale#handlers#eslint#GetCommand',
+\ 'executable': function('ale#handlers#eslint#GetExecutable'),
+\ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle',
\})
diff --git a/ale_linters/typescript/tslint.vim b/ale_linters/typescript/tslint.vim
index ccdca936..f70c2e45 100644
--- a/ale_linters/typescript/tslint.vim
+++ b/ale_linters/typescript/tslint.vim
@@ -69,7 +69,7 @@ endfunction
call ale#linter#Define('typescript', {
\ 'name': 'tslint',
-\ 'executable_callback': 'ale#handlers#tslint#GetExecutable',
-\ 'command_callback': 'ale_linters#typescript#tslint#GetCommand',
+\ 'executable': function('ale#handlers#tslint#GetExecutable'),
+\ 'command': function('ale_linters#typescript#tslint#GetCommand'),
\ 'callback': 'ale_linters#typescript#tslint#Handle',
\})
diff --git a/ale_linters/typescript/tsserver.vim b/ale_linters/typescript/tsserver.vim
index 7dc8fa85..840889f3 100644
--- a/ale_linters/typescript/tsserver.vim
+++ b/ale_linters/typescript/tsserver.vim
@@ -8,10 +8,10 @@ call ale#Set('typescript_tsserver_use_global', get(g:, 'ale_use_global_executabl
call ale#linter#Define('typescript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
-\ 'executable_callback': ale#node#FindExecutableFunc('typescript_tsserver', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'typescript_tsserver', [
\ 'node_modules/.bin/tsserver',
-\ ]),
+\ ])},
\ 'command': '%e',
-\ 'project_root_callback': 'ale#handlers#tsserver#GetProjectRoot',
+\ 'project_root': function('ale#handlers#tsserver#GetProjectRoot'),
\ 'language': '',
\})
diff --git a/ale_linters/verilog/iverilog.vim b/ale_linters/verilog/iverilog.vim
index c64a3be6..e081f33f 100644
--- a/ale_linters/verilog/iverilog.vim
+++ b/ale_linters/verilog/iverilog.vim
@@ -38,6 +38,6 @@ call ale#linter#Define('verilog', {
\ 'name': 'iverilog',
\ 'output_stream': 'stderr',
\ 'executable': 'iverilog',
-\ 'command_callback': 'ale_linters#verilog#iverilog#GetCommand',
+\ 'command': function('ale_linters#verilog#iverilog#GetCommand'),
\ 'callback': 'ale_linters#verilog#iverilog#Handle',
\})
diff --git a/ale_linters/verilog/verilator.vim b/ale_linters/verilog/verilator.vim
index 18d99043..64bb6e41 100644
--- a/ale_linters/verilog/verilator.vim
+++ b/ale_linters/verilog/verilator.vim
@@ -53,7 +53,7 @@ call ale#linter#Define('verilog', {
\ 'name': 'verilator',
\ 'output_stream': 'stderr',
\ 'executable': 'verilator',
-\ 'command_callback': 'ale_linters#verilog#verilator#GetCommand',
+\ 'command': function('ale_linters#verilog#verilator#GetCommand'),
\ 'callback': 'ale_linters#verilog#verilator#Handle',
\ 'read_buffer': 0,
\})
diff --git a/ale_linters/verilog/vlog.vim b/ale_linters/verilog/vlog.vim
index c7686291..37d21c4c 100644
--- a/ale_linters/verilog/vlog.vim
+++ b/ale_linters/verilog/vlog.vim
@@ -30,7 +30,7 @@ endfunction
call ale#linter#Define('verilog', {
\ 'name': 'vlog',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('verilog_vlog_executable'),
-\ 'command_callback': 'ale_linters#verilog#vlog#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'verilog_vlog_executable')},
+\ 'command': function('ale_linters#verilog#vlog#GetCommand'),
\ 'callback': 'ale_linters#verilog#vlog#Handle',
\})
diff --git a/ale_linters/verilog/xvlog.vim b/ale_linters/verilog/xvlog.vim
index 52498f8f..98b5aae7 100644
--- a/ale_linters/verilog/xvlog.vim
+++ b/ale_linters/verilog/xvlog.vim
@@ -29,7 +29,7 @@ endfunction
call ale#linter#Define('verilog', {
\ 'name': 'xvlog',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('verilog_xvlog_executable'),
-\ 'command_callback': 'ale_linters#verilog#xvlog#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'verilog_xvlog_executable')},
+\ 'command': function('ale_linters#verilog#xvlog#GetCommand'),
\ 'callback': 'ale_linters#verilog#xvlog#Handle',
\})
diff --git a/ale_linters/vhdl/ghdl.vim b/ale_linters/vhdl/ghdl.vim
index c21be242..b09e620b 100644
--- a/ale_linters/vhdl/ghdl.vim
+++ b/ale_linters/vhdl/ghdl.vim
@@ -31,7 +31,7 @@ endfunction
call ale#linter#Define('vhdl', {
\ 'name': 'ghdl',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('vhdl_ghdl_executable'),
-\ 'command_callback': 'ale_linters#vhdl#ghdl#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'vhdl_ghdl_executable')},
+\ 'command': function('ale_linters#vhdl#ghdl#GetCommand'),
\ 'callback': 'ale_linters#vhdl#ghdl#Handle',
\})
diff --git a/ale_linters/vhdl/vcom.vim b/ale_linters/vhdl/vcom.vim
index e4631b68..1914fd33 100644
--- a/ale_linters/vhdl/vcom.vim
+++ b/ale_linters/vhdl/vcom.vim
@@ -32,7 +32,7 @@ endfunction
call ale#linter#Define('vhdl', {
\ 'name': 'vcom',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('vhdl_vcom_executable'),
-\ 'command_callback': 'ale_linters#vhdl#vcom#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'vhdl_vcom_executable')},
+\ 'command': function('ale_linters#vhdl#vcom#GetCommand'),
\ 'callback': 'ale_linters#vhdl#vcom#Handle',
\})
diff --git a/ale_linters/vhdl/xvhdl.vim b/ale_linters/vhdl/xvhdl.vim
index 6e0d411d..8010ff14 100644
--- a/ale_linters/vhdl/xvhdl.vim
+++ b/ale_linters/vhdl/xvhdl.vim
@@ -31,7 +31,7 @@ endfunction
call ale#linter#Define('vhdl', {
\ 'name': 'xvhdl',
\ 'output_stream': 'stdout',
-\ 'executable_callback': ale#VarFunc('vhdl_xvhdl_executable'),
-\ 'command_callback': 'ale_linters#vhdl#xvhdl#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'vhdl_xvhdl_executable')},
+\ 'command': function('ale_linters#vhdl#xvhdl#GetCommand'),
\ 'callback': 'ale_linters#vhdl#xvhdl#Handle',
\})
diff --git a/ale_linters/vim/ale_custom_linting_rules.vim b/ale_linters/vim/ale_custom_linting_rules.vim
index 3abe5d4b..822eb30a 100644
--- a/ale_linters/vim/ale_custom_linting_rules.vim
+++ b/ale_linters/vim/ale_custom_linting_rules.vim
@@ -58,8 +58,8 @@ endfunction
call ale#linter#Define('vim', {
\ 'name': 'ale_custom_linting_rules',
-\ 'executable_callback': 'ale_linters#vim#ale_custom_linting_rules#GetExecutable',
-\ 'command_callback': 'ale_linters#vim#ale_custom_linting_rules#GetCommand',
+\ 'executable': function('ale_linters#vim#ale_custom_linting_rules#GetExecutable'),
+\ 'command': function('ale_linters#vim#ale_custom_linting_rules#GetCommand'),
\ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle',
\ 'read_buffer': 0,
\})
diff --git a/ale_linters/vim/vint.vim b/ale_linters/vim/vint.vim
index cf2d4afd..3808c47e 100644
--- a/ale_linters/vim/vint.vim
+++ b/ale_linters/vim/vint.vim
@@ -65,7 +65,7 @@ endfunction
call ale#linter#Define('vim', {
\ 'name': 'vint',
-\ 'executable_callback': 'ale_linters#vim#vint#GetExecutable',
+\ 'executable': function('ale_linters#vim#vint#GetExecutable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#vim#vint#VersionCommand', 'output_stream': 'stderr'},
\ {'callback': 'ale_linters#vim#vint#GetCommand', 'output_stream': 'stdout'},
diff --git a/ale_linters/vue/vls.vim b/ale_linters/vue/vls.vim
index 7116128b..ac451f3c 100644
--- a/ale_linters/vue/vls.vim
+++ b/ale_linters/vue/vls.vim
@@ -13,10 +13,10 @@ endfunction
call ale#linter#Define('vue', {
\ 'name': 'vls',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#node#FindExecutableFunc('vue_vls', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'vue_vls', [
\ 'node_modules/.bin/vls',
-\ ]),
+\ ])},
\ 'command': '%e --stdio',
\ 'language': 'vue',
-\ 'project_root_callback': 'ale_linters#vue#vls#GetProjectRoot',
+\ 'project_root': function('ale_linters#vue#vls#GetProjectRoot'),
\})
diff --git a/ale_linters/xml/xmllint.vim b/ale_linters/xml/xmllint.vim
index b003b096..553d0883 100644
--- a/ale_linters/xml/xmllint.vim
+++ b/ale_linters/xml/xmllint.vim
@@ -59,7 +59,7 @@ endfunction
call ale#linter#Define('xml', {
\ 'name': 'xmllint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': ale#VarFunc('xml_xmllint_executable'),
-\ 'command_callback': 'ale_linters#xml#xmllint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'xml_xmllint_executable')},
+\ 'command': function('ale_linters#xml#xmllint#GetCommand'),
\ 'callback': 'ale_linters#xml#xmllint#Handle',
\ })
diff --git a/ale_linters/yaml/swaglint.vim b/ale_linters/yaml/swaglint.vim
index 7362536e..1f140e37 100644
--- a/ale_linters/yaml/swaglint.vim
+++ b/ale_linters/yaml/swaglint.vim
@@ -32,9 +32,9 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'swaglint',
-\ 'executable_callback': ale#node#FindExecutableFunc('yaml_swaglint', [
+\ 'executable': {b -> ale#node#FindExecutable(b, 'yaml_swaglint', [
\ 'node_modules/.bin/swaglint',
-\ ]),
+\ ])},
\ 'command': '%e -r compact --stdin',
\ 'callback': 'ale_linters#yaml#swaglint#Handle',
\})
diff --git a/ale_linters/yaml/yamllint.vim b/ale_linters/yaml/yamllint.vim
index 9d2cc7c2..bedb7bf1 100644
--- a/ale_linters/yaml/yamllint.vim
+++ b/ale_linters/yaml/yamllint.vim
@@ -44,7 +44,7 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'yamllint',
-\ 'executable_callback': ale#VarFunc('yaml_yamllint_executable'),
-\ 'command_callback': 'ale_linters#yaml#yamllint#GetCommand',
+\ 'executable': {b -> ale#Var(b, 'yaml_yamllint_executable')},
+\ 'command': function('ale_linters#yaml#yamllint#GetCommand'),
\ 'callback': 'ale_linters#yaml#yamllint#Handle',
\})
diff --git a/ale_linters/yang/yang_lsp.vim b/ale_linters/yang/yang_lsp.vim
index 45776f98..81fcaa0e 100644
--- a/ale_linters/yang/yang_lsp.vim
+++ b/ale_linters/yang/yang_lsp.vim
@@ -9,7 +9,7 @@ endfunction
call ale#linter#Define('yang', {
\ 'name': 'yang_lsp',
\ 'lsp': 'stdio',
-\ 'executable_callback': ale#VarFunc('yang_lsp_executable'),
-\ 'project_root_callback': 'ale_linters#yang#yang_lsp#GetProjectRoot',
+\ 'executable': {b -> ale#Var(b, 'yang_lsp_executable')},
+\ 'project_root': function('ale_linters#yang#yang_lsp#GetProjectRoot'),
\ 'command': '%e',
\})
diff --git a/autoload/ale.vim b/autoload/ale.vim
index f6c23d72..5aa5fbfc 100644
--- a/autoload/ale.vim
+++ b/autoload/ale.vim
@@ -169,11 +169,6 @@ function! ale#Var(buffer, variable_name) abort
return get(l:vars, l:full_name, g:[l:full_name])
endfunction
-" As above, but curry the arguments so only the buffer number is required.
-function! ale#VarFunc(variable_name) abort
- return {buf -> ale#Var(buf, a:variable_name)}
-endfunction
-
" Initialize a variable with a default value, if it isn't already set.
"
" Every variable name will be prefixed with 'ale_'.
diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim
index ef2dab9e..6c2586a6 100644
--- a/autoload/ale/assert.vim
+++ b/autoload/ale/assert.vim
@@ -59,13 +59,18 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
endif
else
let l:command = ale#linter#GetCommand(l:buffer, l:linter)
+
+ while ale#command#IsDeferred(l:command)
+ call ale#test#FlushJobs()
+ let l:command = l:command.value
+ endwhile
endif
if type(l:command) is v:t_string
" Replace %e with the escaped executable, so tests keep passing after
" linters are changed to use %e.
let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g')
- else
+ elseif type(l:command) is v:t_list
call map(l:command, 'substitute(v:val, ''%e'', ''\=ale#Escape(l:executable)'', ''g'')')
endif
@@ -109,14 +114,6 @@ endfunction
function! ale#assert#LSPProject(expected_root) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
- let l:root = ale#util#GetFunction(l:linter.project_root_callback)(l:buffer)
-
- AssertEqual a:expected_root, l:root
-endfunction
-
-function! ale#assert#LSPProjectFull(expected_root) abort
- let l:buffer = bufnr('')
- let l:linter = s:GetLinter()
let l:root = ale#lsp_linter#FindProjectRoot(l:buffer, l:linter)
AssertEqual a:expected_root, l:root
@@ -125,7 +122,7 @@ endfunction
function! ale#assert#LSPAddress(expected_address) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
- let l:address = ale#util#GetFunction(l:linter.address_callback)(l:buffer)
+ let l:address = ale#linter#GetAddress(l:buffer, l:linter)
AssertEqual a:expected_address, l:address
endfunction
@@ -138,7 +135,6 @@ function! ale#assert#SetUpLinterTestCommands() abort
command! -nargs=+ AssertLSPConfig :call ale#assert#LSPConfig(<args>)
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
- command! -nargs=+ AssertLSPProjectFull :call ale#assert#LSPProjectFull(<args>)
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
endfunction
@@ -154,6 +150,12 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
let l:prefix = 'ale_' . a:filetype . '_' . a:name
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
+ Save g:ale_lsp_root
+ let g:ale_lsp_root = {}
+
+ Save b:ale_lsp_root
+ unlet! b:ale_lsp_root
+
Save g:ale_c_build_dir
unlet! g:ale_c_build_dir
@@ -211,10 +213,6 @@ function! ale#assert#TearDownLinterTest() abort
delcommand AssertLSPProject
endif
- if exists(':AssertLSPProjectFull')
- delcommand AssertLSPProjectFull
- endif
-
if exists(':AssertLSPAddress')
delcommand AssertLSPAddress
endif
diff --git a/autoload/ale/command.vim b/autoload/ale/command.vim
index 7a66dc77..33ce577c 100644
--- a/autoload/ale/command.vim
+++ b/autoload/ale/command.vim
@@ -320,6 +320,10 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
call ale#history#Add(a:buffer, l:status, l:job_id, l:command)
endif
+ if !l:job_id
+ return 0
+ endif
+
" We'll return this Dictionary. A `result_callback` can be assigned to it
" later for capturing the result of a:Callback.
"
diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim
index b4035422..340f6913 100644
--- a/autoload/ale/engine.vim
+++ b/autoload/ale/engine.vim
@@ -422,8 +422,16 @@ endfunction
" Run a job.
"
-" Returns 1 when the job was started successfully.
+" Returns 1 when a job was started successfully.
function! s:RunJob(command, options) abort
+ if ale#command#IsDeferred(a:command)
+ let a:command.result_callback = {
+ \ command -> s:RunJob(command, a:options)
+ \}
+
+ return 1
+ endif
+
let l:command = a:command
if empty(l:command)
@@ -451,7 +459,7 @@ function! s:RunJob(command, options) abort
\})
" Only proceed if the job is being run.
- if !l:result._deferred_job_id
+ if empty(l:result)
return 0
endif
diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim
index 7c428f52..b8674606 100644
--- a/autoload/ale/fix.vim
+++ b/autoload/ale/fix.vim
@@ -131,35 +131,55 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
\})
endfunction
-function! s:RunJob(options) abort
+function! s:RunJob(result, options) abort
+ if ale#command#IsDeferred(a:result)
+ let a:result.result_callback = {x -> s:RunJob(x, a:options)}
+
+ return
+ endif
+
let l:buffer = a:options.buffer
- let l:command = a:options.command
let l:input = a:options.input
- let l:ChainWith = a:options.chain_with
- let l:read_buffer = a:options.read_buffer
- if empty(l:command)
- " If there's nothing further to chain the command with, stop here.
- if l:ChainWith is v:null
- return v:false
+ if a:result is 0 || type(a:result) is v:t_list
+ if type(a:result) is v:t_list
+ let l:input = a:result
endif
- " If there's another chained callback to run, then run that.
call s:RunFixer({
\ 'buffer': l:buffer,
\ 'input': l:input,
- \ 'callback_index': a:options.callback_index,
+ \ 'callback_index': a:options.callback_index + 1,
+ \ 'callback_list': a:options.callback_list,
+ \})
+
+ return
+ endif
+
+ let l:command = get(a:result, 'command', '')
+ let l:ChainWith = get(a:result, 'chain_with', v:null)
+
+ if empty(l:command)
+ " If the command is empty, skip to the next item, or call the
+ " chain_with function.
+ call s:RunFixer({
+ \ 'buffer': l:buffer,
+ \ 'input': l:input,
+ \ 'callback_index': a:options.callback_index + (l:ChainWith is v:null),
\ 'callback_list': a:options.callback_list,
\ 'chain_callback': l:ChainWith,
\ 'output': [],
\})
- return v:true
+ return
endif
- let l:output_stream = a:options.output_stream
+ let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
+ " Default to piping the buffer for the last fixer in the chain.
+ let l:read_buffer = get(a:result, 'read_buffer', l:ChainWith is v:null)
+ let l:output_stream = get(a:result, 'output_stream', 'stdout')
- if a:options.read_temporary_file
+ if l:read_temporary_file
let l:output_stream = 'none'
endif
@@ -168,10 +188,10 @@ function! s:RunJob(options) abort
\ 'chain_with': l:ChainWith,
\ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list,
- \ 'process_with': a:options.process_with,
- \ 'read_temporary_file': a:options.read_temporary_file,
+ \ 'process_with': get(a:result, 'process_with', v:null),
+ \ 'read_temporary_file': l:read_temporary_file,
\}])
- let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
+ let l:run_result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'output_stream': l:output_stream,
\ 'executable': '',
\ 'read_buffer': l:read_buffer,
@@ -179,70 +199,54 @@ function! s:RunJob(options) abort
\ 'log_output': 0,
\})
- return l:result._deferred_job_id != 0
+ if empty(l:run_result)
+ call s:RunFixer({
+ \ 'buffer': l:buffer,
+ \ 'input': l:input,
+ \ 'callback_index': a:options.callback_index + 1,
+ \ 'callback_list': a:options.callback_list,
+ \})
+ endif
endfunction
function! s:RunFixer(options) abort
let l:buffer = a:options.buffer
let l:input = a:options.input
let l:index = a:options.callback_index
+
+ if len(a:options.callback_list) <= l:index
+ call ale#fix#ApplyFixes(l:buffer, l:input)
+
+ return
+ endif
+
let l:ChainCallback = get(a:options, 'chain_callback', v:null)
+ let l:Function = l:ChainCallback isnot v:null
+ \ ? ale#util#GetFunction(l:ChainCallback)
+ \ : a:options.callback_list[l:index]
+
" Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer')
- while len(a:options.callback_list) > l:index
- let l:Function = l:ChainCallback isnot v:null
- \ ? ale#util#GetFunction(l:ChainCallback)
- \ : a:options.callback_list[l:index]
-
- if l:ChainCallback isnot v:null
- " Chained commands accept (buffer, output, [input])
- let l:result = ale#util#FunctionArgCount(l:Function) == 2
- \ ? call(l:Function, [l:buffer, a:options.output])
- \ : call(l:Function, [l:buffer, a:options.output, copy(l:input)])
- else
- " Chained commands accept (buffer, [done, input])
- let l:result = ale#util#FunctionArgCount(l:Function) == 1
- \ ? call(l:Function, [l:buffer])
- \ : call(l:Function, [l:buffer, v:null, copy(l:input)])
- endif
-
- if type(l:result) is v:t_number && l:result == 0
- " When `0` is returned, skip this item.
- let l:index += 1
- elseif type(l:result) is v:t_list
- let l:input = l:result
- let l:index += 1
- else
- let l:ChainWith = get(l:result, 'chain_with', v:null)
- " Default to piping the buffer for the last fixer in the chain.
- let l:read_buffer = get(l:result, 'read_buffer', l:ChainWith is v:null)
-
- let l:job_ran = s:RunJob({
- \ 'buffer': l:buffer,
- \ 'command': l:result.command,
- \ 'input': l:input,
- \ 'output_stream': get(l:result, 'output_stream', 'stdout'),
- \ 'read_temporary_file': get(l:result, 'read_temporary_file', 0),
- \ 'read_buffer': l:read_buffer,
- \ 'chain_with': l:ChainWith,
- \ 'callback_list': a:options.callback_list,
- \ 'callback_index': l:index,
- \ 'process_with': get(l:result, 'process_with', v:null),
- \})
-
- if !l:job_ran
- " The job failed to run, so skip to the next item.
- let l:index += 1
- else
- " Stop here, we will handle exit later on.
- return
- endif
- endif
- endwhile
+ if l:ChainCallback isnot v:null
+ " Chained commands accept (buffer, output, [input])
+ let l:result = ale#util#FunctionArgCount(l:Function) == 2
+ \ ? call(l:Function, [l:buffer, a:options.output])
+ \ : call(l:Function, [l:buffer, a:options.output, copy(l:input)])
+ else
+ " Regular fixer commands accept (buffer, [input])
+ let l:result = ale#util#FunctionArgCount(l:Function) == 1
+ \ ? call(l:Function, [l:buffer])
+ \ : call(l:Function, [l:buffer, copy(l:input)])
+ endif
- call ale#fix#ApplyFixes(l:buffer, l:input)
+ call s:RunJob(l:result, {
+ \ 'buffer': l:buffer,
+ \ 'input': l:input,
+ \ 'callback_list': a:options.callback_list,
+ \ 'callback_index': l:index,
+ \})
endfunction
function! s:AddSubCallbacks(full_list, callbacks) abort
diff --git a/autoload/ale/fixers/generic.vim b/autoload/ale/fixers/generic.vim
index 1d88553e..cb8865b4 100644
--- a/autoload/ale/fixers/generic.vim
+++ b/autoload/ale/fixers/generic.vim
@@ -1,7 +1,7 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Generic functions for fixing files with.
-function! ale#fixers#generic#RemoveTrailingBlankLines(buffer, done, lines) abort
+function! ale#fixers#generic#RemoveTrailingBlankLines(buffer, lines) abort
let l:end_index = len(a:lines) - 1
while l:end_index > 0 && empty(a:lines[l:end_index])
@@ -12,7 +12,7 @@ function! ale#fixers#generic#RemoveTrailingBlankLines(buffer, done, lines) abort
endfunction
" Remove all whitespaces at the end of lines
-function! ale#fixers#generic#TrimWhitespace(buffer, done, lines) abort
+function! ale#fixers#generic#TrimWhitespace(buffer, lines) abort
let l:index = 0
let l:lines_new = range(len(a:lines))
diff --git a/autoload/ale/fixers/generic_python.vim b/autoload/ale/fixers/generic_python.vim
index 9a929b96..d55a23c3 100644
--- a/autoload/ale/fixers/generic_python.vim
+++ b/autoload/ale/fixers/generic_python.vim
@@ -2,7 +2,7 @@
" Description: Generic fixer functions for Python.
" Add blank lines before control statements.
-function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, done, lines) abort
+function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, lines) abort
let l:new_lines = []
let l:last_indent_size = 0
let l:last_line_is_blank = 0
@@ -41,7 +41,7 @@ endfunction
" This function breaks up long lines so that autopep8 or other tools can
" fix the badly-indented code which is produced as a result.
-function! ale#fixers#generic_python#BreakUpLongLines(buffer, done, lines) abort
+function! ale#fixers#generic_python#BreakUpLongLines(buffer, lines) abort
" Default to a maximum line length of 79
let l:max_line_length = 79
let l:conf = ale#path#FindNearestFile(a:buffer, 'setup.cfg')
diff --git a/autoload/ale/fixers/help.vim b/autoload/ale/fixers/help.vim
index 9fb0717b..b20740fe 100644
--- a/autoload/ale/fixers/help.vim
+++ b/autoload/ale/fixers/help.vim
@@ -1,7 +1,7 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Generic fixer functions for Vim help documents.
-function! ale#fixers#help#AlignTags(buffer, done, lines) abort
+function! ale#fixers#help#AlignTags(buffer, lines) abort
let l:new_lines = []
for l:line in a:lines
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index 86ee506c..4937a6d7 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -177,7 +177,8 @@ function! ale#linter#PreProcess(filetype, linter) abort
let l:obj.command = a:linter.command
if type(l:obj.command) isnot v:t_string
- throw '`command` must be a string if defined'
+ \&& type(l:obj.command) isnot v:t_func
+ throw '`command` must be a String or Function if defined'
endif
else
throw 'Either `command`, `executable_callback`, `command_chain` '
@@ -194,9 +195,16 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
if !l:needs_address
- if has_key(a:linter, 'address_callback')
- throw '`address_callback` cannot be used when lsp != ''socket'''
+ if has_key(a:linter, 'address') || has_key(a:linter, 'address_callback')
+ throw '`address` or `address_callback` cannot be used when lsp != ''socket'''
endif
+ elseif has_key(a:linter, 'address')
+ if type(a:linter.address) isnot v:t_string
+ \&& type(a:linter.address) isnot v:t_func
+ throw '`address` must be a String or Function if defined'
+ endif
+
+ let l:obj.address = a:linter.address
elseif has_key(a:linter, 'address_callback')
let l:obj.address_callback = a:linter.address_callback
@@ -204,7 +212,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`address_callback` must be a callback if defined'
endif
else
- throw '`address_callback` must be defined for getting the LSP address'
+ throw '`address` or `address_callback` must be defined for getting the LSP address'
endif
if l:needs_lsp_details
@@ -221,20 +229,34 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
else
" Default to using the filetype as the language.
- let l:obj.language = get(a:linter, 'language', a:filetype)
-
- if type(l:obj.language) isnot v:t_string
- throw '`language` must be a string'
+ let l:Language = get(a:linter, 'language', a:filetype)
+
+ if type(l:Language) is v:t_string
+ " Make 'language_callback' return the 'language' value.
+ let l:obj.language = l:Language
+ let l:obj.language_callback = function('s:LanguageGetter')
+ elseif type(l:Language) is v:t_func
+ let l:obj.language_callback = l:Language
+ else
+ throw '`language` must be a String or Funcref'
endif
-
- " Make 'language_callback' return the 'language' value.
- let l:obj.language_callback = function('s:LanguageGetter')
endif
- let l:obj.project_root_callback = get(a:linter, 'project_root_callback')
+ if has_key(a:linter, 'project_root')
+ let l:obj.project_root = a:linter.project_root
- if !s:IsCallback(l:obj.project_root_callback)
- throw '`project_root_callback` must be a callback for LSP linters'
+ if type(l:obj.project_root) isnot v:t_string
+ \&& type(l:obj.project_root) isnot v:t_func
+ throw '`project_root` must be a String or Function if defined'
+ endif
+ elseif has_key(a:linter, 'project_root_callback')
+ let l:obj.project_root_callback = a:linter.project_root_callback
+
+ if !s:IsCallback(l:obj.project_root_callback)
+ throw '`project_root_callback` must be a callback if defined'
+ endif
+ else
+ throw '`project_root` or `project_root_callback` must be defined for LSP linters'
endif
if has_key(a:linter, 'completion_filter')
@@ -258,6 +280,11 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options
+
+ if type(l:obj.initialization_options) isnot v:t_dict
+ \&& type(l:obj.initialization_options) isnot v:t_func
+ throw '`initialization_options` must be a String or Function if defined'
+ endif
endif
if has_key(a:linter, 'lsp_config_callback')
@@ -272,7 +299,8 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
elseif has_key(a:linter, 'lsp_config')
if type(a:linter.lsp_config) isnot v:t_dict
- throw '`lsp_config` must be a Dictionary'
+ \&& type(a:linter.lsp_config) isnot v:t_func
+ throw '`lsp_config` must be a Dictionary or Function if defined'
endif
let l:obj.lsp_config = a:linter.lsp_config
@@ -312,6 +340,8 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`aliases` must be a List of String values'
endif
+ " TODO: Emit deprecation warnings for deprecated options later.
+
return l:obj
endfunction
@@ -489,14 +519,22 @@ endfunction
" Given a buffer and linter, get the command String for the linter.
" The command_chain key is not supported.
function! ale#linter#GetCommand(buffer, linter) abort
- return has_key(a:linter, 'command_callback')
- \ ? ale#util#GetFunction(a:linter.command_callback)(a:buffer)
+ let l:Command = has_key(a:linter, 'command_callback')
+ \ ? function(a:linter.command_callback)
\ : a:linter.command
+
+ return type(l:Command) is v:t_func
+ \ ? l:Command(a:buffer)
+ \ : l:Command
endfunction
" Given a buffer and linter, get the address for connecting to the server.
function! ale#linter#GetAddress(buffer, linter) abort
- return has_key(a:linter, 'address_callback')
- \ ? ale#util#GetFunction(a:linter.address_callback)(a:buffer)
+ let l:Address = has_key(a:linter, 'address_callback')
+ \ ? function(a:linter.address_callback)
\ : a:linter.address
+
+ return type(l:Address) is v:t_func
+ \ ? l:Address(a:buffer)
+ \ : l:Address
endfunction
diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim
index 8da95ef6..7186d2a9 100644
--- a/autoload/ale/lsp.vim
+++ b/autoload/ale/lsp.vim
@@ -57,6 +57,15 @@ function! ale#lsp#RemoveConnectionWithID(id) abort
endif
endfunction
+function! ale#lsp#ResetConnections() abort
+ let s:connections = {}
+endfunction
+
+" Used only in tests.
+function! ale#lsp#GetConnections() abort
+ return s:connections
+endfunction
+
" This is only needed for tests
function! ale#lsp#MarkDocumentAsOpen(id, buffer) abort
let l:conn = get(s:connections, a:id, {})
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index 610d897f..d544916a 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -129,27 +129,39 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
endfunction
function! ale#lsp_linter#GetOptions(buffer, linter) abort
- let l:initialization_options = {}
-
if has_key(a:linter, 'initialization_options_callback')
- let l:initialization_options = ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
- elseif has_key(a:linter, 'initialization_options')
- let l:initialization_options = a:linter.initialization_options
+ return ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer)
+ endif
+
+ if has_key(a:linter, 'initialization_options')
+ let l:Options = a:linter.initialization_options
+
+ if type(l:Options) is v:t_func
+ let l:Options = l:Options(a:buffer)
+ endif
+
+ return l:Options
endif
- return l:initialization_options
+ return {}
endfunction
function! ale#lsp_linter#GetConfig(buffer, linter) abort
- let l:config = {}
-
if has_key(a:linter, 'lsp_config_callback')
- let l:config = ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer)
- elseif has_key(a:linter, 'lsp_config')
- let l:config = a:linter.lsp_config
+ return ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer)
endif
- return l:config
+ if has_key(a:linter, 'lsp_config')
+ let l:Config = a:linter.lsp_config
+
+ if type(l:Config) is v:t_func
+ let l:Config = l:Config(a:buffer)
+ endif
+
+ return l:Config
+ endif
+
+ return {}
endfunction
function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
@@ -182,6 +194,12 @@ function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
endif
" Fall back to the linter-specific configuration
+ if has_key(a:linter, 'project_root')
+ let l:Root = a:linter.project_root
+
+ return type(l:Root) is v:t_func ? l:Root(a:buffer) : l:Root
+ endif
+
return ale#util#GetFunction(a:linter.project_root_callback)(a:buffer)
endfunction
@@ -210,69 +228,134 @@ function! ale#lsp_linter#OnInit(linter, details, Callback) abort
call a:Callback(a:linter, a:details)
endfunction
-" Given a buffer, an LSP linter, start up an LSP linter and get ready to
-" receive messages for the document.
-function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
- let l:command = ''
- let l:address = ''
- let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter)
-
- if empty(l:root) && a:linter.lsp isnot# 'tsserver'
- " If there's no project root, then we can't check files with LSP,
- " unless we are using tsserver, which doesn't use project roots.
- return 0
- endif
+function! s:StartLSP(options, address, executable, command) abort
+ let l:buffer = a:options.buffer
+ let l:linter = a:options.linter
+ let l:root = a:options.root
+ let l:Callback = a:options.callback
- let l:init_options = ale#lsp_linter#GetOptions(a:buffer, a:linter)
+ let l:init_options = ale#lsp_linter#GetOptions(l:buffer, l:linter)
- if a:linter.lsp is# 'socket'
- let l:address = ale#linter#GetAddress(a:buffer, a:linter)
- let l:conn_id = ale#lsp#Register(l:address, l:root, l:init_options)
- let l:ready = ale#lsp#ConnectToAddress(l:conn_id, l:address)
+ if l:linter.lsp is# 'socket'
+ let l:conn_id = ale#lsp#Register(a:address, l:root, l:init_options)
+ let l:ready = ale#lsp#ConnectToAddress(l:conn_id, a:address)
+ let l:command = ''
else
- let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
-
- if !ale#engine#IsExecutable(a:buffer, l:executable)
- return 0
- endif
-
- let l:conn_id = ale#lsp#Register(l:executable, l:root, l:init_options)
+ let l:conn_id = ale#lsp#Register(a:executable, l:root, l:init_options)
" tsserver behaves differently, so tell the LSP API that it is tsserver.
- if a:linter.lsp is# 'tsserver'
+ if l:linter.lsp is# 'tsserver'
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif
- let l:command = ale#linter#GetCommand(a:buffer, a:linter)
- " Format the command, so %e can be formatted into it.
- let l:command = ale#command#FormatCommand(a:buffer, l:executable, l:command, 0, v:false)[1]
- let l:command = ale#job#PrepareCommand(a:buffer, l:command)
- let l:ready = ale#lsp#StartProgram(l:conn_id, l:executable, l:command)
+ let l:command = ale#command#FormatCommand(l:buffer, a:executable, a:command, 0, v:false)[1]
+ let l:command = ale#job#PrepareCommand(l:buffer, l:command)
+ let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
endif
if !l:ready
- if g:ale_history_enabled && !empty(l:command)
- call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
+ if g:ale_history_enabled && !empty(a:command)
+ call ale#history#Add(l:buffer, 'failed', l:conn_id, a:command)
endif
return 0
endif
-
let l:details = {
- \ 'buffer': a:buffer,
+ \ 'buffer': l:buffer,
\ 'connection_id': l:conn_id,
\ 'command': l:command,
\ 'project_root': l:root,
\}
call ale#lsp#OnInit(l:conn_id, {->
- \ ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)
+ \ ale#lsp_linter#OnInit(l:linter, l:details, l:Callback)
\})
return 1
endfunction
+function! s:StartWithAddress(options, address) abort
+ if ale#command#IsDeferred(a:address)
+ let a:address.result_callback = {
+ \ address -> s:StartWithAddress(a:options, address)
+ \}
+
+ return 1
+ endif
+
+ if empty(a:address)
+ return 0
+ endif
+
+ return s:StartLSP(a:options, a:address, '', '')
+endfunction
+
+function! s:StartWithCommand(options, executable, command) abort
+ if ale#command#IsDeferred(a:command)
+ let a:command.result_callback = {
+ \ command -> s:StartWithCommand(a:options, a:executable, command)
+ \}
+
+ return 1
+ endif
+
+ if empty(a:command)
+ return 0
+ endif
+
+ return s:StartLSP(a:options, '', a:executable, a:command)
+endfunction
+
+function! s:StartIfExecutable(options, executable) abort
+ if ale#command#IsDeferred(a:executable)
+ let a:executable.result_callback = {
+ \ executable -> s:StartIfExecutable(a:options, executable)
+ \}
+
+ return 1
+ endif
+
+ if !ale#engine#IsExecutable(a:options.buffer, a:executable)
+ return 0
+ endif
+
+ let l:command = ale#linter#GetCommand(a:options.buffer, a:options.linter)
+
+ return s:StartWithCommand(a:options, a:executable, l:command)
+endfunction
+
+" Given a buffer, an LSP linter, start up an LSP linter and get ready to
+" receive messages for the document.
+function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
+ let l:command = ''
+ let l:address = ''
+ let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter)
+
+ if empty(l:root) && a:linter.lsp isnot# 'tsserver'
+ " If there's no project root, then we can't check files with LSP,
+ " unless we are using tsserver, which doesn't use project roots.
+ return 0
+ endif
+
+ let l:options = {
+ \ 'buffer': a:buffer,
+ \ 'linter': a:linter,
+ \ 'callback': a:Callback,
+ \ 'root': l:root,
+ \}
+
+ if a:linter.lsp is# 'socket'
+ let l:address = ale#linter#GetAddress(a:buffer, a:linter)
+
+ return s:StartWithAddress(l:options, l:address)
+ endif
+
+ let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
+
+ return s:StartIfExecutable(l:options, l:executable)
+endfunction
+
function! s:CheckWithLSP(linter, details) abort
let l:buffer = a:details.buffer
let l:info = get(g:ale_buffer_info, l:buffer)
diff --git a/autoload/ale/node.vim b/autoload/ale/node.vim
index 5c579c75..f75280b7 100644
--- a/autoload/ale/node.vim
+++ b/autoload/ale/node.vim
@@ -23,11 +23,6 @@ function! ale#node#FindExecutable(buffer, base_var_name, path_list) abort
return ale#Var(a:buffer, a:base_var_name . '_executable')
endfunction
-" As above, but curry the arguments so only the buffer number is required.
-function! ale#node#FindExecutableFunc(base_var_name, path_list) abort
- return {buf -> ale#node#FindExecutable(buf, a:base_var_name, a:path_list)}
-endfunction
-
" Create a executable string which executes a Node.js script command with a
" Node.js executable if needed.
"
diff --git a/autoload/ale/path.vim b/autoload/ale/path.vim
index 89b119f4..ca3afc52 100644
--- a/autoload/ale/path.vim
+++ b/autoload/ale/path.vim
@@ -197,15 +197,18 @@ function! ale#path#ToURI(path) abort
endfunction
function! ale#path#FromURI(uri) abort
- let l:i = len('file://')
- let l:encoded_path = a:uri[: l:i - 1] is# 'file://' ? a:uri[l:i :] : a:uri
-
- let l:path = ale#uri#Decode(l:encoded_path)
+ if a:uri[:6] is? 'file://'
+ let l:encoded_path = a:uri[7:]
+ elseif a:uri[:4] is? 'file:'
+ let l:encoded_path = a:uri[5:]
+ else
+ let l:encoded_path = a:uri
+ endif
" If the path is like /C:/foo/bar, it should be C:\foo\bar instead.
- if l:path =~# '^/[a-zA-Z]:'
- let l:path = substitute(l:path[1:], '/', '\\', 'g')
+ if l:encoded_path =~# '^/[a-zA-Z]:'
+ let l:encoded_path = substitute(l:encoded_path[1:], '/', '\\', 'g')
endif
- return l:path
+ return ale#uri#Decode(l:encoded_path)
endfunction
diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim
index c911c046..2f28214b 100644
--- a/autoload/ale/python.vim
+++ b/autoload/ale/python.vim
@@ -28,6 +28,8 @@ function! ale#python#FindProjectRootIni(buffer) abort
\|| filereadable(l:path . '/flake8.cfg')
\|| filereadable(l:path . '/.flake8rc')
\|| filereadable(l:path . '/pylama.ini')
+ \|| filereadable(l:path . '/pylintrc')
+ \|| filereadable(l:path . '/.pylintrc')
\|| filereadable(l:path . '/Pipfile')
\|| filereadable(l:path . '/Pipfile.lock')
return l:path
diff --git a/autoload/ale/toggle.vim b/autoload/ale/toggle.vim
index 8e642b3f..1311e527 100644
--- a/autoload/ale/toggle.vim
+++ b/autoload/ale/toggle.vim
@@ -13,6 +13,10 @@ function! s:DisablePostamble() abort
if g:ale_set_highlights
call ale#highlight#UpdateHighlights()
endif
+
+ if g:ale_virtualtext_cursor
+ call ale#virtualtext#Clear()
+ endif
endfunction
function! ale#toggle#Toggle() abort
diff --git a/doc/ale-python.txt b/doc/ale-python.txt
index f74e4e83..dd946ad4 100644
--- a/doc/ale-python.txt
+++ b/doc/ale-python.txt
@@ -32,6 +32,8 @@ ALE will look for configuration files with the following filenames. >
flake8.cfg
.flake8rc
pylama.ini
+ pylintrc
+ .pylintrc
Pipfile
Pipfile.lock
<
@@ -88,6 +90,17 @@ g:ale_python_bandit_options *g:ale_python_bandit_options*
bandit invocation.
+g:ale_python_bandit_use_config *g:ale_python_bandit_use_config*
+ *b:ale_python_bandit_use_config*
+ Type: |Number|
+ Default: `1`
+
+ If this variable is true and a `.bandit` file exists in the directory of the
+ file being checked or a parent directory, an `--ini` option is added to the
+ `bandit` command for the nearest `.bandit` file. Set this variable false to
+ disable adding the `--ini` option automatically.
+
+
g:ale_python_bandit_use_global *g:ale_python_bandit_use_global*
*b:ale_python_bandit_use_global*
Type: |Number|
@@ -512,10 +525,12 @@ g:ale_python_pylint_change_directory *g:ale_python_pylint_change_directory*
Type: |Number|
Default: `1`
- If set to `1`, ALE will switch to the directory the Python file being
- checked with `pylint` is in before checking it. This helps `pylint` find
- configuration files more easily. This option can be turned off if you want
- to control the directory Python is executed from yourself.
+ If set to `1`, `pylint` will be run from a detected project root, per
+ |ale-python-root|. Since `pylint` only checks for `pylintrc` in the packages
+ above its current directory before falling back to user and global `pylintrc`
+ files, this is necessary for `pylint` to use a project `pylintrc` file, if
+ present. This option can be turned off if you want to control the directory
+ Python is executed from yourself.
g:ale_python_pylint_executable *g:ale_python_pylint_executable*
diff --git a/doc/ale-rust.txt b/doc/ale-rust.txt
index 7510dfbd..3393b9c0 100644
--- a/doc/ale-rust.txt
+++ b/doc/ale-rust.txt
@@ -172,6 +172,20 @@ g:ale_rust_rls_toolchain *g:ale_rust_rls_toolchain*
The `rls` server will only be started once per executable.
+g:ale_rust_rls_config *g:ale_rust_rls_config*
+ *b:ale_rust_rls_config*
+ Type: |Dictionary|
+ Default: `{}`
+
+ Dictionary with configuration settings for rls. For example, to force
+ using clippy as linter: >
+ {
+ \ 'rust': {
+ \ 'clippy_preference': 'on'
+ \ }
+ \ }
+
+
===============================================================================
rustc *ale-rust-rustc*
diff --git a/doc/ale.txt b/doc/ale.txt
index 22639251..44ddb2e2 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -578,14 +578,10 @@ The values for `g:ale_fixers` can be a list of |String|, |Funcref|, or
for a function set in the ALE fixer registry.
Each function for fixing errors must accept either one argument `(buffer)` or
-three arguments `(buffer, done, lines)`, representing the buffer being fixed,
-a function to call with results, and the lines to fix. The functions must
-return either `0`, for changing nothing, a |List| for new lines to set, a
-|Dictionary| for describing a command to be run in the background, or `v:true`
-for indicating that results will be provided asynchronously via the `done`
-callback.
-
-NOTE: The `done` function has not been implemented yet.
+two arguments `(buffer, lines)`, representing the buffer being fixed and the
+lines to fix. The functions must return either `0`, for changing nothing, a
+|List| for new lines to set, a |Dictionary| for describing a command to be
+run in the background, or the result of |ale#command#Run()|.
Functions receiving a variable number of arguments will not receive the second
argument `lines`. Functions should name two arguments if the `lines` argument
@@ -615,26 +611,6 @@ are supported for running the commands.
A |List| of |String|s must be returned.
- `chain_with` An optional key for defining a callback to call next.
-
- The callback must accept two or three arguments,
- `(buffer, output)` or `(buffer, output, input)` .
- Functions receiving a variable number of arguments will
- only receive the first two values. The `output` argument
- will contain the lines of output from the command run.
- The `input` argument is the List of lines for the
- buffer, after applying any previous fixers.
-
- The callback must return the same values returned for
- any fixer function. This allows fixer functions to be
- chained recursively.
-
- When the command string returned for a fixer is an empty
- string, the next command in the chain will still be run.
- This allows commands to be skipped, like version checks
- that are cached. An empty List will be passed to the
- next callback in the chain for the `output`.
-
`read_buffer` An optional key for disabling reading the buffer.
When set to `0`, ALE will not pipe the buffer's data
@@ -642,10 +618,7 @@ are supported for running the commands.
the buffer is not read when `read_temporary_file` is
`1`.
- This option defaults to `0` when `chain_with` is defined
- as anything other than `v:null`, and defaults to `1`
- otherwise. This is so earlier commands in a chain
- do not receive the buffer's data by default.
+ This option defaults to `1`.
*ale-fix-configuration*
@@ -2940,6 +2913,85 @@ ale#command#CreateFile(buffer) *ale#command#CreateFile()*
returning a linter command to run.
+ale#command#Run(buffer, command, callback, [options]) *ale#command#Run()*
+
+ Start running a job in the background, and pass the results to the given
+ callback later.
+
+ This function can be used for computing the results of ALE linter or fixer
+ functions asynchronously with jobs. `buffer` must match the buffer being
+ linted or fixed, `command` must be a |String| for a shell command to
+ execute, `callback` must be defined as a |Funcref| to call later with the
+ results, and an optional |Dictionary| of `options` can be provided.
+
+ The `callback` will receive the arguments `(buffer, output, metadata)`,
+ where the `buffer` will match the buffer given to the function, the `output`
+ will be a `List` of lines of output from the job that was run, and the
+ `metadata` will be a |Dictionary| with additional information about the job
+ that was run, including:
+
+ `exit_code` - A |Number| with the exit code for the program that was run.
+
+ The result of this function is either a special |Dictionary| ALE will use
+ for waiting for the command to finish, or `0` if the job is not started. The
+ The return value of the `callback` will be used as the eventual result for
+ whatever value is being given to ALE. For example: >
+
+ function! s:GetCommand(buffer, output, meta) abort
+ " Do something with a:output here, from the foo command.
+
+ " This is used as the command to run for linting.
+ return 'final command'
+ endfunction
+
+ " ...
+
+ 'command': {b -> ale#command#Run(b, 'foo', function('s:GetCommand'))}
+<
+ The result of a callback can also be the result of another call to this
+ function, so that several commands can be arbitrarily chained together. For
+ example: >
+
+ function! s:GetAnotherCommand(buffer, output, meta) abort
+ " We can finally return this command.
+ return 'last command'
+ endfunction
+
+ function! s:GetCommand(buffer, output, meta) abort
+ " We can return another deferred result.
+ return ale#command#Run(
+ \ a:buffer,
+ \ 'second command',
+ \ function('s:GetAnotherCommand')
+ \)
+ endfunction
+
+ " ...
+
+ 'command': {b -> ale#command#Run(b, 'foo', function('s:GetCommand'))}
+<
+
+ The following `options` can be provided.
+
+ `output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or `'none`' for
+ selecting which output streams to read lines from.
+
+ The default is `'stdout'`
+
+ `executable` - An executable for formatting into `%e` in the command.
+ If this option is not provided, formatting commands with
+ `%e` will not work.
+
+ `read_buffer` - If set to `1`, the buffer will be piped into the
+ command.
+
+ The default is `0`.
+
+ `input` - When creating temporary files with `%t` or piping text
+ into a command `input` can be set to a |List| of text to
+ use instead of the buffer's text.
+
+
ale#command#EscapeCommandPart(command_part) *ale#command#EscapeCommandPart()*
Given a |String|, return a |String| with all `%` characters replaced with
@@ -3110,74 +3162,26 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
for computing the executable, accepting a buffer
number.
- This value will be used to check if the
- program requested is installed or not.
+ The result can be computed with |ale#command#Run()|.
+
+ This value will be used to check if the program
+ requested is installed or not.
- Either this or the `executable_callback` argument
- must be provided.
+ If an `executable` is not defined, the command will
+ be run without checking if a program is executable
+ first. Defining an executable path is recommended to
+ avoid starting too many processes.
- `executable_callback ` A |String| or |Funcref| for a callback function
- accepting a buffer number. A |String| should be
- returned for the executable to check. This can be
- used in place of `executable` when more complicated
- processing is needed.
+ `command` A |String| for a command to run asynchronously, or a
+ |Funcref| for a function to call for computing the
+ command, accepting a buffer number.
+
+ The result can be computed with |ale#command#Run()|.
- `command` A |String| for an executable to run asynchronously.
This command will be fed the lines from the buffer to
check, and will produce the lines of output given to
the `callback`.
- `command_callback` A |String| or |Funcref| for a callback function
- accepting a buffer number. A |String| should be
- returned for a command to run. This can be used in
- place of `command` when more complicated processing
- is needed.
-
- If an empty string is returned from the callback,
- no jobs for linting will be run for that linter.
- This can be used for skipping a linter call,
- say if no configuration file was found.
-
- *ale-command-chain*
- `command_chain` A |List| of |Dictionary| items defining a series
- of commands to be run. At least one |Dictionary|
- should be provided. Each Dictionary must contain the
- key `callback`, defining a |String| or |Funcref| for
- a function returning a |String| for a command to run.
-
- The callback functions for each command after the
- first command in in the chain should accept two
- arguments `(buffer, output)`, a buffer number and a
- |List| of lines of output from the previous command
- in the chain.
-
- The first callback function in a chain accepts only
- a `(buffer)` argument, as there are no previous
- commands to run which return `output`.
-
- If an empty string is returned for a command in a
- chain, that command in the chain will be skipped,
- and the next function in the chain will be called
- immediately instead. If the last command in a chain
- returns an empty string, then no linting will be
- performed.
-
- Commands in the chain will all use the
- `output_stream` value provided in the root
- |Dictionary|. Each command in the chain can also
- provide an `output_stream` key to override this value.
- See the `output_stream` description for more
- information.
-
- Commands in the chain all behave as if `read_buffer`
- is set to `0` by default, except for the last command
- in the chain, which uses the value set for
- `read_buffer` in the root |Dictionary|. Each command
- in the chain can also provide a `read_buffer` key
- to override these values.
- See the `read_buffer` description for more
- information.
-
`output_stream` A |String| for the output stream the lines of output
should be read from for the command which is run. The
accepted values are `'stdout'`, `'stderr'`, and
@@ -3223,21 +3227,20 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
linter will be defined as an LSP linter which keeps a
process for a language server running, and
communicates with it directly via a |channel|.
- `executable` or `executable_callback` must be set,
- and `command` or `command_callback` must be set.
+ `executable` and `command` must be set.
When this argument is set to `'socket'`, then the
linter will be defined as an LSP linter via a TCP
- socket connection. `address_callback` must be set
- with a callback returning an address to connect to.
+ socket connection. `address` must be set.
+
ALE will not start a server automatically.
- When this argument is not empty
- `project_root_callback` must be defined.
+ When this argument is not empty `project_root` must
+ be defined.
- `language` or `language_callback` can be defined to
- describe the language for a file. The filetype will
- be used as the language by default.
+ `language` can be defined to describe the language
+ for a file. The filetype will be used as the language
+ by default.
LSP linters handle diagnostics automatically, so
the `callback` argument must not be defined.
@@ -3245,45 +3248,41 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
An optional `completion_filter` callback may be
defined for filtering completion results.
- An optional `initialization_options` or
- `initialization_options_callback` may be defined to
- pass initialization options to the LSP.
+ `initialization_options` may be defined to pass
+ initialization options to the LSP.
- An optional `lsp_config` or `lsp_config_callback` may
- be defined to pass configuration settings to the LSP.
+ `lsp_config` may be defined to pass configuration
+ settings to the LSP.
- `address_callback` A |String| or |Funcref| for a callback function
- accepting a buffer number. A |String| should be
- returned with an address to connect to.
+ `address` A |String| representing an address to connect to,
+ or a |Funcref| accepting a buffer number and
+ returning the |String|.
+
+ The result can be computed with |ale#command#Run()|.
This argument must only be set if the `lsp` argument
is set to `'socket'`.
- `project_root_callback` A |String| or |Funcref| for a callback function
- accepting a buffer number. A |String| should be
- returned representing the path to the project for the
- file being checked with the language server. If an
- empty string is returned, the file will not be
+ `project_root` A |String| representing a path to the project for
+ the file being checked with the language server, or
+ a |Funcref| accepting a buffer number and returning
+ the |String|.
+
+ If an empty string is returned, the file will not be
checked at all.
This argument must only be set if the `lsp` argument
is also set to a non-empty string.
`language` A |String| representing the name of the language
- being checked. This string will be sent to the LSP to
- tell it what type of language is being checked.
+ being checked, or a |Funcref| accepting a buffer
+ number and returning the |String|. This string will
+ be sent to the LSP to tell it what type of language
+ is being checked.
- If this or `language_callback` isn't set, the
- language will default to the value of the filetype
- given to |ale#linter#Define|.
-
- `language_callback` A |String| or |Funcref| for a callback function
- accepting a buffer number. A |String| should be
- returned representing the name of the language being
- checked.
-
- This option can be used instead of `language` if a
- linter can check multiple languages.
+ If a language isn't provided, the language will
+ default to the value of the filetype given to
+ |ale#linter#Define|.
`completion_filter` A |String| or |Funcref| for a callback function
accepting a buffer number and a completion item.
@@ -3301,38 +3300,24 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
setting can make it easier to guess the linter name
by offering a few alternatives.
- `initialization_options` A |Dictionary| of initialization options for LSPs.
+ `initialization_options` A |Dictionary| of initialization options for LSPs,
+ or a |Funcref| for a callback function accepting
+ a buffer number and returning the |Dictionary|.
+
This will be fed (as JSON) to the LSP in the
initialize command.
- `initialization_options_callback`
- A |String| or |Funcref| for a callback function
- accepting a buffer number. A |Dictionary| should be
- returned for initialization options to pass the LSP.
- This can be used in place of `initialization_options`
- when more complicated processing is needed.
+ `lsp_config` A |Dictionary| for configuring a language server,
+ or a |Funcref| for a callback function accepting
+ a buffer number and returning the |Dictionary|.
- `lsp_config` A |Dictionary| of configuration settings for LSPs.
This will be fed (as JSON) to the LSP in the
workspace/didChangeConfiguration command.
- `lsp_config_callback` A |String| or |Funcref| for a callback function
- accepting a buffer number. A |Dictionary| should be
- returned for configuration settings to pass the LSP.
- This can be used in place of `lsp_config` when more
- complicated processing is needed.
-
- Only one of `command`, `command_callback`, or `command_chain` should be
- specified. `command_callback` is generally recommended when a command string
- needs to be generated dynamically, or any global options are used.
- `command_chain` is recommended where any system calls need to be made to
- retrieve some kind of information before running the final command.
-
If temporary files or directories are created for commands run with
- `command_callback` or `command_chain`, then these tempoary files or
- directories can be managed by ALE, for automatic deletion.
- See |ale#engine#ManageFile()| and |ale#engine#ManageDirectory| for more
- information.
+ `command`, then these temporary files or directories can be managed by ALE,
+ for automatic deletion. See |ale#command#ManageFile()| and
+ |ale#command#ManageDirectory| for more information.
*ale-command-format-strings*
@@ -3350,16 +3335,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
strings will reference the one temporary file. The temporary file will be
created inside a temporary directory, and the entire temporary directory
will be automatically deleted, following the behaviour of
- |ale#engine#ManageDirectory|. This option can be used for some linters which
+ |ale#command#ManageDirectory|. This option can be used for some linters which
do not support reading from stdin.
For example: >
'command': 'ghc -fno-code -v0 %t',
<
Any substring `%e` will be replaced with the escaped executable supplied
- with `executable` or `executable_callback`. This provides a convenient way
- to define a command string which needs to include a dynamic executable name,
- but which is otherwise static.
+ with `executable`. This provides a convenient way to define a command string
+ which needs to include a dynamic executable name, but which is otherwise
+ static.
For example: >
'command': '%e --some-argument',
@@ -3370,7 +3355,7 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
If a callback for a command generates part of a command string which might
possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting
- behavior is not desired, the |ale#engine#EscapeCommandPart()| function can
+ behavior is not desired, the |ale#command#EscapeCommandPart()| function can
be used to replace those characters to avoid formatting issues.
*ale-linter-loading-behavior*
diff --git a/test/command_callback/python_paths/with_bandit/.bandit b/test/command_callback/python_paths/with_bandit/.bandit
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_bandit/.bandit
diff --git a/test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py b/test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py
diff --git a/test/command_callback/python_paths/with_bandit/namespace/foo/bar.py b/test/command_callback/python_paths/with_bandit/namespace/foo/bar.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_bandit/namespace/foo/bar.py
diff --git a/test/command_callback/test_bandit_command_callback.vader b/test/command_callback/test_bandit_command_callback.vader
index 5d1e6fd3..274ce901 100644
--- a/test/command_callback/test_bandit_command_callback.vader
+++ b/test/command_callback/test_bandit_command_callback.vader
@@ -47,3 +47,25 @@ Execute(Pipenv is detected when python_bandit_auto_pipenv is set):
\ . ' run bandit'
\ . b:bandit_flags
\ . ' -'
+
+Execute(The bandit command callback should add .bandit by default):
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_bandit/namespace/foo/bar.py')
+
+ let b:config_path = ale#path#Simplify(
+ \ g:dir . '/python_paths/with_bandit/.bandit'
+ \)
+
+ AssertLinter 'bandit',
+ \ ale#Escape('bandit')
+ \ . ' --ini ' . ale#Escape(b:config_path)
+ \ . b:bandit_flags
+ \ . ' -'
+
+Execute(The bandit command callback should support not using .bandit):
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_bandit/subdir/foo/bar.py')
+ let g:ale_python_bandit_use_config = 0
+
+ AssertLinter 'bandit',
+ \ ale#Escape('bandit')
+ \ . b:bandit_flags
+ \ . ' -'
diff --git a/test/command_callback/test_pylint_command_callback.vader b/test/command_callback/test_pylint_command_callback.vader
index 6b21b127..c41c8398 100644
--- a/test/command_callback/test_pylint_command_callback.vader
+++ b/test/command_callback/test_pylint_command_callback.vader
@@ -39,7 +39,7 @@ Execute(The pylint callbacks shouldn't detect virtualenv directories where they
silent execute 'file ' . fnameescape(g:dir . '/python_paths/no_virtualenv/subdir/foo/bar.py')
AssertLinter 'pylint',
- \ ale#path#BufferCdString(bufnr(''))
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/no_virtualenv/subdir'))
\ . ale#Escape('pylint') . ' ' . b:command_tail
Execute(The pylint callbacks should detect virtualenv directories):
@@ -50,7 +50,7 @@ Execute(The pylint callbacks should detect virtualenv directories):
\)
AssertLinter b:executable,
- \ ale#path#BufferCdString(bufnr(''))
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
\ . ale#Escape(b:executable) . ' ' . b:command_tail
Execute(You should able able to use the global pylint instead):
@@ -58,7 +58,7 @@ Execute(You should able able to use the global pylint instead):
let g:ale_python_pylint_use_global = 1
AssertLinter 'pylint',
- \ ale#path#BufferCdString(bufnr(''))
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
\ . ale#Escape('pylint') . ' ' . b:command_tail
Execute(Setting executable to 'pipenv' appends 'run pylint'):
diff --git a/test/command_callback/test_rust_rls_callbacks.vader b/test/command_callback/test_rust_rls_callbacks.vader
index a710161d..ef4735d2 100644
--- a/test/command_callback/test_rust_rls_callbacks.vader
+++ b/test/command_callback/test_rust_rls_callbacks.vader
@@ -23,3 +23,8 @@ Execute(The project root should be detected correctly):
call ale#test#SetFilename('rust-rls-project/test.rs')
AssertLSPProject ale#path#Simplify(g:dir . '/rust-rls-project')
+
+Execute(Should accept configuration settings):
+ AssertLSPConfig {}
+ let b:ale_rust_rls_config = {'rust': {'clippy_preference': 'on'}}
+ AssertLSPConfig {'rust': {'clippy_preference': 'on'}}
diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader
index 500eb71c..52df2a62 100644
--- a/test/fix/test_ale_fix.vader
+++ b/test/fix/test_ale_fix.vader
@@ -34,21 +34,21 @@ Before:
call ale#test#SetFilename('test.txt')
call ale#linter#PreventLoading('testft')
- function AddCarets(buffer, done, lines) abort
+ function AddCarets(buffer, lines) abort
" map() is applied to the original lines here.
" This way, we can ensure that defensive copies are made.
return map(a:lines, '''^'' . v:val')
endfunction
- function AddDollars(buffer, done, lines) abort
+ function AddDollars(buffer, lines) abort
return map(a:lines, '''$'' . v:val')
endfunction
- function DoNothing(buffer, done, lines) abort
+ function DoNothing(buffer, lines) abort
return 0
endfunction
- function CatLine(buffer, done, lines) abort
+ function CatLine(buffer, lines) abort
return {'command': 'cat - <(echo d)'}
endfunction
@@ -56,15 +56,21 @@ Before:
return {'command': 'cat - <(echo d)'}
endfunction
- function ReplaceWithTempFile(buffer, done, lines) abort
+ function CatLineDeferred(buffer, lines) abort
+ return ale#command#Run(a:buffer, 'echo', {
+ \ -> ale#command#Run(a:buffer, 'echo', {-> {'command': 'cat - <(echo d)'}})
+ \})
+ endfunction
+
+ function ReplaceWithTempFile(buffer, lines) abort
return {'command': 'echo x > %t', 'read_temporary_file': 1}
endfunction
- function CatWithTempFile(buffer, done, lines) abort
+ function CatWithTempFile(buffer, lines) abort
return {'command': 'cat %t <(echo d)'}
endfunction
- function RemoveLastLine(buffer, done, lines) abort
+ function RemoveLastLine(buffer, lines) abort
return ['a', 'b']
endfunction
@@ -127,11 +133,11 @@ Before:
endfunction
" echo will output a single blank line, and we should ingore it.
- function! IgnoredEmptyOutput(buffer, done, output)
+ function! IgnoredEmptyOutput(buffer, output)
return {'command': has('win32') ? 'echo(' : 'echo'}
endfunction
- function! EchoLineNoPipe(buffer, done, output)
+ function! EchoLineNoPipe(buffer, output)
return {'command': 'echo new line', 'read_buffer': 0}
endfunction
@@ -180,6 +186,7 @@ Before:
After:
Restore
+ unlet! g:test_filename
unlet! g:ale_run_synchronously
unlet! g:ale_set_lists_synchronously
unlet! g:ale_run_synchronously_callbacks
@@ -192,6 +199,7 @@ After:
delfunction DoNothing
delfunction CatLine
delfunction CatLineOneArg
+ delfunction CatLineDeferred
delfunction ReplaceWithTempFile
delfunction CatWithTempFile
delfunction RemoveLastLine
@@ -224,8 +232,8 @@ After:
setlocal buftype=nofile
- if filereadable('fix_test_file')
- call delete('fix_test_file')
+ if exists('g:test_filename') && filereadable(g:test_filename)
+ call delete(g:test_filename)
endif
call setloclist(0, [])
@@ -438,7 +446,7 @@ Execute(ALEFix should accept lambdas):
" to make the test pass.
call setline(1, ['a', 'b', 'c', 'd'])
else
- let g:ale_fixers.testft = [{buffer, done, lines -> lines + ['d']}]
+ let g:ale_fixers.testft = [{buffer, lines -> lines + ['d']}]
ALEFix
call ale#test#FlushJobs()
endif
@@ -479,8 +487,9 @@ Execute(ALEFix should fix files on the save event):
let g:ale_lint_on_save = 1
let g:ale_enabled = 1
- noautocmd silent file fix_test_file
- call writefile(getline(1, '$'), 'fix_test_file')
+ let g:test_filename = tempname()
+ execute 'noautocmd silent file ' . fnameescape(g:test_filename)
+ call writefile(getline(1, '$'), g:test_filename)
let g:ale_fixers.testft = ['AddDollars']
@@ -492,8 +501,8 @@ Execute(ALEFix should fix files on the save event):
call ale#test#FlushJobs()
" We should save the file.
- AssertEqual ['$a', '$b', '$c'], readfile('fix_test_file')
- Assert !&modified, 'The was marked as ''modified'''
+ AssertEqual ['$a', '$b', '$c'], readfile(g:test_filename)
+ Assert !&modified, 'The file was marked as ''modified'''
if !has('win32')
" We should have run the linter.
@@ -520,8 +529,9 @@ Execute(ALEFix should not fix files on :wq):
let g:ale_lint_on_save = 1
let g:ale_enabled = 1
- noautocmd silent file fix_test_file
- call writefile(getline(1, '$'), 'fix_test_file')
+ let g:test_filename = tempname()
+ execute 'noautocmd silent file ' . fnameescape(g:test_filename)
+ call writefile(getline(1, '$'), g:test_filename)
let g:ale_fixers.testft = ['AddDollars']
@@ -534,7 +544,7 @@ Execute(ALEFix should not fix files on :wq):
call ale#events#SaveEvent(bufnr(''))
" We should save the file.
- AssertEqual ['a', 'b', 'c'], readfile('fix_test_file')
+ AssertEqual ['a', 'b', 'c'], readfile(g:test_filename)
Assert &modified, 'The was not marked as ''modified'''
" We should not run the linter.
@@ -555,7 +565,8 @@ Execute(ALEFix should still lint with no linters to be applied):
let g:ale_lint_on_save = 1
let g:ale_enabled = 1
- noautocmd silent file fix_test_file
+ let g:test_filename = tempname()
+ execute 'noautocmd silent file ' . fnameescape(g:test_filename)
let g:ale_fixers.testft = []
@@ -563,7 +574,7 @@ Execute(ALEFix should still lint with no linters to be applied):
call ale#events#SaveEvent(bufnr(''))
call ale#test#FlushJobs()
- Assert !filereadable('fix_test_file'), 'The file should not have been saved'
+ Assert !filereadable(g:test_filename), 'The file should not have been saved'
if !has('win32')
" We have run the linter.
@@ -590,7 +601,8 @@ Execute(ALEFix should still lint when nothing was fixed on save):
let g:ale_lint_on_save = 1
let g:ale_enabled = 1
- noautocmd silent file fix_test_file
+ let g:test_filename = tempname()
+ execute 'noautocmd silent file ' . fnameescape(g:test_filename)
let g:ale_fixers.testft = ['DoNothing']
@@ -598,7 +610,7 @@ Execute(ALEFix should still lint when nothing was fixed on save):
call ale#events#SaveEvent(bufnr(''))
call ale#test#FlushJobs()
- Assert !filereadable('fix_test_file'), 'The file should not have been saved'
+ Assert !filereadable(g:test_filename), 'The file should not have been saved'
if !has('win32')
" We should have run the linter.
@@ -626,7 +638,8 @@ Given testft (A file with three lines):
c
Execute(ale#fix#InitBufferData() should set up the correct data):
- noautocmd silent file fix_test_file
+ let g:test_filename = tempname()
+ execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call ale#fix#InitBufferData(bufnr(''), 'save_file')
@@ -801,3 +814,19 @@ Execute(ALEFix should apply autocmds):
AssertEqual g:pre_success, 1
AssertEqual g:post_success, 1
+
+Execute(ALEFix should support ale#command#Run):
+ if has('win32')
+ " Just skip this test on Windows, we can't run it.
+ call setline(1, ['a', 'b', 'c', 'd'])
+ else
+ let g:ale_fixers.testft = ['CatLineDeferred']
+ ALEFix
+ call ale#test#FlushJobs()
+ endif
+
+Expect(The extra line should be added):
+ a
+ b
+ c
+ d
diff --git a/test/fixers/test_break_up_long_lines_python_fixer.vader b/test/fixers/test_break_up_long_lines_python_fixer.vader
index 847d3358..5fd991f0 100644
--- a/test/fixers/test_break_up_long_lines_python_fixer.vader
+++ b/test/fixers/test_break_up_long_lines_python_fixer.vader
@@ -16,7 +16,7 @@ Execute(Long lines with basic function calls should be broken up correctly):
\ ' bar,',
\ '))',
\ ],
- \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), v:null, [
+ \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), [
\ 'def foo():',
\ ' some_variable = this_is_a_longer_function(first_argument, second_argument, third_with_function_call(foo, bar))',
\ ])
@@ -33,7 +33,7 @@ Execute(Longer lines should be permitted if a configuration file allows it):
\ ' a_third_long_word,',
\ ')'
\ ],
- \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), v:null, [
+ \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), [
\ 'x = this_line_is_between_79_and_90_characters(first, second, third, fourth, fifth)',
\ 'y = this_line_is_longer_than_90_characters(much_longer_word, another_longer_word, a_third_long_word)',
\ ])
diff --git a/test/fixers/test_trim_whitespace.vader b/test/fixers/test_trim_whitespace.vader
index 10070374..2ffbcb04 100644
--- a/test/fixers/test_trim_whitespace.vader
+++ b/test/fixers/test_trim_whitespace.vader
@@ -16,13 +16,13 @@ Execute(Should delete all whitespace at the end of different lines):
\ ' bar,',
\ '))',
\ ],
- \ ale#fixers#generic#TrimWhitespace(bufnr(''), v:null, [
- \ 'def foo():',
- \ ' some_variable = this_is_a_longer_function(',
- \ 'first_argument,',
- \ ' second_argument,',
- \ ' third_with_function_call(',
- \ 'foo,',
- \ ' bar,',
- \ '))',
+ \ ale#fixers#generic#TrimWhitespace(bufnr(''), [
+ \ 'def foo():',
+ \ ' some_variable = this_is_a_longer_function(',
+ \ 'first_argument,',
+ \ ' second_argument,',
+ \ ' third_with_function_call(',
+ \ 'foo,',
+ \ ' bar,',
+ \ '))',
\ ])
diff --git a/test/lsp/test_lsp_root_detection.vader b/test/lsp/test_lsp_root_detection.vader
index 2575a62c..b7827248 100644
--- a/test/lsp/test_lsp_root_detection.vader
+++ b/test/lsp/test_lsp_root_detection.vader
@@ -16,48 +16,47 @@ Execute(The buffer-specific variable can be a string):
let b:ale_lsp_root = '/some/path'
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull '/some/path'
+ AssertLSPProject '/some/path'
Execute(The buffer-specific variable can be a dictionary):
let b:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/other/path'}
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull '/some/path'
+ AssertLSPProject '/some/path'
Execute(The buffer-specific variable can have funcrefs):
let b:ale_lsp_root = {'clangd': function('Hook1'), 'golangserver': '/path'}
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull 'abc123'
+ AssertLSPProject 'abc123'
Execute(The global variable can be a dictionary):
let g:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/other/path'}
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull '/some/path'
+ AssertLSPProject '/some/path'
Execute(The global variable can have funcrefs):
let g:ale_lsp_root = {'clangd': function('Hook1'), 'golangserver': '/path'}
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull 'abc123'
+ AssertLSPProject 'abc123'
Execute(The buffer-specific variable overrides the global variable):
let b:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/other/path'}
let g:ale_lsp_root = {'clangd': '/not/this/path', 'golangserver': '/elsewhere'}
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull '/some/path'
+ AssertLSPProject '/some/path'
Execute(The global variable is queried if the buffer-specific has no value):
let b:ale_lsp_root = {'golangserver': '/other/path'}
let g:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/elsewhere'}
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull '/some/path'
-
+ AssertLSPProject '/some/path'
Execute(The default hook value is acceptable):
call ale#test#SetFilename('other-file.c')
- AssertLSPProjectFull ''
+ AssertLSPProject ''
diff --git a/test/lsp/test_lsp_startup.vader b/test/lsp/test_lsp_startup.vader
new file mode 100644
index 00000000..2fbd32de
--- /dev/null
+++ b/test/lsp/test_lsp_startup.vader
@@ -0,0 +1,364 @@
+Before:
+ Save g:ale_run_synchronously
+
+ let g:ale_run_synchronously = 1
+ unlet! g:ale_run_synchronously_callbacks
+
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/engine.vim
+ runtime autoload/ale/job.vim
+ runtime autoload/ale/socket.vim
+
+ let g:job_map = {}
+ let g:emulate_job_failure = 0
+ let g:next_job_id = 1
+
+ let g:socket_map = {}
+ let g:emulate_socket_failure = 0
+ let g:next_channel_id = 0
+
+ let g:message_buffer = ''
+ let g:calls = []
+
+ function! ale#engine#IsExecutable(buffer, executable) abort
+ return !empty(a:executable)
+ endfunction
+
+ function! ale#job#HasOpenChannel(job_id) abort
+ return has_key(g:job_map, a:job_id)
+ endfunction
+
+ function! ale#job#Stop(job_id) abort
+ if has_key(g:job_map, a:job_id)
+ call remove(g:job_map, a:job_id)
+ endif
+ endfunction
+
+ function! ale#job#Start(command, options) abort
+ if g:emulate_job_failure
+ return 0
+ endif
+
+ let l:job_id = g:next_job_id
+ let g:next_job_id += 1
+ let g:job_map[l:job_id] = [a:command, a:options]
+
+ return l:job_id
+ endfunction
+
+ function! ale#job#SendRaw(job_id, data) abort
+ let g:message_buffer .= a:data
+ endfunction
+
+ function! ale#socket#IsOpen(channel_id) abort
+ return has_key(g:socket_map, a:channel_id)
+ endfunction
+
+ function! ale#socket#Close(channel_id) abort
+ if has_key(g:socket_map, a:channel_id)
+ call remove(g:socket_map, a:channel_id)
+ endif
+ endfunction
+
+ function! ale#socket#Open(address, options) abort
+ if g:emulate_socket_failure
+ return -1
+ endif
+
+ let l:channel_id = g:next_channel_id
+ let g:next_channel_id += 1
+ let g:socket_map[l:channel_id] = [a:address, a:options]
+
+ return l:channel_id
+ endfunction
+
+ function! ale#socket#Send(channel_id, data) abort
+ let g:message_buffer .= a:data
+ endfunction
+
+ function! PopMessages() abort
+ let l:message_list = []
+
+ for l:line in split(g:message_buffer, '\(\r\|\n\|Content-Length\)\+')
+ if l:line[:0] is '{'
+ let l:data = json_decode(l:line)
+
+ call add(l:message_list, l:data)
+ endif
+ endfor
+
+ let g:message_buffer = ''
+
+ return l:message_list
+ endfunction
+
+ function! SendMessage(message) abort
+ let l:conn_id = keys(ale#lsp#GetConnections())[0]
+ let l:body = json_encode(a:message)
+ let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body
+
+ call ale#lsp#HandleMessage(l:conn_id, l:data)
+ endfunction
+
+ function! Start() abort
+ let l:linter = values(ale#linter#GetLintersLoaded())[0][0]
+
+ return ale#lsp_linter#StartLSP(
+ \ bufnr(''),
+ \ l:linter,
+ \ {linter, details -> add(g:calls, [linter.name, details])},
+ \)
+ endfunction
+
+ function! AssertInitSuccess(linter_name, conn_prefix, language, root, command) abort
+ let l:messages = PopMessages()
+
+ if a:linter_name is# 'tsserver'
+ AssertEqual
+ \ [
+ \ {
+ \ 'seq': v:null,
+ \ 'arguments': {
+ \ 'file': expand('%:p'),
+ \ },
+ \ 'type': 'request',
+ \ 'command': 'open',
+ \ },
+ \ ],
+ \ l:messages
+ else
+ AssertEqual
+ \ [
+ \ {
+ \ 'method': 'initialize',
+ \ 'jsonrpc': '2.0',
+ \ 'id': 1,
+ \ 'params': {
+ \ 'initializationOptions': {},
+ \ 'rootUri': ale#path#ToURI(a:root),
+ \ 'capabilities': {},
+ \ 'rootPath': a:root,
+ \ 'processId': getpid(),
+ \ },
+ \ },
+ \ ],
+ \ l:messages
+
+ call SendMessage({
+ \ 'jsonrpc': '2.0',
+ \ 'id': 1,
+ \ 'result': {
+ \ 'capabilities': {
+ \ 'renameProvider': v:true,
+ \ 'executeCommandProvider': {
+ \ 'commands': [],
+ \ },
+ \ 'hoverProvider': v:true,
+ \ 'documentSymbolProvider': v:true,
+ \ 'documentRangeFormattingProvider': v:true,
+ \ 'codeLensProvider': {
+ \ 'resolveProvider': v:false
+ \ },
+ \ 'referencesProvider': v:true,
+ \ 'textDocumentSync': 2,
+ \ 'documentFormattingProvider': v:true,
+ \ 'codeActionProvider': v:true,
+ \ 'signatureHelpProvider': {
+ \ 'triggerCharacters': ['(', ','],
+ \ },
+ \ 'completionProvider': {
+ \ 'triggerCharacters': ['.'],
+ \ 'resolveProvider': v:false
+ \ },
+ \ 'definitionProvider': v:true,
+ \ 'experimental': {},
+ \ 'documentHighlightProvider': v:true,
+ \ 'workspaceSymbolProvider': v:true,
+ \ },
+ \ },
+ \})
+
+ let l:messages = PopMessages()
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'method': 'initialized',
+ \ 'jsonrpc': '2.0',
+ \ 'params': {},
+ \ },
+ \ {
+ \ 'method': 'textDocument/didOpen',
+ \ 'jsonrpc': '2.0',
+ \ 'params': {
+ \ 'textDocument': {
+ \ 'uri': ale#path#ToURI(expand('%:p')),
+ \ 'version': ale#lsp#message#GetNextVersionID() - 1,
+ \ 'languageId': a:language,
+ \ 'text': "\n",
+ \ },
+ \ },
+ \ },
+ \ ],
+ \ l:messages
+ endif
+
+ AssertEqual
+ \ [
+ \ [
+ \ a:linter_name,
+ \ {
+ \ 'connection_id': a:conn_prefix . ':' . a:root,
+ \ 'project_root': a:root,
+ \ 'buffer': bufnr(''),
+ \ 'command': !empty(a:command) ? ale#job#PrepareCommand(bufnr(''), a:command) : '',
+ \ },
+ \ ],
+ \ ],
+ \ g:calls
+ endfunction
+
+ function! AssertInitFailure() abort
+ let l:messages = PopMessages()
+
+ AssertEqual [], l:messages
+ AssertEqual [], g:calls
+ endfunction
+
+ call ale#linter#Reset()
+
+After:
+ Restore
+
+ call ale#linter#Reset()
+ call ale#lsp#ResetConnections()
+
+ unlet! g:job_map
+ unlet! g:emulate_job_failure
+ unlet! g:next_job_id
+
+ unlet! g:socket_map
+ unlet! g:emulate_socket_failure
+ unlet! g:next_channel_id
+
+ unlet! g:message_buffer
+ unlet! g:calls
+
+ delfunction PopMessages
+ delfunction Start
+ delfunction AssertInitSuccess
+ delfunction AssertInitFailure
+
+ runtime autoload/ale/engine.vim
+ runtime autoload/ale/job.vim
+ runtime autoload/ale/socket.vim
+
+Execute(tsserver should be started correctly):
+ runtime ale_linters/typescript/tsserver.vim
+
+ Assert Start()
+ call AssertInitSuccess('tsserver', 'tsserver', '', '', ale#Escape('tsserver'))
+
+Execute(tsserver failures should be handled appropriately):
+ runtime ale_linters/typescript/tsserver.vim
+
+ let g:emulate_job_failure = 1
+
+ Assert !Start()
+ call AssertInitFailure()
+
+Execute(LSP jobs should start correctly):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'stdio',
+ \ 'executable': 'foo',
+ \ 'command': 'foo',
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ Assert Start()
+ call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', 'foo')
+
+Execute(LSP job failures should be handled):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'stdio',
+ \ 'executable': 'foo',
+ \ 'command': 'foo',
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ let g:emulate_job_failure = 1
+
+ Assert !Start()
+ call AssertInitFailure()
+
+Execute(LSP TCP connections should start correctly):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo',
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ Assert Start()
+ call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', '')
+
+Execute(LSP TCP connection failures should be handled):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo',
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ let g:emulate_socket_failure = 1
+
+ Assert !Start()
+ call AssertInitFailure()
+
+Execute(Deferred executables should be handled correctly):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'stdio',
+ \ 'executable': {b -> ale#command#Run(b, 'echo', {-> 'foo'})},
+ \ 'command': '%e -c',
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ Assert Start()
+ call ale#test#FlushJobs()
+ call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', ale#Escape('foo') . ' -c')
+
+Execute(Deferred commands should be handled correctly):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'stdio',
+ \ 'executable': 'foo',
+ \ 'command': {b -> ale#command#Run(b, 'echo', {-> '%e -c'})},
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ Assert Start()
+ call ale#test#FlushJobs()
+ call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', ale#Escape('foo') . ' -c')
+
+Execute(Deferred addresses should be handled correctly):
+ call ale#linter#Define('foobar', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address': {b -> ale#command#Run(b, 'echo', {-> 'localhost:1234'})},
+ \ 'project_root': '/foo/bar',
+ \ 'initialization_options': {},
+ \})
+
+ Assert Start()
+ call ale#test#FlushJobs()
+ call AssertInitSuccess('foo', 'localhost:1234', 'foobar', '/foo/bar', '')
diff --git a/test/test_deferred_command_string.vader b/test/test_deferred_command_string.vader
new file mode 100644
index 00000000..4d0c8977
--- /dev/null
+++ b/test/test_deferred_command_string.vader
@@ -0,0 +1,46 @@
+Before:
+ Save g:ale_run_synchronously
+ Save g:ale_emulate_job_failure
+ Save g:ale_buffer_info
+
+ let g:ale_run_synchronously = 1
+ let g:ale_buffer_info = {}
+ let b:ale_history = []
+
+ call ale#linter#Reset()
+ call ale#assert#SetUpLinterTestCommands()
+ call ale#linter#Define('foobar', {
+ \ 'name': 'lint_file_linter',
+ \ 'callback': 'LintFileCallback',
+ \ 'executable': 'echo',
+ \ 'command': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 'foo'})})},
+ \ 'read_buffer': 0,
+ \})
+
+After:
+ Restore
+
+ call ale#assert#TearDownLinterTest()
+
+Given foobar (Some imaginary filetype):
+Execute(It should be possible to compute an executable to check based on the result of commands):
+ AssertLinter 'echo', 'foo'
+
+ ALELint
+ call ale#test#FlushJobs()
+
+ AssertEqual
+ \ 1,
+ \ len(filter(copy(b:ale_history), 'string(v:val.command) =~# ''foo'''))
+
+Execute(It handle the deferred command failing):
+ let g:ale_emulate_job_failure = 1
+
+ AssertLinter 'echo', 0
+
+ ALELint
+ call ale#test#FlushJobs()
+
+ AssertEqual
+ \ 0,
+ \ len(filter(copy(b:ale_history), 'string(v:val.command) =~# ''foo'''))
diff --git a/test/test_deferred_executable_string.vader b/test/test_deferred_executable_string.vader
index ad2e752b..3bdc5251 100644
--- a/test/test_deferred_executable_string.vader
+++ b/test/test_deferred_executable_string.vader
@@ -1,9 +1,11 @@
Before:
Save g:ale_run_synchronously
+ Save g:ale_emulate_job_failure
Save g:ale_buffer_info
let g:ale_run_synchronously = 1
let g:ale_buffer_info = {}
+ let b:ale_history = []
call ale#linter#Reset()
call ale#assert#SetUpLinterTestCommands()
@@ -22,8 +24,6 @@ After:
Given foobar (Some imaginary filetype):
Execute(It should be possible to compute an executable to check based on the result of commands):
- let b:ale_history = []
-
AssertLinter 'foo', 'echo'
ALELint
@@ -32,3 +32,15 @@ Execute(It should be possible to compute an executable to check based on the res
AssertEqual
\ [{'status': 0, 'job_id': 'executable', 'command': 'foo'}],
\ filter(copy(b:ale_history), 'v:val.job_id is# ''executable''')
+
+Execute(It handle the deferred command failing):
+ let g:ale_emulate_job_failure = 1
+
+ AssertLinter 0, 'echo'
+
+ ALELint
+ call ale#test#FlushJobs()
+
+ AssertEqual
+ \ [],
+ \ filter(copy(b:ale_history), 'v:val.job_id is# ''executable''')
diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader
index 321c6212..cd32ebc8 100644
--- a/test/test_linter_defintion_processing.vader
+++ b/test/test_linter_defintion_processing.vader
@@ -1,4 +1,10 @@
Before:
+ Save g:ale_lsp_root
+ Save b:ale_lsp_root
+
+ let g:ale_lsp_root = {}
+ unlet! b:ale_lsp_root
+
let g:linter = {}
After:
@@ -82,7 +88,15 @@ Execute (PreProcess should throw when command is not a string):
\ 'executable': 'echo',
\ 'command': [],
\})
- AssertEqual '`command` must be a string if defined', g:vader_exception
+ AssertEqual '`command` must be a String or Function if defined', g:vader_exception
+
+Execute (PreProcess should allow command to be a callback):
+ call ale#linter#PreProcess('testft', {
+ \ 'name': 'foo',
+ \ 'callback': 'SomeFunction',
+ \ 'executable': 'echo',
+ \ 'command': function('type'),
+ \})
Execute (PreProcess should throw when command_callback is not a callback):
AssertThrows call ale#linter#PreProcess('testft', {
@@ -453,6 +467,18 @@ Execute(PreProcess should complain about using language and language_callback to
AssertThrows call ale#linter#PreProcess('testft', g:linter)
AssertEqual 'Only one of `language` or `language_callback` should be set', g:vader_exception
+Execute(PreProcess should complain about invalid language values):
+ let g:linter = {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 0,
+ \ 'project_root_callback': 'x',
+ \}
+
+ AssertThrows call ale#linter#PreProcess('testft', g:linter)
+ AssertEqual '`language` must be a String or Funcref', g:vader_exception
+
Execute(PreProcess should use the filetype as the language string by default):
let g:linter = {
\ 'name': 'x',
@@ -463,6 +489,17 @@ Execute(PreProcess should use the filetype as the language string by default):
AssertEqual 'testft', ale#linter#PreProcess('testft', g:linter).language_callback(0)
+Execute(PreProcess should allow language to be set to a callback):
+ let g:linter = {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': {-> 'foo'},
+ \ 'project_root_callback': 'x',
+ \}
+
+ AssertEqual 'foo', ale#linter#PreProcess('testft', g:linter).language_callback(0)
+
Execute(PreProcess should require an address_callback for LSP socket configurations):
let g:linter = {
\ 'name': 'x',
@@ -470,7 +507,7 @@ Execute(PreProcess should require an address_callback for LSP socket configurati
\}
AssertThrows call ale#linter#PreProcess('testft', g:linter)
- AssertEqual '`address_callback` must be defined for getting the LSP address', g:vader_exception
+ AssertEqual '`address` or `address_callback` must be defined for getting the LSP address', g:vader_exception
Execute(PreProcess should complain about address_callback for non-LSP linters):
let g:linter = {
@@ -482,7 +519,112 @@ Execute(PreProcess should complain about address_callback for non-LSP linters):
\}
AssertThrows call ale#linter#PreProcess('testft', g:linter)
- AssertEqual '`address_callback` cannot be used when lsp != ''socket''', g:vader_exception
+ AssertEqual '`address` or `address_callback` cannot be used when lsp != ''socket''', g:vader_exception
+
+Execute(PreProcess accept valid address_callback values):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address_callback': {-> 'foo:123'},
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \})
+
+ AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter)
+
+Execute(PreProcess accept address as a String):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \})
+
+ AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter)
+
+Execute(PreProcess accept address as a Function):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': {-> 'foo:123'},
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \})
+
+ AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter)
+
+Execute(PreProcess should complain about invalid address values):
+ AssertThrows call ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 0,
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \})
+ AssertEqual '`address` must be a String or Function if defined', g:vader_exception
+
+Execute(PreProcess should accept allow the project root be set as a String):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root': '/foo/bar',
+ \})
+
+ AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter)
+
+Execute(PreProcess should accept allow the project root be set as a Function):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root': {-> '/foo/bar'},
+ \})
+
+ AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter)
+
+Execute(PreProcess should complain when the project_root valid is invalid):
+ AssertThrows call ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root': 0,
+ \})
+ AssertEqual '`project_root` must be a String or Function if defined', g:vader_exception
+
+Execute(PreProcess should accept project_root_callback as a String):
+ call ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'Foobar',
+ \})
+
+Execute(PreProcess should accept project_root_callback as a Function):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root_callback': {-> '/foo/bar'},
+ \})
+
+ AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter)
+
+Execute(PreProcess should complain when the project_root_callback valid is invalid):
+ AssertThrows call ale#linter#PreProcess('testft', {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address': 'foo:123',
+ \ 'language': 'x',
+ \ 'project_root_callback': 0,
+ \})
+ AssertEqual '`project_root_callback` must be a callback if defined', g:vader_exception
Execute(PreProcess should complain about using initialization_options and initialization_options_callback together):
let g:linter = {
@@ -509,6 +651,41 @@ Execute(PreProcess should throw when initialization_options_callback is not a ca
\})
AssertEqual '`initialization_options_callback` must be a callback if defined', g:vader_exception
+Execute(PreProcess should throw when initialization_options is not a Dictionary or callback):
+ AssertThrows call ale#linter#PreProcess('testft', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'initialization_options': 0,
+ \})
+ AssertEqual '`initialization_options` must be a String or Function if defined', g:vader_exception
+
+Execute(PreProcess should accept initialization_options as a Dictionary):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'initialization_options': {'foo': v:true},
+ \})
+
+ AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter)
+
+Execute(PreProcess should accept initialization_options as a Funcref):
+ let g:linter = ale#linter#PreProcess('testft', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'initialization_options': {-> {'foo': v:true}},
+ \})
+
+ AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter)
+
Execute(PreProcess should complain about using lsp_config and lsp_config_callback together):
let g:linter = {
\ 'name': 'x',
@@ -535,22 +712,30 @@ Execute(PreProcess should throw when lsp_config_callback is not a callback):
AssertEqual '`lsp_config_callback` must be a callback if defined', g:vader_exception
Execute(PreProcess should accept LSP configuration options via lsp_config):
- let g:ale_lsp_configuration = {
- \ 'foo': 'bar'
+ let g:linter = {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language_callback': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'lsp_config': {'foo': 'bar'},
\}
+ AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter)
+
+Execute(PreProcess should accept LSP configuration options via lsp_config as a function):
let g:linter = {
\ 'name': 'x',
\ 'lsp': 'socket',
\ 'address_callback': 'X',
\ 'language_callback': 'x',
\ 'project_root_callback': 'x',
- \ 'lsp_config': g:ale_lsp_configuration,
+ \ 'lsp_config': {-> {'foo': 'bar'}},
\}
- AssertEqual {'foo': 'bar'}, ale#linter#PreProcess('testft', g:linter).lsp_config
+ AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter)
-Execute(PreProcess should throw when lsp_config is not a Dictionary):
+Execute(PreProcess should throw when lsp_config is not a Dictionary or Function):
AssertThrows call ale#linter#PreProcess('testft', {
\ 'name': 'foo',
\ 'lsp': 'socket',
@@ -559,4 +744,4 @@ Execute(PreProcess should throw when lsp_config is not a Dictionary):
\ 'project_root_callback': 'x',
\ 'lsp_config': 'x',
\})
- AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception
+ AssertEqual '`lsp_config` must be a Dictionary or Function if defined', g:vader_exception
diff --git a/test/test_no_linting_on_write_quit.vader b/test/test_no_linting_on_write_quit.vader
index 7ad08d08..bbd80d8f 100644
--- a/test/test_no_linting_on_write_quit.vader
+++ b/test/test_no_linting_on_write_quit.vader
@@ -23,7 +23,7 @@ Before:
return [{'lnum': 1, 'col': 1, 'text': 'xxx'}]
endfunction
- function AddLine(buffer, done, lines) abort
+ function AddLine(buffer, lines) abort
return a:lines + ['x']
endfunction
diff --git a/test/test_path_uri.vader b/test/test_path_uri.vader
index a3e68d98..504aba77 100644
--- a/test/test_path_uri.vader
+++ b/test/test_path_uri.vader
@@ -2,8 +2,22 @@ Execute(ale#path#ToURI should work for Windows paths):
AssertEqual 'file:///C:/foo/bar/baz.tst', ale#path#ToURI('C:\foo\bar\baz.tst')
AssertEqual 'foo/bar/baz.tst', ale#path#ToURI('foo\bar\baz.tst')
+Execute(ale#path#FromURI should work for Unix paths):
+ AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('file:///foo/bar/baz.tst')
+ AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('file:/foo/bar/baz.tst')
+ AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('FILE:///foo/bar/baz.tst')
+ AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('FILE:/foo/bar/baz.tst')
+
Execute(ale#path#FromURI should work for Windows paths):
AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('file:///C:/foo/bar/baz.tst')
+ AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('file:/C:/foo/bar/baz.tst')
+ AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromURI('file:///c:/foo/bar/baz.tst')
+ AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromURI('file:/c:/foo/bar/baz.tst')
+ AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('FILE:///C:/foo/bar/baz.tst')
+ AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('FILE:/C:/foo/bar/baz.tst')
+
+Execute(ale#path#FromURI should handle encoded paths that look like drive letters):
+ AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromURI('file:///C%3A/foo/bar/baz.tst')
Execute(ale#path#ToURI should work for Unix paths):
AssertEqual 'file:///foo/bar/baz.tst', ale#path#ToURI('/foo/bar/baz.tst')