summaryrefslogtreecommitdiff
path: root/ale_linters
diff options
context:
space:
mode:
Diffstat (limited to 'ale_linters')
-rw-r--r--ale_linters/ada/gcc.vim54
-rw-r--r--ale_linters/ansible/ansible_lint.vim13
-rw-r--r--ale_linters/apiblueprint/drafter.vim2
-rw-r--r--ale_linters/asciidoc/vale.vim9
-rw-r--r--ale_linters/asm/gcc.vim13
-rw-r--r--ale_linters/awk/gawk.vim18
-rw-r--r--ale_linters/c/ccls.vim14
-rw-r--r--ale_linters/c/clang.vim17
-rw-r--r--ale_linters/c/clangd.vim12
-rw-r--r--ale_linters/c/clangtidy.vim30
-rw-r--r--ale_linters/c/cppcheck.vim9
-rw-r--r--ale_linters/c/cquery.vim28
-rw-r--r--ale_linters/c/flawfinder.vim12
-rw-r--r--ale_linters/c/gcc.vim17
-rw-r--r--ale_linters/chef/foodcritic.vim11
-rw-r--r--ale_linters/clojure/joker.vim4
-rw-r--r--ale_linters/cpp/ccls.vim14
-rw-r--r--ale_linters/cpp/clang.vim17
-rw-r--r--ale_linters/cpp/clangcheck.vim13
-rw-r--r--ale_linters/cpp/clangd.vim23
-rw-r--r--ale_linters/cpp/clangtidy.vim30
-rw-r--r--ale_linters/cpp/clazy.vim32
-rw-r--r--ale_linters/cpp/cppcheck.vim9
-rw-r--r--ale_linters/cpp/cpplint.vim10
-rw-r--r--ale_linters/cpp/cquery.vim17
-rw-r--r--ale_linters/cpp/flawfinder.vim10
-rw-r--r--ale_linters/cpp/gcc.vim17
-rw-r--r--ale_linters/css/stylelint.vim13
-rw-r--r--ale_linters/cucumber/cucumber.vim1
-rw-r--r--ale_linters/cuda/nvcc.vim17
-rw-r--r--ale_linters/d/dls.vim22
-rw-r--r--ale_linters/d/dmd.vim16
-rw-r--r--ale_linters/dafny/dafny.vim1
-rw-r--r--ale_linters/dart/dartanalyzer.vim9
-rw-r--r--ale_linters/dart/language_server.vim8
-rw-r--r--ale_linters/dockerfile/dockerfile_lint.vim61
-rw-r--r--ale_linters/dockerfile/hadolint.vim2
-rw-r--r--ale_linters/elixir/credo.vim23
-rw-r--r--ale_linters/elixir/dialyxir.vim9
-rw-r--r--ale_linters/elixir/dogma.vim9
-rw-r--r--ale_linters/elixir/elixir_ls.vim21
-rw-r--r--ale_linters/elixir/mix.vim15
-rw-r--r--ale_linters/elm/make.vim28
-rw-r--r--ale_linters/erlang/syntaxerl.vim24
-rw-r--r--ale_linters/eruby/ruumba.vim62
-rw-r--r--ale_linters/fortran/gcc.vim28
-rw-r--r--ale_linters/fortran/language_server.vim12
-rw-r--r--ale_linters/fuse/fusionlint.vim9
-rw-r--r--ale_linters/gitcommit/gitlint.vim23
-rw-r--r--ale_linters/glsl/glslang.vim14
-rw-r--r--ale_linters/glsl/glslls.vim11
-rw-r--r--ale_linters/go/gobuild.vim40
-rw-r--r--ale_linters/go/golangci_lint.vim56
-rw-r--r--ale_linters/go/golint.vim15
-rw-r--r--ale_linters/go/gometalinter.vim11
-rw-r--r--ale_linters/go/govet.vim12
-rw-r--r--ale_linters/go/langserver.vim28
-rw-r--r--ale_linters/hack/hack.vim22
-rw-r--r--ale_linters/hack/hhast.vim40
-rw-r--r--ale_linters/haml/hamllint.vim10
-rw-r--r--ale_linters/handlebars/embertemplatelint.vim17
-rw-r--r--ale_linters/haskell/ghc-mod.vim18
-rw-r--r--ale_linters/haskell/ghc_mod.vim19
-rw-r--r--ale_linters/haskell/hdevtools.vim14
-rw-r--r--ale_linters/haskell/hie.vim47
-rw-r--r--ale_linters/haskell/hlint.vim16
-rw-r--r--ale_linters/haskell/stack_build.vim2
-rw-r--r--ale_linters/haskell/stack_ghc.vim2
-rw-r--r--ale_linters/html/htmlhint.vim14
-rw-r--r--ale_linters/html/stylelint.vim27
-rw-r--r--ale_linters/html/tidy.vim8
-rw-r--r--ale_linters/idris/idris.vim14
-rw-r--r--ale_linters/ispc/ispc.vim45
-rw-r--r--ale_linters/java/checkstyle.vim18
-rw-r--r--ale_linters/java/javac.vim12
-rw-r--r--ale_linters/java/javalsp.vim23
-rw-r--r--ale_linters/java/pmd.vim2
-rwxr-xr-xale_linters/javascript/flow.vim3
-rw-r--r--ale_linters/javascript/flow_ls.vim18
-rw-r--r--ale_linters/javascript/jscs.vim14
-rw-r--r--ale_linters/javascript/jshint.vim15
-rw-r--r--ale_linters/javascript/tsserver.vim19
-rw-r--r--ale_linters/json/jsonlint.vim1
-rw-r--r--ale_linters/julia/languageserver.vim21
-rw-r--r--ale_linters/kotlin/kotlinc.vim7
-rw-r--r--ale_linters/kotlin/languageserver.vim13
-rwxr-xr-xale_linters/less/lessc.vim21
-rw-r--r--ale_linters/less/stylelint.vim15
-rw-r--r--ale_linters/llvm/llc.vim16
-rw-r--r--ale_linters/lua/luac.vim13
-rw-r--r--ale_linters/lua/luacheck.vim16
-rw-r--r--ale_linters/make/checkmake.vim1
-rw-r--r--ale_linters/markdown/remark_lint.vim17
-rw-r--r--ale_linters/matlab/mlint.vim17
-rw-r--r--ale_linters/mercury/mmc.vim9
-rw-r--r--ale_linters/nasm/nasm.vim26
-rw-r--r--ale_linters/objc/ccls.vim14
-rw-r--r--ale_linters/objc/clang.vim2
-rw-r--r--ale_linters/objc/clangd.vim23
-rw-r--r--ale_linters/objcpp/clang.vim2
-rw-r--r--ale_linters/objcpp/clangd.vim23
-rw-r--r--ale_linters/perl/perl.vim22
-rw-r--r--ale_linters/perl/perlcritic.vim25
-rw-r--r--ale_linters/perl6/perl6.vim166
-rw-r--r--ale_linters/php/hack.vim28
-rw-r--r--ale_linters/php/langserver.vim16
-rw-r--r--ale_linters/php/php.vim6
-rw-r--r--ale_linters/php/phpcs.vim21
-rw-r--r--ale_linters/php/phpmd.vim13
-rw-r--r--ale_linters/php/phpstan.vim31
-rw-r--r--ale_linters/php/psalm.vim21
-rw-r--r--ale_linters/pony/ponyc.vim9
-rw-r--r--ale_linters/prolog/swipl.vim100
-rw-r--r--ale_linters/pug/puglint.vim14
-rw-r--r--ale_linters/puppet/languageserver.vim16
-rw-r--r--ale_linters/puppet/puppet.vim14
-rw-r--r--ale_linters/puppet/puppetlint.vim16
-rw-r--r--ale_linters/pyrex/cython.vim11
-rw-r--r--ale_linters/python/flake8.vim7
-rw-r--r--ale_linters/python/mypy.vim6
-rw-r--r--ale_linters/python/prospector.vim7
-rw-r--r--ale_linters/python/pycodestyle.vim6
-rw-r--r--ale_linters/python/pyflakes.vim6
-rw-r--r--ale_linters/python/pylint.vim6
-rw-r--r--ale_linters/python/pyls.vim6
-rw-r--r--ale_linters/python/pyre.vim6
-rw-r--r--ale_linters/python/vulture.vim85
-rw-r--r--ale_linters/qml/qmlfmt.vim33
-rw-r--r--ale_linters/rst/rstcheck.vim1
-rw-r--r--ale_linters/ruby/brakeman.vim12
-rw-r--r--ale_linters/ruby/rails_best_practices.vim14
-rw-r--r--ale_linters/ruby/reek.vim13
-rw-r--r--ale_linters/ruby/rubocop.vim12
-rw-r--r--ale_linters/ruby/ruby.vim14
-rw-r--r--ale_linters/ruby/solargraph.vim22
-rw-r--r--ale_linters/rust/cargo.vim15
-rw-r--r--ale_linters/rust/rls.vim13
-rw-r--r--ale_linters/rust/rustc.vim2
-rw-r--r--ale_linters/sass/stylelint.vim17
-rw-r--r--ale_linters/scala/fsc.vim23
-rw-r--r--ale_linters/scala/sbtserver.vim31
-rw-r--r--ale_linters/scala/scalac.vim23
-rw-r--r--ale_linters/scala/scalastyle.vim2
-rw-r--r--ale_linters/scss/stylelint.vim13
-rw-r--r--ale_linters/sh/shellcheck.vim11
-rw-r--r--ale_linters/sml/smlnj_cm.vim1
-rw-r--r--ale_linters/solidity/solhint.vim1
-rw-r--r--ale_linters/spec/rpmlint.vim17
-rw-r--r--ale_linters/stylus/stylelint.vim14
-rw-r--r--ale_linters/tcl/nagelfar.vim11
-rw-r--r--ale_linters/terraform/tflint.vim12
-rw-r--r--ale_linters/tex/lacheck.vim16
-rw-r--r--ale_linters/thrift/thrift.vim13
-rw-r--r--ale_linters/typescript/tsserver.vim19
-rw-r--r--ale_linters/vim/ale_custom_linting_rules.vim65
-rw-r--r--ale_linters/vue/vls.vim18
-rw-r--r--ale_linters/xml/xmllint.vim12
-rw-r--r--ale_linters/yaml/swaglint.vim17
-rw-r--r--ale_linters/yaml/yamllint.vim16
-rw-r--r--ale_linters/yang/yang_lsp.vim15
160 files changed, 1841 insertions, 1092 deletions
diff --git a/ale_linters/ada/gcc.vim b/ale_linters/ada/gcc.vim
new file mode 100644
index 00000000..d6f973ae
--- /dev/null
+++ b/ale_linters/ada/gcc.vim
@@ -0,0 +1,54 @@
+" Author: Martino Pilia <martino.pilia@gmail.com>
+" Description: Lint Ada files with GCC
+
+call ale#Set('ada_gcc_executable', 'gcc')
+
+" -gnatwa: activate most optional warnings
+" -gnatq: try semantic analysis even if syntax errors have been found
+call ale#Set('ada_gcc_options', '-gnatwa -gnatq')
+
+function! ale_linters#ada#gcc#GetCommand(buffer) abort
+ " Build a suitable output file name. The output file is specified because
+ " the .ali file may be created even if no code generation is attempted.
+ " The output file name must match the source file name (except for the
+ " extension), so here we cannot use the null file as output.
+ let l:tmp_dir = fnamemodify(ale#engine#CreateDirectory(a:buffer), ':p')
+ let l:out_file = l:tmp_dir . fnamemodify(bufname(a:buffer), ':t:r') . '.o'
+
+ " -gnatc: Check syntax and semantics only (no code generation attempted)
+ return '%e -x ada -c -gnatc'
+ \ . ' -o ' . ale#Escape(l:out_file)
+ \ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
+ \ . ' %t'
+endfunction
+
+" For the message format please refer to:
+" https://gcc.gnu.org/onlinedocs/gnat_ugn/Output-and-Error-Message-Control.html
+" https://gcc.gnu.org/onlinedocs/gnat_ugn/Warning-Message-Control.html
+function! ale_linters#ada#gcc#Handle(buffer, lines) abort
+ " Error format: <filename>:<lnum>:<col>: <text>
+ " Warning format: <filename>:<lnum>:<col>: warning: <text>
+ let l:re = '\v(.+):([0-9]+):([0-9]+):\s+(warning:)?\s*(.+)\s*'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:re)
+ call add(l:output, {
+ \ 'bufnr': a:buffer,
+ \ 'lnum': str2nr(l:match[2]),
+ \ 'col': str2nr(l:match[3]),
+ \ 'type': l:match[4] is# 'warning:' ? 'W' : 'E',
+ \ 'text': l:match[5],
+ \})
+ endfor
+
+ return l:output
+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',
+\ 'callback': 'ale_linters#ada#gcc#Handle',
+\})
diff --git a/ale_linters/ansible/ansible_lint.vim b/ale_linters/ansible/ansible_lint.vim
index 0b3b39c8..99fff6c3 100644
--- a/ale_linters/ansible/ansible_lint.vim
+++ b/ale_linters/ansible/ansible_lint.vim
@@ -1,6 +1,12 @@
" Author: Bjorn Neergaard <bjorn@neersighted.com>
" Description: ansible-lint for ansible-yaml files
+call ale#Set('ansible_ansible_lint_executable', 'ansible-lint')
+
+function! ale_linters#ansible#ansible_lint#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'ansible_ansible_lint_executable')
+endfunction
+
function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
for l:line in a:lines[:10]
if match(l:line, '^Traceback') >= 0
@@ -42,8 +48,9 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
endfunction
call ale#linter#Define('ansible', {
-\ 'name': 'ansible',
-\ 'executable': 'ansible',
-\ 'command': 'ansible-lint -p %t',
+\ 'name': 'ansible_lint',
+\ 'aliases': ['ansible', 'ansible-lint'],
+\ 'executable_callback': 'ale_linters#ansible#ansible_lint#GetExecutable',
+\ 'command': '%e -p %t',
\ 'callback': 'ale_linters#ansible#ansible_lint#Handle',
\})
diff --git a/ale_linters/apiblueprint/drafter.vim b/ale_linters/apiblueprint/drafter.vim
index 198709f9..5d40c53a 100644
--- a/ale_linters/apiblueprint/drafter.vim
+++ b/ale_linters/apiblueprint/drafter.vim
@@ -16,10 +16,12 @@ function! ale_linters#apiblueprint#drafter#HandleErrors(buffer, lines) abort
\ 'lnum': l:match[3] + 0,
\ 'col': l:match[4] + 0,
\}
+
if l:match[5] isnot# ''
let l:item.end_lnum = l:match[6] + 0
let l:item.end_col = l:match[7] + 0
endif
+
call add(l:output, l:item)
endfor
diff --git a/ale_linters/asciidoc/vale.vim b/ale_linters/asciidoc/vale.vim
new file mode 100644
index 00000000..b3cf4547
--- /dev/null
+++ b/ale_linters/asciidoc/vale.vim
@@ -0,0 +1,9 @@
+" Author: Jeff Kreeftmeijer https://github.com/jeffkreeftmeijer
+" Description: vale for AsciiDoc files
+
+call ale#linter#Define('asciidoc', {
+\ 'name': 'vale',
+\ 'executable': 'vale',
+\ 'command': 'vale --output=line %t',
+\ 'callback': 'ale#handlers#unix#HandleAsWarning',
+\})
diff --git a/ale_linters/asm/gcc.vim b/ale_linters/asm/gcc.vim
index 4ac876f8..fdd0ee83 100644
--- a/ale_linters/asm/gcc.vim
+++ b/ale_linters/asm/gcc.vim
@@ -4,15 +4,10 @@
call ale#Set('asm_gcc_executable', 'gcc')
call ale#Set('asm_gcc_options', '-Wall')
-function! ale_linters#asm#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'asm_gcc_executable')
-endfunction
-
function! ale_linters#asm#gcc#GetCommand(buffer) abort
- return ale#Escape(ale_linters#asm#gcc#GetExecutable(a:buffer))
- \ . ' -x assembler -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
- \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
+ return '%e -x assembler -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction
function! ale_linters#asm#gcc#Handle(buffer, lines) abort
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('asm', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#asm#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('asm_gcc_executable'),
\ 'command_callback': '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 8b60815f..eb92e45e 100644
--- a/ale_linters/awk/gawk.vim
+++ b/ale_linters/awk/gawk.vim
@@ -1,29 +1,21 @@
" Author: kmarc <korondi.mark@gmail.com>
" Description: This file adds support for using GNU awk with sripts.
-let g:ale_awk_gawk_executable =
-\ get(g:, 'ale_awk_gawk_executable', 'gawk')
-
-let g:ale_awk_gawk_options =
-\ get(g:, 'ale_awk_gawk_options', '')
-
-function! ale_linters#awk#gawk#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'awk_gawk_executable')
-endfunction
+call ale#Set('awk_gawk_executable', 'gawk')
+call ale#Set('awk_gawk_options', '')
function! ale_linters#awk#gawk#GetCommand(buffer) abort
" note the --source 'BEGIN ...' is to prevent
" gawk from attempting to execute the body of the script
" it is linting.
- return ale#Escape(ale_linters#awk#gawk#GetExecutable(a:buffer))
- \ . " --source 'BEGIN { exit } END { exit 1 }'"
+ return '%e --source ' . ale#Escape('BEGIN { exit } END { exit 1 }')
\ . ale#Pad(ale#Var(a:buffer, 'awk_gawk_options'))
- \ . ' ' . '-f %t --lint /dev/null'
+ \ . ' -f %t --lint /dev/null'
endfunction
call ale#linter#Define('awk', {
\ 'name': 'gawk',
-\ 'executable_callback': 'ale_linters#awk#gawk#GetExecutable',
+\ 'executable_callback': ale#VarFunc('awk_gawk_executable'),
\ 'command_callback': 'ale_linters#awk#gawk#GetCommand',
\ 'callback': 'ale#handlers#gawk#HandleGawkFormat',
\ 'output_stream': 'both'
diff --git a/ale_linters/c/ccls.vim b/ale_linters/c/ccls.vim
new file mode 100644
index 00000000..5dc2339f
--- /dev/null
+++ b/ale_linters/c/ccls.vim
@@ -0,0 +1,14 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for C
+
+call ale#Set('c_ccls_executable', 'ccls')
+call ale#Set('c_ccls_init_options', {})
+
+call ale#linter#Define('c', {
+\ 'name': 'ccls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('c_ccls_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
+\ 'initialization_options_callback':ale#VarFunc('c_ccls_init_options'),
+\})
diff --git a/ale_linters/c/clang.vim b/ale_linters/c/clang.vim
index ddec4fcb..f1bd675b 100644
--- a/ale_linters/c/clang.vim
+++ b/ale_linters/c/clang.vim
@@ -4,29 +4,24 @@
call ale#Set('c_clang_executable', 'clang')
call ale#Set('c_clang_options', '-std=c11 -Wall')
-function! ale_linters#c#clang#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_clang_executable')
-endfunction
-
function! ale_linters#c#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#c#clang#GetExecutable(a:buffer))
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'c_clang_options') . ' -'
+ return '%e -S -x c -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#c#clang#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_clang_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#c#clang#GetCommand'}
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/c/clangd.vim b/ale_linters/c/clangd.vim
index 5aa2e221..6cad601a 100644
--- a/ale_linters/c/clangd.vim
+++ b/ale_linters/c/clangd.vim
@@ -6,24 +6,18 @@ call ale#Set('c_clangd_options', '')
function! ale_linters#c#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
- return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
-endfunction
-function! ale_linters#c#clangd#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_clangd_executable')
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#c#clangd#GetCommand(buffer) abort
- let l:executable = ale_linters#c#clangd#GetExecutable(a:buffer)
- let l:options = ale#Var(a:buffer, 'c_clangd_options')
-
- return ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
endfunction
call ale#linter#Define('c', {
\ 'name': 'clangd',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#c#clangd#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_clangd_executable'),
\ 'command_callback': 'ale_linters#c#clangd#GetCommand',
\ 'project_root_callback': 'ale_linters#c#clangd#GetProjectRoot',
\})
diff --git a/ale_linters/c/clangtidy.vim b/ale_linters/c/clangtidy.vim
index 47faa1ef..4f334655 100644
--- a/ale_linters/c/clangtidy.vim
+++ b/ale_linters/c/clangtidy.vim
@@ -10,44 +10,22 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy')
" Consult the check list in clang-tidy's documentation:
" http://clang.llvm.org/extra/clang-tidy/checks/list.html
-call ale#Set('c_clangtidy_checks', ['*'])
+call ale#Set('c_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection.
call ale#Set('c_clangtidy_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#c#clangtidy#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_clangtidy_executable')
-endfunction
-
-function! s:GetBuildDirectory(buffer) abort
- " Don't include build directory for header files, as compile_commands.json
- " files don't consider headers to be translation units, and provide no
- " commands for compiling header files.
- if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
- return ''
- endif
-
- let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
-
- " c_build_dir has the priority if defined
- if !empty(l:build_dir)
- return l:build_dir
- endif
-
- return ale#c#FindCompileCommands(a:buffer)
-endfunction
-
function! ale_linters#c#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'c_clangtidy_checks'), ',')
- let l:build_dir = s:GetBuildDirectory(a:buffer)
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
" Get the extra options if we couldn't find a build directory.
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'c_clangtidy_options')
\ : ''
- return ale#Escape(ale_linters#c#clangtidy#GetExecutable(a:buffer))
+ return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
@@ -57,7 +35,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#c#clangtidy#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_clangtidy_executable'),
\ 'command_callback': '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 4db93f74..5e8c7936 100644
--- a/ale_linters/c/cppcheck.vim
+++ b/ale_linters/c/cppcheck.vim
@@ -4,10 +4,6 @@
call ale#Set('c_cppcheck_executable', 'cppcheck')
call ale#Set('c_cppcheck_options', '--enable=style')
-function! ale_linters#c#cppcheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_cppcheck_executable')
-endfunction
-
function! ale_linters#c#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json.
"
@@ -23,8 +19,7 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
\ : ''
return l:cd_command
- \ . ale#Escape(ale_linters#c#cppcheck#GetExecutable(a:buffer))
- \ . ' -q --language=c '
+ \ . '%e -q --language=c '
\ . l:compile_commands_option
\ . ale#Var(a:buffer, 'c_cppcheck_options')
\ . ' %t'
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale_linters#c#cppcheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_cppcheck_executable'),
\ 'command_callback': 'ale_linters#c#cppcheck#GetCommand',
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\})
diff --git a/ale_linters/c/cquery.vim b/ale_linters/c/cquery.vim
new file mode 100644
index 00000000..a20782a2
--- /dev/null
+++ b/ale_linters/c/cquery.vim
@@ -0,0 +1,28 @@
+" Author: Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for C
+
+call ale#Set('c_cquery_executable', 'cquery')
+call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery'))
+
+function! ale_linters#c#cquery#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ if empty(l:project_root)
+ let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
+ endif
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort
+ return {'cacheDirectory': ale#Var(a:buffer, 'c_cquery_cache_directory')}
+endfunction
+
+call ale#linter#Define('c', {
+\ 'name': 'cquery',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('c_cquery_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale_linters#c#cquery#GetProjectRoot',
+\ 'initialization_options_callback': 'ale_linters#c#cquery#GetInitializationOptions',
+\})
diff --git a/ale_linters/c/flawfinder.vim b/ale_linters/c/flawfinder.vim
index df6fbebe..7e1f6769 100644
--- a/ale_linters/c/flawfinder.vim
+++ b/ale_linters/c/flawfinder.vim
@@ -6,18 +6,12 @@ call ale#Set('c_flawfinder_options', '')
call ale#Set('c_flawfinder_minlevel', 1)
call ale#Set('c_flawfinder_error_severity', 6)
-function! ale_linters#c#flawfinder#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_flawfinder_executable')
-endfunction
-
function! ale_linters#c#flawfinder#GetCommand(buffer) abort
-
" Set the minimum vulnerability level for flawfinder to bother with
let l:minlevel = ' --minlevel=' . ale#Var(a:buffer, 'c_flawfinder_minlevel')
- return ale#Escape(ale_linters#c#flawfinder#GetExecutable(a:buffer))
- \ . ' -CDQS'
- \ . ale#Var(a:buffer, 'c_flawfinder_options')
+ return '%e -CDQS'
+ \ . ale#Pad(ale#Var(a:buffer, 'c_flawfinder_options'))
\ . l:minlevel
\ . ' %t'
endfunction
@@ -25,7 +19,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'flawfinder',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#c#flawfinder#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_flawfinder_executable'),
\ 'command_callback': '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 98563952..60ecb712 100644
--- a/ale_linters/c/gcc.vim
+++ b/ale_linters/c/gcc.vim
@@ -4,29 +4,24 @@
call ale#Set('c_gcc_executable', 'gcc')
call ale#Set('c_gcc_options', '-std=c11 -Wall')
-function! ale_linters#c#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_gcc_executable')
-endfunction
-
function! ale_linters#c#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#c#gcc#GetExecutable(a:buffer))
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'c_gcc_options') . ' -'
+ return '%e -S -x c -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#c#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_gcc_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#c#gcc#GetCommand'}
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/chef/foodcritic.vim b/ale_linters/chef/foodcritic.vim
index 2c28246c..c86336d6 100644
--- a/ale_linters/chef/foodcritic.vim
+++ b/ale_linters/chef/foodcritic.vim
@@ -6,17 +6,10 @@
call ale#Set('chef_foodcritic_executable', 'foodcritic')
call ale#Set('chef_foodcritic_options', '')
-function! ale_linters#chef#foodcritic#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'chef_foodcritic_executable')
-endfunction
-
function! ale_linters#chef#foodcritic#GetCommand(buffer) abort
- let l:executable = ale_linters#chef#foodcritic#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'chef_foodcritic_options')
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . escape(l:options, '~') : '')
- \ . ' %s'
+ return '%e' . ale#Pad(escape(l:options, '~')) . ' %s'
endfunction
function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
@@ -41,7 +34,7 @@ endfunction
call ale#linter#Define('chef', {
\ 'name': 'foodcritic',
-\ 'executable_callback': 'ale_linters#chef#foodcritic#GetExecutable',
+\ 'executable_callback': ale#VarFunc('chef_foodcritic_executable'),
\ 'command_callback': 'ale_linters#chef#foodcritic#GetCommand',
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/clojure/joker.vim b/ale_linters/clojure/joker.vim
index e78066fe..2f61148b 100644
--- a/ale_linters/clojure/joker.vim
+++ b/ale_linters/clojure/joker.vim
@@ -9,9 +9,11 @@ function! ale_linters#clojure#joker#HandleJokerFormat(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:type = 'E'
+
if l:match[4] is? 'Parse warning'
let l:type = 'W'
endif
+
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
@@ -27,6 +29,6 @@ call ale#linter#Define('clojure', {
\ 'name': 'joker',
\ 'output_stream': 'stderr',
\ 'executable': 'joker',
-\ 'command': 'joker --lint %t',
+\ 'command': 'joker --working-dir %s --lint %t',
\ 'callback': 'ale_linters#clojure#joker#HandleJokerFormat',
\})
diff --git a/ale_linters/cpp/ccls.vim b/ale_linters/cpp/ccls.vim
new file mode 100644
index 00000000..501fd685
--- /dev/null
+++ b/ale_linters/cpp/ccls.vim
@@ -0,0 +1,14 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for C++
+
+call ale#Set('cpp_ccls_executable', 'ccls')
+call ale#Set('cpp_ccls_init_options', {})
+
+call ale#linter#Define('cpp', {
+\ 'name': 'ccls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('cpp_ccls_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
+\ 'initialization_options_callback': ale#VarFunc('cpp_ccls_init_options'),
+\})
diff --git a/ale_linters/cpp/clang.vim b/ale_linters/cpp/clang.vim
index e8d96187..649c5993 100644
--- a/ale_linters/cpp/clang.vim
+++ b/ale_linters/cpp/clang.vim
@@ -4,29 +4,24 @@
call ale#Set('cpp_clang_executable', 'clang++')
call ale#Set('cpp_clang_options', '-std=c++14 -Wall')
-function! ale_linters#cpp#clang#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_clang_executable')
-endfunction
-
function! ale_linters#cpp#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#cpp#clang#GetExecutable(a:buffer))
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'cpp_clang_options') . ' -'
+ return '%e -S -x c++ -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#clang#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_clang_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#cpp#clang#GetCommand'},
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/cpp/clangcheck.vim b/ale_linters/cpp/clangcheck.vim
index a109d5d3..c66d6702 100644
--- a/ale_linters/cpp/clangcheck.vim
+++ b/ale_linters/cpp/clangcheck.vim
@@ -5,10 +5,6 @@ call ale#Set('cpp_clangcheck_executable', 'clang-check')
call ale#Set('cpp_clangcheck_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#cpp#clangcheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_clangcheck_executable')
-endfunction
-
function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:user_options = ale#Var(a:buffer, 'cpp_clangcheck_options')
@@ -16,23 +12,22 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:build_dir)
- let l:build_dir = ale#c#FindCompileCommands(a:buffer)
+ let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endif
" The extra arguments in the command are used to prevent .plist files from
" being generated. These are only added if no build directory can be
" detected.
- return ale#Escape(ale_linters#cpp#clangcheck#GetExecutable(a:buffer))
- \ . ' -analyze %s'
+ return '%e -analyze %s'
\ . (empty(l:build_dir) ? ' -extra-arg -Xclang -extra-arg -analyzer-output=text' : '')
- \ . (!empty(l:user_options) ? ' ' . l:user_options : '')
+ \ . ale#Pad(l:user_options)
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangcheck',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#clangcheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_clangcheck_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..9139f054
--- /dev/null
+++ b/ale_linters/cpp/clangd.vim
@@ -0,0 +1,23 @@
+" Author: Andrey Melentyev <andrey.melentyev@protonmail.com>
+" Description: Clangd language server
+
+call ale#Set('cpp_clangd_executable', 'clangd')
+call ale#Set('cpp_clangd_options', '')
+
+function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#cpp#clangd#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
+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',
+\})
diff --git a/ale_linters/cpp/clangtidy.vim b/ale_linters/cpp/clangtidy.vim
index 1d5fb77a..9c3da8db 100644
--- a/ale_linters/cpp/clangtidy.vim
+++ b/ale_linters/cpp/clangtidy.vim
@@ -4,44 +4,22 @@
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" Set this option to check the checks clang-tidy will apply.
-call ale#Set('cpp_clangtidy_checks', ['*'])
+call ale#Set('cpp_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection.
call ale#Set('cpp_clangtidy_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#cpp#clangtidy#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_clangtidy_executable')
-endfunction
-
-function! s:GetBuildDirectory(buffer) abort
- " Don't include build directory for header files, as compile_commands.json
- " files don't consider headers to be translation units, and provide no
- " commands for compiling header files.
- if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
- return ''
- endif
-
- let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
-
- " c_build_dir has the priority if defined
- if !empty(l:build_dir)
- return l:build_dir
- endif
-
- return ale#c#FindCompileCommands(a:buffer)
-endfunction
-
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',')
- let l:build_dir = s:GetBuildDirectory(a:buffer)
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
" Get the extra options if we couldn't find a build directory.
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
\ : ''
- return ale#Escape(ale_linters#cpp#clangtidy#GetExecutable(a:buffer))
+ return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
@@ -51,7 +29,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#cpp#clangtidy#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_clangtidy_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..cbbd0ccf
--- /dev/null
+++ b/ale_linters/cpp/clazy.vim
@@ -0,0 +1,32 @@
+" Description: clazy linter for cpp files (clang-based and Qt-oriented)
+
+call ale#Set('cpp_clazy_executable', 'clazy-standalone')
+" Set this option to check the checks clazy will apply.
+call ale#Set('cpp_clazy_checks', ['level1'])
+" Set this option to manually set some options for clazy.
+" This will disable compile_commands.json detection.
+call ale#Set('cpp_clazy_options', '')
+call ale#Set('c_build_dir', '')
+
+function! ale_linters#cpp#clazy#GetCommand(buffer) abort
+ let l:checks = join(ale#Var(a:buffer, 'cpp_clazy_checks'), ',')
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
+
+ " Get the extra options if we couldn't find a build directory.
+ let l:options = ale#Var(a:buffer, 'cpp_clazy_options')
+
+ return '%e'
+ \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
+ \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' %s'
+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',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/cpp/cppcheck.vim b/ale_linters/cpp/cppcheck.vim
index 8b2aa802..229d6133 100644
--- a/ale_linters/cpp/cppcheck.vim
+++ b/ale_linters/cpp/cppcheck.vim
@@ -4,10 +4,6 @@
call ale#Set('cpp_cppcheck_executable', 'cppcheck')
call ale#Set('cpp_cppcheck_options', '--enable=style')
-function! ale_linters#cpp#cppcheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_cppcheck_executable')
-endfunction
-
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json.
"
@@ -23,8 +19,7 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
\ : ''
return l:cd_command
- \ . ale#Escape(ale_linters#cpp#cppcheck#GetExecutable(a:buffer))
- \ . ' -q --language=c++ '
+ \ . '%e -q --language=c++ '
\ . l:compile_commands_option
\ . ale#Var(a:buffer, 'cpp_cppcheck_options')
\ . ' %t'
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale_linters#cpp#cppcheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_cppcheck_executable'),
\ 'command_callback': '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 346ac815..d135fa79 100644
--- a/ale_linters/cpp/cpplint.vim
+++ b/ale_linters/cpp/cpplint.vim
@@ -4,22 +4,16 @@
call ale#Set('cpp_cpplint_executable', 'cpplint')
call ale#Set('cpp_cpplint_options', '')
-function! ale_linters#cpp#cpplint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_cpplint_executable')
-endfunction
-
function! ale_linters#cpp#cpplint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'cpp_cpplint_options')
- return ale#Escape(ale_linters#cpp#cpplint#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' %s'
+ return '%e' . ale#Pad(l:options) . ' %s'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cpplint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#cpplint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_cpplint_executable'),
\ 'command_callback': '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 7997c843..b1c81989 100644
--- a/ale_linters/cpp/cquery.vim
+++ b/ale_linters/cpp/cquery.vim
@@ -7,16 +7,11 @@ call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
- return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
-endfunction
+ if empty(l:project_root)
+ let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
+ endif
-function! ale_linters#cpp#cquery#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_cquery_executable')
-endfunction
-
-function! ale_linters#cpp#cquery#GetCommand(buffer) abort
- let l:executable = ale_linters#cpp#cquery#GetExecutable(a:buffer)
- return ale#Escape(l:executable)
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort
@@ -26,8 +21,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cquery',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#cpp#cquery#GetExecutable',
-\ 'command_callback': 'ale_linters#cpp#cquery#GetCommand',
+\ 'executable_callback': ale#VarFunc('cpp_cquery_executable'),
+\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#cpp#cquery#GetProjectRoot',
\ 'initialization_options_callback': 'ale_linters#cpp#cquery#GetInitializationOptions',
\})
diff --git a/ale_linters/cpp/flawfinder.vim b/ale_linters/cpp/flawfinder.vim
index 5a7092cf..4f669bff 100644
--- a/ale_linters/cpp/flawfinder.vim
+++ b/ale_linters/cpp/flawfinder.vim
@@ -6,17 +6,11 @@ call ale#Set('cpp_flawfinder_options', '')
call ale#Set('cpp_flawfinder_minlevel', 1)
call ale#Set('c_flawfinder_error_severity', 6)
-function! ale_linters#cpp#flawfinder#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_flawfinder_executable')
-endfunction
-
function! ale_linters#cpp#flawfinder#GetCommand(buffer) abort
-
" Set the minimum vulnerability level for flawfinder to bother with
let l:minlevel = ' --minlevel=' . ale#Var(a:buffer, 'cpp_flawfinder_minlevel')
- return ale#Escape(ale_linters#cpp#flawfinder#GetExecutable(a:buffer))
- \ . ' -CDQS'
+ return '%e -CDQS'
\ . ale#Var(a:buffer, 'cpp_flawfinder_options')
\ . l:minlevel
\ . ' %t'
@@ -25,7 +19,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'flawfinder',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#cpp#flawfinder#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_flawfinder_executable'),
\ 'command_callback': '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 a663eaa3..9935b0bb 100644
--- a/ale_linters/cpp/gcc.vim
+++ b/ale_linters/cpp/gcc.vim
@@ -4,30 +4,25 @@
call ale#Set('cpp_gcc_executable', 'gcc')
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
-function! ale_linters#cpp#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_gcc_executable')
-endfunction
-
function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#cpp#gcc#GetExecutable(a:buffer))
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'cpp_gcc_options') . ' -'
+ return '%e -S -x c++ -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'gcc',
\ 'aliases': ['g++'],
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_gcc_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#cpp#gcc#GetCommand'},
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/css/stylelint.vim b/ale_linters/css/stylelint.vim
index a16dfde2..6f8bef68 100644
--- a/ale_linters/css/stylelint.vim
+++ b/ale_linters/css/stylelint.vim
@@ -4,21 +4,16 @@ call ale#Set('css_stylelint_executable', 'stylelint')
call ale#Set('css_stylelint_options', '')
call ale#Set('css_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#css#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'css_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#css#stylelint#GetCommand(buffer) abort
- return ale_linters#css#stylelint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'css_stylelint_options')
+ return '%e ' . ale#Pad(ale#Var(a:buffer, 'css_stylelint_options'))
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('css', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#css#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('css_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': '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 6708d32f..e8ae09ff 100644
--- a/ale_linters/cucumber/cucumber.vim
+++ b/ale_linters/cucumber/cucumber.vim
@@ -22,6 +22,7 @@ function! ale_linters#cucumber#cucumber#Handle(buffer, lines) abort
endtry
let l:output = []
+
for l:element in get(l:json, 'elements', [])
for l:step in l:element['steps']
if l:step['result']['status'] is# 'undefined'
diff --git a/ale_linters/cuda/nvcc.vim b/ale_linters/cuda/nvcc.vim
index 3764fe9d..f4442cb8 100644
--- a/ale_linters/cuda/nvcc.vim
+++ b/ale_linters/cuda/nvcc.vim
@@ -4,20 +4,14 @@
call ale#Set('cuda_nvcc_executable', 'nvcc')
call ale#Set('cuda_nvcc_options', '-std=c++11')
-function! ale_linters#cuda#nvcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cuda_nvcc_executable')
-endfunction
-
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#engine#ManageFile(a:buffer, l:output_file)
-
- return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer))
- \ . ' -cuda '
- \ . ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
- \ . ale#Var(a:buffer, 'cuda_nvcc_options') . ' %s'
- \ . ' -o ' . g:ale#util#nul_file
+ return '%e -cuda'
+ \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
+ \ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))
+ \ . ' %s -o ' . g:ale#util#nul_file
endfunction
function! ale_linters#cuda#nvcc#HandleNVCCFormat(buffer, lines) abort
@@ -28,7 +22,6 @@ function! ale_linters#cuda#nvcc#HandleNVCCFormat(buffer, lines) abort
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
-
let l:item = {
\ 'lnum': str2nr(l:match[2]),
\ 'type': l:match[4] =~# 'error' ? 'E' : 'W',
@@ -49,7 +42,7 @@ endfunction
call ale#linter#Define('cuda', {
\ 'name': 'nvcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cuda#nvcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cuda_nvcc_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..7210d21e
--- /dev/null
+++ b/ale_linters/d/dls.vim
@@ -0,0 +1,22 @@
+" Author: aurieh <me@aurieh.me>
+" Description: A Language Server implementation for D
+
+call ale#Set('d_dls_executable', 'dls')
+
+function! ale_linters#d#dls#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'd_dls_executable')
+endfunction
+
+function! ale_linters#d#dls#FindProjectRoot(buffer) abort
+ " Note: this will return . if dub config is empty
+ " dls can run outside DUB projects just fine
+ return fnamemodify(ale#d#FindDUBConfig(a:buffer), ':h')
+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',
+\})
diff --git a/ale_linters/d/dmd.vim b/ale_linters/d/dmd.vim
index d64b6c3d..c816d592 100644
--- a/ale_linters/d/dmd.vim
+++ b/ale_linters/d/dmd.vim
@@ -1,20 +1,6 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: "dmd for D files"
-function! s:FindDUBConfig(buffer) abort
- " Find a DUB configuration file in ancestor paths.
- " The most DUB-specific names will be tried first.
- for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
- let l:dub_file = ale#path#FindNearestFile(a:buffer, l:possible_filename)
-
- if !empty(l:dub_file)
- return l:dub_file
- endif
- endfor
-
- return ''
-endfunction
-
function! ale_linters#d#dmd#DUBCommand(buffer) abort
" If we can't run dub, then skip this command.
if !executable('dub')
@@ -22,7 +8,7 @@ function! ale_linters#d#dmd#DUBCommand(buffer) abort
return ''
endif
- let l:dub_file = s:FindDUBConfig(a:buffer)
+ let l:dub_file = ale#d#FindDUBConfig(a:buffer)
if empty(l:dub_file)
return ''
diff --git a/ale_linters/dafny/dafny.vim b/ale_linters/dafny/dafny.vim
index 8bbf1b13..b5b90675 100644
--- a/ale_linters/dafny/dafny.vim
+++ b/ale_linters/dafny/dafny.vim
@@ -13,6 +13,7 @@ function! ale_linters#dafny#dafny#Handle(buffer, lines) abort
\ 'type': l:match[4] =~# '^Error' ? 'E' : 'W'
\ })
endfor
+
return l:output
endfunction
diff --git a/ale_linters/dart/dartanalyzer.vim b/ale_linters/dart/dartanalyzer.vim
index ef33c9d4..26817df5 100644
--- a/ale_linters/dart/dartanalyzer.vim
+++ b/ale_linters/dart/dartanalyzer.vim
@@ -3,15 +3,10 @@
call ale#Set('dart_dartanalyzer_executable', 'dartanalyzer')
-function! ale_linters#dart#dartanalyzer#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'dart_dartanalyzer_executable')
-endfunction
-
function! ale_linters#dart#dartanalyzer#GetCommand(buffer) abort
- let l:executable = ale_linters#dart#dartanalyzer#GetExecutable(a:buffer)
let l:path = ale#path#FindNearestFile(a:buffer, '.packages')
- return ale#Escape(l:executable)
+ return '%e'
\ . (!empty(l:path) ? ' --packages ' . ale#Escape(l:path) : '')
\ . ' %s'
endfunction
@@ -34,7 +29,7 @@ endfunction
call ale#linter#Define('dart', {
\ 'name': 'dartanalyzer',
-\ 'executable_callback': 'ale_linters#dart#dartanalyzer#GetExecutable',
+\ 'executable_callback': ale#VarFunc('dart_dartanalyzer_executable'),
\ 'command_callback': '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 2265e37a..8e0c139b 100644
--- a/ale_linters/dart/language_server.vim
+++ b/ale_linters/dart/language_server.vim
@@ -3,10 +3,6 @@
call ale#Set('dart_language_server_executable', 'dart_language_server')
-function! ale_linters#dart#language_server#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'dart_language_server_executable')
-endfunction
-
function! ale_linters#dart#language_server#GetProjectRoot(buffer) abort
" Note: pub only looks for pubspec.yaml, there's no point in adding
" support for pubspec.yml
@@ -18,7 +14,7 @@ endfunction
call ale#linter#Define('dart', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#dart#language_server#GetExecutable',
-\ 'command_callback': 'ale_linters#dart#language_server#GetExecutable',
+\ 'executable_callback': ale#VarFunc('dart_language_server_executable'),
+\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#dart#language_server#GetProjectRoot',
\})
diff --git a/ale_linters/dockerfile/dockerfile_lint.vim b/ale_linters/dockerfile/dockerfile_lint.vim
new file mode 100644
index 00000000..a5a846f2
--- /dev/null
+++ b/ale_linters/dockerfile/dockerfile_lint.vim
@@ -0,0 +1,61 @@
+" Author: Alexander Olofsson <alexander.olofsson@liu.se>
+
+call ale#Set('dockerfile_dockerfile_lint_executable', 'dockerfile_lint')
+call ale#Set('dockerfile_dockerfile_lint_options', '')
+
+function! ale_linters#dockerfile#dockerfile_lint#GetType(type) abort
+ if a:type is? 'error'
+ return 'E'
+ elseif a:type is? 'warn'
+ return 'W'
+ endif
+
+ return 'I'
+endfunction
+
+function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
+ try
+ let l:data = json_decode(join(a:lines, ''))
+ catch
+ return []
+ endtry
+
+ if empty(l:data)
+ " Should never happen, but it's better to be on the safe side
+ return []
+ endif
+
+ let l:messages = []
+
+ for l:type in ['error', 'warn', 'info']
+ for l:object in l:data[l:type]['data']
+ let l:line = get(l:object, 'line', -1)
+ let l:message = l:object['message']
+
+ if get(l:object, 'description', 'None') isnot# 'None'
+ let l:message = l:message . '. ' . l:object['description']
+ endif
+
+ call add(l:messages, {
+ \ 'lnum': l:line,
+ \ 'text': l:message,
+ \ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
+ \})
+ endfor
+ endfor
+
+ return l:messages
+endfunction
+
+function! ale_linters#dockerfile#dockerfile_lint#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'dockerfile_dockerfile_lint_options'))
+ \ . ' -p -j -f'
+ \ . ' %t'
+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',
+\ 'callback': 'ale_linters#dockerfile#dockerfile_lint#Handle',
+\})
diff --git a/ale_linters/dockerfile/hadolint.vim b/ale_linters/dockerfile/hadolint.vim
index 7772afbd..dc0f5b9e 100644
--- a/ale_linters/dockerfile/hadolint.vim
+++ b/ale_linters/dockerfile/hadolint.vim
@@ -82,9 +82,11 @@ endfunction
function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort
let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer)
+
if l:command is# 'docker'
return 'docker run --rm -i ' . ale#Var(a:buffer, 'dockerfile_hadolint_docker_image')
endif
+
return 'hadolint -'
endfunction
diff --git a/ale_linters/elixir/credo.vim b/ale_linters/elixir/credo.vim
index af2ff48a..d778471c 100644
--- a/ale_linters/elixir/credo.vim
+++ b/ale_linters/elixir/credo.vim
@@ -11,10 +11,18 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
let l:type = l:match[3]
let l:text = l:match[4]
- if l:type is# 'C'
- let l:type = 'E'
- elseif l:type is# 'R'
+ " Refactoring opportunities
+ if l:type is# 'F'
+ let l:type = 'W'
+ " Consistency
+ elseif l:type is# 'C'
let l:type = 'W'
+ " Software Design
+ elseif l:type is# 'D'
+ let l:type = 'I'
+ " Code Readability
+ elseif l:type is# 'R'
+ let l:type = 'I'
endif
call add(l:output, {
@@ -29,9 +37,16 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#elixir#credo#GetCommand(buffer) abort
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+
+ return ale#path#CdString(l:project_root)
+ \ . ' mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
+endfunction
+
call ale#linter#Define('elixir', {
\ 'name': 'credo',
\ 'executable': 'mix',
-\ 'command': 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s',
+\ 'command_callback': '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 bba0ae14..d28d3c70 100644
--- a/ale_linters/elixir/dialyxir.vim
+++ b/ale_linters/elixir/dialyxir.vim
@@ -25,10 +25,17 @@ function! ale_linters#elixir#dialyxir#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#elixir#dialyxir#GetCommand(buffer) abort
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+
+ return ale#path#CdString(l:project_root)
+ \ . ' mix help dialyzer && mix dialyzer'
+endfunction
+
call ale#linter#Define('elixir', {
\ 'name': 'dialyxir',
\ 'executable': 'mix',
-\ 'command': 'mix help dialyzer && mix dialyzer',
+\ 'command_callback': '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 71cf4f4c..dcfb6f28 100644
--- a/ale_linters/elixir/dogma.vim
+++ b/ale_linters/elixir/dogma.vim
@@ -29,10 +29,17 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#elixir#dogma#GetCommand(buffer) abort
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+
+ return ale#path#CdString(l:project_root)
+ \ . ' mix help dogma && mix dogma %s --format=flycheck'
+endfunction
+
call ale#linter#Define('elixir', {
\ 'name': 'dogma',
\ 'executable': 'mix',
-\ 'command': 'mix help dogma && mix dogma %s --format=flycheck',
+\ 'command_callback': '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
new file mode 100644
index 00000000..3b299ec6
--- /dev/null
+++ b/ale_linters/elixir/elixir_ls.vim
@@ -0,0 +1,21 @@
+" Author: Jon Parise <jon@indelible.org>
+" Description: ElixirLS integration (https://github.com/JakeBecker/elixir-ls)
+
+call ale#Set('elixir_elixir_ls_release', 'elixir-ls')
+call ale#Set('elixir_elixir_ls_config', {})
+
+function! ale_linters#elixir#elixir_ls#GetExecutable(buffer) abort
+ let l:dir = ale#path#Simplify(ale#Var(a:buffer, 'elixir_elixir_ls_release'))
+ let l:cmd = ale#Has('win32') ? '\language_server.bat' : '/language_server.sh'
+
+ return l:dir . l:cmd
+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'),
+\})
diff --git a/ale_linters/elixir/mix.vim b/ale_linters/elixir/mix.vim
index 1a95e37f..dc3c1818 100644
--- a/ale_linters/elixir/mix.vim
+++ b/ale_linters/elixir/mix.vim
@@ -10,7 +10,6 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort
"
" TODO: Warning format
" warning: variable "foobar" does not exist and is being expanded to "foobar()", please use parentheses to remove the ambiguity or change the variable name
-
let l:pattern = '\v\(([^\)]+Error)\) ([^:]+):([^:]+): (.+)$'
let l:output = []
@@ -30,16 +29,8 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#elixir#mix#FindProjectRoot(buffer) abort
- let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs')
- if !empty(l:mix_file)
- return fnamemodify(l:mix_file, ':p:h')
- endif
- return '.'
-endfunction
-
function! ale_linters#elixir#mix#GetCommand(buffer) abort
- let l:project_root = ale_linters#elixir#mix#FindProjectRoot(a:buffer)
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:temp_dir = ale#engine#CreateDirectory(a:buffer)
@@ -48,8 +39,8 @@ function! ale_linters#elixir#mix#GetCommand(buffer) abort
\ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir)
return ale#path#CdString(l:project_root)
- \ . l:mix_build_path
- \ . ' mix compile %s'
+ \ . l:mix_build_path
+ \ . ' mix compile %s'
endfunction
call ale#linter#Define('elixir', {
diff --git a/ale_linters/elm/make.vim b/ale_linters/elm/make.vim
index d5bc19eb..ddea983f 100644
--- a/ale_linters/elm/make.vim
+++ b/ale_linters/elm/make.vim
@@ -4,12 +4,6 @@
call ale#Set('elm_make_executable', 'elm')
call ale#Set('elm_make_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#elm#make#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'elm_make', [
- \ 'node_modules/.bin/elm',
- \])
-endfunction
-
function! ale_linters#elm#make#Handle(buffer, lines) abort
let l:output = []
let l:unparsed_lines = []
@@ -136,7 +130,7 @@ function! ale_linters#elm#make#ParseMessage(message) abort
endfunction
function! ale_linters#elm#make#ParseMessageItem(item) abort
- if type(a:item) == type('')
+ if type(a:item) is v:t_string
return a:item
else
return a:item.string
@@ -147,7 +141,6 @@ endfunction
" If it doesn't, then this will fail when imports are needed.
function! ale_linters#elm#make#GetCommand(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
- let l:elm_exe = ale_linters#elm#make#GetExecutable(a:buffer)
if empty(l:elm_json)
" Fallback to Elm 0.18
@@ -165,18 +158,15 @@ function! ale_linters#elm#make#GetCommand(buffer) abort
" a sort of flag to tell the compiler not to generate an output file,
" which is why this is hard coded here.
" Source: https://github.com/elm-lang/elm-compiler/blob/19d5a769b30ec0b2fc4475985abb4cd94cd1d6c3/builder/src/Generate/Output.hs#L253
- let l:elm_cmd = ale#Escape(l:elm_exe)
- \ . ' make'
- \ . ' --report=json'
- \ . ' --output=/dev/null'
-
- return l:dir_set_cmd . ' ' . l:elm_cmd . ' %t'
+ return l:dir_set_cmd . '%e make --report=json --output=/dev/null %t'
endfunction
call ale#linter#Define('elm', {
-\ 'name': 'make',
-\ 'executable_callback': 'ale_linters#elm#make#GetExecutable',
-\ 'output_stream': 'both',
-\ 'command_callback': 'ale_linters#elm#make#GetCommand',
-\ 'callback': 'ale_linters#elm#make#Handle'
+\ 'name': 'make',
+\ 'executable_callback': ale#node#FindExecutableFunc('elm_make', [
+\ 'node_modules/.bin/elm',
+\ ]),
+\ 'output_stream': 'both',
+\ 'command_callback': 'ale_linters#elm#make#GetCommand',
+\ 'callback': 'ale_linters#elm#make#Handle'
\})
diff --git a/ale_linters/erlang/syntaxerl.vim b/ale_linters/erlang/syntaxerl.vim
index 46ecdcb7..5b679743 100644
--- a/ale_linters/erlang/syntaxerl.vim
+++ b/ale_linters/erlang/syntaxerl.vim
@@ -3,24 +3,12 @@
call ale#Set('erlang_syntaxerl_executable', 'syntaxerl')
-
-function! ale_linters#erlang#syntaxerl#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'erlang_syntaxerl_executable')
-endfunction
-
-
-function! ale_linters#erlang#syntaxerl#FeatureCheck(buffer) abort
- return s:GetEscapedExecutable(a:buffer) . ' -h'
-endfunction
-
-
function! ale_linters#erlang#syntaxerl#GetCommand(buffer, output) abort
let l:use_b_option = match(a:output, '\C\V-b, --base\>') > -1
- return s:GetEscapedExecutable(a:buffer) . (l:use_b_option ? ' -b %s %t' : ' %t')
+ return '%e' . (l:use_b_option ? ' -b %s %t' : ' %t')
endfunction
-
function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort
let l:pattern = '\v\C:(\d+):( warning:)? (.+)'
let l:loclist = []
@@ -36,17 +24,11 @@ function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort
return l:loclist
endfunction
-
-function! s:GetEscapedExecutable(buffer) abort
- return ale#Escape(ale_linters#erlang#syntaxerl#GetExecutable(a:buffer))
-endfunction
-
-
call ale#linter#Define('erlang', {
\ 'name': 'syntaxerl',
-\ 'executable_callback': 'ale_linters#erlang#syntaxerl#GetExecutable',
+\ 'executable_callback': ale#VarFunc('erlang_syntaxerl_executable'),
\ 'command_chain': [
-\ {'callback': 'ale_linters#erlang#syntaxerl#FeatureCheck'},
+\ {'callback': {-> '%e -h'}},
\ {'callback': 'ale_linters#erlang#syntaxerl#GetCommand'},
\ ],
\ 'callback': 'ale_linters#erlang#syntaxerl#Handle',
diff --git a/ale_linters/eruby/ruumba.vim b/ale_linters/eruby/ruumba.vim
new file mode 100644
index 00000000..24f112e4
--- /dev/null
+++ b/ale_linters/eruby/ruumba.vim
@@ -0,0 +1,62 @@
+" Author: aclemons - https://github.com/aclemons
+" based on the ale rubocop linter
+" Description: Ruumba, RuboCop linting for ERB templates.
+
+call ale#Set('eruby_ruumba_executable', 'ruumba')
+call ale#Set('eruby_ruumba_options', '')
+
+function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'eruby_ruumba_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'ruumba')
+ \ . ' --format json --force-exclusion '
+ \ . ale#Var(a:buffer, 'eruby_ruumba_options')
+ \ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
+endfunction
+
+function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort
+ try
+ let l:errors = json_decode(a:lines[0])
+ catch
+ return []
+ endtry
+
+ if !has_key(l:errors, 'summary')
+ \|| l:errors['summary']['offense_count'] == 0
+ \|| empty(l:errors['files'])
+ return []
+ endif
+
+ let l:output = []
+
+ for l:error in l:errors['files'][0]['offenses']
+ let l:start_col = l:error['location']['column'] + 0
+ call add(l:output, {
+ \ 'lnum': l:error['location']['line'] + 0,
+ \ 'col': l:start_col,
+ \ 'end_col': l:start_col + l:error['location']['length'] - 1,
+ \ 'code': l:error['cop_name'],
+ \ 'text': l:error['message'],
+ \ 'type': ale_linters#eruby#ruumba#GetType(l:error['severity']),
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+function! ale_linters#eruby#ruumba#GetType(severity) abort
+ if a:severity is? 'convention'
+ \|| a:severity is? 'warning'
+ \|| a:severity is? 'refactor'
+ return 'W'
+ endif
+
+ return 'E'
+endfunction
+
+call ale#linter#Define('eruby', {
+\ 'name': 'ruumba',
+\ 'executable_callback': ale#VarFunc('eruby_ruumba_executable'),
+\ 'command_callback': '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 5f2ac018..f1595789 100644
--- a/ale_linters/fortran/gcc.vim
+++ b/ale_linters/fortran/gcc.vim
@@ -2,18 +2,10 @@
" Description: gcc for Fortran files
" This option can be set to 0 to use -ffixed-form
-if !exists('g:ale_fortran_gcc_use_free_form')
- let g:ale_fortran_gcc_use_free_form = 1
-endif
-
-if !exists('g:ale_fortran_gcc_executable')
- let g:ale_fortran_gcc_executable = 'gcc'
-endif
-
+call ale#Set('fortran_gcc_use_free_form', 1)
+call ale#Set('fortran_gcc_executable', 'gcc')
" Set this option to change the GCC options for warnings for Fortran.
-if !exists('g:ale_fortran_gcc_options')
- let g:ale_fortran_gcc_options = '-Wall'
-endif
+call ale#Set('fortran_gcc_options', '-Wall')
function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
" We have to match a starting line and a later ending line together,
@@ -61,26 +53,20 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#fortran#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'fortran_gcc_executable')
-endfunction
-
function! ale_linters#fortran#gcc#GetCommand(buffer) abort
let l:layout_option = ale#Var(a:buffer, 'fortran_gcc_use_free_form')
\ ? '-ffree-form'
\ : '-ffixed-form'
- return ale_linters#fortran#gcc#GetExecutable(a:buffer)
- \ . ' -S -x f95 -fsyntax-only '
- \ . l:layout_option . ' '
- \ . ale#Var(a:buffer, 'fortran_gcc_options') . ' '
- \ . '-'
+ return '%e -S -x f95 -fsyntax-only ' . l:layout_option
+ \ . ale#Pad(ale#Var(a:buffer, 'fortran_gcc_options'))
+ \ . ' -'
endfunction
call ale#linter#Define('fortran', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#fortran#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('fortran_gcc_executable'),
\ 'command_callback': '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 fd763fcf..4e5f5dc4 100644
--- a/ale_linters/fortran/language_server.vim
+++ b/ale_linters/fortran/language_server.vim
@@ -4,14 +4,6 @@
call ale#Set('fortran_language_server_executable', 'fortls')
call ale#Set('fortran_language_server_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#fortran#language_server#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'fortran_language_server_executable')
-endfunction
-
-function! ale_linters#fortran#language_server#GetCommand(buffer) abort
- return ale#Escape(ale_linters#fortran#language_server#GetExecutable(a:buffer))
-endfunction
-
function! ale_linters#fortran#language_server#GetProjectRoot(buffer) abort
let l:fortls_file = ale#path#FindNearestFile(a:buffer, '.fortls')
@@ -21,7 +13,7 @@ endfunction
call ale#linter#Define('fortran', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#fortran#language_server#GetExecutable',
-\ 'command_callback': 'ale_linters#fortran#language_server#GetCommand',
+\ 'executable_callback': ale#VarFunc('fortran_language_server_executable'),
+\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#fortran#language_server#GetProjectRoot',
\})
diff --git a/ale_linters/fuse/fusionlint.vim b/ale_linters/fuse/fusionlint.vim
index cf20e1b4..ab8f143b 100644
--- a/ale_linters/fuse/fusionlint.vim
+++ b/ale_linters/fuse/fusionlint.vim
@@ -4,13 +4,8 @@
call ale#Set('fuse_fusionlint_executable', 'fusion-lint')
call ale#Set('fuse_fusionlint_options', '')
-function! ale_linters#fuse#fusionlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'fuse_fusionlint_executable')
-endfunction
-
function! ale_linters#fuse#fusionlint#GetCommand(buffer) abort
- return ale#Escape(ale_linters#fuse#fusionlint#GetExecutable(a:buffer))
- \ . ale#Pad(ale#Var(a:buffer, 'fuse_fusionlint_options'))
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'fuse_fusionlint_options'))
\ . ' --filename %s -i'
endfunction
@@ -32,7 +27,7 @@ endfunction
call ale#linter#Define('fuse', {
\ 'name': 'fusionlint',
-\ 'executable_callback': 'ale_linters#fuse#fusionlint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('fuse_fusionlint_executable'),
\ 'command_callback': '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 64731055..a9c4822d 100644
--- a/ale_linters/gitcommit/gitlint.vim
+++ b/ale_linters/gitcommit/gitlint.vim
@@ -1,11 +1,9 @@
" Author: Nick Yamane <nick.diego@gmail.com>
" Description: gitlint for git commit message files
-let g:ale_gitcommit_gitlint_executable =
-\ get(g:, 'ale_gitcommit_gitlint_executable', 'gitlint')
-let g:ale_gitcommit_gitlint_options = get(g:, 'ale_gitcommit_gitlint_options', '')
-let g:ale_gitcommit_gitlint_use_global = get(g:, 'ale_gitcommit_gitlint_use_global', get(g:, 'ale_use_global_executables', 0))
-
+call ale#Set('gitcommit_gitlint_executable', 'gitlint')
+call ale#Set('gitcommit_gitlint_options', '')
+call ale#Set('gitcommit_gitlint_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#gitcommit#gitlint#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'gitcommit_gitlint', ['gitlint'])
@@ -13,12 +11,9 @@ endfunction
function! ale_linters#gitcommit#gitlint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'gitcommit_gitlint_options')
- let l:executable = ale_linters#gitcommit#gitlint#GetExecutable(a:buffer)
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' lint'
-endfunction
+ return '%e' . ale#Pad(l:options) . ' lint'
+endfunction
function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
" Matches patterns line the following:
@@ -28,8 +23,10 @@ function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[2]
- if l:code is# 'T2' && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
- continue
+ if !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
+ if l:code is# 'T2' || l:code is# 'B2'
+ continue
+ endif
endif
let l:item = {
@@ -45,7 +42,6 @@ function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
return l:output
endfunction
-
call ale#linter#Define('gitcommit', {
\ 'name': 'gitlint',
\ 'output_stream': 'stderr',
@@ -53,4 +49,3 @@ call ale#linter#Define('gitcommit', {
\ 'command_callback': '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 d494df0e..d55a5e7c 100644
--- a/ale_linters/glsl/glslang.vim
+++ b/ale_linters/glsl/glslang.vim
@@ -4,17 +4,11 @@
" TODO: Once https://github.com/KhronosGroup/glslang/pull/1047 is accepted,
" we can use stdin.
-let g:ale_glsl_glslang_executable =
-\ get(g:, 'ale_glsl_glslang_executable', 'glslangValidator')
-
-let g:ale_glsl_glslang_options = get(g:, 'ale_glsl_glslang_options', '')
-
-function! ale_linters#glsl#glslang#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'glsl_glslang_executable')
-endfunction
+call ale#Set('glsl_glslang_executable', 'glslangValidator')
+call ale#Set('glsl_glslang_options', '')
function! ale_linters#glsl#glslang#GetCommand(buffer) abort
- return ale#Escape(ale_linters#glsl#glslang#GetExecutable(a:buffer))
+ return '%e'
\ . ale#Pad(ale#Var(a:buffer, 'glsl_glslang_options'))
\ . ' -C %t'
endfunction
@@ -40,7 +34,7 @@ endfunction
call ale#linter#Define('glsl', {
\ 'name': 'glslang',
-\ 'executable_callback': 'ale_linters#glsl#glslang#GetExecutable',
+\ 'executable_callback': ale#VarFunc('glsl_glslang_executable'),
\ 'command_callback': '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 77e30f9c..8c6d9bd9 100644
--- a/ale_linters/glsl/glslls.vim
+++ b/ale_linters/glsl/glslls.vim
@@ -4,18 +4,15 @@
call ale#Set('glsl_glslls_executable', 'glslls')
call ale#Set('glsl_glslls_logfile', '')
-function! ale_linters#glsl#glslls#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'glsl_glslls_executable')
-endfunction
-
function! ale_linters#glsl#glslls#GetCommand(buffer) abort
- let l:executable = ale_linters#glsl#glslls#GetExecutable(a:buffer)
let l:logfile = ale#Var(a:buffer, 'glsl_glslls_logfile')
let l:logfile_args = ''
+
if l:logfile isnot# ''
let l:logfile_args = ' --verbose -l ' . l:logfile
endif
- return ale#Escape(l:executable) . l:logfile_args . ' --stdin'
+
+ return '%e' . l:logfile_args . ' --stdin'
endfunction
function! ale_linters#glsl#glslls#GetProjectRoot(buffer) abort
@@ -27,7 +24,7 @@ endfunction
call ale#linter#Define('glsl', {
\ 'name': 'glslls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#glsl#glslls#GetExecutable',
+\ 'executable_callback': ale#VarFunc('glsl_glslls_executable'),
\ 'command_callback': 'ale_linters#glsl#glslls#GetCommand',
\ 'project_root_callback': 'ale_linters#glsl#glslls#GetProjectRoot',
\})
diff --git a/ale_linters/go/gobuild.vim b/ale_linters/go/gobuild.vim
index c4608071..cef1ff88 100644
--- a/ale_linters/go/gobuild.vim
+++ b/ale_linters/go/gobuild.vim
@@ -3,38 +3,15 @@
" Description: go build for Go files
" inspired by work from dzhou121 <dzhou121@gmail.com>
+call ale#Set('go_go_executable', 'go')
call ale#Set('go_gobuild_options', '')
-function! ale_linters#go#gobuild#ResetEnv() abort
- unlet! s:go_env
-endfunction
-
-function! ale_linters#go#gobuild#GoEnv(buffer) abort
- if exists('s:go_env')
- return ''
- endif
-
- return 'go env GOPATH GOROOT'
-endfunction
-
-function! ale_linters#go#gobuild#GetCommand(buffer, goenv_output) abort
+function! ale_linters#go#gobuild#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_gobuild_options')
- if !exists('s:go_env')
- let s:go_env = {
- \ 'GOPATH': a:goenv_output[0],
- \ 'GOROOT': a:goenv_output[1],
- \}
- endif
-
- let l:gopath_env_command = has('win32')
- \ ? 'set GOPATH=' . ale#Escape(s:go_env.GOPATH) . ' && '
- \ : 'GOPATH=' . ale#Escape(s:go_env.GOPATH) . ' '
-
" Run go test in local directory with relative path
- return l:gopath_env_command
- \ . ale#path#BufferCdString(a:buffer)
- \ . 'go test'
+ return ale#path#BufferCdString(a:buffer)
+ \ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./'
endfunction
@@ -45,7 +22,6 @@ function! ale_linters#go#gobuild#GetMatches(lines) abort
" file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args
" file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
" file.go:5:2: expected declaration, found 'STRING' "log"
-
" go test returns relative paths so use tail of filename as part of pattern matcher
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? (.+)$'
@@ -72,11 +48,9 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gobuild',
\ 'aliases': ['go build'],
-\ 'executable': 'go',
-\ 'command_chain': [
-\ {'callback': 'ale_linters#go#gobuild#GoEnv', 'output_stream': 'stdout'},
-\ {'callback': 'ale_linters#go#gobuild#GetCommand', 'output_stream': 'stderr'},
-\ ],
+\ 'executable_callback': ale#VarFunc('go_go_executable'),
+\ 'command_callback': '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
new file mode 100644
index 00000000..dd9a3c64
--- /dev/null
+++ b/ale_linters/go/golangci_lint.vim
@@ -0,0 +1,56 @@
+" Author: Sascha Grunert <mail@saschagrunert.de>
+" Description: Adds support of golangci-lint
+
+call ale#Set('go_golangci_lint_options', '--enable-all')
+call ale#Set('go_golangci_lint_executable', 'golangci-lint')
+call ale#Set('go_golangci_lint_package', 0)
+
+function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
+ let l:filename = expand('#' . a:buffer . ':t')
+ let l:options = ale#Var(a:buffer, 'go_golangci_lint_options')
+ let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package')
+
+ if l:lint_package
+ return ale#path#BufferCdString(a:buffer)
+ \ . '%e run '
+ \ . l:options
+ endif
+
+ return ale#path#BufferCdString(a:buffer)
+ \ . '%e run '
+ \ . ale#Escape(l:filename)
+ \ . ' ' . l:options
+endfunction
+
+function! ale_linters#go#golangci_lint#GetMatches(lines) abort
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:?:?:?\s\*?(.+)$'
+
+ return ale#util#GetMatches(a:lines, l:pattern)
+endfunction
+
+function! ale_linters#go#golangci_lint#Handler(buffer, lines) abort
+ let l:dir = expand('#' . a:buffer . ':p:h')
+ let l:output = []
+
+ for l:match in ale_linters#go#golangci_lint#GetMatches(a:lines)
+ " l:match[1] will already be an absolute path, output from
+ " golangci_lint
+ call add(l:output, {
+ \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
+ \ 'lnum': l:match[2] + 0,
+ \ 'col': l:match[3] + 0,
+ \ 'type': 'E',
+ \ 'text': l:match[4],
+ \})
+ endfor
+
+ return l:output
+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',
+\ '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 d580fda2..4bf14fcc 100644
--- a/ale_linters/go/golint.vim
+++ b/ale_linters/go/golint.vim
@@ -1,10 +1,21 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: golint for Go files
+call ale#Set('go_golint_executable', 'golint')
+call ale#Set('go_golint_options', '')
+
+function! ale_linters#go#golint#GetCommand(buffer) abort
+ let l:options = ale#Var(a:buffer, 'go_golint_options')
+
+ return '%e'
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' %t'
+endfunction
+
call ale#linter#Define('go', {
\ 'name': 'golint',
\ 'output_stream': 'both',
-\ 'executable': 'golint',
-\ 'command': 'golint %t',
+\ 'executable_callback': ale#VarFunc('go_golint_executable'),
+\ 'command_callback': '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 375a8b0f..d005e1d2 100644
--- a/ale_linters/go/gometalinter.vim
+++ b/ale_linters/go/gometalinter.vim
@@ -5,12 +5,7 @@ call ale#Set('go_gometalinter_options', '')
call ale#Set('go_gometalinter_executable', 'gometalinter')
call ale#Set('go_gometalinter_lint_package', 0)
-function! ale_linters#go#gometalinter#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'go_gometalinter_executable')
-endfunction
-
function! ale_linters#go#gometalinter#GetCommand(buffer) abort
- let l:executable = ale_linters#go#gometalinter#GetExecutable(a:buffer)
let l:filename = expand('#' . a:buffer . ':t')
let l:options = ale#Var(a:buffer, 'go_gometalinter_options')
let l:lint_package = ale#Var(a:buffer, 'go_gometalinter_lint_package')
@@ -19,12 +14,12 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
" be calculated to absolute paths in the Handler
if l:lint_package
return ale#path#BufferCdString(a:buffer)
- \ . ale#Escape(l:executable)
+ \ . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif
return ale#path#BufferCdString(a:buffer)
- \ . ale#Escape(l:executable)
+ \ . '%e'
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endfunction
@@ -55,7 +50,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gometalinter',
-\ 'executable_callback': 'ale_linters#go#gometalinter#GetExecutable',
+\ 'executable_callback': ale#VarFunc('go_gometalinter_executable'),
\ 'command_callback': 'ale_linters#go#gometalinter#GetCommand',
\ 'callback': 'ale_linters#go#gometalinter#Handler',
\ 'lint_file': 1,
diff --git a/ale_linters/go/govet.vim b/ale_linters/go/govet.vim
index e94e6ecd..3d0d2adf 100644
--- a/ale_linters/go/govet.vim
+++ b/ale_linters/go/govet.vim
@@ -4,15 +4,23 @@
" Author: John Eikenberry <jae@zhar.net>
" Description: updated to work with go1.10
+call ale#Set('go_go_executable', 'go')
+call ale#Set('go_govet_options', '')
+
function! ale_linters#go#govet#GetCommand(buffer) abort
- return ale#path#BufferCdString(a:buffer) . ' go vet .'
+ let l:options = ale#Var(a:buffer, 'go_govet_options')
+
+ return ale#path#BufferCdString(a:buffer) . ' '
+ \ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' .'
endfunction
call ale#linter#Define('go', {
\ 'name': 'govet',
\ 'aliases': ['go vet'],
\ 'output_stream': 'stderr',
-\ 'executable': 'go',
+\ 'executable_callback': ale#VarFunc('go_go_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..df956483
--- /dev/null
+++ b/ale_linters/go/langserver.vim
@@ -0,0 +1,28 @@
+" Author: Horacio Sanson <https://github.com/hsanson>
+" Description: Support for go-langserver https://github.com/sourcegraph/go-langserver
+
+call ale#Set('go_langserver_executable', 'go-langserver')
+call ale#Set('go_langserver_options', '')
+
+function! ale_linters#go#langserver#GetCommand(buffer) abort
+ let l:executable = [ale#Escape(ale#Var(a:buffer, 'go_langserver_executable'))]
+ let l:options = ale#Var(a:buffer, 'go_langserver_options')
+ let l:options = substitute(l:options, '-gocodecompletion', '', 'g')
+ let l:options = filter(split(l:options, ' '), 'empty(v:val) != 1')
+
+ if(ale#Var(a:buffer, 'completion_enabled') == 1)
+ call add(l:options, '-gocodecompletion')
+ endif
+
+ let l:options = uniq(sort(l:options))
+
+ return join(extend(l:executable, l:options), ' ')
+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',
+\})
diff --git a/ale_linters/hack/hack.vim b/ale_linters/hack/hack.vim
new file mode 100644
index 00000000..aea428cc
--- /dev/null
+++ b/ale_linters/hack/hack.vim
@@ -0,0 +1,22 @@
+" Author: Fred Emmott <fe@fb.com>
+" Description: Hack support via `hack lsp`
+
+call ale#Set('hack_hack_executable', 'hh_client')
+
+function! ale_linters#hack#hack#GetProjectRoot(buffer) abort
+ let l:hhconfig = ale#path#FindNearestFile(a:buffer, '.hhconfig')
+
+ return !empty(l:hhconfig) ? fnamemodify(l:hhconfig, ':h') : ''
+endfunction
+
+function! ale_linters#hack#hack#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'hack_hack_executable')
+endfunction
+
+call ale#linter#Define('hack', {
+\ 'name': 'hack',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#hack#hack#GetExecutable',
+\ 'command': '%e lsp --from vim-ale',
+\ 'project_root_callback': 'ale_linters#hack#hack#GetProjectRoot',
+\})
diff --git a/ale_linters/hack/hhast.vim b/ale_linters/hack/hhast.vim
new file mode 100644
index 00000000..710b7b25
--- /dev/null
+++ b/ale_linters/hack/hhast.vim
@@ -0,0 +1,40 @@
+" Author: Fred Emmott <fe@fb.com>
+" Description: Hack support via `hhast lsp`
+
+call ale#Set('hack_hhast_executable', 'vendor/bin/hhast-lint')
+
+function! ale_linters#hack#hhast#GetProjectRoot(buffer) abort
+ " Find the hack root, then figure out if it's also an HHAST root.
+ " Don't try to use lint configurations from vendor/foo/bar/hhast-lint.json
+ let l:hhconfig = ale#path#FindNearestFile(a:buffer, '.hhconfig')
+
+ if empty(l:hhconfig)
+ return ''
+ endif
+
+ let l:root = fnamemodify(l:hhconfig, ':h')
+ let l:hhast_config = findfile('hhast-lint.json', l:root)
+
+ return !empty(l:hhast_config) ? l:root : ''
+endfunction
+
+function! ale_linters#hack#hhast#GetExecutable(buffer) abort
+ let l:root = ale_linters#hack#hhast#GetProjectRoot(a:buffer)
+ let l:relative = ale#Var(a:buffer, 'hack_hhast_executable')
+ let l:absolute = findfile(l:relative, l:root)
+
+ return !empty(l:absolute) ? l:absolute : ''
+endfunction
+
+function! ale_linters#hack#hhast#GetInitializationOptions(buffer) abort
+ return {'lintMode': 'open-files'}
+endfunction
+
+call ale#linter#Define('hack', {
+\ 'name': 'hhast',
+\ 'lsp': 'stdio',
+\ 'executable_callback': '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',
+\})
diff --git a/ale_linters/haml/hamllint.vim b/ale_linters/haml/hamllint.vim
index d6633599..6598f81a 100644
--- a/ale_linters/haml/hamllint.vim
+++ b/ale_linters/haml/hamllint.vim
@@ -1,6 +1,12 @@
" Author: Patrick Lewis - https://github.com/patricklewis, thenoseman - https://github.com/thenoseman
" Description: haml-lint for Haml files
+call ale#Set('haml_hamllint_executable', 'haml-lint')
+
+function! ale_linters#haml#hamllint#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'haml_hamllint_executable')
+endfunction
+
function! ale_linters#haml#hamllint#GetCommand(buffer) abort
let l:prefix = ''
@@ -21,7 +27,7 @@ function! ale_linters#haml#hamllint#GetCommand(buffer) abort
endif
return (!empty(l:prefix) ? l:prefix . ' ' : '')
- \ . 'haml-lint'
+ \ . ale_linters#haml#hamllint#GetExecutable(a:buffer)
\ . (!empty(l:hamllint_config_file_path) ? ' --config ' . ale#Escape(l:hamllint_config_file_path) : '')
\ . ' %t'
endfunction
@@ -45,7 +51,7 @@ endfunction
call ale#linter#Define('haml', {
\ 'name': 'hamllint',
-\ 'executable': 'haml-lint',
+\ 'executable_callback': 'ale_linters#haml#hamllint#GetExecutable',
\ 'command_callback': '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 162a033c..4fc0f20d 100644
--- a/ale_linters/handlebars/embertemplatelint.vim
+++ b/ale_linters/handlebars/embertemplatelint.vim
@@ -4,17 +4,6 @@
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#handlebars#embertemplatelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [
- \ 'node_modules/.bin/ember-template-lint',
- \])
-endfunction
-
-function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer) abort
- return ale_linters#handlebars#embertemplatelint#GetExecutable(a:buffer)
- \ . ' --json %t'
-endfunction
-
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
@@ -42,7 +31,9 @@ endfunction
call ale#linter#Define('handlebars', {
\ 'name': 'ember-template-lint',
-\ 'executable_callback': 'ale_linters#handlebars#embertemplatelint#GetExecutable',
-\ 'command_callback': 'ale_linters#handlebars#embertemplatelint#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('handlebars_embertemplatelint', [
+\ 'node_modules/.bin/ember-template-lint',
+\ ]),
+\ 'command': '%e --json %t',
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\})
diff --git a/ale_linters/haskell/ghc-mod.vim b/ale_linters/haskell/ghc-mod.vim
deleted file mode 100644
index eb032f50..00000000
--- a/ale_linters/haskell/ghc-mod.vim
+++ /dev/null
@@ -1,18 +0,0 @@
-" Author: wizzup <wizzup@gmail.com>
-" Description: ghc-mod for Haskell files
-
-call ale#linter#Define('haskell', {
-\ 'name': 'ghc_mod',
-\ 'aliases': ['ghc-mod'],
-\ 'executable': 'ghc-mod',
-\ 'command': 'ghc-mod --map-file %s=%t check %s',
-\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
-\})
-
-call ale#linter#Define('haskell', {
-\ 'name': 'stack_ghc_mod',
-\ 'aliases': ['stack-ghc-mod'],
-\ 'executable': 'stack',
-\ 'command': 'stack exec ghc-mod -- --map-file %s=%t check %s',
-\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
-\})
diff --git a/ale_linters/haskell/ghc_mod.vim b/ale_linters/haskell/ghc_mod.vim
new file mode 100644
index 00000000..9762be7a
--- /dev/null
+++ b/ale_linters/haskell/ghc_mod.vim
@@ -0,0 +1,19 @@
+" Author: wizzup <wizzup@gmail.com>
+" Description: ghc-mod for Haskell files
+
+call ale#Set('haskell_ghc_mod_executable', 'ghc-mod')
+
+function! ale_linters#haskell#ghc_mod#GetCommand (buffer) abort
+ let l:executable = ale#Var(a:buffer, 'haskell_ghc_mod_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'ghc-mod')
+ \ . ' --map-file %s=%t check %s'
+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',
+\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
+\})
diff --git a/ale_linters/haskell/hdevtools.vim b/ale_linters/haskell/hdevtools.vim
index dc902152..cc5ce56f 100644
--- a/ale_linters/haskell/hdevtools.vim
+++ b/ale_linters/haskell/hdevtools.vim
@@ -4,19 +4,17 @@
call ale#Set('haskell_hdevtools_executable', 'hdevtools')
call ale#Set('haskell_hdevtools_options', get(g:, 'hdevtools_options', '-g -Wall'))
-function! ale_linters#haskell#hdevtools#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'haskell_hdevtools_executable')
-endfunction
-
function! ale_linters#haskell#hdevtools#GetCommand(buffer) abort
- return ale#Escape(ale_linters#haskell#hdevtools#GetExecutable(a:buffer))
- \ . ' check ' . ale#Var(a:buffer, 'haskell_hdevtools_options')
- \ . ' -p %s %t'
+ let l:executable = ale#Var(a:buffer, 'haskell_hdevtools_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hdevtools')
+ \ . ' check' . ale#Pad(ale#Var(a:buffer, 'haskell_hdevtools_options'))
+ \ . ' -p %s %t'
endfunction
call ale#linter#Define('haskell', {
\ 'name': 'hdevtools',
-\ 'executable_callback': 'ale_linters#haskell#hdevtools#GetExecutable',
+\ 'executable_callback': ale#VarFunc('haskell_hdevtools_executable'),
\ 'command_callback': 'ale_linters#haskell#hdevtools#GetCommand',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/hie.vim b/ale_linters/haskell/hie.vim
new file mode 100644
index 00000000..3ff1180a
--- /dev/null
+++ b/ale_linters/haskell/hie.vim
@@ -0,0 +1,47 @@
+" Author: Luxed <devildead13@gmail.com>
+" Description: A language server for Haskell
+
+call ale#Set('haskell_hie_executable', 'hie')
+
+function! ale_linters#haskell#hie#GetProjectRoot(buffer) abort
+ " Search for the stack file first
+ let l:project_file = ale#path#FindNearestFile(a:buffer, 'stack.yaml')
+
+ " If it's empty, search for the cabal file
+ if empty(l:project_file)
+ let l:cabal_file = fnamemodify(bufname(a:buffer), ':p:h')
+ let l:paths = ''
+
+ while empty(matchstr(l:cabal_file, '^\(\/\|\(\w:\\\)\)$'))
+ let l:cabal_file = fnamemodify(l:cabal_file, ':h')
+ let l:paths = l:paths . l:cabal_file . ','
+ endwhile
+
+ let l:project_file = globpath(l:paths, '*.cabal')
+ endif
+
+ " Either extract the project directory or take the current working
+ " directory
+ if !empty(l:project_file)
+ let l:project_file = fnamemodify(l:project_file, ':h')
+ else
+ let l:project_file = expand('#' . a:buffer . ':p:h')
+ endif
+
+ return l:project_file
+endfunction
+
+function! ale_linters#haskell#hie#GetCommand(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'haskell_hie_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hie')
+\ . ' --lsp'
+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',
+\})
diff --git a/ale_linters/haskell/hlint.vim b/ale_linters/haskell/hlint.vim
index be40d92c..0cc7437f 100644
--- a/ale_linters/haskell/hlint.vim
+++ b/ale_linters/haskell/hlint.vim
@@ -1,6 +1,9 @@
" Author: jparoz <jesse.paroz@gmail.com>
" Description: hlint for Haskell files
+call ale#Set('haskell_hlint_executable', 'hlint')
+call ale#Set('haskell_hlint_options', get(g:, 'hlint_options', ''))
+
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
let l:output = []
@@ -26,9 +29,18 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#haskell#hlint#GetCommand(buffer) abort
+ let l:hlintopts = '--color=never --json'
+
+ return ale#handlers#hlint#GetExecutable(a:buffer)
+ \ . ' ' . ale#Var(a:buffer, 'haskell_hlint_options')
+ \ . ' ' . l:hlintopts
+ \ . ' -'
+endfunction
+
call ale#linter#Define('haskell', {
\ 'name': 'hlint',
-\ 'executable': 'hlint',
-\ 'command': 'hlint --color=never --json -',
+\ 'executable_callback': ale#VarFunc('haskell_hlint_executable'),
+\ 'command_callback': '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 f5bdf4b8..95a54587 100644
--- a/ale_linters/haskell/stack_build.vim
+++ b/ale_linters/haskell/stack_build.vim
@@ -16,7 +16,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_build',
\ 'aliases': ['stack-build'],
\ 'output_stream': 'stderr',
-\ 'executable': 'stack',
+\ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
\ 'command_callback': '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 d702aa68..8f42b96c 100644
--- a/ale_linters/haskell/stack_ghc.vim
+++ b/ale_linters/haskell/stack_ghc.vim
@@ -5,7 +5,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_ghc',
\ 'aliases': ['stack-ghc'],
\ 'output_stream': 'stderr',
-\ 'executable': 'stack',
+\ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
\ 'command': 'stack ghc -- -fno-code -v0 %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/html/htmlhint.vim b/ale_linters/html/htmlhint.vim
index caa15bbb..234c1176 100644
--- a/ale_linters/html/htmlhint.vim
+++ b/ale_linters/html/htmlhint.vim
@@ -5,12 +5,6 @@ call ale#Set('html_htmlhint_options', '')
call ale#Set('html_htmlhint_executable', 'htmlhint')
call ale#Set('html_htmlhint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#html#htmlhint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'html_htmlhint', [
- \ 'node_modules/.bin/htmlhint',
- \])
-endfunction
-
function! ale_linters#html#htmlhint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'html_htmlhint_options')
let l:config = l:options !~# '--config'
@@ -25,14 +19,14 @@ function! ale_linters#html#htmlhint#GetCommand(buffer) abort
let l:options = substitute(l:options, '--format=unix', '', '')
endif
- return ale#Escape(ale_linters#html#htmlhint#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --format=unix %t'
+ return '%e' . ale#Pad(l:options) . ' --format=unix %t'
endfunction
call ale#linter#Define('html', {
\ 'name': 'htmlhint',
-\ 'executable_callback': 'ale_linters#html#htmlhint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('html_htmlhint', [
+\ 'node_modules/.bin/htmlhint',
+\ ]),
\ 'command_callback': 'ale_linters#html#htmlhint#GetCommand',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/html/stylelint.vim b/ale_linters/html/stylelint.vim
new file mode 100644
index 00000000..908c4b02
--- /dev/null
+++ b/ale_linters/html/stylelint.vim
@@ -0,0 +1,27 @@
+" Author: Filipe Kiss <hello@filipekiss.com.br> http://github.com/filipekiss
+
+call ale#Set('html_stylelint_executable', 'stylelint')
+call ale#Set('html_stylelint_options', '')
+call ale#Set('html_stylelint_use_global', 0)
+
+function! ale_linters#html#stylelint#GetExecutable(buffer) abort
+ return ale#node#FindExecutable(a:buffer, 'html_stylelint', [
+ \ 'node_modules/.bin/stylelint',
+ \])
+endfunction
+
+function! ale_linters#html#stylelint#GetCommand(buffer) abort
+ let l:executable = ale_linters#html#stylelint#GetExecutable(a:buffer)
+ let l:options = ale#Var(a:buffer, 'html_stylelint_options')
+
+ return ale#Escape(l:executable)
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' --stdin-filename %s'
+endfunction
+
+call ale#linter#Define('html', {
+\ 'name': 'stylelint',
+\ 'executable_callback': 'ale_linters#html#stylelint#GetExecutable',
+\ 'command_callback': '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 913cdade..4ec29091 100644
--- a/ale_linters/html/tidy.vim
+++ b/ale_linters/html/tidy.vim
@@ -25,6 +25,7 @@ function! ale_linters#html#tidy#GetCommand(buffer) abort
" On macOS, old tidy (released on 31 Oct 2006) is installed. It does not
" consider HTML5 so we should avoid it.
let l:executable = ale#Var(a:buffer, 'html_tidy_executable')
+
if has('mac') && l:executable is# 'tidy' && exists('*exepath')
\ && exepath(l:executable) is# '/usr/bin/tidy'
return ''
@@ -37,14 +38,9 @@ function! ale_linters#html#tidy#GetCommand(buffer) abort
\)
endfunction
-function! ale_linters#html#tidy#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'html_tidy_executable')
-endfunction
-
function! ale_linters#html#tidy#Handle(buffer, lines) abort
" Matches patterns lines like the following:
" line 7 column 5 - Warning: missing </title> before </head>
-
let l:pattern = '^line \(\d\+\) column \(\d\+\) - \(Warning\|Error\): \(.\+\)$'
let l:output = []
@@ -67,7 +63,7 @@ endfunction
call ale#linter#Define('html', {
\ 'name': 'tidy',
-\ 'executable_callback': 'ale_linters#html#tidy#GetExecutable',
+\ 'executable_callback': ale#VarFunc('html_tidy_executable'),
\ 'output_stream': 'stderr',
\ 'command_callback': '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 115d04fc..feac0f10 100644
--- a/ale_linters/idris/idris.vim
+++ b/ale_linters/idris/idris.vim
@@ -4,21 +4,15 @@
call ale#Set('idris_idris_executable', 'idris')
call ale#Set('idris_idris_options', '--total --warnpartial --warnreach --warnipkg')
-function! ale_linters#idris#idris#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'idris_idris_executable')
-endfunction
-
function! ale_linters#idris#idris#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'idris_idris_options')
- return ale#Escape(ale_linters#idris#idris#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --check %s'
+ return '%e' . ale#Pad(l:options) . ' --check %s'
endfunction
function! ale_linters#idris#idris#Handle(buffer, lines) abort
" This was copied almost verbatim from ale#handlers#haskell#HandleGHCFormat
-
+ "
" Look for lines like the following:
" foo.idr:2:6:When checking right hand side of main with expected type
" bar.idr:11:11-13:
@@ -36,6 +30,7 @@ function! ale_linters#idris#idris#Handle(buffer, lines) abort
else
let l:corrected_lines[-1] .= l:line
endif
+
let l:corrected_lines[-1] = substitute(l:corrected_lines[-1], '\s\+', ' ', 'g')
endif
endfor
@@ -80,8 +75,7 @@ endfunction
call ale#linter#Define('idris', {
\ 'name': 'idris',
-\ 'executable_callback': 'ale_linters#idris#idris#GetExecutable',
+\ 'executable_callback': ale#VarFunc('idris_idris_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..de7ceafa
--- /dev/null
+++ b/ale_linters/ispc/ispc.vim
@@ -0,0 +1,45 @@
+" Author: Martino Pilia <martino.pilia@gmail.com>
+" Description: Lint ispc files with the Intel(R) SPMD Program Compiler
+
+call ale#Set('ispc_ispc_executable', 'ispc')
+call ale#Set('ispc_ispc_options', '')
+
+function! ale_linters#ispc#ispc#GetCommand(buffer) abort
+ " --nowrap: do not wrap message lines
+ return '%e --nowrap'
+ \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
+ \ . ale#Pad(ale#Var(a:buffer, 'ispc_ispc_options'))
+ \ . ' %s'
+endfunction
+
+" Note that we ignore the two warnings in the beginning of the compiler output
+" ('no output file specified' and 'no --target specified'), since they have
+" nothing to do with linting.
+function! ale_linters#ispc#ispc#Handle(buffer, lines) abort
+ " Message format: <filename>:<lnum>:<col> <type>: <text>
+ " As far as I know, <type> can be any of:
+ " 'error', 'Error', 'fatal error', 'Warning', 'Performance Warning'
+ let l:re = '\v.+:([0-9]+):([0-9]+):\s+([^:]+):\s+(.+)'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:re)
+ call add(l:output, {
+ \ 'bufnr': a:buffer,
+ \ 'lnum': str2nr(l:match[1]),
+ \ 'col': str2nr(l:match[2]),
+ \ 'type': l:match[3] =~? 'error' ? 'E' : 'W',
+ \ 'text': l:match[4],
+ \})
+ endfor
+
+ return l:output
+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',
+\ 'callback': 'ale_linters#ispc#ispc#Handle',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/java/checkstyle.vim b/ale_linters/java/checkstyle.vim
index 8155170a..c07b65d0 100644
--- a/ale_linters/java/checkstyle.vim
+++ b/ale_linters/java/checkstyle.vim
@@ -2,9 +2,11 @@
" Description: checkstyle for Java files
function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
- let l:pattern = '\v\[(WARN|ERROR)\] [a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.*) \[(.+)\]$'
let l:output = []
+ " modern checkstyle versions
+ let l:pattern = '\v\[(WARN|ERROR)\] [a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.*) \[(.+)\]$'
+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'type': l:match[1] is? 'WARN' ? 'W' : 'E',
@@ -15,13 +17,24 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
\})
endfor
+ " old checkstyle versions
+ let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$'
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'type': l:match[3] is? 'warning' ? 'W' : 'E',
+ \ 'lnum': l:match[2] + 0,
+ \ 'text': l:match[4],
+ \})
+ endfor
+
return l:output
endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
return 'checkstyle '
\ . ale#Var(a:buffer, 'java_checkstyle_options')
- \ . ' %t'
+ \ . ' %s'
endfunction
if !exists('g:ale_java_checkstyle_options')
@@ -33,4 +46,5 @@ call ale#linter#Define('java', {
\ 'executable': 'checkstyle',
\ 'command_callback': '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 d7a39aa7..63dcdd94 100644
--- a/ale_linters/java/javac.vim
+++ b/ale_linters/java/javac.vim
@@ -16,6 +16,7 @@ function! ale_linters#java#javac#GetImportPaths(buffer) abort
endif
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
+
if !empty(l:classpath_command)
return l:classpath_command
endif
@@ -36,10 +37,6 @@ function! s:BuildClassPathOption(buffer, import_paths) abort
\ : ''
endfunction
-function! ale_linters#java#javac#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'java_javac_executable')
-endfunction
-
function! ale_linters#java#javac#GetCommand(buffer, import_paths) abort
let l:cp_option = s:BuildClassPathOption(a:buffer, a:import_paths)
let l:sp_option = ''
@@ -77,13 +74,11 @@ function! ale_linters#java#javac#GetCommand(buffer, import_paths) abort
" Create .class files in a temporary directory, which we will delete later.
let l:class_file_directory = ale#engine#CreateDirectory(a:buffer)
- let l:executable = ale_linters#java#javac#GetExecutable(a:buffer)
" Always run javac from the directory the file is in, so we can resolve
" relative paths correctly.
return ale#path#BufferCdString(a:buffer)
- \ . ale#Escape(l:executable)
- \ . ' -Xlint'
+ \ . '%e -Xlint'
\ . ale#Pad(l:cp_option)
\ . ale#Pad(l:sp_option)
\ . ' -d ' . ale#Escape(l:class_file_directory)
@@ -96,7 +91,6 @@ function! ale_linters#java#javac#Handle(buffer, lines) abort
"
" Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
" Main.java:16: error: ';' expected
-
let l:directory = expand('#' . a:buffer . ':p:h')
let l:pattern = '\v^(.*):(\d+): (.+):(.+)$'
let l:col_pattern = '\v^(\s*\^)$'
@@ -126,7 +120,7 @@ endfunction
call ale#linter#Define('java', {
\ 'name': 'javac',
-\ 'executable_callback': 'ale_linters#java#javac#GetExecutable',
+\ 'executable_callback': ale#VarFunc('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
new file mode 100644
index 00000000..5d1a0c63
--- /dev/null
+++ b/ale_linters/java/javalsp.vim
@@ -0,0 +1,23 @@
+" Author: Horacio Sanson <https://github.com/hsanson>
+" Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac
+
+call ale#Set('java_javalsp_jar', 'javacs.jar')
+
+function! ale_linters#java#javalsp#Executable(buffer) abort
+ return 'java'
+endfunction
+
+function! ale_linters#java#javalsp#Command(buffer) abort
+ let l:jar = ale#Var(a:buffer, 'java_javalsp_jar')
+
+ return ale#Escape('java -cp ' . l:jar . ' -Xverify:none org.javacs.Main')
+endfunction
+
+call ale#linter#Define('java', {
+\ 'name': 'javalsp',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#java#javalsp#Executable',
+\ 'command_callback': 'ale_linters#java#javalsp#Command',
+\ 'language': 'java',
+\ 'project_root_callback': 'ale#java#FindProjectRoot',
+\})
diff --git a/ale_linters/java/pmd.vim b/ale_linters/java/pmd.vim
index d461e094..b530ad09 100644
--- a/ale_linters/java/pmd.vim
+++ b/ale_linters/java/pmd.vim
@@ -2,7 +2,7 @@
" Description: PMD for Java files
function! ale_linters#java#pmd#Handle(buffer, lines) abort
- let l:pattern = '"\(\d\+\)",".\+","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
+ let l:pattern = '"\(\d\+\)",".*","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim
index d555184e..cdb289c7 100755
--- a/ale_linters/javascript/flow.vim
+++ b/ale_linters/javascript/flow.vim
@@ -91,7 +91,6 @@ function! s:GetDetails(error) abort
let l:detail = ''
for l:extra_error in a:error.extra
-
if has_key(l:extra_error, 'message')
for l:extra_message in l:extra_error.message
let l:detail = s:ExtraErrorMsg(l:detail, l:extra_message.descr)
@@ -105,7 +104,6 @@ function! s:GetDetails(error) abort
endfor
endfor
endif
-
endfor
return l:detail
@@ -161,7 +159,6 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
endif
call add(l:output, l:errorToAdd)
-
endfor
return l:output
diff --git a/ale_linters/javascript/flow_ls.vim b/ale_linters/javascript/flow_ls.vim
index 20fc2217..75377183 100644
--- a/ale_linters/javascript/flow_ls.vim
+++ b/ale_linters/javascript/flow_ls.vim
@@ -6,18 +6,6 @@ call ale#Set('javascript_flow_ls_use_global',
\ get(g:, 'ale_use_global_executables', 0)
\)
-function! ale_linters#javascript#flow_ls#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_flow_ls', [
- \ 'node_modules/.bin/flow',
- \])
-endfunction
-
-function! ale_linters#javascript#flow_ls#GetCommand(buffer) abort
- let l:executable = ale_linters#javascript#flow_ls#GetExecutable(a:buffer)
-
- return ale#Escape(l:executable) . ' lsp --from ale-lsp'
-endfunction
-
function! ale_linters#javascript#flow_ls#FindProjectRoot(buffer) abort
let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig')
@@ -31,8 +19,10 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'flow-language-server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#javascript#flow_ls#GetExecutable',
-\ 'command_callback': 'ale_linters#javascript#flow_ls#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_flow_ls', [
+\ 'node_modules/.bin/flow',
+\ ]),
+\ 'command': '%e lsp --from ale-lsp',
\ 'project_root_callback': 'ale_linters#javascript#flow_ls#FindProjectRoot',
\ 'language': 'javascript',
\})
diff --git a/ale_linters/javascript/jscs.vim b/ale_linters/javascript/jscs.vim
index 60044037..a38766a6 100644
--- a/ale_linters/javascript/jscs.vim
+++ b/ale_linters/javascript/jscs.vim
@@ -4,12 +4,6 @@
call ale#Set('javascript_jscs_executable', 'jscs')
call ale#Set('javascript_jscs_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#javascript#jscs#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_jscs', [
- \ 'node_modules/.bin/jscs',
- \])
-endfunction
-
function! ale_linters#javascript#jscs#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jscs_config = ale#path#ResolveLocalPath(
@@ -18,8 +12,7 @@ function! ale_linters#javascript#jscs#GetCommand(buffer) abort
\ get(g:, 'ale_jscs_config_loc', '')
\)
- let l:command = ale#Escape(ale_linters#javascript#jscs#GetExecutable(a:buffer))
- let l:command .= ' --reporter inline --no-colors'
+ let l:command = '%e --reporter inline --no-colors'
if !empty(l:jscs_config)
let l:command .= ' --config ' . ale#Escape(l:jscs_config)
@@ -60,8 +53,9 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jscs',
-\ 'executable_callback': 'ale_linters#javascript#jscs#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_jscs', [
+\ 'node_modules/.bin/jscs',
+\ ]),
\ 'command_callback': '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 2e9bb9fd..cb7f66fc 100644
--- a/ale_linters/javascript/jshint.vim
+++ b/ale_linters/javascript/jshint.vim
@@ -4,12 +4,6 @@
call ale#Set('javascript_jshint_executable', 'jshint')
call ale#Set('javascript_jshint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#javascript#jshint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_jshint', [
- \ 'node_modules/.bin/jshint',
- \])
-endfunction
-
function! ale_linters#javascript#jshint#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jshint_config = ale#path#ResolveLocalPath(
@@ -18,21 +12,22 @@ function! ale_linters#javascript#jshint#GetCommand(buffer) abort
\ get(g:, 'ale_jshint_config_loc', '')
\)
- let l:command = ale#Escape(ale_linters#javascript#jshint#GetExecutable(a:buffer))
- let l:command .= ' --reporter unix --extract auto'
+ let l:command = '%e --reporter unix --extract auto'
if !empty(l:jshint_config)
let l:command .= ' --config ' . ale#Escape(l:jshint_config)
endif
- let l:command .= ' -'
+ let l:command .= ' --filename %s -'
return l:command
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jshint',
-\ 'executable_callback': 'ale_linters#javascript#jshint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_jshint', [
+\ 'node_modules/.bin/jshint',
+\ ]),
\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/javascript/tsserver.vim b/ale_linters/javascript/tsserver.vim
index 62dded10..6cf08dd6 100644
--- a/ale_linters/javascript/tsserver.vim
+++ b/ale_linters/javascript/tsserver.vim
@@ -5,22 +5,13 @@ call ale#Set('javascript_tsserver_executable', 'tsserver')
call ale#Set('javascript_tsserver_config_path', '')
call ale#Set('javascript_tsserver_use_global', get(g:, 'ale_use_global_executables', 0))
-" These functions need to be defined just to comply with the API for LSP.
-function! ale_linters#javascript#tsserver#GetProjectRoot(buffer) abort
- return ''
-endfunction
-
-function! ale_linters#javascript#tsserver#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_tsserver', [
- \ 'node_modules/.bin/tsserver',
- \])
-endfunction
-
call ale#linter#Define('javascript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
-\ 'executable_callback': 'ale_linters#javascript#tsserver#GetExecutable',
-\ 'command_callback': 'ale_linters#javascript#tsserver#GetExecutable',
-\ 'project_root_callback': 'ale_linters#javascript#tsserver#GetProjectRoot',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_tsserver', [
+\ 'node_modules/.bin/tsserver',
+\ ]),
+\ 'command': '%e',
+\ 'project_root_callback': {-> ''},
\ 'language': '',
\})
diff --git a/ale_linters/json/jsonlint.vim b/ale_linters/json/jsonlint.vim
index 75f47088..f01553d6 100644
--- a/ale_linters/json/jsonlint.vim
+++ b/ale_linters/json/jsonlint.vim
@@ -3,7 +3,6 @@
function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
" Matches patterns like the following:
" line 2, col 15, found: 'STRING' - expected: 'EOF', '}', ',', ']'.
-
let l:pattern = '^line \(\d\+\), col \(\d*\), \(.\+\)$'
let l:output = []
diff --git a/ale_linters/julia/languageserver.vim b/ale_linters/julia/languageserver.vim
new file mode 100644
index 00000000..cd2000de
--- /dev/null
+++ b/ale_linters/julia/languageserver.vim
@@ -0,0 +1,21 @@
+" Author: Bartolomeo Stellato <bartolomeo.stellato@gmail.com>
+" Description: A language server for Julia
+
+" Set julia executable variable
+call ale#Set('julia_executable', 'julia')
+
+function! ale_linters#julia#languageserver#GetCommand(buffer) abort
+ let l:julia_executable = ale#Var(a:buffer, 'julia_executable')
+ let l:cmd_string = 'using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);'
+
+ return ale#Escape(l:julia_executable) . ' --startup-file=no --history-file=no -e ' . ale#Escape(l:cmd_string)
+endfunction
+
+call ale#linter#Define('julia', {
+\ 'name': 'languageserver',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('julia_executable'),
+\ 'command_callback': 'ale_linters#julia#languageserver#GetCommand',
+\ 'language': 'julia',
+\ 'project_root_callback': 'ale#julia#FindProjectRoot',
+\})
diff --git a/ale_linters/kotlin/kotlinc.vim b/ale_linters/kotlin/kotlinc.vim
index 00f94be5..4a993986 100644
--- a/ale_linters/kotlin/kotlinc.vim
+++ b/ale_linters/kotlin/kotlinc.vim
@@ -17,12 +17,14 @@ function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort
return ''
else
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
+
if !empty(l:pom_path) && executable('mvn')
return ale#path#CdString(fnamemodify(l:pom_path, ':h'))
\ . 'mvn dependency:build-classpath'
endif
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
+
if !empty(l:classpath_command)
return l:classpath_command
endif
@@ -78,12 +80,13 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
endif
let l:fname = ''
+
if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') isnot# ''
let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' '
else
" Find the src directory for files in this project.
-
let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
+
if !empty(l:project_root)
let l:src_dir = l:project_root
else
@@ -93,6 +96,7 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
let l:fname .= expand(l:src_dir, 1) . ' '
endif
+
let l:fname .= ale#Escape(expand('#' . a:buffer . ':p'))
let l:command .= l:kotlinc_opts . ' ' . l:fname
@@ -124,6 +128,7 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
if l:buf_abspath isnot# l:curbuf_abspath
continue
endif
+
let l:type_marker_str = l:type is# 'warning' ? 'W' : 'E'
call add(l:output, {
diff --git a/ale_linters/kotlin/languageserver.vim b/ale_linters/kotlin/languageserver.vim
index 0ab673ec..aea817ba 100644
--- a/ale_linters/kotlin/languageserver.vim
+++ b/ale_linters/kotlin/languageserver.vim
@@ -3,15 +3,6 @@
call ale#Set('kotlin_languageserver_executable', 'kotlin-language-server')
-function! ale_linters#kotlin#languageserver#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'kotlin_languageserver_executable')
-endfunction
-
-function! ale_linters#kotlin#languageserver#GetCommand(buffer) abort
- let l:executable = ale_linters#kotlin#languageserver#GetExecutable(a:buffer)
- return ale#Escape(l:executable)
-endfunction
-
function! ale_linters#kotlin#languageserver#GetProjectRoot(buffer) abort
let l:gradle_root = ale#gradle#FindProjectRoot(a:buffer)
@@ -31,8 +22,8 @@ endfunction
call ale#linter#Define('kotlin', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#kotlin#languageserver#GetExecutable',
-\ 'command_callback': 'ale_linters#kotlin#languageserver#GetCommand',
+\ 'executable_callback': ale#VarFunc('kotlin_languageserver_executable'),
+\ 'command': '%e',
\ 'language': 'kotlin',
\ 'project_root_callback': 'ale_linters#kotlin#languageserver#GetProjectRoot',
\})
diff --git a/ale_linters/less/lessc.vim b/ale_linters/less/lessc.vim
index 5fd9a383..37600649 100755
--- a/ale_linters/less/lessc.vim
+++ b/ale_linters/less/lessc.vim
@@ -5,21 +5,10 @@ call ale#Set('less_lessc_executable', 'lessc')
call ale#Set('less_lessc_options', '')
call ale#Set('less_lessc_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#less#lessc#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'less_lessc', [
- \ 'node_modules/.bin/lessc',
- \])
-endfunction
-
function! ale_linters#less#lessc#GetCommand(buffer) abort
- let l:executable = ale_linters#less#lessc#GetExecutable(a:buffer)
- let l:dir = expand('#' . a:buffer . ':p:h')
- let l:options = ale#Var(a:buffer, 'less_lessc_options')
-
- return ale#Escape(l:executable)
- \ . ' --no-color --lint'
- \ . ' --include-path=' . ale#Escape(l:dir)
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ return '%e --no-color --lint'
+ \ . ' --include-path=' . ale#Escape(expand('#' . a:buffer . ':p:h'))
+ \ . ale#Pad(ale#Var(a:buffer, 'less_lessc_options'))
\ . ' -'
endfunction
@@ -49,7 +38,9 @@ endfunction
call ale#linter#Define('less', {
\ 'name': 'lessc',
-\ 'executable_callback': 'ale_linters#less#lessc#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('less_lessc', [
+\ 'node_modules/.bin/lessc',
+\ ]),
\ 'command_callback': '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 8e16a098..479808c2 100644
--- a/ale_linters/less/stylelint.vim
+++ b/ale_linters/less/stylelint.vim
@@ -4,24 +4,17 @@ call ale#Set('less_stylelint_executable', 'stylelint')
call ale#Set('less_stylelint_options', '')
call ale#Set('less_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#less#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'less_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#less#stylelint#GetCommand(buffer) abort
- let l:executable = ale_linters#less#stylelint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'less_stylelint_options')
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --stdin-filename %s'
+ return '%e' . ale#Pad(l:options) . ' --stdin-filename %s'
endfunction
call ale#linter#Define('less', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#less#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('less_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': '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 15201cbe..044f8c44 100644
--- a/ale_linters/llvm/llc.vim
+++ b/ale_linters/llvm/llc.vim
@@ -3,21 +3,11 @@
call ale#Set('llvm_llc_executable', 'llc')
-function! ale_linters#llvm#llc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'llvm_llc_executable')
-endfunction
-
-function! ale_linters#llvm#llc#GetCommand(buffer) abort
- return ale#Escape(ale_linters#llvm#llc#GetExecutable(a:buffer))
- \ . ' -filetype=null -o=' . g:ale#util#nul_file
-endfunction
-
function! ale_linters#llvm#llc#HandleErrors(buffer, lines) abort
" Handle '{path}: {file}:{line}:{col}: error: {message}' format
let l:pattern = '\v^[a-zA-Z]?:?[^:]+: [^:]+:(\d+):(\d+): (.+)$'
- let l:matches = ale#util#GetMatches(a:lines, l:pattern)
- return map(l:matches, "{
+ return map(ale#util#GetMatches(a:lines, l:pattern), "{
\ 'lnum': str2nr(v:val[1]),
\ 'col': str2nr(v:val[2]),
\ 'text': v:val[3],
@@ -27,8 +17,8 @@ endfunction
call ale#linter#Define('llvm', {
\ 'name': 'llc',
-\ 'executable_callback': 'ale_linters#llvm#llc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('llvm_llc_executable'),
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#llvm#llc#GetCommand',
+\ 'command_callback': {-> '%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 4a6bb403..bca2cd8d 100644
--- a/ale_linters/lua/luac.vim
+++ b/ale_linters/lua/luac.vim
@@ -3,15 +3,6 @@
call ale#Set('lua_luac_executable', 'luac')
-function! ale_linters#lua#luac#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'lua_luac_executable')
-endfunction
-
-function! ale_linters#lua#luac#GetCommand(buffer) abort
- let l:executable = ale_linters#lua#luac#GetExecutable(a:buffer)
- return ale#Escape(l:executable) . ' -p - '
-endfunction
-
function! ale_linters#lua#luac#Handle(buffer, lines) abort
" Matches patterns line the following:
"
@@ -33,8 +24,8 @@ endfunction
call ale#linter#Define('lua', {
\ 'name': 'luac',
-\ 'executable_callback': 'ale_linters#lua#luac#GetExecutable',
-\ 'command_callback': 'ale_linters#lua#luac#GetCommand',
+\ 'executable_callback': ale#VarFunc('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 725153c6..669103b8 100644
--- a/ale_linters/lua/luacheck.vim
+++ b/ale_linters/lua/luacheck.vim
@@ -1,19 +1,11 @@
" Author: Sol Bekic https://github.com/s-ol
" Description: luacheck linter for lua files
-let g:ale_lua_luacheck_executable =
-\ get(g:, 'ale_lua_luacheck_executable', 'luacheck')
-
-let g:ale_lua_luacheck_options =
-\ get(g:, 'ale_lua_luacheck_options', '')
-
-function! ale_linters#lua#luacheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'lua_luacheck_executable')
-endfunction
+call ale#Set('lua_luacheck_executable', 'luacheck')
+call ale#Set('lua_luacheck_options', '')
function! ale_linters#lua#luacheck#GetCommand(buffer) abort
- return ale#Escape(ale_linters#lua#luacheck#GetExecutable(a:buffer))
- \ . ' ' . ale#Var(a:buffer, 'lua_luacheck_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'lua_luacheck_options'))
\ . ' --formatter plain --codes --filename %s -'
endfunction
@@ -46,7 +38,7 @@ endfunction
call ale#linter#Define('lua', {
\ 'name': 'luacheck',
-\ 'executable_callback': 'ale_linters#lua#luacheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('lua_luacheck_executable'),
\ 'command_callback': 'ale_linters#lua#luacheck#GetCommand',
\ 'callback': 'ale_linters#lua#luacheck#Handle',
\})
diff --git a/ale_linters/make/checkmake.vim b/ale_linters/make/checkmake.vim
index 63c35db3..5ebdf91e 100644
--- a/ale_linters/make/checkmake.vim
+++ b/ale_linters/make/checkmake.vim
@@ -13,6 +13,7 @@ function! ale_linters#make#checkmake#Handle(buffer, lines) abort
\ 'text': l:match[3],
\})
endfor
+
return l:output
endfunction
diff --git a/ale_linters/markdown/remark_lint.vim b/ale_linters/markdown/remark_lint.vim
index d9c2efb6..4f8d48fa 100644
--- a/ale_linters/markdown/remark_lint.vim
+++ b/ale_linters/markdown/remark_lint.vim
@@ -5,19 +5,10 @@ call ale#Set('markdown_remark_lint_executable', 'remark')
call ale#Set('markdown_remark_lint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('markdown_remark_lint_options', '')
-function! ale_linters#markdown#remark_lint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'markdown_remark_lint', [
- \ 'node_modules/.bin/remark',
- \])
-endfunction
-
function! ale_linters#markdown#remark_lint#GetCommand(buffer) abort
- let l:executable = ale_linters#markdown#remark_lint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options')
- return ale#node#Executable(a:buffer, l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --no-stdout --no-color'
+ return '%e' . ale#Pad(l:options) . ' --no-stdout --no-color'
endfunction
function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort
@@ -33,10 +24,12 @@ function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort
\ 'type': l:match[6] is# 'error' ? 'E' : 'W',
\ 'text': l:match[7],
\}
+
if l:match[3] isnot# ''
let l:item.end_lnum = l:match[4] + 0
let l:item.end_col = l:match[5] + 0
endif
+
call add(l:output, l:item)
endfor
@@ -46,7 +39,9 @@ endfunction
call ale#linter#Define('markdown', {
\ 'name': 'remark_lint',
\ 'aliases': ['remark-lint'],
-\ 'executable_callback': 'ale_linters#markdown#remark_lint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('markdown_remark_lint', [
+\ 'node_modules/.bin/remark',
+\ ]),
\ 'command_callback': 'ale_linters#markdown#remark_lint#GetCommand',
\ 'callback': 'ale_linters#markdown#remark_lint#Handle',
\ 'output_stream': 'stderr',
diff --git a/ale_linters/matlab/mlint.vim b/ale_linters/matlab/mlint.vim
index 32766334..3435045e 100644
--- a/ale_linters/matlab/mlint.vim
+++ b/ale_linters/matlab/mlint.vim
@@ -1,18 +1,7 @@
" Author: awlayton <alex@layton.in>
" Description: mlint for MATLAB files
-let g:ale_matlab_mlint_executable =
-\ get(g:, 'ale_matlab_mlint_executable', 'mlint')
-
-function! ale_linters#matlab#mlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'matlab_mlint_executable')
-endfunction
-
-function! ale_linters#matlab#mlint#GetCommand(buffer) abort
- let l:executable = ale_linters#matlab#mlint#GetExecutable(a:buffer)
-
- return l:executable . ' -id %t'
-endfunction
+call ale#Set('matlab_mlint_executable', 'mlint')
function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
" Matches patterns like the following:
@@ -48,8 +37,8 @@ endfunction
call ale#linter#Define('matlab', {
\ 'name': 'mlint',
-\ 'executable_callback': 'ale_linters#matlab#mlint#GetExecutable',
-\ 'command_callback': 'ale_linters#matlab#mlint#GetCommand',
+\ 'executable_callback': ale#VarFunc('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 c7bfc59d..76d357f0 100644
--- a/ale_linters/mercury/mmc.vim
+++ b/ale_linters/mercury/mmc.vim
@@ -4,16 +4,11 @@
call ale#Set('mercury_mmc_executable', 'mmc')
call ale#Set('mercury_mmc_options', '--make --output-compile-error-lines 100')
-function! ale_linters#mercury#mmc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'mercury_mmc_executable')
-endfunction
-
function! ale_linters#mercury#mmc#GetCommand(buffer) abort
let l:module_name = expand('#' . a:buffer . ':t:r')
return ale#path#BufferCdString(a:buffer)
- \ . ale_linters#mercury#mmc#GetExecutable(a:buffer)
- \ . ' --errorcheck-only '
+ \ . '%e --errorcheck-only '
\ . ale#Var(a:buffer, 'mercury_mmc_options')
\ . ' ' . l:module_name
endfunction
@@ -38,7 +33,7 @@ endfunction
call ale#linter#Define('mercury', {
\ 'name': 'mmc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#mercury#mmc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('mercury_mmc_executable'),
\ 'command_callback': '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 77d57e18..cb2119a6 100644
--- a/ale_linters/nasm/nasm.vim
+++ b/ale_linters/nasm/nasm.vim
@@ -4,32 +4,23 @@
call ale#Set('nasm_nasm_executable', 'nasm')
call ale#Set('nasm_nasm_options', '')
-function! ale_linters#nasm#nasm#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'nasm_nasm_executable')
-endfunction
-
-function! ale_linters#nasm#nasm#GetOptions(buffer) abort
- return ale#Var(a:buffer, 'nasm_nasm_options')
-endfunction
-
function! ale_linters#nasm#nasm#GetCommand(buffer) abort
- " Note that NASM require a trailing slash to the -I option.
- let l:executable = ale#Escape(ale_linters#nasm#nasm#GetExecutable(a:buffer))
+ " Note that NASM requires a trailing slash for the -I option.
let l:separator = has('win32') ? '\' : '/'
- let l:path = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h') . l:separator)
- let l:options = ale_linters#nasm#nasm#GetOptions(a:buffer)
+ let l:path = fnamemodify(bufname(a:buffer), ':p:h') . l:separator
+ let l:output_null = has('win32') ? 'NUL' : '/dev/null'
- return l:executable
- \ . ' -X gnu'
- \ . ' -I ' . l:path
- \ . ' ' . l:options
+ return '%e -X gnu -I ' . ale#Escape(l:path)
+ \ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
\ . ' %s'
+ \ . ' -o ' . l:output_null
endfunction
function! ale_linters#nasm#nasm#Handle(buffer, lines) abort
" Note that we treat 'fatal' as errors.
let l:pattern = '^.\+:\(\d\+\): \([^:]\+\): \(.\+\)$'
let l:output = []
+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
@@ -37,6 +28,7 @@ function! ale_linters#nasm#nasm#Handle(buffer, lines) abort
\ 'text': l:match[3],
\})
endfor
+
return l:output
endfunction
@@ -44,7 +36,7 @@ call ale#linter#Define('nasm', {
\ 'name': 'nasm',
\ 'output_stream': 'stderr',
\ 'lint_file': 1,
-\ 'executable_callback': 'ale_linters#nasm#nasm#GetExecutable',
+\ 'executable_callback': ale#VarFunc('nasm_nasm_executable'),
\ 'command_callback': 'ale_linters#nasm#nasm#GetCommand',
\ 'callback': 'ale_linters#nasm#nasm#Handle',
\})
diff --git a/ale_linters/objc/ccls.vim b/ale_linters/objc/ccls.vim
new file mode 100644
index 00000000..0aa6a5e5
--- /dev/null
+++ b/ale_linters/objc/ccls.vim
@@ -0,0 +1,14 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for Objective-C
+
+call ale#Set('objc_ccls_executable', 'ccls')
+call ale#Set('objc_ccls_init_options', {})
+
+call ale#linter#Define('objc', {
+\ 'name': 'ccls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('objc_ccls_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
+\ 'initialization_options_callback': ale#VarFunc('objc_ccls_init_options'),
+\})
diff --git a/ale_linters/objc/clang.vim b/ale_linters/objc/clang.vim
index f4725a0e..4e80ac5c 100644
--- a/ale_linters/objc/clang.vim
+++ b/ale_linters/objc/clang.vim
@@ -19,5 +19,5 @@ call ale#linter#Define('objc', {
\ 'output_stream': 'stderr',
\ 'executable': 'clang',
\ 'command_callback': 'ale_linters#objc#clang#GetCommand',
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/objc/clangd.vim b/ale_linters/objc/clangd.vim
new file mode 100644
index 00000000..f090e6ce
--- /dev/null
+++ b/ale_linters/objc/clangd.vim
@@ -0,0 +1,23 @@
+" Author: Andrey Melentyev <andrey.melentyev@protonmail.com>
+" Description: Clangd language server
+
+call ale#Set('objc_clangd_executable', 'clangd')
+call ale#Set('objc_clangd_options', '')
+
+function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#objc#clangd#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options'))
+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',
+\})
diff --git a/ale_linters/objcpp/clang.vim b/ale_linters/objcpp/clang.vim
index 0e9cefe9..d1474f17 100644
--- a/ale_linters/objcpp/clang.vim
+++ b/ale_linters/objcpp/clang.vim
@@ -19,5 +19,5 @@ call ale#linter#Define('objcpp', {
\ 'output_stream': 'stderr',
\ 'executable': 'clang++',
\ 'command_callback': 'ale_linters#objcpp#clang#GetCommand',
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/objcpp/clangd.vim b/ale_linters/objcpp/clangd.vim
new file mode 100644
index 00000000..a09753be
--- /dev/null
+++ b/ale_linters/objcpp/clangd.vim
@@ -0,0 +1,23 @@
+" Author: Andrey Melentyev <andrey.melentyev@protonmail.com>
+" Description: Clangd language server
+
+call ale#Set('objcpp_clangd_executable', 'clangd')
+call ale#Set('objcpp_clangd_options', '')
+
+function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#objcpp#clangd#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options'))
+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',
+\})
diff --git a/ale_linters/perl/perl.vim b/ale_linters/perl/perl.vim
index 1b9aa95e..1cb20fa7 100644
--- a/ale_linters/perl/perl.vim
+++ b/ale_linters/perl/perl.vim
@@ -1,20 +1,11 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl syntax
-let g:ale_perl_perl_executable =
-\ get(g:, 'ale_perl_perl_executable', 'perl')
-
-let g:ale_perl_perl_options =
-\ get(g:, 'ale_perl_perl_options', '-c -Mwarnings -Ilib')
-
-function! ale_linters#perl#perl#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'perl_perl_executable')
-endfunction
+call ale#Set('perl_perl_executable', 'perl')
+call ale#Set('perl_perl_options', '-c -Mwarnings -Ilib')
function! ale_linters#perl#perl#GetCommand(buffer) abort
- return ale#Escape(ale_linters#perl#perl#GetExecutable(a:buffer))
- \ . ' ' . ale#Var(a:buffer, 'perl_perl_options')
- \ . ' %t'
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'perl_perl_options')) . ' %t'
endfunction
let s:begin_failed_skip_pattern = '\v' . join([
@@ -23,11 +14,16 @@ let s:begin_failed_skip_pattern = '\v' . join([
\], '|')
function! ale_linters#perl#perl#Handle(buffer, lines) abort
+ if empty(a:lines)
+ return []
+ endif
+
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
let l:output = []
let l:basename = expand('#' . a:buffer . ':t')
let l:type = 'E'
+
if a:lines[-1] =~# 'syntax OK'
let l:type = 'W'
endif
@@ -61,7 +57,7 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perl',
-\ 'executable_callback': 'ale_linters#perl#perl#GetExecutable',
+\ 'executable_callback': ale#VarFunc('perl_perl_executable'),
\ 'output_stream': 'both',
\ 'command_callback': '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 e91c8a03..8619a404 100644
--- a/ale_linters/perl/perlcritic.vim
+++ b/ale_linters/perl/perlcritic.vim
@@ -1,21 +1,10 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>, Chris Weyl <cweyl@alumni.drew.edu>
" Description: This file adds support for checking perl with perl critic
-let g:ale_perl_perlcritic_executable =
-\ get(g:, 'ale_perl_perlcritic_executable', 'perlcritic')
-
-let g:ale_perl_perlcritic_profile =
-\ get(g:, 'ale_perl_perlcritic_profile', '.perlcriticrc')
-
-let g:ale_perl_perlcritic_options =
-\ get(g:, 'ale_perl_perlcritic_options', '')
-
-let g:ale_perl_perlcritic_showrules =
-\ get(g:, 'ale_perl_perlcritic_showrules', 0)
-
-function! ale_linters#perl#perlcritic#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'perl_perlcritic_executable')
-endfunction
+call ale#Set('perl_perlcritic_executable', 'perlcritic')
+call ale#Set('perl_perlcritic_profile', '.perlcriticrc')
+call ale#Set('perl_perlcritic_options', '')
+call ale#Set('perl_perlcritic_showrules', 0)
function! ale_linters#perl#perlcritic#GetProfile(buffer) abort
" first see if we've been overridden
@@ -39,11 +28,11 @@ function! ale_linters#perl#perlcritic#GetCommand(buffer) abort
let l:profile = ale_linters#perl#perlcritic#GetProfile(a:buffer)
let l:options = ale#Var(a:buffer, 'perl_perlcritic_options')
- return ale#Escape(ale_linters#perl#perlcritic#GetExecutable(a:buffer))
+ return '%e'
\ . ' --verbose ' . ale#Escape(l:critic_verbosity)
\ . ' --nocolor'
\ . (!empty(l:profile) ? ' --profile ' . ale#Escape(l:profile) : '')
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ale#Pad(l:options)
endfunction
@@ -66,7 +55,7 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perlcritic',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#perl#perlcritic#GetExecutable',
+\ 'executable_callback': ale#VarFunc('perl_perlcritic_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..b33a0c51
--- /dev/null
+++ b/ale_linters/perl6/perl6.vim
@@ -0,0 +1,166 @@
+" Author:Travis Gibson <https://github.com/Garland-g>
+" Description: This file adds support for checking perl6 syntax
+
+let g:ale_perl6_perl6_executable =
+\ get(g:, 'ale_perl6_perl6_executable', 'perl6')
+
+let g:ale_perl6_perl6_options =
+\ get(g:, 'ale_perl6_perl6_options', '-c -Ilib')
+
+let $PERL6_EXCEPTIONS_HANDLER = 'JSON'
+
+let $RAKUDO_ERROR_COLOR = 0
+
+function! ale_linters#perl6#perl6#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'perl6_perl6_executable')
+endfunction
+
+function! ale_linters#perl6#perl6#GetCommand(buffer) abort
+ return ale_linters#perl6#perl6#GetExecutable(a:buffer)
+ \ . ' ' . ale#Var(a:buffer, 'perl6_perl6_options')
+ \ . ' %t'
+endfunction
+
+function! ale_linters#perl6#perl6#ExtractError(dict, item, type, buffer) abort
+ let l:file = ''
+ let l:line = 1
+ let l:column = ''
+ let l:text = ''
+ let l:pre = ''
+ let l:counter = 2
+ let l:end_line = ''
+ let l:linepatternmessage = 'at\s\+line\s\+\(\d\+\)'
+
+ if has_key(a:dict[a:item], 'filename') && !empty(a:dict[a:item]['filename'])
+ let l:file = a:dict[a:item]['filename']
+ endif
+
+ if has_key(a:dict[a:item], 'line') && !empty(a:dict[a:item]['line'])
+ let l:line = a:dict[a:item]['line']
+ let l:counter -= 1
+ endif
+
+ if has_key(a:dict[a:item], 'column') && !empty(a:dict[a:item]['column'])
+ let l:column = a:dict[a:item]['column']
+ endif
+
+ if has_key(a:dict[a:item], 'message') && !empty(a:dict[a:item]['message'])
+ let l:text = substitute(a:dict[a:item]['message'], '\s*\n\s*', ' ', 'g')
+ let l:counter -= 1
+ endif
+
+ if has_key(a:dict[a:item], 'line-real') && !empty(a:dict[a:item]['line-real'])
+ let l:end_line = l:line
+ let l:line = a:dict[a:item]['line-real']
+ endif
+
+ for l:match in ale#util#GetMatches(l:text, l:linepatternmessage)
+ let l:line = l:match[1]
+ let l:counter -= 1
+ endfor
+
+" Currently, filenames and line numbers are not always given in the error output
+ if l:counter < 2
+ \&& ( ale#path#IsBufferPath(a:buffer, l:file) || l:file is# '' )
+ return {
+ \ 'lnum': '' . l:line,
+ \ 'text': l:text,
+ \ 'type': a:type,
+ \ 'col': l:column,
+ \ 'end_lnum': l:end_line,
+ \ 'code': a:item,
+ \}
+ endif
+
+ return ''
+endfunction
+
+function! ale_linters#perl6#perl6#Handle(buffer, lines) abort
+ let l:output = []
+
+ if empty(a:lines)
+ return l:output
+ endif
+
+ if a:lines[0] is# 'Syntax OK'
+ return l:output
+ endif
+
+ try
+ let l:json = json_decode(join(a:lines, ''))
+ catch /E474/
+ call add(l:output, {
+ \ 'lnum': '1',
+ \ 'text': 'Received output in the default Perl6 error format. See :ALEDetail for details',
+ \ 'detail': join(a:lines, "\n"),
+ \ 'type': 'W',
+ \ })
+
+ return l:output
+ endtry
+
+ if type(l:json) is v:t_dict
+ for l:key in keys(l:json)
+ if has_key(l:json[l:key], 'sorrows') &&
+ \ has_key(l:json[l:key], 'worries')
+ if !empty(l:json[l:key]['sorrows'])
+ for l:dictionary in get(l:json[l:key], 'sorrows')
+ for l:item in keys(l:dictionary)
+ let l:result =
+ \ ale_linters#perl6#perl6#ExtractError(
+ \ l:dictionary,
+ \ l:item,
+ \ 'E',
+ \ a:buffer,
+ \ )
+
+ if l:result isnot# ''
+ call add(l:output, l:result)
+ endif
+ endfor
+ endfor
+ endif
+
+ if !empty(l:json[l:key]['worries'])
+ for l:dictionary in get(l:json[l:key], 'worries')
+ for l:item in keys(l:dictionary)
+ let l:result =
+ \ ale_linters#perl6#perl6#ExtractError(
+ \ l:dictionary,
+ \ l:item,
+ \ 'W',
+ \ a:buffer,
+ \ )
+
+ if l:result isnot# ''
+ call add(l:output, l:result)
+ endif
+ endfor
+ endfor
+ endif
+ else
+ let l:result = ale_linters#perl6#perl6#ExtractError(
+ \ l:json,
+ \ l:key,
+ \ 'E',
+ \ a:buffer,
+ \ )
+
+ if l:result isnot# ''
+ call add(l:output, l:result)
+ endif
+ endif
+ endfor
+ endif
+
+ return l:output
+endfunction
+
+call ale#linter#Define('perl6', {
+\ 'name': 'perl6',
+\ 'executable_callback': 'ale_linters#perl6#perl6#GetExecutable',
+\ 'output_stream': 'both',
+\ 'command_callback': 'ale_linters#perl6#perl6#GetCommand',
+\ 'callback': 'ale_linters#perl6#perl6#Handle',
+\})
+
diff --git a/ale_linters/php/hack.vim b/ale_linters/php/hack.vim
deleted file mode 100644
index 77d3a588..00000000
--- a/ale_linters/php/hack.vim
+++ /dev/null
@@ -1,28 +0,0 @@
-" Author: Zefei Xuan <https://github.com/zefei>
-" Description: Hack type checking (http://hacklang.org/)
-
-function! ale_linters#php#hack#Handle(buffer, lines) abort
- let l:pattern = '^\(.*\):\(\d\+\):\(\d\+\),\(\d\+\): \(.\+])\)$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- if a:buffer != bufnr(l:match[1])
- continue
- endif
-
- call add(l:output, {
- \ 'lnum': l:match[2] + 0,
- \ 'col': l:match[3] + 0,
- \ 'text': l:match[5],
- \})
- endfor
-
- return l:output
-endfunction
-
-call ale#linter#Define('php', {
-\ 'name': 'hack',
-\ 'executable': 'hh_client',
-\ 'command': 'hh_client --retries 0 --retry-if-init false',
-\ 'callback': 'ale_linters#php#hack#Handle',
-\})
diff --git a/ale_linters/php/langserver.vim b/ale_linters/php/langserver.vim
index 38b42df9..ca91db4c 100644
--- a/ale_linters/php/langserver.vim
+++ b/ale_linters/php/langserver.vim
@@ -4,16 +4,6 @@
call ale#Set('php_langserver_executable', 'php-language-server.php')
call ale#Set('php_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#php#langserver#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'php_langserver', [
- \ 'vendor/bin/php-language-server.php',
- \])
-endfunction
-
-function! ale_linters#php#langserver#GetCommand(buffer) abort
- return 'php ' . ale#Escape(ale_linters#php#langserver#GetExecutable(a:buffer))
-endfunction
-
function! ale_linters#php#langserver#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
@@ -23,7 +13,9 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'langserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#php#langserver#GetExecutable',
-\ 'command_callback': 'ale_linters#php#langserver#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('php_langserver', [
+\ 'vendor/bin/php-language-server.php',
+\ ]),
+\ 'command': 'php %e',
\ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot',
\})
diff --git a/ale_linters/php/php.vim b/ale_linters/php/php.vim
index 6470383b..5d87196c 100644
--- a/ale_linters/php/php.vim
+++ b/ale_linters/php/php.vim
@@ -1,6 +1,8 @@
" Author: Spencer Wood <https://github.com/scwood>, Adriaan Zonnenberg <amz@adriaan.xyz>
" Description: This file adds support for checking PHP with php-cli
+call ale#Set('php_php_executable', 'php')
+
function! ale_linters#php#php#Handle(buffer, lines) abort
" Matches patterns like the following:
"
@@ -30,8 +32,8 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'php',
-\ 'executable': 'php',
+\ 'executable_callback': ale#VarFunc('php_php_executable'),
\ 'output_stream': 'stdout',
-\ 'command': 'php -l -d error_reporting=E_ALL -d display_errors=1 -d log_errors=0 --',
+\ '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 faf8ad55..408c2652 100644
--- a/ale_linters/php/phpcs.vim
+++ b/ale_linters/php/phpcs.vim
@@ -3,26 +3,20 @@
let g:ale_php_phpcs_standard = get(g:, 'ale_php_phpcs_standard', '')
+call ale#Set('php_phpcs_options', '')
call ale#Set('php_phpcs_executable', 'phpcs')
call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#php#phpcs#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'php_phpcs', [
- \ 'vendor/bin/phpcs',
- \ 'phpcs'
- \])
-endfunction
-
function! ale_linters#php#phpcs#GetCommand(buffer) abort
- let l:executable = ale_linters#php#phpcs#GetExecutable(a:buffer)
-
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
let l:standard_option = !empty(l:standard)
\ ? '--standard=' . l:standard
\ : ''
+ let l:options = ale#Var(a:buffer, 'php_phpcs_options')
- return ale#Escape(l:executable)
- \ . ' -s --report=emacs --stdin-path=%s ' . l:standard_option
+ return '%e -s --report=emacs --stdin-path=%s'
+ \ . ale#Pad(l:standard_option)
+ \ . ale#Pad(l:options)
endfunction
function! ale_linters#php#phpcs#Handle(buffer, lines) abort
@@ -50,7 +44,10 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpcs',
-\ 'executable_callback': 'ale_linters#php#phpcs#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('php_phpcs', [
+\ 'vendor/bin/phpcs',
+\ 'phpcs'
+\ ]),
\ 'command_callback': '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 e9450752..65f1cc3c 100644
--- a/ale_linters/php/phpmd.vim
+++ b/ale_linters/php/phpmd.vim
@@ -6,16 +6,9 @@ let g:ale_php_phpmd_executable = get(g:, 'ale_php_phpmd_executable', 'phpmd')
" Set to change the ruleset
let g:ale_php_phpmd_ruleset = get(g:, 'ale_php_phpmd_ruleset', 'cleancode,codesize,controversial,design,naming,unusedcode')
-function! ale_linters#php#phpmd#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'php_phpmd_executable')
-endfunction
-
function! ale_linters#php#phpmd#GetCommand(buffer) abort
- let l:executable = ale_linters#php#phpmd#GetExecutable(a:buffer)
-
- return ale#Escape(l:executable)
- \ . ' %s text '
- \ . ale#Var(a:buffer, 'php_phpmd_ruleset')
+ return '%e %s text'
+ \ . ale#Pad(ale#Var(a:buffer, 'php_phpmd_ruleset'))
\ . ' --ignore-violations-on-exit %t'
endfunction
@@ -39,7 +32,7 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpmd',
-\ 'executable_callback': 'ale_linters#php#phpmd#GetExecutable',
+\ 'executable_callback': ale#VarFunc('php_phpmd_executable'),
\ 'command_callback': '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 24762086..1c831e1b 100644
--- a/ale_linters/php/phpstan.vim
+++ b/ale_linters/php/phpstan.vim
@@ -10,18 +10,36 @@ function! ale_linters#php#phpstan#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'php_phpstan_executable')
endfunction
-function! ale_linters#php#phpstan#GetCommand(buffer) abort
+function! ale_linters#php#phpstan#VersionCheck(buffer) abort
let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer)
+ " If we have previously stored the version number in a cache, then
+ " don't look it up again.
+ if ale#semver#HasVersion(l:executable)
+ " Returning an empty string skips this command.
+ return ''
+ endif
+
+ let l:executable = ale#Escape(l:executable)
+
+ return l:executable . ' --version'
+endfunction
+
+function! ale_linters#php#phpstan#GetCommand(buffer, version_output) abort
let l:configuration = ale#Var(a:buffer, 'php_phpstan_configuration')
let l:configuration_option = !empty(l:configuration)
\ ? ' -c ' . l:configuration
\ : ''
- return ale#Escape(l:executable)
- \ . ' analyze -l'
+ let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer)
+ let l:version = ale#semver#GetVersion(l:executable, a:version_output)
+ let l:error_format = ale#semver#GTE(l:version, [0, 10, 3])
+ \ ? ' --error-format raw'
+ \ : ' --errorFormat raw'
+
+ return '%e analyze -l'
\ . ale#Var(a:buffer, 'php_phpstan_level')
- \ . ' --errorFormat raw'
+ \ . l:error_format
\ . l:configuration_option
\ . ' %s'
endfunction
@@ -48,6 +66,9 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpstan',
\ 'executable_callback': 'ale_linters#php#phpstan#GetExecutable',
-\ 'command_callback': 'ale_linters#php#phpstan#GetCommand',
+\ 'command_chain': [
+\ {'callback': 'ale_linters#php#phpstan#VersionCheck'},
+\ {'callback': 'ale_linters#php#phpstan#GetCommand'},
+\ ],
\ 'callback': 'ale_linters#php#phpstan#Handle',
\})
diff --git a/ale_linters/php/psalm.vim b/ale_linters/php/psalm.vim
new file mode 100644
index 00000000..dce59178
--- /dev/null
+++ b/ale_linters/php/psalm.vim
@@ -0,0 +1,21 @@
+" Author: Matt Brown <https://github.com/muglug>
+" Description: plugin for Psalm, static analyzer for PHP
+
+call ale#Set('psalm_langserver_executable', 'psalm-language-server')
+call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
+
+function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
+ let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
+
+ return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
+endfunction
+
+call ale#linter#Define('php', {
+\ 'name': 'psalm',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#node#FindExecutableFunc('psalm_langserver', [
+\ 'vendor/bin/psalm-language-server',
+\ ]),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale_linters#php#psalm#GetProjectRoot',
+\})
diff --git a/ale_linters/pony/ponyc.vim b/ale_linters/pony/ponyc.vim
index b3329053..19e7e828 100644
--- a/ale_linters/pony/ponyc.vim
+++ b/ale_linters/pony/ponyc.vim
@@ -3,19 +3,14 @@
call ale#Set('pony_ponyc_executable', 'ponyc')
call ale#Set('pony_ponyc_options', '--pass paint')
-function! ale_linters#pony#ponyc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'pony_ponyc_executable')
-endfunction
-
function! ale_linters#pony#ponyc#GetCommand(buffer) abort
- return ale#Escape(ale_linters#pony#ponyc#GetExecutable(a:buffer))
- \ . ' ' . ale#Var(a:buffer, 'pony_ponyc_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'pony_ponyc_options'))
endfunction
call ale#linter#Define('pony', {
\ 'name': 'ponyc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#pony#ponyc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('pony_ponyc_executable'),
\ 'command_callback': 'ale_linters#pony#ponyc#GetCommand',
\ 'callback': 'ale#handlers#pony#HandlePonycFormat',
\})
diff --git a/ale_linters/prolog/swipl.vim b/ale_linters/prolog/swipl.vim
new file mode 100644
index 00000000..401e52b6
--- /dev/null
+++ b/ale_linters/prolog/swipl.vim
@@ -0,0 +1,100 @@
+" Author: Takuya Fujiwara <tyru.exe@gmail.com>
+" Description: swipl syntax / semantic check for Prolog files
+
+call ale#Set('prolog_swipl_executable', 'swipl')
+call ale#Set('prolog_swipl_load', 'current_prolog_flag(argv, [File]), load_files(File, [sandboxed(true)]), halt.')
+call ale#Set('prolog_swipl_timeout', 3)
+call ale#Set('prolog_swipl_alarm', 'alarm(%t, (%h), _, [])')
+call ale#Set('prolog_swipl_alarm_handler', 'writeln(user_error, "ERROR: Exceeded %t seconds, Please change g:prolog_swipl_timeout to modify the limit."), halt(1)')
+
+function! ale_linters#prolog#swipl#GetCommand(buffer) abort
+ let l:goals = ale#Var(a:buffer, 'prolog_swipl_load')
+ let l:goals = l:goals =~# '^\s*$' ? 'halt' : l:goals
+ let l:timeout = ale#Var(a:buffer, 'prolog_swipl_timeout') + 0
+
+ if l:timeout > 0
+ let l:goals = s:GetAlarm(a:buffer, l:timeout) . ', ' . l:goals
+ endif
+
+ return '%e -g ' . ale#Escape(l:goals) . ' -- %s'
+endfunction
+
+function! s:GetAlarm(buffer, timeout) abort
+ let l:handler = ale#Var(a:buffer, 'prolog_swipl_alarm_handler')
+ let l:handler = s:Subst(l:handler, {'t': a:timeout})
+ let l:alarm = ale#Var(a:buffer, 'prolog_swipl_alarm')
+ let l:alarm = s:Subst(l:alarm, {'t': a:timeout, 'h': l:handler})
+
+ return l:alarm
+endfunction
+
+function! s:Subst(format, vars) abort
+ let l:vars = extend(copy(a:vars), {'%': '%'})
+
+ return substitute(a:format, '%\(.\)', '\=get(l:vars, submatch(1), "")', 'g')
+endfunction
+
+function! ale_linters#prolog#swipl#Handle(buffer, lines) abort
+ let l:pattern = '\v^(ERROR|Warning)+%(:\s*[^:]+:(\d+)%(:(\d+))?)?:\s*(.*)$'
+ let l:output = []
+ let l:i = 0
+
+ while l:i < len(a:lines)
+ let l:match = matchlist(a:lines[l:i], l:pattern)
+
+ if empty(l:match)
+ let l:i += 1
+ continue
+ endif
+
+ let [l:i, l:text] = s:GetErrMsg(l:i, a:lines, l:match[4])
+ let l:item = {
+ \ 'lnum': (l:match[2] + 0 ? l:match[2] + 0 : 1),
+ \ 'col': l:match[3] + 0,
+ \ 'text': l:text,
+ \ 'type': (l:match[1] is# 'ERROR' ? 'E' : 'W'),
+ \}
+
+ if !s:Ignore(l:item)
+ call add(l:output, l:item)
+ endif
+ endwhile
+
+ return l:output
+endfunction
+
+" This returns [<next line number>, <error message string>]
+function! s:GetErrMsg(i, lines, text) abort
+ if a:text !~# '^\s*$'
+ return [a:i + 1, a:text]
+ endif
+
+ let l:i = a:i + 1
+ let l:text = []
+
+ while l:i < len(a:lines) && a:lines[l:i] =~# '^\s'
+ call add(l:text, s:Trim(a:lines[l:i]))
+ let l:i += 1
+ endwhile
+
+ return [l:i, join(l:text, '. ')]
+endfunction
+
+function! s:Trim(str) abort
+ return substitute(a:str, '\v^\s+|\s+$', '', 'g')
+endfunction
+
+" Skip sandbox error which is caused by directives
+" because what we want is syntactic or semantic check.
+function! s:Ignore(item) abort
+ return a:item.type is# 'E' &&
+ \ a:item.text =~# '\vNo permission to (call|directive|assert) sandboxed'
+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',
+\ 'callback': 'ale_linters#prolog#swipl#Handle',
+\})
diff --git a/ale_linters/pug/puglint.vim b/ale_linters/pug/puglint.vim
index 165e68b7..63208986 100644
--- a/ale_linters/pug/puglint.vim
+++ b/ale_linters/pug/puglint.vim
@@ -5,12 +5,6 @@ call ale#Set('pug_puglint_options', '')
call ale#Set('pug_puglint_executable', 'pug-lint')
call ale#Set('pug_puglint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#pug#puglint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'pug_puglint', [
- \ 'node_modules/.bin/pug-lint',
- \])
-endfunction
-
function! s:FindConfig(buffer) abort
for l:filename in [
\ '.pug-lintrc',
@@ -29,19 +23,19 @@ function! s:FindConfig(buffer) abort
endfunction
function! ale_linters#pug#puglint#GetCommand(buffer) abort
- let l:executable = ale_linters#pug#puglint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'pug_puglint_options')
let l:config = s:FindConfig(a:buffer)
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ return '%e' . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' -r inline %t'
endfunction
call ale#linter#Define('pug', {
\ 'name': 'puglint',
-\ 'executable_callback': 'ale_linters#pug#puglint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('pug_puglint', [
+\ 'node_modules/.bin/pug-lint',
+\ ]),
\ 'output_stream': 'stderr',
\ 'command_callback': '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 52880f32..a3060e65 100644
--- a/ale_linters/puppet/languageserver.vim
+++ b/ale_linters/puppet/languageserver.vim
@@ -3,21 +3,12 @@
call ale#Set('puppet_languageserver_executable', 'puppet-languageserver')
-function! ale_linters#puppet#languageserver#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'puppet_languageserver_executable')
-endfunction
-
-function! ale_linters#puppet#languageserver#GetCommand(buffer) abort
- let l:exe = ale#Escape(ale_linters#puppet#languageserver#GetExecutable(a:buffer))
-
- return l:exe . ' --stdio'
-endfunction
-
function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort
" Note: The metadata.json file is recommended for Puppet 4+ modules, but
" there's no requirement to have it, so fall back to the other possible
" Puppet module directories
let l:root_path = ale#path#FindNearestFile(a:buffer, 'metadata.json')
+
if !empty(l:root_path)
return fnamemodify(l:root_path, ':h')
endif
@@ -27,6 +18,7 @@ function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort
\ 'templates',
\]
let l:root_path = ale#path#FindNearestDirectory(a:buffer, l:test_path)
+
if !empty(l:root_path)
return fnamemodify(l:root_path, ':h:h')
endif
@@ -38,8 +30,8 @@ endfunction
call ale#linter#Define('puppet', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#puppet#languageserver#GetExecutable',
-\ 'command_callback': 'ale_linters#puppet#languageserver#GetCommand',
+\ 'executable_callback': ale#VarFunc('puppet_languageserver_executable'),
+\ 'command': '%e --stdio',
\ 'language': 'puppet',
\ 'project_root_callback': 'ale_linters#puppet#languageserver#GetProjectRoot',
\})
diff --git a/ale_linters/puppet/puppet.vim b/ale_linters/puppet/puppet.vim
index 4ca0dd55..0e37bdbd 100644
--- a/ale_linters/puppet/puppet.vim
+++ b/ale_linters/puppet/puppet.vim
@@ -1,11 +1,13 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
+call ale#Set('puppet_puppet_executable', 'puppet')
+call ale#Set('puppet_puppet_options', '')
+
function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
" Matches patterns like the following:
" Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12
" Error: Could not parse for environment production: Syntax error at '='; expected '}' at /root/puppetcode/modules/pancakes/manifests/init.pp:5"
" Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 4, column: 5)
-
let l:pattern = '^Error: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)'
let l:output = []
@@ -20,10 +22,16 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#puppet#puppet#GetCommand(buffer) abort
+ return '%e parser validate --color=false '
+ \ . ale#Pad(ale#Var(a:buffer, 'puppet_puppet_options'))
+ \ . ' %t'
+endfunction
+
call ale#linter#Define('puppet', {
\ 'name': 'puppet',
-\ 'executable': 'puppet',
+\ 'executable_callback': ale#VarFunc('puppet_puppet_executable'),
\ 'output_stream': 'stderr',
-\ 'command': 'puppet parser validate --color=false %t',
+\ 'command_callback': '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 13da511b..c9c16f5e 100644
--- a/ale_linters/puppet/puppetlint.vim
+++ b/ale_linters/puppet/puppetlint.vim
@@ -1,26 +1,18 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>, Robert Flechtner <flechtner@chemmedia.de>
" Description: puppet-lint for puppet files
-let g:ale_puppet_puppetlint_executable =
-\ get(g:, 'ale_puppet_puppetlint_executable', 'puppet-lint')
-
-let g:ale_puppet_puppetlint_options =
-\ get(g:, 'ale_puppet_puppetlint_options', '--no-autoloader_layout-check')
-
-function! ale_linters#puppet#puppetlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'puppet_puppetlint_executable')
-endfunction
+call ale#Set('puppet_puppetlint_executable', 'puppet-lint')
+call ale#Set('puppet_puppetlint_options', '--no-autoloader_layout-check')
function! ale_linters#puppet#puppetlint#GetCommand(buffer) abort
- return ale_linters#puppet#puppetlint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'puppet_puppetlint_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'puppet_puppetlint_options'))
\ . ' --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"'
\ . ' %t'
endfunction
call ale#linter#Define('puppet', {
\ 'name': 'puppetlint',
-\ 'executable_callback': 'ale_linters#puppet#puppetlint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('puppet_puppetlint_executable'),
\ 'command_callback': '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 9b6b39d7..d260698c 100644
--- a/ale_linters/pyrex/cython.vim
+++ b/ale_linters/pyrex/cython.vim
@@ -5,16 +5,11 @@
call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra')
-function! ale_linters#pyrex#cython#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'pyrex_cython_executable')
-endfunction
-
function! ale_linters#pyrex#cython#GetCommand(buffer) abort
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
- return ale#Escape(ale_linters#pyrex#cython#GetExecutable(a:buffer))
- \ . ' --working ' . l:local_dir . ' --include-dir ' . l:local_dir
- \ . ' ' . ale#Var(a:buffer, 'pyrex_cython_options')
+ return '%e --working ' . l:local_dir . ' --include-dir ' . l:local_dir
+ \ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
\ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction
@@ -37,7 +32,7 @@ endfunction
call ale#linter#Define('pyrex', {
\ 'name': 'cython',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#pyrex#cython#GetExecutable',
+\ 'executable_callback': ale#VarFunc('pyrex_cython_executable'),
\ 'command_callback': 'ale_linters#pyrex#cython#GetCommand',
\ 'callback': 'ale_linters#pyrex#cython#Handle',
\})
diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim
index 358f51a4..14b67d77 100644
--- a/ale_linters/python/flake8.vim
+++ b/ale_linters/python/flake8.vim
@@ -5,12 +5,18 @@ call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '')
call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_flake8_change_directory', 1)
+call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort
return ale#Var(a:buffer, 'python_flake8_options') =~# ' *-m flake8'
endfunction
function! ale_linters#python#flake8#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_flake8_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
if !s:UsingModule(a:buffer)
return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8'])
endif
@@ -104,6 +110,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
let l:item = {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
+ \ 'vcol': 1,
\ 'text': l:match[4],
\ 'code': l:code,
\ 'type': 'W',
diff --git a/ale_linters/python/mypy.vim b/ale_linters/python/mypy.vim
index b38ccdeb..0c90a3c7 100644
--- a/ale_linters/python/mypy.vim
+++ b/ale_linters/python/mypy.vim
@@ -5,8 +5,14 @@ call ale#Set('python_mypy_executable', 'mypy')
call ale#Set('python_mypy_ignore_invalid_syntax', 0)
call ale#Set('python_mypy_options', '')
call ale#Set('python_mypy_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_mypy_auto_pipenv', 0)
function! ale_linters#python#mypy#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_mypy_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy'])
endfunction
diff --git a/ale_linters/python/prospector.vim b/ale_linters/python/prospector.vim
index fff37147..b01cec87 100644
--- a/ale_linters/python/prospector.vim
+++ b/ale_linters/python/prospector.vim
@@ -1,6 +1,8 @@
" Author: chocoelho <carlospecter@gmail.com>
" Description: prospector linter python files
+call ale#Set('python_prospector_auto_pipenv', 0)
+
let g:ale_python_prospector_executable =
\ get(g:, 'ale_python_prospector_executable', 'prospector')
@@ -10,6 +12,11 @@ let g:ale_python_prospector_options =
let g:ale_python_prospector_use_global = get(g:, 'ale_python_prospector_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#python#prospector#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_prospector_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_prospector', ['prospector'])
endfunction
diff --git a/ale_linters/python/pycodestyle.vim b/ale_linters/python/pycodestyle.vim
index de96363f..f0269585 100644
--- a/ale_linters/python/pycodestyle.vim
+++ b/ale_linters/python/pycodestyle.vim
@@ -4,8 +4,14 @@
call ale#Set('python_pycodestyle_executable', 'pycodestyle')
call ale#Set('python_pycodestyle_options', '')
call ale#Set('python_pycodestyle_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pycodestyle_auto_pipenv', 0)
function! ale_linters#python#pycodestyle#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycodestyle_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pycodestyle', ['pycodestyle'])
endfunction
diff --git a/ale_linters/python/pyflakes.vim b/ale_linters/python/pyflakes.vim
index 86ff8773..091408d5 100644
--- a/ale_linters/python/pyflakes.vim
+++ b/ale_linters/python/pyflakes.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyflakes_executable', 'pyflakes')
call ale#Set('python_pyflakes_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyflakes_auto_pipenv', 0)
function! ale_linters#python#pyflakes#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyflakes_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyflakes', ['pyflakes'])
endfunction
diff --git a/ale_linters/python/pylint.vim b/ale_linters/python/pylint.vim
index 9239f835..01c3cb37 100644
--- a/ale_linters/python/pylint.vim
+++ b/ale_linters/python/pylint.vim
@@ -5,8 +5,14 @@ call ale#Set('python_pylint_executable', 'pylint')
call ale#Set('python_pylint_options', '')
call ale#Set('python_pylint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pylint_change_directory', 1)
+call ale#Set('python_pylint_auto_pipenv', 0)
function! ale_linters#python#pylint#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylint_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
endfunction
diff --git a/ale_linters/python/pyls.vim b/ale_linters/python/pyls.vim
index ae71f022..83fe8066 100644
--- a/ale_linters/python/pyls.vim
+++ b/ale_linters/python/pyls.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyls_executable', 'pyls')
call ale#Set('python_pyls_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyls_auto_pipenv', 0)
function! ale_linters#python#pyls#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyls_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyls', ['pyls'])
endfunction
diff --git a/ale_linters/python/pyre.vim b/ale_linters/python/pyre.vim
index 5efef409..adc185f2 100644
--- a/ale_linters/python/pyre.vim
+++ b/ale_linters/python/pyre.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyre_executable', 'pyre')
call ale#Set('python_pyre_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyre_auto_pipenv', 0)
function! ale_linters#python#pyre#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyre_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyre', ['pyre'])
endfunction
diff --git a/ale_linters/python/vulture.vim b/ale_linters/python/vulture.vim
new file mode 100644
index 00000000..80828013
--- /dev/null
+++ b/ale_linters/python/vulture.vim
@@ -0,0 +1,85 @@
+" Author: Yauheni Kirylau <actionless.loveless@gmail.com>
+" Description: vulture linting for python files
+
+call ale#Set('python_vulture_executable', 'vulture')
+call ale#Set('python_vulture_options', '')
+call ale#Set('python_vulture_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_vulture_change_directory', 1)
+
+
+" The directory to change to before running vulture
+function! s:GetDir(buffer) abort
+ let l:project_root = ale#python#FindProjectRoot(a:buffer)
+
+ return !empty(l:project_root)
+ \ ? l:project_root
+ \ : expand('#' . a:buffer . ':p:h')
+endfunction
+
+
+function! ale_linters#python#vulture#GetExecutable(buffer) abort
+ return ale#python#FindExecutable(a:buffer, 'python_vulture', ['vulture'])
+endfunction
+
+
+function! ale_linters#python#vulture#GetCommand(buffer) abort
+ let l:change_dir = ale#Var(a:buffer, 'python_vulture_change_directory')
+ \ ? ale#path#CdString(s:GetDir(a:buffer))
+ \ : ''
+
+ let l:executable = ale_linters#python#vulture#GetExecutable(a:buffer)
+
+ let l:exec_args = l:executable =~? 'pipenv$'
+ \ ? ' run vulture'
+ \ : ''
+
+ let l:lint_dest = ale#Var(a:buffer, 'python_vulture_change_directory')
+ \ ? ' .'
+ \ : ' %s'
+
+ return l:change_dir
+ \ . ale#Escape(l:executable) . l:exec_args
+ \ . ' '
+ \ . ale#Var(a:buffer, 'python_vulture_options')
+ \ . l:lint_dest
+endfunction
+
+
+function! ale_linters#python#vulture#Handle(buffer, lines) abort
+ for l:line in a:lines[:10]
+ if match(l:line, '^Traceback') >= 0
+ return [{
+ \ 'lnum': 1,
+ \ 'text': 'An exception was thrown. See :ALEDetail',
+ \ 'detail': join(a:lines, "\n"),
+ \}]
+ endif
+ endfor
+
+ " Matches patterns line the following:
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+): (.*)$'
+ let l:output = []
+ let l:dir = s:GetDir(a:buffer)
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ let l:abspath = ale#path#GetAbsPath(l:dir, l:match[1])
+ let l:item = {
+ \ 'filename': l:abspath,
+ \ 'lnum': l:match[2] + 0,
+ \ 'text': l:match[3],
+ \ 'type': 'W',
+ \}
+ call add(l:output, l:item)
+ endfor
+
+ return l:output
+endfunction
+
+
+call ale#linter#Define('python', {
+\ 'name': 'vulture',
+\ 'executable_callback': 'ale_linters#python#vulture#GetExecutable',
+\ 'command_callback': '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 85b131fd..12f3e97b 100644
--- a/ale_linters/qml/qmlfmt.vim
+++ b/ale_linters/qml/qmlfmt.vim
@@ -1,40 +1,25 @@
" Author: pylipp (www.github.com/pylipp)
" Description: qmlfmt for QML files
-let g:ale_qml_qmlfmt_executable = get(g:, 'ale_qml_qmlfmt_executable', 'qmlfmt')
-
-function! ale_linters#qml#qmlfmt#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'qml_qmlfmt_executable')
-endfunction
-
-function! ale_linters#qml#qmlfmt#GetCommand(buffer) abort
- return ale#Escape(ale_linters#qml#qmlfmt#GetExecutable(a:buffer))
- \ . ' -e'
-endfunction
+call ale#Set('qml_qmlfmt_executable', 'qmlfmt')
" Find lines like
" Error:11:1: Expected token `}'
function! ale_linters#qml#qmlfmt#Handle(buffer, lines) abort
let l:pattern = '\v^(Error|Warning):(\d+):(\d+): (.+)$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- let l:item = {
- \ 'lnum': l:match[2] + 0,
- \ 'col': l:match[3] + 0,
- \ 'text': l:match[4],
- \ 'type': l:match[1] is# 'Warning' ? 'W' : 'E',
- \}
- call add(l:output, l:item)
- endfor
- return l:output
+ return map(ale#util#GetMatches(a:lines, l:pattern), "{
+ \ 'lnum': v:val[2] + 0,
+ \ 'col': v:val[3] + 0,
+ \ 'text': v:val[4],
+ \ 'type': v:val[1] is# 'Warning' ? 'W' : 'E',
+ \}")
endfunction
call ale#linter#Define('qml', {
\ 'name': 'qmlfmt',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#qml#qmlfmt#GetExecutable',
-\ 'command_callback': 'ale_linters#qml#qmlfmt#GetCommand',
+\ 'executable_callback': ale#VarFunc('qml_qmlfmt_executable'),
+\ 'command': '%e -e',
\ 'callback': 'ale_linters#qml#qmlfmt#Handle',
\})
diff --git a/ale_linters/rst/rstcheck.vim b/ale_linters/rst/rstcheck.vim
index b660627f..8504738b 100644
--- a/ale_linters/rst/rstcheck.vim
+++ b/ale_linters/rst/rstcheck.vim
@@ -8,6 +8,7 @@ function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort
let l:pattern = '\v^(.+):(\d*): \(([a-zA-Z]*)/\d*\) (.+)$'
let l:dir = expand('#' . a:buffer . ':p:h')
let l:output = []
+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
diff --git a/ale_linters/ruby/brakeman.vim b/ale_linters/ruby/brakeman.vim
index 85cfc184..122e0b5b 100644
--- a/ale_linters/ruby/brakeman.vim
+++ b/ale_linters/ruby/brakeman.vim
@@ -1,8 +1,9 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: Brakeman, a static analyzer for Rails security
-let g:ale_ruby_brakeman_options =
-\ get(g:, 'ale_ruby_brakeman_options', '')
+call ale#Set('ruby_brakeman_options', '')
+call ale#Set('ruby_brakeman_executable', 'brakeman')
+call ale#Set('ruby_brakeman_options', '')
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
let l:output = []
@@ -33,14 +34,17 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
return ''
endif
- return 'brakeman -f json -q '
+ let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'brakeman')
+ \ . ' -f json -q '
\ . ale#Var(a:buffer, 'ruby_brakeman_options')
\ . ' -p ' . ale#Escape(l:rails_root)
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'brakeman',
-\ 'executable': 'brakeman',
+\ 'executable_callback': ale#VarFunc('ruby_brakeman_executable'),
\ 'command_callback': '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 4ba1f3fe..20cadca8 100644
--- a/ale_linters/ruby/rails_best_practices.vim
+++ b/ale_linters/ruby/rails_best_practices.vim
@@ -22,26 +22,18 @@ function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#ruby#rails_best_practices#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
-endfunction
-
function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
- let l:executable = ale_linters#ruby#rails_best_practices#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rails_best_practices'
- \ : ''
-
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer)
if l:rails_root is? ''
return ''
endif
+ let l:executable = ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
let l:output_file = ale#Has('win32') ? '%t ' : '/dev/stdout '
let l:cat_file = ale#Has('win32') ? '; type %t' : ''
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
\ . ' --silent -f json --output-file ' . l:output_file
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
\ . ale#Escape(l:rails_root)
@@ -50,7 +42,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rails_best_practices',
-\ 'executable_callback': 'ale_linters#ruby#rails_best_practices#GetExecutable',
+\ 'executable_callback': ale#VarFunc('ruby_rails_best_practices_executable'),
\ 'command_callback': '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 aa5d8d70..53363d31 100644
--- a/ale_linters/ruby/reek.vim
+++ b/ale_linters/ruby/reek.vim
@@ -3,6 +3,8 @@
call ale#Set('ruby_reek_show_context', 0)
call ale#Set('ruby_reek_show_wiki_link', 0)
+call ale#Set('ruby_reek_options', '')
+call ale#Set('ruby_reek_executable', 'reek')
function! ale_linters#ruby#reek#VersionCheck(buffer) abort
" If we have previously stored the version number in a cache, then
@@ -12,18 +14,23 @@ function! ale_linters#ruby#reek#VersionCheck(buffer) abort
return ''
endif
- return 'reek --version'
+ let l:executable = ale#Var(a:buffer, 'ruby_reek_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ \ . ' --version'
endfunction
function! ale_linters#ruby#reek#GetCommand(buffer, version_output) abort
let l:version = ale#semver#GetVersion('reek', a:version_output)
+ let l:executable = ale#Var(a:buffer, 'ruby_reek_executable')
" Tell reek what the filename is if the version of reek is new enough.
let l:display_name_args = ale#semver#GTE(l:version, [5, 0, 0])
\ ? ' --stdin-filename %s'
\ : ''
- return 'reek -f json --no-progress --no-color'
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ \ . ' -f json --no-progress --no-color --force-exclusion'
\ . l:display_name_args
endfunction
@@ -62,7 +69,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'reek',
-\ 'executable': 'reek',
+\ 'executable_callback': ale#VarFunc('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 777f457a..45218394 100644
--- a/ale_linters/ruby/rubocop.vim
+++ b/ale_linters/ruby/rubocop.vim
@@ -1,13 +1,13 @@
" Author: ynonp - https://github.com/ynonp, Eddie Lebow https://github.com/elebow
" Description: RuboCop, a code style analyzer for Ruby files
+call ale#Set('ruby_rubocop_executable', 'rubocop')
+call ale#Set('ruby_rubocop_options', '')
+
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
- let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rubocop'
- \ : ''
+ let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
@@ -55,7 +55,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rubocop',
-\ 'executable_callback': 'ale#handlers#rubocop#GetExecutable',
+\ 'executable_callback': ale#VarFunc('ruby_rubocop_executable'),
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
\ 'callback': 'ale_linters#ruby#rubocop#Handle',
\})
diff --git a/ale_linters/ruby/ruby.vim b/ale_linters/ruby/ruby.vim
index 1aa88851..2bc4ec4b 100644
--- a/ale_linters/ruby/ruby.vim
+++ b/ale_linters/ruby/ruby.vim
@@ -3,20 +3,10 @@
call ale#Set('ruby_ruby_executable', 'ruby')
-function! ale_linters#ruby#ruby#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_ruby_executable')
-endfunction
-
-function! ale_linters#ruby#ruby#GetCommand(buffer) abort
- let l:executable = ale_linters#ruby#ruby#GetExecutable(a:buffer)
-
- return ale#Escape(l:executable) . ' -w -c -T1 %t'
-endfunction
-
call ale#linter#Define('ruby', {
\ 'name': 'ruby',
-\ 'executable_callback': 'ale_linters#ruby#ruby#GetExecutable',
-\ 'command_callback': 'ale_linters#ruby#ruby#GetCommand',
+\ 'executable_callback': ale#VarFunc('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
new file mode 100644
index 00000000..5ff0a759
--- /dev/null
+++ b/ale_linters/ruby/solargraph.vim
@@ -0,0 +1,22 @@
+" Author: Horacio Sanson - https://github.com/hsanson
+" Description: Solargraph Language Server https://solargraph.org/
+"
+" Author: Devon Meunier <devon.meunier@gmail.com>
+" Description: updated to use stdio
+
+call ale#Set('ruby_solargraph_executable', 'solargraph')
+call ale#Set('ruby_solargraph_options', {})
+
+function! ale_linters#ruby#solargraph#GetCommand(buffer) abort
+ return '%e' . ale#Pad('stdio')
+endfunction
+
+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'),
+\})
diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim
index e6c3870a..cf6187f8 100644
--- a/ale_linters/rust/cargo.vim
+++ b/ale_linters/rust/cargo.vim
@@ -9,6 +9,8 @@ call ale#Set('rust_cargo_check_tests', 0)
call ale#Set('rust_cargo_avoid_whole_workspace', 1)
call ale#Set('rust_cargo_default_feature_behavior', 'default')
call ale#Set('rust_cargo_include_features', '')
+call ale#Set('rust_cargo_use_clippy', 0)
+call ale#Set('rust_cargo_clippy_options', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
@@ -42,6 +44,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
\ && ale#semver#GTE(l:version, [0, 22, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
+
if !empty(l:include_features)
let l:include_features = ' --features ' . ale#Escape(l:include_features)
endif
@@ -59,6 +62,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
endif
let l:default_feature_behavior = ale#Var(a:buffer, 'rust_cargo_default_feature_behavior')
+
if l:default_feature_behavior is# 'all'
let l:include_features = ''
let l:default_feature = ' --all-features'
@@ -68,14 +72,23 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
let l:default_feature = ''
endif
+ let l:subcommand = l:use_check ? 'check' : 'build'
+ let l:clippy_options = ''
+
+ if ale#Var(a:buffer, 'rust_cargo_use_clippy')
+ let l:subcommand = 'clippy'
+ let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options')
+ endif
+
return l:nearest_cargo_prefix . 'cargo '
- \ . (l:use_check ? 'check' : 'build')
+ \ . l:subcommand
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features
+ \ . l:clippy_options
endfunction
call ale#linter#Define('rust', {
diff --git a/ale_linters/rust/rls.vim b/ale_linters/rust/rls.vim
index cd13291d..60dd3667 100644
--- a/ale_linters/rust/rls.vim
+++ b/ale_linters/rust/rls.vim
@@ -4,19 +4,10 @@
call ale#Set('rust_rls_executable', 'rls')
call ale#Set('rust_rls_toolchain', 'nightly')
-function! ale_linters#rust#rls#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'rust_rls_executable')
-endfunction
-
function! ale_linters#rust#rls#GetCommand(buffer) abort
- let l:executable = ale_linters#rust#rls#GetExecutable(a:buffer)
let l:toolchain = ale#Var(a:buffer, 'rust_rls_toolchain')
- if empty(l:toolchain)
- return ale#Escape(l:executable)
- else
- return ale#Escape(l:executable) . ' +' . ale#Escape(l:toolchain)
- endif
+ return '%e' . (!empty(l:toolchain) ? ' +' . ale#Escape(l:toolchain) : '')
endfunction
function! ale_linters#rust#rls#GetProjectRoot(buffer) abort
@@ -28,7 +19,7 @@ endfunction
call ale#linter#Define('rust', {
\ 'name': 'rls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#rust#rls#GetExecutable',
+\ 'executable_callback': ale#VarFunc('rust_rls_executable'),
\ 'command_callback': 'ale_linters#rust#rls#GetCommand',
\ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot',
\})
diff --git a/ale_linters/rust/rustc.vim b/ale_linters/rust/rustc.vim
index 3cd401b3..33fb72f4 100644
--- a/ale_linters/rust/rustc.vim
+++ b/ale_linters/rust/rustc.vim
@@ -1,7 +1,7 @@
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>
" Description: rustc for rust files
-call ale#Set('rust_rustc_options', '-Z no-trans')
+call ale#Set('rust_rustc_options', '-Z no-codegen')
function! ale_linters#rust#rustc#RustcCommand(buffer) abort
" Try to guess the library search path. If the project is managed by cargo,
diff --git a/ale_linters/sass/stylelint.vim b/ale_linters/sass/stylelint.vim
index fe941d6a..b6286f18 100644
--- a/ale_linters/sass/stylelint.vim
+++ b/ale_linters/sass/stylelint.vim
@@ -3,20 +3,11 @@
call ale#Set('sass_stylelint_executable', 'stylelint')
call ale#Set('sass_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#sass#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'sass_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
-function! ale_linters#sass#stylelint#GetCommand(buffer) abort
- return ale_linters#sass#stylelint#GetExecutable(a:buffer)
- \ . ' --stdin-filename %s'
-endfunction
-
call ale#linter#Define('sass', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#sass#stylelint#GetExecutable',
-\ 'command_callback': 'ale_linters#sass#stylelint#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('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 17b26f0b..fbdce20e 100644
--- a/ale_linters/scala/fsc.vim
+++ b/ale_linters/scala/fsc.vim
@@ -1,29 +1,14 @@
" Author: Nils Leuzinger - https://github.com/PawkyPenguin
" Description: Basic scala support using fsc
-"
-function! ale_linters#scala#fsc#GetExecutable(buffer) abort
- if index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
- " Don't check sbt files
- return ''
- endif
- return 'fsc'
-endfunction
-
-function! ale_linters#scala#fsc#GetCommand(buffer) abort
- let l:executable = ale_linters#scala#fsc#GetExecutable(a:buffer)
-
- if empty(l:executable)
- return ''
- endif
-
- return ale#Escape(l:executable) . ' -Ystop-after:parser %t'
+function! s:IsSbt(buffer) abort
+ return index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
endfunction
call ale#linter#Define('scala', {
\ 'name': 'fsc',
-\ 'executable_callback': 'ale_linters#scala#fsc#GetExecutable',
-\ 'command_callback': 'ale_linters#scala#fsc#GetCommand',
+\ 'executable_callback': {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
new file mode 100644
index 00000000..694241d7
--- /dev/null
+++ b/ale_linters/scala/sbtserver.vim
@@ -0,0 +1,31 @@
+" Author: ophirr33 <coghlan.ty@gmail.com>
+" Description: TCP lsp client for sbt Server
+
+call ale#Set('scala_sbtserver_address', '127.0.0.1:4273')
+call ale#Set('scala_sbtserver_project_root', '')
+
+function! ale_linters#scala#sbtserver#GetProjectRoot(buffer) abort
+ let l:project_root = ale#Var(a:buffer, 'scala_sbtserver_project_root')
+
+ if l:project_root is? ''
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'build.sbt')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+ endif
+
+ return l:project_root
+endfunction
+
+function! ale_linters#scala#sbtserver#GetAddress(buffer) abort
+ let l:address = ale#Var(a:buffer, 'scala_sbtserver_address')
+
+ return l:address
+endfunction
+
+call ale#linter#Define('scala', {
+\ 'name': 'sbtserver',
+\ 'lsp': 'socket',
+\ 'address_callback': 'ale_linters#scala#sbtserver#GetAddress',
+\ 'language': 'scala',
+\ 'project_root_callback': 'ale_linters#scala#sbtserver#GetProjectRoot',
+\})
diff --git a/ale_linters/scala/scalac.vim b/ale_linters/scala/scalac.vim
index 551284af..ba105927 100644
--- a/ale_linters/scala/scalac.vim
+++ b/ale_linters/scala/scalac.vim
@@ -2,29 +2,14 @@
" w0rp <devw0rp@gmail.com>
" Description: Basic scala support using scalac
-function! ale_linters#scala#scalac#GetExecutable(buffer) abort
- if index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
- " Don't check sbt files
- return ''
- endif
-
- return 'scalac'
-endfunction
-
-function! ale_linters#scala#scalac#GetCommand(buffer) abort
- let l:executable = ale_linters#scala#scalac#GetExecutable(a:buffer)
-
- if empty(l:executable)
- return ''
- endif
-
- return ale#Escape(l:executable) . ' -Ystop-after:parser %t'
+function! s:IsSbt(buffer) abort
+ return index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
endfunction
call ale#linter#Define('scala', {
\ 'name': 'scalac',
-\ 'executable_callback': 'ale_linters#scala#scalac#GetExecutable',
-\ 'command_callback': 'ale_linters#scala#scalac#GetCommand',
+\ 'executable_callback': {buf -> s:IsSbt(buf) ? '' : 'scalac'},
+\ 'command': '%e -Ystop-before:jvm %t',
\ 'callback': 'ale#handlers#scala#HandleScalacLintFormat',
\ 'output_stream': 'stderr',
\})
diff --git a/ale_linters/scala/scalastyle.vim b/ale_linters/scala/scalastyle.vim
index 3232d70b..42228cf6 100644
--- a/ale_linters/scala/scalastyle.vim
+++ b/ale_linters/scala/scalastyle.vim
@@ -53,12 +53,14 @@ function! ale_linters#scala#scalastyle#GetCommand(buffer) abort
\ 'scalastyle_config.xml',
\ 'scalastyle-config.xml'
\]
+
for l:config in l:potential_configs
let l:scalastyle_config = ale#path#ResolveLocalPath(
\ a:buffer,
\ l:config,
\ ''
\)
+
if !empty(l:scalastyle_config)
break
endif
diff --git a/ale_linters/scss/stylelint.vim b/ale_linters/scss/stylelint.vim
index 6bfdd09a..2bffa8e1 100644
--- a/ale_linters/scss/stylelint.vim
+++ b/ale_linters/scss/stylelint.vim
@@ -1,22 +1,19 @@
" Author: diartyz <diartyz@gmail.com>
call ale#Set('scss_stylelint_executable', 'stylelint')
+call ale#Set('scss_stylelint_options', '')
call ale#Set('scss_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#scss#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'scss_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#scss#stylelint#GetCommand(buffer) abort
- return ale_linters#scss#stylelint#GetExecutable(a:buffer)
+ return '%e ' . ale#Pad(ale#Var(a:buffer, 'scss_stylelint_options'))
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('scss', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#scss#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('scss_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': 'ale_linters#scss#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim
index 27c74531..0f68e62c 100644
--- a/ale_linters/sh/shellcheck.vim
+++ b/ale_linters/sh/shellcheck.vim
@@ -6,14 +6,9 @@
" codes to exclude from shellcheck. For example:
"
" let g:ale_sh_shellcheck_exclusions = 'SC2002,SC2004'
-let g:ale_sh_shellcheck_exclusions =
-\ get(g:, 'ale_sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_exclusions', ''))
-
-let g:ale_sh_shellcheck_executable =
-\ get(g:, 'ale_sh_shellcheck_executable', 'shellcheck')
-
-let g:ale_sh_shellcheck_options =
-\ get(g:, 'ale_sh_shellcheck_options', '')
+call ale#Set('sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_exclusions', ''))
+call ale#Set('sh_shellcheck_executable', 'shellcheck')
+call ale#Set('sh_shellcheck_options', '')
function! ale_linters#sh#shellcheck#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'sh_shellcheck_executable')
diff --git a/ale_linters/sml/smlnj_cm.vim b/ale_linters/sml/smlnj_cm.vim
index 7a482307..bfa4bc05 100644
--- a/ale_linters/sml/smlnj_cm.vim
+++ b/ale_linters/sml/smlnj_cm.vim
@@ -3,6 +3,7 @@
function! ale_linters#sml#smlnj_cm#GetCommand(buffer) abort
let l:cmfile = ale#handlers#sml#GetCmFile(a:buffer)
+
return 'sml -m ' . l:cmfile . ' < /dev/null'
endfunction
diff --git a/ale_linters/solidity/solhint.vim b/ale_linters/solidity/solhint.vim
index 519fd49d..8ea33e07 100644
--- a/ale_linters/solidity/solhint.vim
+++ b/ale_linters/solidity/solhint.vim
@@ -4,7 +4,6 @@
function! ale_linters#solidity#solhint#Handle(buffer, lines) abort
" Matches patterns like the following:
" /path/to/file/file.sol: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)
-
let l:pattern = '\v^[^:]+: line (\d+), col (\d+), (Error|Warning) - (.*) \((.*)\)$'
let l:output = []
diff --git a/ale_linters/spec/rpmlint.vim b/ale_linters/spec/rpmlint.vim
index f5308af6..486bef1e 100644
--- a/ale_linters/spec/rpmlint.vim
+++ b/ale_linters/spec/rpmlint.vim
@@ -26,19 +26,12 @@
" And this is always output at the end and should just be ignored:
" 0 packages and 1 specfiles checked; 4 errors, 0 warnings.
-let g:ale_spec_rpmlint_executable =
-\ get(g:, 'ale_spec_rpmlint_executable', 'rpmlint')
-
-let g:ale_spec_rpmlint_options =
-\ get(g:, 'ale_spec_rpmlint_options', '')
-
-function! ale_linters#spec#rpmlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'spec_rpmlint_executable')
-endfunction
+call ale#Set('spec_rpmlint_executable', 'rpmlint')
+call ale#Set('spec_rpmlint_options', '')
function! ale_linters#spec#rpmlint#GetCommand(buffer) abort
- return ale_linters#spec#rpmlint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'spec_rpmlint_options')
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'spec_rpmlint_options'))
\ . ' -o "NetworkEnabled False"'
\ . ' -v'
\ . ' %t'
@@ -79,7 +72,7 @@ endfunction
call ale#linter#Define('spec', {
\ 'name': 'rpmlint',
-\ 'executable_callback': 'ale_linters#spec#rpmlint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('spec_rpmlint_executable'),
\ 'command_callback': '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 1562692a..2256f3c0 100644
--- a/ale_linters/stylus/stylelint.vim
+++ b/ale_linters/stylus/stylelint.vim
@@ -4,21 +4,17 @@ call ale#Set('stylus_stylelint_executable', 'stylelint')
call ale#Set('stylus_stylelint_options', '')
call ale#Set('stylus_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#stylus#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'stylus_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#stylus#stylelint#GetCommand(buffer) abort
- return ale_linters#stylus#stylelint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'stylus_stylelint_options')
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'stylus_stylelint_options'))
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('stylus', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#stylus#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('stylus_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': 'ale_linters#stylus#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/tcl/nagelfar.vim b/ale_linters/tcl/nagelfar.vim
index 13b7a549..05fe581b 100644
--- a/ale_linters/tcl/nagelfar.vim
+++ b/ale_linters/tcl/nagelfar.vim
@@ -4,16 +4,10 @@
call ale#Set('tcl_nagelfar_executable', 'nagelfar.tcl')
call ale#Set('tcl_nagelfar_options', '')
-function! ale_linters#tcl#nagelfar#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'tcl_nagelfar_executable')
-endfunction
-
function! ale_linters#tcl#nagelfar#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'tcl_nagelfar_options')
- return ale#Escape(ale_linters#tcl#nagelfar#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' %s'
+ return '%e' . ale#Pad(l:options) . ' %s'
endfunction
function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort
@@ -21,7 +15,6 @@ function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort
" Line 5: W Found constant "bepa" which is also a variable.
" Line 13: E Wrong number of arguments (3) to "set"
" Line 93: N Close brace not aligned with line 90 (4 0)
-
let l:pattern = '^Line\s\+\([0-9]\+\): \([NEW]\) \(.*\)$'
let l:output = []
@@ -39,7 +32,7 @@ endfunction
call ale#linter#Define('tcl', {
\ 'name': 'nagelfar',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#tcl#nagelfar#GetExecutable',
+\ 'executable_callback': ale#VarFunc('tcl_nagelfar_executable'),
\ 'command_callback': '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 93966ff3..0d77835a 100644
--- a/ale_linters/terraform/tflint.vim
+++ b/ale_linters/terraform/tflint.vim
@@ -30,19 +30,17 @@ function! ale_linters#terraform#tflint#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#terraform#tflint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'terraform_tflint_executable')
-endfunction
-
function! ale_linters#terraform#tflint#GetCommand(buffer) abort
- let l:cmd = ale#Escape(ale#Var(a:buffer, 'terraform_tflint_executable'))
+ let l:cmd = '%e'
let l:config_file = ale#path#FindNearestFile(a:buffer, '.tflint.hcl')
+
if !empty(l:config_file)
let l:cmd .= ' --config ' . ale#Escape(l:config_file)
endif
let l:opts = ale#Var(a:buffer, 'terraform_tflint_options')
+
if !empty(l:opts)
let l:cmd .= ' ' . l:opts
endif
@@ -54,9 +52,7 @@ endfunction
call ale#linter#Define('terraform', {
\ 'name': 'tflint',
-\ 'executable_callback': 'ale_linters#terraform#tflint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('terraform_tflint_executable'),
\ 'command_callback': 'ale_linters#terraform#tflint#GetCommand',
\ 'callback': 'ale_linters#terraform#tflint#Handle',
\})
-
-" vim:sw=4
diff --git a/ale_linters/tex/lacheck.vim b/ale_linters/tex/lacheck.vim
index e5a9632b..5e5a94f1 100644
--- a/ale_linters/tex/lacheck.vim
+++ b/ale_linters/tex/lacheck.vim
@@ -1,23 +1,13 @@
" Author: Andrew Balmos - <andrew@balmos.org>
" Description: lacheck for LaTeX files
-let g:ale_tex_lacheck_executable =
-\ get(g:, 'ale_tex_lacheck_executable', 'lacheck')
-
-function! ale_linters#tex#lacheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'tex_lacheck_executable')
-endfunction
-
-function! ale_linters#tex#lacheck#GetCommand(buffer) abort
- return ale#Var(a:buffer, 'tex_lacheck_executable') . ' %t'
-endfunction
+call ale#Set('tex_lacheck_executable', 'lacheck')
function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
" Mattes lines like:
"
" "book.tex", line 37: possible unwanted space at "{"
" "book.tex", line 38: missing `\ ' after "etc."
-
let l:pattern = '^".\+", line \(\d\+\): \(.\+\)$'
let l:output = []
@@ -41,7 +31,7 @@ endfunction
call ale#linter#Define('tex', {
\ 'name': 'lacheck',
-\ 'executable_callback': 'ale_linters#tex#lacheck#GetExecutable',
-\ 'command_callback': 'ale_linters#tex#lacheck#GetCommand',
+\ 'executable_callback': ale#VarFunc('tex_lacheck_executable'),
+\ 'command': '%e %t',
\ 'callback': 'ale_linters#tex#lacheck#Handle'
\})
diff --git a/ale_linters/thrift/thrift.vim b/ale_linters/thrift/thrift.vim
index a8fe10b6..36a8656e 100644
--- a/ale_linters/thrift/thrift.vim
+++ b/ale_linters/thrift/thrift.vim
@@ -2,13 +2,9 @@
call ale#Set('thrift_thrift_executable', 'thrift')
call ale#Set('thrift_thrift_generators', ['cpp'])
-call ale#Set('thrift_thrift_includes', [])
+call ale#Set('thrift_thrift_includes', ['.'])
call ale#Set('thrift_thrift_options', '-strict')
-function! ale_linters#thrift#thrift#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'thrift_thrift_executable')
-endfunction
-
function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:generators = ale#Var(a:buffer, 'thrift_thrift_generators')
let l:includes = ale#Var(a:buffer, 'thrift_thrift_includes')
@@ -22,7 +18,7 @@ function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:output_dir = ale#engine#CreateDirectory(a:buffer)
- return ale#Escape(ale_linters#thrift#thrift#GetExecutable(a:buffer))
+ return '%e'
\ . ale#Pad(join(map(copy(l:generators), "'--gen ' . v:val")))
\ . ale#Pad(join(map(copy(l:includes), "'-I ' . v:val")))
\ . ale#Pad(ale#Var(a:buffer, 'thrift_thrift_options'))
@@ -46,12 +42,14 @@ function! ale_linters#thrift#thrift#Handle(buffer, lines) abort
let l:line = a:lines[l:index]
let l:match = matchlist(l:line, l:pattern)
+
if empty(l:match)
let l:index += 1
continue
endif
let l:severity = l:match[1]
+
if l:severity is# 'WARNING'
let l:type = 'W'
else
@@ -61,6 +59,7 @@ function! ale_linters#thrift#thrift#Handle(buffer, lines) abort
" If our text looks like "(last token was ';')", the *next* line
" should contain a more descriptive error message.
let l:text = l:match[4]
+
if l:text =~# '\(last token was .*\)'
let l:index += 1
let l:text = get(a:lines, l:index, 'Unknown error ' . l:text)
@@ -83,7 +82,7 @@ call ale#linter#Define('thrift', {
\ 'name': 'thrift',
\ 'executable': 'thrift',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale_linters#thrift#thrift#GetExecutable',
+\ 'executable_callback': ale#VarFunc('thrift_thrift_executable'),
\ 'command_callback': 'ale_linters#thrift#thrift#GetCommand',
\ 'callback': 'ale_linters#thrift#thrift#Handle',
\})
diff --git a/ale_linters/typescript/tsserver.vim b/ale_linters/typescript/tsserver.vim
index 08bd0f41..bac63229 100644
--- a/ale_linters/typescript/tsserver.vim
+++ b/ale_linters/typescript/tsserver.vim
@@ -5,22 +5,13 @@ call ale#Set('typescript_tsserver_executable', 'tsserver')
call ale#Set('typescript_tsserver_config_path', '')
call ale#Set('typescript_tsserver_use_global', get(g:, 'ale_use_global_executables', 0))
-" These functions need to be defined just to comply with the API for LSP.
-function! ale_linters#typescript#tsserver#GetProjectRoot(buffer) abort
- return ''
-endfunction
-
-function! ale_linters#typescript#tsserver#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'typescript_tsserver', [
- \ 'node_modules/.bin/tsserver',
- \])
-endfunction
-
call ale#linter#Define('typescript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
-\ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable',
-\ 'command_callback': 'ale_linters#typescript#tsserver#GetExecutable',
-\ 'project_root_callback': 'ale_linters#typescript#tsserver#GetProjectRoot',
+\ 'executable_callback': ale#node#FindExecutableFunc('typescript_tsserver', [
+\ 'node_modules/.bin/tsserver',
+\ ]),
+\ 'command': '%e',
+\ 'project_root_callback': {-> ''},
\ 'language': '',
\})
diff --git a/ale_linters/vim/ale_custom_linting_rules.vim b/ale_linters/vim/ale_custom_linting_rules.vim
new file mode 100644
index 00000000..3da44206
--- /dev/null
+++ b/ale_linters/vim/ale_custom_linting_rules.vim
@@ -0,0 +1,65 @@
+" Author: w0rp <devw0rp@gmail.com>
+" Description: A linter for checking ALE project code itself.
+
+function! ale_linters#vim#ale_custom_linting_rules#GetExecutable(buffer) abort
+ let l:filename = expand('#' . a:buffer . ':p')
+ let l:dir_list = []
+
+ for l:dir in split(&runtimepath, ',')
+ if l:filename[:len(l:dir) - 1] is# l:dir
+ call add(l:dir_list, l:dir)
+ endif
+ endfor
+
+ return !empty(l:dir_list)
+ \ ? findfile('test/script/custom-linting-rules', join(l:dir_list, ','))
+ \ : ''
+endfunction
+
+function! s:GetALEProjectDir(buffer) abort
+ let l:executable = ale_linters#vim#ale_custom_linting_rules#GetExecutable(a:buffer)
+
+ return ale#path#Dirname(ale#path#Dirname(ale#path#Dirname(l:executable)))
+endfunction
+
+function! ale_linters#vim#ale_custom_linting_rules#GetCommand(buffer) abort
+ let l:dir = s:GetALEProjectDir(a:buffer)
+
+ let l:temp_dir = ale#engine#CreateDirectory(a:buffer)
+ let l:temp_file = l:temp_dir . '/example.vim'
+
+ let l:lines = getbufline(a:buffer, 1, '$')
+ call ale#util#Writefile(a:buffer, l:lines, l:temp_file)
+
+ return ale#path#CdString(l:dir) . '%e ' . ale#Escape(l:temp_dir)
+endfunction
+
+function! ale_linters#vim#ale_custom_linting_rules#Handle(buffer, lines) abort
+ let l:dir = s:GetALEProjectDir(a:buffer)
+ let l:output = []
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+) (.+)$'
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ " Ignore trailing whitespace errors if we've turned them off.
+ if !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
+ \&& l:match[3] is# 'Trailing whitespace'
+ continue
+ endif
+
+ call add(l:output, {
+ \ 'lnum': l:match[2],
+ \ 'text': l:match[3],
+ \ 'type': 'W',
+ \})
+ endfor
+
+ return l:output
+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',
+\ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle',
+\ 'read_buffer': 0,
+\})
diff --git a/ale_linters/vue/vls.vim b/ale_linters/vue/vls.vim
index 0d4bf9f6..7116128b 100644
--- a/ale_linters/vue/vls.vim
+++ b/ale_linters/vue/vls.vim
@@ -4,18 +4,6 @@
call ale#Set('vue_vls_executable', 'vls')
call ale#Set('vue_vls_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#vue#vls#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'vue_vls', [
- \ 'node_modules/.bin/vls',
- \])
-endfunction
-
-function! ale_linters#vue#vls#GetCommand(buffer) abort
- let l:exe = ale#Escape(ale_linters#vue#vls#GetExecutable(a:buffer))
-
- return l:exe . ' --stdio'
-endfunction
-
function! ale_linters#vue#vls#GetProjectRoot(buffer) abort
let l:package_path = ale#path#FindNearestFile(a:buffer, 'package.json')
@@ -25,8 +13,10 @@ endfunction
call ale#linter#Define('vue', {
\ 'name': 'vls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#vue#vls#GetExecutable',
-\ 'command_callback': 'ale_linters#vue#vls#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('vue_vls', [
+\ 'node_modules/.bin/vls',
+\ ]),
+\ 'command': '%e --stdio',
\ 'language': 'vue',
\ 'project_root_callback': 'ale_linters#vue#vls#GetProjectRoot',
\})
diff --git a/ale_linters/xml/xmllint.vim b/ale_linters/xml/xmllint.vim
index 9d79438e..59f43d16 100644
--- a/ale_linters/xml/xmllint.vim
+++ b/ale_linters/xml/xmllint.vim
@@ -5,12 +5,8 @@
let g:ale_xml_xmllint_executable = get(g:, 'ale_xml_xmllint_executable', 'xmllint')
let g:ale_xml_xmllint_options = get(g:, 'ale_xml_xmllint_options', '')
-function! ale_linters#xml#xmllint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'xml_xmllint_executable')
-endfunction
-
function! ale_linters#xml#xmllint#GetCommand(buffer) abort
- return ale#Escape(ale_linters#xml#xmllint#GetExecutable(a:buffer))
+ return '%e'
\ . ale#Pad(ale#Var(a:buffer, 'xml_xmllint_options'))
\ . ' --noout -'
endfunction
@@ -29,9 +25,9 @@ function! ale_linters#xml#xmllint#Handle(buffer, lines) abort
let l:output = []
for l:line in a:lines
-
" Parse error/warning lines
let l:match_message = matchlist(l:line, l:pattern_message)
+
if !empty(l:match_message)
let l:line = l:match_message[2] + 0
let l:type = l:match_message[4] =~? 'warning' ? 'W' : 'E'
@@ -48,13 +44,13 @@ function! ale_linters#xml#xmllint#Handle(buffer, lines) abort
" Parse column position
let l:match_column_token = matchlist(l:line, l:pattern_column_token)
+
if !empty(l:output) && !empty(l:match_column_token)
let l:previous = l:output[len(l:output) - 1]
let l:previous['col'] = len(l:match_column_token[0])
continue
endif
-
endfor
return l:output
@@ -63,7 +59,7 @@ endfunction
call ale#linter#Define('xml', {
\ 'name': 'xmllint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#xml#xmllint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('xml_xmllint_executable'),
\ 'command_callback': '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 4a22c70f..7362536e 100644
--- a/ale_linters/yaml/swaglint.vim
+++ b/ale_linters/yaml/swaglint.vim
@@ -4,17 +4,6 @@
call ale#Set('yaml_swaglint_executable', 'swaglint')
call ale#Set('yaml_swaglint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#yaml#swaglint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'yaml_swaglint', [
- \ 'node_modules/.bin/swaglint',
- \])
-endfunction
-
-function! ale_linters#yaml#swaglint#GetCommand(buffer) abort
- return ale_linters#yaml#swaglint#GetExecutable(a:buffer)
- \ . ' -r compact --stdin'
-endfunction
-
function! ale_linters#yaml#swaglint#Handle(buffer, lines) abort
let l:pattern = ': \([^\s]\+\) @ \(\d\+\):\(\d\+\) - \(.\+\)$'
let l:output = []
@@ -43,7 +32,9 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'swaglint',
-\ 'executable_callback': 'ale_linters#yaml#swaglint#GetExecutable',
-\ 'command_callback': 'ale_linters#yaml#swaglint#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('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 f100667e..9d2cc7c2 100644
--- a/ale_linters/yaml/yamllint.vim
+++ b/ale_linters/yaml/yamllint.vim
@@ -1,18 +1,10 @@
" Author: KabbAmine <amine.kabb@gmail.com>
-let g:ale_yaml_yamllint_executable =
-\ get(g:, 'ale_yaml_yamllint_executable', 'yamllint')
-
-let g:ale_yaml_yamllint_options =
-\ get(g:, 'ale_yaml_yamllint_options', '')
-
-function! ale_linters#yaml#yamllint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'yaml_yamllint_executable')
-endfunction
+call ale#Set('yaml_yamllint_executable', 'yamllint')
+call ale#Set('yaml_yamllint_options', '')
function! ale_linters#yaml#yamllint#GetCommand(buffer) abort
- return ale_linters#yaml#yamllint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'yaml_yamllint_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'yaml_yamllint_options'))
\ . ' -f parsable %t'
endfunction
@@ -52,7 +44,7 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'yamllint',
-\ 'executable_callback': 'ale_linters#yaml#yamllint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('yaml_yamllint_executable'),
\ 'command_callback': '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
new file mode 100644
index 00000000..45776f98
--- /dev/null
+++ b/ale_linters/yang/yang_lsp.vim
@@ -0,0 +1,15 @@
+call ale#Set('yang_lsp_executable', 'yang-language-server')
+
+function! ale_linters#yang#yang_lsp#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'yang.settings')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+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',
+\ 'command': '%e',
+\})