summaryrefslogtreecommitdiff
path: root/ale_linters
diff options
context:
space:
mode:
Diffstat (limited to 'ale_linters')
-rw-r--r--ale_linters/bats/shellcheck.vim4
-rw-r--r--ale_linters/c/ccls.vim3
-rw-r--r--ale_linters/c/clangd.vim7
-rw-r--r--ale_linters/c/clangtidy.vim13
-rw-r--r--ale_linters/c/cppcheck.vim2
-rw-r--r--ale_linters/clojure/clj_kondo.vim2
-rw-r--r--ale_linters/cpp/ccls.vim3
-rw-r--r--ale_linters/cpp/clangcheck.vim2
-rw-r--r--ale_linters/cpp/clangd.vim7
-rw-r--r--ale_linters/cpp/clangtidy.vim18
-rw-r--r--ale_linters/cpp/cppcheck.vim2
-rw-r--r--ale_linters/crystal/crystal.vim4
-rw-r--r--ale_linters/dockerfile/dockerfile_lint.vim17
-rw-r--r--ale_linters/elm/elm_ls.vim11
-rw-r--r--ale_linters/erlang/dialyzer.vim4
-rw-r--r--ale_linters/eruby/ruumba.vim2
-rw-r--r--ale_linters/go/revive.vim21
-rw-r--r--ale_linters/graphql/eslint.vim2
-rw-r--r--ale_linters/ink/ls.vim35
-rw-r--r--ale_linters/java/checkstyle.vim2
-rw-r--r--ale_linters/java/eclipselsp.vim48
-rw-r--r--ale_linters/java/javac.vim35
-rw-r--r--[-rwxr-xr-x]ale_linters/javascript/flow.vim0
-rw-r--r--ale_linters/javascript/standard.vim2
-rw-r--r--ale_linters/kotlin/kotlinc.vim1
-rw-r--r--ale_linters/kotlin/ktlint.vim2
-rw-r--r--[-rwxr-xr-x]ale_linters/less/lessc.vim0
-rw-r--r--ale_linters/markdown/markdownlint.vim13
-rw-r--r--ale_linters/markdown/mdl.vim11
-rw-r--r--ale_linters/nim/nimcheck.vim14
-rw-r--r--ale_linters/nim/nimlsp.vim33
-rw-r--r--ale_linters/objc/ccls.vim3
-rw-r--r--ale_linters/php/psalm.vim11
-rw-r--r--[-rwxr-xr-x]ale_linters/powershell/powershell.vim1
-rw-r--r--ale_linters/puppet/puppet.vim8
-rw-r--r--ale_linters/python/mypy.vim23
-rw-r--r--ale_linters/python/pyright.vim43
-rw-r--r--ale_linters/ruby/brakeman.vim2
-rw-r--r--ale_linters/ruby/debride.vim42
-rw-r--r--ale_linters/ruby/rails_best_practices.vim2
-rw-r--r--ale_linters/ruby/reek.vim2
-rw-r--r--ale_linters/ruby/rubocop.vim2
-rw-r--r--ale_linters/ruby/sorbet.vim2
-rw-r--r--ale_linters/ruby/standardrb.vim2
-rw-r--r--ale_linters/rust/analyzer.vim24
-rw-r--r--ale_linters/rust/cargo.vim5
-rw-r--r--ale_linters/scala/metals.vim50
-rw-r--r--ale_linters/sh/bashate.vim43
-rw-r--r--ale_linters/sh/shell.vim6
-rw-r--r--ale_linters/sh/shellcheck.vim107
-rw-r--r--ale_linters/solidity/solc.vim35
-rw-r--r--[-rwxr-xr-x]ale_linters/terraform/terraform.vim0
-rw-r--r--ale_linters/terraform/terraform_lsp.vim25
-rw-r--r--ale_linters/terraform/tflint.vim78
-rw-r--r--ale_linters/typescript/standard.vim31
-rw-r--r--ale_linters/verilog/hdl_checker.vim5
-rw-r--r--ale_linters/verilog/verilator.vim27
-rw-r--r--ale_linters/verilog/vlog.vim22
-rw-r--r--ale_linters/vhdl/hdl_checker.vim5
-rw-r--r--ale_linters/vim/vimls.vim61
-rw-r--r--ale_linters/zig/zls.vim20
61 files changed, 812 insertions, 195 deletions
diff --git a/ale_linters/bats/shellcheck.vim b/ale_linters/bats/shellcheck.vim
new file mode 100644
index 00000000..5c2a0ea9
--- /dev/null
+++ b/ale_linters/bats/shellcheck.vim
@@ -0,0 +1,4 @@
+" Author: Ian2020 <https://github.com/Ian2020>
+" Description: shellcheck linter for bats scripts.
+
+call ale#handlers#shellcheck#DefineLinter('bats')
diff --git a/ale_linters/c/ccls.vim b/ale_linters/c/ccls.vim
index 9e3dafe9..9f105712 100644
--- a/ale_linters/c/ccls.vim
+++ b/ale_linters/c/ccls.vim
@@ -3,6 +3,7 @@
call ale#Set('c_ccls_executable', 'ccls')
call ale#Set('c_ccls_init_options', {})
+call ale#Set('c_build_dir', '')
call ale#linter#Define('c', {
\ 'name': 'ccls',
@@ -10,5 +11,5 @@ call ale#linter#Define('c', {
\ 'executable': {b -> ale#Var(b, 'c_ccls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
-\ 'initialization_options': {b -> ale#Var(b, 'c_ccls_init_options')},
+\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'c_ccls_init_options')},
\})
diff --git a/ale_linters/c/clangd.vim b/ale_linters/c/clangd.vim
index 79b600fa..c42d4497 100644
--- a/ale_linters/c/clangd.vim
+++ b/ale_linters/c/clangd.vim
@@ -3,9 +3,14 @@
call ale#Set('c_clangd_executable', 'clangd')
call ale#Set('c_clangd_options', '')
+call ale#Set('c_build_dir', '')
function! ale_linters#c#clangd#GetCommand(buffer) abort
- return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
+
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
+ \ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '')
endfunction
call ale#linter#Define('c', {
diff --git a/ale_linters/c/clangtidy.vim b/ale_linters/c/clangtidy.vim
index f998866a..553cc23b 100644
--- a/ale_linters/c/clangtidy.vim
+++ b/ale_linters/c/clangtidy.vim
@@ -19,14 +19,17 @@ call ale#Set('c_clangtidy_options', '')
call ale#Set('c_clangtidy_extra_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#c#clangtidy#GetCommand(buffer) abort
+function! ale_linters#c#clangtidy#GetCommand(buffer, output) abort
let l:checks = join(ale#Var(a:buffer, 'c_clangtidy_checks'), ',')
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
+ let l:options = ''
" 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')
- \ : ''
+ if empty(l:build_dir)
+ let l:options = ale#Var(a:buffer, 'c_clangtidy_options')
+ let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
+ let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
+ endif
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'c_clangtidy_extra_options')
@@ -43,7 +46,7 @@ call ale#linter#Define('c', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
\ 'executable': {b -> ale#Var(b, 'c_clangtidy_executable')},
-\ 'command': function('ale_linters#c#clangtidy#GetCommand'),
+\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clangtidy#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/c/cppcheck.vim b/ale_linters/c/cppcheck.vim
index 309b2851..b671fc8b 100644
--- a/ale_linters/c/cppcheck.vim
+++ b/ale_linters/c/cppcheck.vim
@@ -10,9 +10,11 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : ''
+ let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
return l:cd_command
\ . '%e -q --language=c'
+ \ . l:template
\ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
\ . l:buffer_path_include
diff --git a/ale_linters/clojure/clj_kondo.vim b/ale_linters/clojure/clj_kondo.vim
index 5dd11c12..eb60ce77 100644
--- a/ale_linters/clojure/clj_kondo.vim
+++ b/ale_linters/clojure/clj_kondo.vim
@@ -29,6 +29,6 @@ call ale#linter#Define('clojure', {
\ 'name': 'clj-kondo',
\ 'output_stream': 'stdout',
\ 'executable': 'clj-kondo',
-\ 'command': 'clj-kondo --lint %t',
+\ 'command': 'clj-kondo --cache --lint %t',
\ 'callback': 'ale_linters#clojure#clj_kondo#HandleCljKondoFormat',
\})
diff --git a/ale_linters/cpp/ccls.vim b/ale_linters/cpp/ccls.vim
index b265ff70..38f8df9c 100644
--- a/ale_linters/cpp/ccls.vim
+++ b/ale_linters/cpp/ccls.vim
@@ -3,6 +3,7 @@
call ale#Set('cpp_ccls_executable', 'ccls')
call ale#Set('cpp_ccls_init_options', {})
+call ale#Set('c_build_dir', '')
call ale#linter#Define('cpp', {
\ 'name': 'ccls',
@@ -10,5 +11,5 @@ call ale#linter#Define('cpp', {
\ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
-\ 'initialization_options': {b -> ale#Var(b, 'cpp_ccls_init_options')},
+\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'cpp_ccls_init_options')},
\})
diff --git a/ale_linters/cpp/clangcheck.vim b/ale_linters/cpp/clangcheck.vim
index 7d32a57c..4cb04864 100644
--- a/ale_linters/cpp/clangcheck.vim
+++ b/ale_linters/cpp/clangcheck.vim
@@ -20,7 +20,7 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
" being generated. These are only added if no build directory can be
" detected.
return '%e -analyze %s'
- \ . (empty(l:build_dir) ? ' -extra-arg -Xclang -extra-arg -analyzer-output=text' : '')
+ \ . (empty(l:build_dir) ? ' --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics': '')
\ . ale#Pad(l:user_options)
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
endfunction
diff --git a/ale_linters/cpp/clangd.vim b/ale_linters/cpp/clangd.vim
index fab605f4..14f3fe55 100644
--- a/ale_linters/cpp/clangd.vim
+++ b/ale_linters/cpp/clangd.vim
@@ -3,9 +3,14 @@
call ale#Set('cpp_clangd_executable', 'clangd')
call ale#Set('cpp_clangd_options', '')
+call ale#Set('c_build_dir', '')
function! ale_linters#cpp#clangd#GetCommand(buffer) abort
- return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
+
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
+ \ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '')
endfunction
call ale#linter#Define('cpp', {
diff --git a/ale_linters/cpp/clangtidy.vim b/ale_linters/cpp/clangtidy.vim
index 085bc332..5e062d86 100644
--- a/ale_linters/cpp/clangtidy.vim
+++ b/ale_linters/cpp/clangtidy.vim
@@ -13,14 +13,22 @@ call ale#Set('cpp_clangtidy_options', '')
call ale#Set('cpp_clangtidy_extra_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
+function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',')
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
+ let l:options = ''
" 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')
- \ : ''
+ if empty(l:build_dir)
+ let l:options = ale#Var(a:buffer, 'cpp_clangtidy_options')
+ let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
+ let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags
+ endif
+
+ " Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file.
+ if expand('#' . a:buffer) =~# '\.h$'
+ let l:options .= !empty(l:options) ? ' -x c++' : '-x c++'
+ endif
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')
@@ -37,7 +45,7 @@ call ale#linter#Define('cpp', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
\ 'executable': {b -> ale#Var(b, 'cpp_clangtidy_executable')},
-\ 'command': function('ale_linters#cpp#clangtidy#GetCommand'),
+\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clangtidy#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/cpp/cppcheck.vim b/ale_linters/cpp/cppcheck.vim
index 7cd80dbc..2c832246 100644
--- a/ale_linters/cpp/cppcheck.vim
+++ b/ale_linters/cpp/cppcheck.vim
@@ -10,9 +10,11 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : ''
+ let l:template = ' --template=''{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}'''
return l:cd_command
\ . '%e -q --language=c++'
+ \ . l:template
\ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
\ . l:buffer_path_include
diff --git a/ale_linters/crystal/crystal.vim b/ale_linters/crystal/crystal.vim
index 3c2fefb7..8a905b12 100644
--- a/ale_linters/crystal/crystal.vim
+++ b/ale_linters/crystal/crystal.vim
@@ -5,6 +5,10 @@ function! ale_linters#crystal#crystal#Handle(buffer, lines) abort
let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
+ if !has_key(l:error, 'file')
+ continue
+ endif
+
call add(l:output, {
\ 'lnum': l:error.line + 0,
\ 'col': l:error.column + 0,
diff --git a/ale_linters/dockerfile/dockerfile_lint.vim b/ale_linters/dockerfile/dockerfile_lint.vim
index 95768b12..0c0ad533 100644
--- a/ale_linters/dockerfile/dockerfile_lint.vim
+++ b/ale_linters/dockerfile/dockerfile_lint.vim
@@ -32,14 +32,29 @@ function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
let l:line = get(l:object, 'line', -1)
let l:message = l:object['message']
+ let l:link = get(l:object, 'reference_url', '')
+
+ if type(l:link) == v:t_list
+ " Somehow, reference_url is returned as two-part list.
+ " Anchor markers in that list are sometimes duplicated.
+ " See https://github.com/projectatomic/dockerfile_lint/issues/134
+ let l:link = join(l:link, '')
+ let l:link = substitute(l:link, '##', '#', '')
+ endif
+
+ let l:detail = l:message
+
if get(l:object, 'description', 'None') isnot# 'None'
- let l:message = l:message . '. ' . l:object['description']
+ let l:detail .= "\n\n" . l:object['description']
endif
+ let l:detail .= "\n\n" . l:link
+
call add(l:messages, {
\ 'lnum': l:line,
\ 'text': l:message,
\ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
+ \ 'detail': l:detail,
\})
endfor
endfor
diff --git a/ale_linters/elm/elm_ls.vim b/ale_linters/elm/elm_ls.vim
index 374ef8de..2fa71adb 100644
--- a/ale_linters/elm/elm_ls.vim
+++ b/ale_linters/elm/elm_ls.vim
@@ -3,9 +3,12 @@
call ale#Set('elm_ls_executable', 'elm-language-server')
call ale#Set('elm_ls_use_global', get(g:, 'ale_use_global_executables', 1))
-call ale#Set('elm_ls_elm_path', 'elm')
-call ale#Set('elm_ls_elm_format_path', 'elm-format')
-call ale#Set('elm_ls_elm_test_path', 'elm-test')
+
+" elm-language-server will search for local and global binaries, if empty
+call ale#Set('elm_ls_elm_path', '')
+call ale#Set('elm_ls_elm_format_path', '')
+call ale#Set('elm_ls_elm_test_path', '')
+call ale#Set('elm_ls_elm_analyse_trigger', 'change')
function! elm_ls#GetRootDir(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
@@ -15,10 +18,10 @@ endfunction
function! elm_ls#GetOptions(buffer) abort
return {
- \ 'runtime': 'node',
\ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'),
\ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'),
\ 'elmTestPath': ale#Var(a:buffer, 'elm_ls_elm_test_path'),
+ \ 'elmAnalyseTrigger': ale#Var(a:buffer, 'elm_ls_elm_analyse_trigger'),
\}
endfunction
diff --git a/ale_linters/erlang/dialyzer.vim b/ale_linters/erlang/dialyzer.vim
index 7af64c4f..395647a0 100644
--- a/ale_linters/erlang/dialyzer.vim
+++ b/ale_linters/erlang/dialyzer.vim
@@ -15,10 +15,10 @@ endfunction
function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort
let l:plt_file = ''
let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer)
- let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build' . l:rebar3_profile)
+ let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build/' . l:rebar3_profile)
if !empty(l:plt_file_directory)
- let l:plt_file = split(globpath(l:plt_file_directory, '/*_plt'), '\n')
+ let l:plt_file = globpath(l:plt_file_directory, '*_plt', 0, 1)
endif
if !empty(l:plt_file)
diff --git a/ale_linters/eruby/ruumba.vim b/ale_linters/eruby/ruumba.vim
index e68bb51d..2e84acf7 100644
--- a/ale_linters/eruby/ruumba.vim
+++ b/ale_linters/eruby/ruumba.vim
@@ -8,7 +8,7 @@ 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')
+ return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
diff --git a/ale_linters/go/revive.vim b/ale_linters/go/revive.vim
new file mode 100644
index 00000000..b14b5ab9
--- /dev/null
+++ b/ale_linters/go/revive.vim
@@ -0,0 +1,21 @@
+" Author: Penghui Liao <liaoishere@gmail.com>
+" Description: Adds support for revive
+
+call ale#Set('go_revive_executable', 'revive')
+call ale#Set('go_revive_options', '')
+
+function! ale_linters#go#revive#GetCommand(buffer) abort
+ let l:options = ale#Var(a:buffer, 'go_revive_options')
+
+ return ale#go#EnvString(a:buffer) . '%e'
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' %t'
+endfunction
+
+call ale#linter#Define('go', {
+\ 'name': 'revive',
+\ 'output_stream': 'both',
+\ 'executable': {b -> ale#Var(b, 'go_revive_executable')},
+\ 'command': function('ale_linters#go#revive#GetCommand'),
+\ 'callback': 'ale#handlers#unix#HandleAsWarning',
+\})
diff --git a/ale_linters/graphql/eslint.vim b/ale_linters/graphql/eslint.vim
index 654b8c17..aed1a371 100644
--- a/ale_linters/graphql/eslint.vim
+++ b/ale_linters/graphql/eslint.vim
@@ -5,5 +5,5 @@ call ale#linter#Define('graphql', {
\ 'name': 'eslint',
\ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'command': function('ale#handlers#eslint#GetCommand'),
-\ 'callback': 'ale#handlers#eslint#Handle',
+\ 'callback': 'ale#handlers#eslint#HandleJSON',
\})
diff --git a/ale_linters/ink/ls.vim b/ale_linters/ink/ls.vim
new file mode 100644
index 00000000..1cc93583
--- /dev/null
+++ b/ale_linters/ink/ls.vim
@@ -0,0 +1,35 @@
+" Author: Andreww Hayworth <ahayworth@gmail.com>
+" Description: Integrate ALE with ink-language-server
+
+call ale#Set('ink_ls_executable', 'ink-language-server')
+call ale#Set('ink_ls_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('ink_ls_initialization_options', {})
+
+function! ale_linters#ink#ls#GetExecutable(buffer) abort
+ return ale#node#FindExecutable(a:buffer, 'ink_ls', [
+ \ 'ink-language-server',
+ \ 'node_modules/.bin/ink-language-server',
+ \])
+endfunction
+
+function! ale_linters#ink#ls#GetCommand(buffer) abort
+ let l:executable = ale_linters#ink#ls#GetExecutable(a:buffer)
+
+ return ale#Escape(l:executable) . ' --stdio'
+endfunction
+
+function! ale_linters#ink#ls#FindProjectRoot(buffer) abort
+ let l:main_file = get(ale#Var(a:buffer, 'ink_ls_initialization_options'), 'mainStoryPath', 'main.ink')
+ let l:config = ale#path#ResolveLocalPath(a:buffer, l:main_file, expand('#' . a:buffer . ':p'))
+
+ return ale#path#Dirname(l:config)
+endfunction
+
+call ale#linter#Define('ink', {
+\ 'name': 'ink-language-server',
+\ 'lsp': 'stdio',
+\ 'executable': function('ale_linters#ink#ls#GetExecutable'),
+\ 'command': function('ale_linters#ink#ls#GetCommand'),
+\ 'project_root': function('ale_linters#ink#ls#FindProjectRoot'),
+\ 'initialization_options': {b -> ale#Var(b, 'ink_ls_initialization_options')},
+\})
diff --git a/ale_linters/java/checkstyle.vim b/ale_linters/java/checkstyle.vim
index 7901ff7e..ec7339d1 100644
--- a/ale_linters/java/checkstyle.vim
+++ b/ale_linters/java/checkstyle.vim
@@ -52,7 +52,7 @@ endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'java_checkstyle_options')
let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config')
- let l:config = l:options !~# '\v(^| )-c' && !empty(l:config_option)
+ let l:config = l:options !~# '\v(^| )-c ' && !empty(l:config_option)
\ ? s:GetConfig(a:buffer, l:config_option)
\ : ''
diff --git a/ale_linters/java/eclipselsp.vim b/ale_linters/java/eclipselsp.vim
index 2648893b..8bc09039 100644
--- a/ale_linters/java/eclipselsp.vim
+++ b/ale_linters/java/eclipselsp.vim
@@ -7,6 +7,7 @@ call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls'
call ale#Set('java_eclipselsp_config_path', '')
call ale#Set('java_eclipselsp_workspace_path', '')
call ale#Set('java_eclipselsp_executable', 'java')
+call ale#Set('java_eclipselsp_javaagent', '')
function! ale_linters#java#eclipselsp#Executable(buffer) abort
return ale#Var(a:buffer, 'java_eclipselsp_executable')
@@ -19,25 +20,39 @@ endfunction
function! ale_linters#java#eclipselsp#JarPath(buffer) abort
let l:path = ale_linters#java#eclipselsp#TargetPath(a:buffer)
+ if has('win32')
+ let l:platform = 'win32'
+ elseif has('macunix')
+ let l:platform = 'macosx'
+ else
+ let l:platform = 'linux'
+ endif
+
" Search jar file within repository path when manually built using mvn
- let l:repo_path = l:path . '/org.eclipse.jdt.ls.product/target/repository'
- let l:files = globpath(l:repo_path, '**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
+ let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
- if len(l:files) == 1
+ if len(l:files) >= 1
return l:files[0]
endif
" Search jar file within VSCode extensions folder.
- let l:files = globpath(l:path, '**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
+ let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
+
+ if len(l:files) >= 1
+ return l:files[0]
+ endif
+
+ " Search jar file within unzipped tar.gz file
+ let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
- if len(l:files) == 1
+ if len(l:files) >= 1
return l:files[0]
endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
- if len(l:files) == 1
+ if len(l:files) >= 1
return l:files[0]
endif
@@ -100,12 +115,30 @@ function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort
return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer))
endfunction
+function! ale_linters#java#eclipselsp#Javaagent(buffer) abort
+ let l:rets = []
+ let l:raw = ale#Var(a:buffer, 'java_eclipselsp_javaagent')
+
+ if empty(l:raw)
+ return ''
+ endif
+
+ let l:jars = split(l:raw)
+
+ for l:jar in l:jars
+ call add(l:rets, ale#Escape('-javaagent:' . l:jar))
+ endfor
+
+ return join(l:rets, ' ')
+endfunction
+
function! ale_linters#java#eclipselsp#Command(buffer, version) abort
let l:path = ale#Var(a:buffer, 'java_eclipselsp_path')
let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer)
let l:cmd = [ ale#Escape(l:executable),
+ \ ale_linters#java#eclipselsp#Javaagent(a:buffer),
\ '-Declipse.application=org.eclipse.jdt.ls.core.id1',
\ '-Dosgi.bundles.defaultStartLevel=4',
\ '-Declipse.product=org.eclipse.jdt.ls.core.product',
@@ -147,7 +180,8 @@ function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort
return ale#command#Run(
\ a:buffer,
\ l:command,
- \ function('ale_linters#java#eclipselsp#CommandWithVersion')
+ \ function('ale_linters#java#eclipselsp#CommandWithVersion'),
+ \ { 'output_stream': 'both' }
\)
endfunction
diff --git a/ale_linters/java/javac.vim b/ale_linters/java/javac.vim
index 8bb52c0b..f866eb09 100644
--- a/ale_linters/java/javac.vim
+++ b/ale_linters/java/javac.vim
@@ -6,6 +6,7 @@ let s:classpath_sep = has('unix') ? ':' : ';'
call ale#Set('java_javac_executable', 'javac')
call ale#Set('java_javac_options', '')
call ale#Set('java_javac_classpath', '')
+call ale#Set('java_javac_sourcepath', '')
function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
let l:command = ''
@@ -40,10 +41,15 @@ endfunction
function! s:BuildClassPathOption(buffer, import_paths) abort
" Filter out lines like [INFO], etc.
let l:class_paths = filter(a:import_paths[:], 'v:val !~# ''[''')
- call extend(
- \ l:class_paths,
- \ split(ale#Var(a:buffer, 'java_javac_classpath'), s:classpath_sep),
- \)
+ let l:cls_path = ale#Var(a:buffer, 'java_javac_classpath')
+
+ if !empty(l:cls_path) && type(l:cls_path) is v:t_string
+ call extend(l:class_paths, split(l:cls_path, s:classpath_sep))
+ endif
+
+ if !empty(l:cls_path) && type(l:cls_path) is v:t_list
+ call extend(l:class_paths, l:cls_path)
+ endif
return !empty(l:class_paths)
\ ? '-cp ' . ale#Escape(join(l:class_paths, s:classpath_sep))
@@ -79,6 +85,27 @@ function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort
endif
endif
+ let l:source_paths = []
+ let l:source_path = ale#Var(a:buffer, 'java_javac_sourcepath')
+
+ if !empty(l:source_path) && type(l:source_path) is v:t_string
+ let l:source_paths = split(l:source_path, s:classpath_sep)
+ endif
+
+ if !empty(l:source_path) && type(l:source_path) is v:t_list
+ let l:source_paths = l:source_path
+ endif
+
+ if !empty(l:source_paths)
+ for l:path in l:source_paths
+ let l:sp_path = ale#path#FindNearestDirectory(a:buffer, l:path)
+
+ if !empty(l:sp_path)
+ call add(l:sp_dirs, l:sp_path)
+ endif
+ endfor
+ endif
+
if !empty(l:sp_dirs)
let l:sp_option = '-sourcepath '
\ . ale#Escape(join(l:sp_dirs, s:classpath_sep))
diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim
index 3135e2e9..3135e2e9 100755..100644
--- a/ale_linters/javascript/flow.vim
+++ b/ale_linters/javascript/flow.vim
diff --git a/ale_linters/javascript/standard.vim b/ale_linters/javascript/standard.vim
index 4cd2c303..1990adce 100644
--- a/ale_linters/javascript/standard.vim
+++ b/ale_linters/javascript/standard.vim
@@ -7,7 +7,9 @@ call ale#Set('javascript_standard_options', '')
function! ale_linters#javascript#standard#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_standard', [
+ \ 'node_modules/standardx/bin/cmd.js',
\ 'node_modules/standard/bin/cmd.js',
+ \ 'node_modules/semistandard/bin/cmd.js',
\ 'node_modules/.bin/standard',
\])
endfunction
diff --git a/ale_linters/kotlin/kotlinc.vim b/ale_linters/kotlin/kotlinc.vim
index 3c6854fa..66c075be 100644
--- a/ale_linters/kotlin/kotlinc.vim
+++ b/ale_linters/kotlin/kotlinc.vim
@@ -174,6 +174,7 @@ endfunction
call ale#linter#Define('kotlin', {
\ 'name': 'kotlinc',
\ 'executable': 'kotlinc',
+\ 'output_stream': 'stderr',
\ 'command': function('ale_linters#kotlin#kotlinc#RunWithImportPaths'),
\ 'callback': 'ale_linters#kotlin#kotlinc#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/kotlin/ktlint.vim b/ale_linters/kotlin/ktlint.vim
index f0384005..0bb64b19 100644
--- a/ale_linters/kotlin/ktlint.vim
+++ b/ale_linters/kotlin/ktlint.vim
@@ -6,5 +6,5 @@ call ale#linter#Define('kotlin', {
\ 'executable': 'ktlint',
\ 'command': function('ale#handlers#ktlint#GetCommand'),
\ 'callback': 'ale#handlers#ktlint#Handle',
-\ 'lint_file': 1
+\ 'output_stream': 'stderr'
\})
diff --git a/ale_linters/less/lessc.vim b/ale_linters/less/lessc.vim
index 4ec8b00e..4ec8b00e 100755..100644
--- a/ale_linters/less/lessc.vim
+++ b/ale_linters/less/lessc.vim
diff --git a/ale_linters/markdown/markdownlint.vim b/ale_linters/markdown/markdownlint.vim
index e935cbfe..7a293938 100644
--- a/ale_linters/markdown/markdownlint.vim
+++ b/ale_linters/markdown/markdownlint.vim
@@ -1,11 +1,22 @@
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com>
" Description: Adds support for markdownlint
+call ale#Set('markdown_markdownlint_options', '')
+
+function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort
+ let l:executable = 'markdownlint'
+
+ let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options')
+
+ return ale#Escape(l:executable)
+ \ . (!empty(l:options) ? ' ' . l:options : '') . ' %s'
+endfunction
+
call ale#linter#Define('markdown', {
\ 'name': 'markdownlint',
\ 'executable': 'markdownlint',
\ 'lint_file': 1,
\ 'output_stream': 'both',
-\ 'command': 'markdownlint %s',
+\ 'command': function('ale_linters#markdown#markdownlint#GetCommand'),
\ 'callback': 'ale#handlers#markdownlint#Handle'
\})
diff --git a/ale_linters/markdown/mdl.vim b/ale_linters/markdown/mdl.vim
index 305f5359..fd44de6e 100644
--- a/ale_linters/markdown/mdl.vim
+++ b/ale_linters/markdown/mdl.vim
@@ -17,18 +17,17 @@ function! ale_linters#markdown#mdl#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'markdown_mdl_options')
return ale#Escape(l:executable) . l:exec_args
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' -j' . (!empty(l:options) ? ' ' . l:options : '')
endfunction
function! ale_linters#markdown#mdl#Handle(buffer, lines) abort
- " matches: '(stdin):173: MD004 Unordered list style'
- let l:pattern = ':\(\d*\): \(.*\)$'
let l:output = []
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
call add(l:output, {
- \ 'lnum': l:match[1] + 0,
- \ 'text': l:match[2],
+ \ 'lnum': l:error['line'],
+ \ 'code': l:error['rule'] . '/' . join(l:error['aliases'], '/'),
+ \ 'text': l:error['description'],
\ 'type': 'W',
\})
endfor
diff --git a/ale_linters/nim/nimcheck.vim b/ale_linters/nim/nimcheck.vim
index b5796dcd..b739ca04 100644
--- a/ale_linters/nim/nimcheck.vim
+++ b/ale_linters/nim/nimcheck.vim
@@ -1,6 +1,15 @@
" Author: Baabelfish
" Description: Typechecking for nim files
+let s:end_col_patterns = [
+\ '\v''([^'']+)'' is declared but not used.*',
+\ '\videntifier expected, but found ''([^'']+)''',
+\ '\vimported and not used: ''([^'']+)''.*',
+\ '\vundeclared identifier: ''([^'']+)''',
+\ '\v''([^'']+)'' cannot be assigned to',
+\ '\vredefinition of ''([^'']+)'';',
+\]
+
function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p:t')
let l:pattern = '^\(.\+\.nim\)(\(\d\+\), \(\d\+\)) \(.\+\)'
@@ -43,6 +52,11 @@ function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort
let l:item.code = l:code_match[2]
endif
+ " Find position end_col.
+ for l:col_match in ale#util#GetMatches(l:item.text, s:end_col_patterns)
+ let l:item.end_col = l:item.col + len(l:col_match[1]) - 1
+ endfor
+
call add(l:output, l:item)
endfor
diff --git a/ale_linters/nim/nimlsp.vim b/ale_linters/nim/nimlsp.vim
new file mode 100644
index 00000000..5d041043
--- /dev/null
+++ b/ale_linters/nim/nimlsp.vim
@@ -0,0 +1,33 @@
+" Author: jeremija <https://github.com/jeremija>
+" Description: Support for nimlsp (language server for nim)
+
+call ale#Set('nim_nimlsp_nim_sources', '')
+
+function! ale_linters#nim#nimlsp#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git')
+
+ if !empty(l:project_root)
+ return fnamemodify(l:project_root, ':h:h')
+ endif
+
+ return ''
+endfunction
+
+function! ale_linters#nim#nimlsp#GetCommand(buffer) abort
+ let l:nim_sources = ale#Var(a:buffer, 'nim_nimlsp_nim_sources')
+
+ if !empty(l:nim_sources)
+ let l:nim_sources = ale#Escape(l:nim_sources)
+ endif
+
+ return '%e' . ale#Pad(l:nim_sources)
+endfunction
+
+call ale#linter#Define('nim', {
+\ 'name': 'nimlsp',
+\ 'lsp': 'stdio',
+\ 'executable': 'nimlsp',
+\ 'command': function('ale_linters#nim#nimlsp#GetCommand'),
+\ 'language': 'nim',
+\ 'project_root': function('ale_linters#nim#nimlsp#GetProjectRoot'),
+\})
diff --git a/ale_linters/objc/ccls.vim b/ale_linters/objc/ccls.vim
index 51ecf056..7aef5325 100644
--- a/ale_linters/objc/ccls.vim
+++ b/ale_linters/objc/ccls.vim
@@ -3,6 +3,7 @@
call ale#Set('objc_ccls_executable', 'ccls')
call ale#Set('objc_ccls_init_options', {})
+call ale#Set('c_build_dir', '')
call ale#linter#Define('objc', {
\ 'name': 'ccls',
@@ -10,5 +11,5 @@ call ale#linter#Define('objc', {
\ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale#handlers#ccls#GetProjectRoot'),
-\ 'initialization_options': {b -> ale#Var(b, 'objc_ccls_init_options')},
+\ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'objc_ccls_init_options')},
\})
diff --git a/ale_linters/php/psalm.vim b/ale_linters/php/psalm.vim
index 3cdb026a..ab4dbbc9 100644
--- a/ale_linters/php/psalm.vim
+++ b/ale_linters/php/psalm.vim
@@ -1,7 +1,8 @@
" 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_executable', 'psalm')
+call ale#Set('psalm_langserver_options', '')
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
@@ -10,12 +11,16 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction
+function! ale_linters#php#psalm#GetCommand(buffer) abort
+ return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'psalm_langserver_options'))
+endfunction
+
call ale#linter#Define('php', {
\ 'name': 'psalm',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
-\ 'vendor/bin/psalm-language-server',
+\ 'vendor/bin/psalm',
\ ])},
-\ 'command': '%e',
+\ 'command': function('ale_linters#php#psalm#GetCommand'),
\ 'project_root': function('ale_linters#php#psalm#GetProjectRoot'),
\})
diff --git a/ale_linters/powershell/powershell.vim b/ale_linters/powershell/powershell.vim
index a63191fd..5f49f72c 100755..100644
--- a/ale_linters/powershell/powershell.vim
+++ b/ale_linters/powershell/powershell.vim
@@ -12,6 +12,7 @@ endfunction
" https://rkeithhill.wordpress.com/2007/10/30/powershell-quicktip-preparsing-scripts-to-check-for-syntax-errors/
function! ale_linters#powershell#powershell#GetCommand(buffer) abort
let l:script = ['Param($Script);
+ \ $ErrorView = "Normal";
\ trap {$_;continue} & {
\ $Contents = Get-Content -Path $Script;
\ $Contents = [string]::Join([Environment]::NewLine, $Contents);
diff --git a/ale_linters/puppet/puppet.vim b/ale_linters/puppet/puppet.vim
index ae648615..59228dc8 100644
--- a/ale_linters/puppet/puppet.vim
+++ b/ale_linters/puppet/puppet.vim
@@ -8,13 +8,15 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
" 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*\)'
+ " Error: Illegal attempt to assign to 'a Name'. Not an assignable reference (file: /tmp/modules/waffles/manifests/syrup.pp, line: 5, column: 11)
+ " Error: Could not parse for environment production: Syntax error at end of input (file: /tmp/modules/bob/manifests/init.pp)
+ let l:pattern = '^Error:\%(.*:\)\? \(.\+\) \((file:\|at\) .\+\.pp\(\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)\|)$\)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
- \ 'lnum': l:match[4] + 0,
- \ 'col': l:match[6] + 0,
+ \ 'lnum': l:match[5] + 0,
+ \ 'col': l:match[7] + 0,
\ 'text': l:match[1],
\})
endfor
diff --git a/ale_linters/python/mypy.vim b/ale_linters/python/mypy.vim
index dc4044e6..94dfae7d 100644
--- a/ale_linters/python/mypy.vim
+++ b/ale_linters/python/mypy.vim
@@ -3,6 +3,7 @@
call ale#Set('python_mypy_executable', 'mypy')
call ale#Set('python_mypy_ignore_invalid_syntax', 0)
+call ale#Set('python_mypy_show_notes', 1)
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)
@@ -18,6 +19,15 @@ endfunction
" The directory to change to before running mypy
function! s:GetDir(buffer) abort
+ " If we find a directory with "mypy.ini" in it use that,
+ " else try and find the "python project" root, or failing
+ " that, run from the same folder as the current file
+ for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
+ if filereadable(l:path . '/mypy.ini')
+ return l:path
+ endif
+ endfor
+
let l:project_root = ale#python#FindProjectRoot(a:buffer)
return !empty(l:project_root)
@@ -51,7 +61,16 @@ function! ale_linters#python#mypy#Handle(buffer, lines) abort
" Lines like these should be ignored below:
"
" file.py:4: note: (Stub files are from https://github.com/python/typeshed)
- let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (error|warning): (.+)$'
+
+ let l:types = 'error|warning'
+
+ if ale#Var(a:buffer, 'python_mypy_show_notes')
+ let l:types = 'error|warning|note'
+ endif
+
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: ('
+ \ . l:types
+ \ . '): (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
@@ -65,7 +84,7 @@ function! ale_linters#python#mypy#Handle(buffer, lines) abort
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
- \ 'type': l:match[4] is# 'error' ? 'E' : 'W',
+ \ 'type': l:match[4] is# 'error' ? 'E' : (l:match[4] is# 'note' ? 'I': 'W'),
\ 'text': l:match[5],
\})
endfor
diff --git a/ale_linters/python/pyright.vim b/ale_linters/python/pyright.vim
new file mode 100644
index 00000000..422ecd61
--- /dev/null
+++ b/ale_linters/python/pyright.vim
@@ -0,0 +1,43 @@
+call ale#Set('python_pyright_executable', 'pyright-langserver')
+call ale#Set('python_pyright_config', {})
+
+function! ale_linters#python#pyright#GetConfig(buffer) abort
+ let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config'))
+
+ if !has_key(l:config, 'python')
+ let l:config.python = {}
+ endif
+
+ if type(l:config.python) is v:t_dict
+ " Automatically detect the virtualenv path and use it.
+ if !has_key(l:config.python, 'venvPath')
+ let l:venv = ale#python#FindVirtualenv(a:buffer)
+
+ if !empty(l:venv)
+ let l:config.python.venvPath = l:venv
+ endif
+ endif
+
+ " Automatically use the version of Python in virtualenv.
+ if type(get(l:config.python, 'venvPath')) is v:t_string
+ \&& !empty(l:config.python.venvPath)
+ \&& !has_key(l:config.python, 'pythonPath')
+ let l:config.python.pythonPath = ale#path#Simplify(
+ \ l:config.python.venvPath
+ \ . (has('win32') ? '/Scripts/python' : '/bin/python')
+ \)
+ endif
+ endif
+
+ return l:config
+endfunction
+
+call ale#linter#Define('python', {
+\ 'name': 'pyright',
+\ 'lsp': 'stdio',
+\ 'executable': {b -> ale#Var(b, 'python_pyright_executable')},
+\ 'command': '%e --stdio',
+\ 'project_root': function('ale#python#FindProjectRoot'),
+\ 'completion_filter': 'ale#completion#python#CompletionItemFilter',
+\ 'lsp_config': function('ale_linters#python#pyright#GetConfig'),
+\})
diff --git a/ale_linters/ruby/brakeman.vim b/ale_linters/ruby/brakeman.vim
index a8088080..2dc48740 100644
--- a/ale_linters/ruby/brakeman.vim
+++ b/ale_linters/ruby/brakeman.vim
@@ -36,7 +36,7 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable')
- return ale#handlers#ruby#EscapeExecutable(l:executable, 'brakeman')
+ return ale#ruby#EscapeExecutable(l:executable, 'brakeman')
\ . ' -f json -q '
\ . ale#Var(a:buffer, 'ruby_brakeman_options')
\ . ' -p ' . ale#Escape(l:rails_root)
diff --git a/ale_linters/ruby/debride.vim b/ale_linters/ruby/debride.vim
new file mode 100644
index 00000000..3b2cc443
--- /dev/null
+++ b/ale_linters/ruby/debride.vim
@@ -0,0 +1,42 @@
+" Author: Eddie Lebow https://github.com/elebow
+" Description: debride, a dead method detector for Ruby files
+
+call ale#Set('ruby_debride_executable', 'debride')
+call ale#Set('ruby_debride_options', '')
+
+function! ale_linters#ruby#debride#GetCommand(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'ruby_debride_executable')
+
+ return ale#ruby#EscapeExecutable(l:executable, 'debride')
+ \ . ale#Var(a:buffer, 'ruby_debride_options')
+ \ . ' %s'
+endfunction
+
+function! ale_linters#ruby#debride#HandleOutput(buffer, lines) abort
+ let l:output = []
+
+ for l:line in a:lines
+ if l:line !~# '^ '
+ continue
+ endif
+
+ let l:elements = split(l:line)
+ let l:method_name = l:elements[0]
+ let l:lnum = split(l:elements[1], ':')[1]
+
+ call add(l:output, {
+ \ 'lnum': 0 + l:lnum,
+ \ 'text': 'Possible unused method: ' . l:method_name,
+ \ 'type': 'W',
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('ruby', {
+\ 'name': 'debride',
+\ 'executable': {b -> ale#Var(b, 'ruby_debride_executable')},
+\ 'command': function('ale_linters#ruby#debride#GetCommand'),
+\ 'callback': 'ale_linters#ruby#debride#HandleOutput',
+\})
diff --git a/ale_linters/ruby/rails_best_practices.vim b/ale_linters/ruby/rails_best_practices.vim
index a94fb671..36646647 100644
--- a/ale_linters/ruby/rails_best_practices.vim
+++ b/ale_linters/ruby/rails_best_practices.vim
@@ -33,7 +33,7 @@ function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
let l:output_file = has('win32') ? '%t ' : '/dev/stdout '
let l:cat_file = has('win32') ? '; type %t' : ''
- return ale#handlers#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
+ return ale#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)
diff --git a/ale_linters/ruby/reek.vim b/ale_linters/ruby/reek.vim
index e39e366f..226b452e 100644
--- a/ale_linters/ruby/reek.vim
+++ b/ale_linters/ruby/reek.vim
@@ -14,7 +14,7 @@ function! ale_linters#ruby#reek#GetCommand(buffer, version) abort
\ ? ' --stdin-filename %s'
\ : ''
- return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ return ale#ruby#EscapeExecutable(l:executable, 'reek')
\ . ' -f json --no-progress --no-color --force-exclusion'
\ . l:display_name_args
endfunction
diff --git a/ale_linters/ruby/rubocop.vim b/ale_linters/ruby/rubocop.vim
index 8b9e9c84..410ed0ea 100644
--- a/ale_linters/ruby/rubocop.vim
+++ b/ale_linters/ruby/rubocop.vim
@@ -7,7 +7,7 @@ call ale#Set('ruby_rubocop_options', '')
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
- return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
+ return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
diff --git a/ale_linters/ruby/sorbet.vim b/ale_linters/ruby/sorbet.vim
index ee765a6e..cae0683c 100644
--- a/ale_linters/ruby/sorbet.vim
+++ b/ale_linters/ruby/sorbet.vim
@@ -5,7 +5,7 @@ function! ale_linters#ruby#sorbet#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable')
let l:options = ale#Var(a:buffer, 'ruby_sorbet_options')
- return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb')
+ return ale#ruby#EscapeExecutable(l:executable, 'srb')
\ . ' tc'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --lsp --disable-watchman'
diff --git a/ale_linters/ruby/standardrb.vim b/ale_linters/ruby/standardrb.vim
index f075a7d5..f751e803 100644
--- a/ale_linters/ruby/standardrb.vim
+++ b/ale_linters/ruby/standardrb.vim
@@ -8,7 +8,7 @@ call ale#Set('ruby_standardrb_options', '')
function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_standardrb_executable')
- return ale#handlers#ruby#EscapeExecutable(l:executable, 'standardrb')
+ return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_standardrb_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
diff --git a/ale_linters/rust/analyzer.vim b/ale_linters/rust/analyzer.vim
new file mode 100644
index 00000000..3666ec03
--- /dev/null
+++ b/ale_linters/rust/analyzer.vim
@@ -0,0 +1,24 @@
+" Author: Jon Gjengset <jon@thesquareplanet.com>
+" Description: The next generation language server for Rust
+
+call ale#Set('rust_analyzer_executable', 'rust-analyzer')
+call ale#Set('rust_analyzer_config', {})
+
+function! ale_linters#rust#analyzer#GetCommand(buffer) abort
+ return '%e'
+endfunction
+
+function! ale_linters#rust#analyzer#GetProjectRoot(buffer) abort
+ let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
+
+ return !empty(l:cargo_file) ? fnamemodify(l:cargo_file, ':h') : ''
+endfunction
+
+call ale#linter#Define('rust', {
+\ 'name': 'analyzer',
+\ 'lsp': 'stdio',
+\ 'lsp_config': {b -> ale#Var(b, 'rust_analyzer_config')},
+\ 'executable': {b -> ale#Var(b, 'rust_analyzer_executable')},
+\ 'command': function('ale_linters#rust#analyzer#GetCommand'),
+\ 'project_root': function('ale_linters#rust#analyzer#GetProjectRoot'),
+\})
diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim
index 99178585..3407abed 100644
--- a/ale_linters/rust/cargo.vim
+++ b/ale_linters/rust/cargo.vim
@@ -11,6 +11,7 @@ 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', '')
+call ale#Set('rust_cargo_target_dir', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
@@ -31,6 +32,9 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
\ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(a:version, [0, 22, 0])
+ let l:target_dir = ale#Var(a:buffer, 'rust_cargo_target_dir')
+ let l:use_target_dir = !empty(l:target_dir)
+ \ && ale#semver#GTE(a:version, [0, 17, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
@@ -82,6 +86,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
+ \ . (l:use_target_dir ? (' --target-dir ' . ale#Escape(l:target_dir)) : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features
diff --git a/ale_linters/scala/metals.vim b/ale_linters/scala/metals.vim
new file mode 100644
index 00000000..da9e855d
--- /dev/null
+++ b/ale_linters/scala/metals.vim
@@ -0,0 +1,50 @@
+" Author: Jeffrey Lau - https://github.com/zoonfafer
+" Description: Metals Language Server for Scala https://scalameta.org/metals/
+
+call ale#Set('scala_metals_executable', 'metals-vim')
+call ale#Set('scala_metals_project_root', '')
+
+function! ale_linters#scala#metals#GetProjectRoot(buffer) abort
+ let l:project_root = ale#Var(a:buffer, 'scala_metals_project_root')
+
+ if !empty(l:project_root)
+ return l:project_root
+ endif
+
+ let l:potential_roots = [
+ \ 'build.sc',
+ \ 'build.sbt',
+ \ '.bloop',
+ \ '.metals',
+ \]
+
+ for l:root in l:potential_roots
+ let l:project_root = ale#path#ResolveLocalPath(
+ \ a:buffer,
+ \ l:root,
+ \ ''
+ \)
+
+ if !empty(l:project_root)
+ return fnamemodify(
+ \ l:project_root,
+ \ ':h',
+ \)
+ endif
+ endfor
+
+ return ''
+endfunction
+
+function! ale_linters#scala#metals#GetCommand(buffer) abort
+ return '%e' . ale#Pad('stdio')
+endfunction
+
+call ale#linter#Define('scala', {
+\ 'name': 'metals',
+\ 'lsp': 'stdio',
+\ 'language': 'scala',
+\ 'executable': {b -> ale#Var(b, 'scala_metals_executable')},
+\ 'command': function('ale_linters#scala#metals#GetCommand'),
+\ 'project_root': function('ale_linters#scala#metals#GetProjectRoot'),
+\})
diff --git a/ale_linters/sh/bashate.vim b/ale_linters/sh/bashate.vim
new file mode 100644
index 00000000..3cd84245
--- /dev/null
+++ b/ale_linters/sh/bashate.vim
@@ -0,0 +1,43 @@
+" Author: hsanson <hsanson@gmail.com>
+" Description: Lints sh files using bashate
+" URL: https://github.com/openstack/bashate
+
+call ale#Set('sh_bashate_executable', 'bashate')
+call ale#Set('sh_bashate_options', '')
+
+function! ale_linters#sh#bashate#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'sh_bashate_executable')
+endfunction
+
+function! ale_linters#sh#bashate#GetCommand(buffer) abort
+ let l:options = ale#Var(a:buffer, 'sh_bashate_options')
+ let l:executable = ale_linters#sh#bashate#GetExecutable(a:buffer)
+
+ return ale#Escape(l:executable) . ' ' . l:options . ' ' . '%t'
+endfunction
+
+function! ale_linters#sh#bashate#Handle(buffer, lines) abort
+ " Matches patterns line the following:
+ "
+ " /path/to/script/file:694:1: E003 Indent not multiple of 4
+ let l:pattern = ':\(\d\+\):\(\d\+\): \(.*\)$'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'lnum': str2nr(l:match[1]),
+ \ 'col': str2nr(l:match[2]),
+ \ 'text': l:match[3],
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('sh', {
+\ 'name': 'bashate',
+\ 'output_stream': 'stdout',
+\ 'executable': function('ale_linters#sh#bashate#GetExecutable'),
+\ 'command': function('ale_linters#sh#bashate#GetCommand'),
+\ 'callback': 'ale_linters#sh#bashate#Handle',
+\})
diff --git a/ale_linters/sh/shell.vim b/ale_linters/sh/shell.vim
index 189dc21d..73ab3608 100644
--- a/ale_linters/sh/shell.vim
+++ b/ale_linters/sh/shell.vim
@@ -1,5 +1,5 @@
" Author: w0rp <devw0rp@gmail.com>
-" Description: Lints sh files using bash -n
+" Description: Lints shell files by invoking the shell with -n
" Backwards compatibility
if exists('g:ale_linters_sh_shell_default_shell')
@@ -34,8 +34,10 @@ function! ale_linters#sh#shell#Handle(buffer, lines) abort
" Matches patterns line the following:
"
" bash: line 13: syntax error near unexpected token `d'
+ " bash:行0: 未预期的符号“done”附近有语法错误
+ " bash: 列 90: 尋找匹配的「"」時遇到了未預期的檔案結束符
" sh: 11: Syntax error: "(" unexpected
- let l:pattern = '\v(line |: ?)(\d+): (.+)$'
+ let l:pattern = '\v([^:]+:\D*)(\d+): (.+)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim
index 1d8b6096..d9945126 100644
--- a/ale_linters/sh/shellcheck.vim
+++ b/ale_linters/sh/shellcheck.vim
@@ -1,107 +1,4 @@
" Author: w0rp <devw0rp@gmail.com>
-" Description: This file adds support for using the shellcheck linter with
-" shell scripts.
+" Description: shellcheck linter for shell scripts.
-" This global variable can be set with a string of comma-separated error
-" codes to exclude from shellcheck. For example:
-"
-" let g:ale_sh_shellcheck_exclusions = 'SC2002,SC2004'
-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_dialect', 'auto')
-call ale#Set('sh_shellcheck_options', '')
-call ale#Set('sh_shellcheck_change_directory', 1)
-
-function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort
- let l:shell_type = ale#handlers#sh#GetShellType(a:buffer)
-
- if !empty(l:shell_type)
- " Use the dash dialect for /bin/ash, etc.
- if l:shell_type is# 'ash'
- return 'dash'
- endif
-
- return l:shell_type
- endif
-
- " If there's no hashbang, try using Vim's buffer variables.
- if getbufvar(a:buffer, 'is_bash', 0)
- return 'bash'
- elseif getbufvar(a:buffer, 'is_sh', 0)
- return 'sh'
- elseif getbufvar(a:buffer, 'is_kornshell', 0)
- return 'ksh'
- endif
-
- return ''
-endfunction
-
-function! ale_linters#sh#shellcheck#GetCommand(buffer, version) abort
- let l:options = ale#Var(a:buffer, 'sh_shellcheck_options')
- let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
- let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect')
- let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : ''
- let l:cd_string = ale#Var(a:buffer, 'sh_shellcheck_change_directory')
- \ ? ale#path#BufferCdString(a:buffer)
- \ : ''
-
- if l:dialect is# 'auto'
- let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer)
- endif
-
- return l:cd_string
- \ . '%e'
- \ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
- \ . l:external_option
- \ . ' -f gcc -'
-endfunction
-
-function! ale_linters#sh#shellcheck#Handle(buffer, lines) abort
- let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+) \[([^\]]+)\]$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- if l:match[4] is# 'error'
- let l:type = 'E'
- elseif l:match[4] is# 'note'
- let l:type = 'I'
- else
- let l:type = 'W'
- endif
-
- let l:item = {
- \ 'lnum': str2nr(l:match[2]),
- \ 'type': l:type,
- \ 'text': l:match[5],
- \ 'code': l:match[6],
- \}
-
- if !empty(l:match[3])
- let l:item.col = str2nr(l:match[3])
- endif
-
- " If the filename is something like <stdin>, <nofile> or -, then
- " this is an error for the file we checked.
- if l:match[1] isnot# '-' && l:match[1][0] isnot# '<'
- let l:item['filename'] = l:match[1]
- endif
-
- call add(l:output, l:item)
- endfor
-
- return l:output
-endfunction
-
-call ale#linter#Define('sh', {
-\ 'name': 'shellcheck',
-\ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')},
-\ 'command': {buffer -> ale#semver#RunWithVersionCheck(
-\ buffer,
-\ ale#Var(buffer, 'sh_shellcheck_executable'),
-\ '%e --version',
-\ function('ale_linters#sh#shellcheck#GetCommand'),
-\ )},
-\ 'callback': 'ale_linters#sh#shellcheck#Handle',
-\})
+call ale#handlers#shellcheck#DefineLinter('sh')
diff --git a/ale_linters/solidity/solc.vim b/ale_linters/solidity/solc.vim
new file mode 100644
index 00000000..e4f220ac
--- /dev/null
+++ b/ale_linters/solidity/solc.vim
@@ -0,0 +1,35 @@
+" Author: Karl Bartel <karl42@gmail.com> - http://karl.berlin/
+" Description: Report solc compiler errors in Solidity code
+
+call ale#Set('solidity_solc_options', '')
+
+function! ale_linters#solidity#solc#Handle(buffer, lines) abort
+ " Matches patterns like the following:
+ " /path/to/file/file.sol:1:10: Error: Identifier not found or not unique.
+ let l:pattern = '\v^[^:]+:(\d+):(\d+): (Error|Warning): (.*)$'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ let l:isError = l:match[3] is? 'error'
+ call add(l:output, {
+ \ 'lnum': l:match[1] + 0,
+ \ 'col': l:match[2] + 0,
+ \ 'text': l:match[4],
+ \ 'type': l:isError ? 'E' : 'W',
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+function! ale_linters#solidity#solc#GetCommand(buffer) abort
+ return 'solc' . ale#Pad(ale#Var(a:buffer, 'solidity_solc_options')) . ' %s'
+endfunction
+
+call ale#linter#Define('solidity', {
+\ 'name': 'solc',
+\ 'executable': 'solc',
+\ 'command': function('ale_linters#solidity#solc#GetCommand'),
+\ 'callback': 'ale_linters#solidity#solc#Handle',
+\ 'output_stream': 'stderr',
+\})
diff --git a/ale_linters/terraform/terraform.vim b/ale_linters/terraform/terraform.vim
index 0429cb7a..0429cb7a 100755..100644
--- a/ale_linters/terraform/terraform.vim
+++ b/ale_linters/terraform/terraform.vim
diff --git a/ale_linters/terraform/terraform_lsp.vim b/ale_linters/terraform/terraform_lsp.vim
new file mode 100644
index 00000000..e2408c15
--- /dev/null
+++ b/ale_linters/terraform/terraform_lsp.vim
@@ -0,0 +1,25 @@
+" Author: OJFord <dev@ojford.com>
+" Description: terraform-lsp integration for ALE (cf. https://github.com/juliosueiras/terraform-lsp)
+
+call ale#Set('terraform_langserver_executable', 'terraform-lsp')
+call ale#Set('terraform_langserver_options', '')
+
+function! ale_linters#terraform#terraform_lsp#GetCommand(buffer) abort
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'terraform_langserver_options'))
+endfunction
+
+function! ale_linters#terraform#terraform_lsp#GetProjectRoot(buffer) abort
+ let l:tf_dir = ale#path#FindNearestDirectory(a:buffer, '.terraform')
+
+ return !empty(l:tf_dir) ? fnamemodify(l:tf_dir, ':h:h') : ''
+endfunction
+
+call ale#linter#Define('terraform', {
+\ 'name': 'terraform_lsp',
+\ 'lsp': 'stdio',
+\ 'executable': {b -> ale#Var(b, 'terraform_langserver_executable')},
+\ 'command': function('ale_linters#terraform#terraform_lsp#GetCommand'),
+\ 'project_root': function('ale_linters#terraform#terraform_lsp#GetProjectRoot'),
+\ 'language': 'terraform',
+\})
diff --git a/ale_linters/terraform/tflint.vim b/ale_linters/terraform/tflint.vim
index 6d54a8b1..f57ee6b6 100644
--- a/ale_linters/terraform/tflint.vim
+++ b/ale_linters/terraform/tflint.vim
@@ -9,23 +9,69 @@ call ale#Set('terraform_tflint_executable', 'tflint')
function! ale_linters#terraform#tflint#Handle(buffer, lines) abort
let l:output = []
+ let l:pattern = '\v^(.*):(\d+),(\d+)-(\d+)?,?(\d+): (.{-1,}); (.+)$'
+ let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
- for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
- if l:error.type is# 'ERROR'
- let l:type = 'E'
- elseif l:error.type is# 'NOTICE'
- let l:type = 'I'
- else
- let l:type = 'W'
- endif
-
- call add(l:output, {
- \ 'lnum': l:error.line,
- \ 'text': l:error.message,
- \ 'type': l:type,
- \ 'code': l:error.detector,
- \})
- endfor
+ " This is a rough test for tflint's output format
+ " On versions prior to 0.11 it outputs all errors as a single level list
+ if type(l:json) is v:t_list
+ for l:error in l:json
+ if l:error.type is# 'ERROR'
+ let l:type = 'E'
+ elseif l:error.type is# 'NOTICE'
+ let l:type = 'I'
+ else
+ let l:type = 'W'
+ endif
+
+ call add(l:output, {
+ \ 'lnum': l:error.line,
+ \ 'text': l:error.message,
+ \ 'type': l:type,
+ \ 'code': l:error.detector,
+ \})
+ endfor
+ else
+ for l:error in get(l:json, 'errors', [])
+ for l:match in ale#util#GetMatches(l:error.message, [l:pattern])
+ if l:match[4] is# ''
+ let l:match[4] = l:match[2]
+ endif
+
+ call add(l:output, {
+ \ 'filename': l:match[1],
+ \ 'lnum': str2nr(l:match[2]),
+ \ 'col': str2nr(l:match[3]),
+ \ 'end_lnum': str2nr(l:match[4]),
+ \ 'end_col': str2nr(l:match[5]),
+ \ 'text': l:match[7],
+ \ 'code': l:match[6],
+ \ 'type': 'E',
+ \})
+ endfor
+ endfor
+
+ for l:error in get(l:json, 'issues', [])
+ if l:error.rule.severity is# 'ERROR'
+ let l:type = 'E'
+ elseif l:error.rule.severity is# 'NOTICE'
+ let l:type = 'I'
+ else
+ let l:type = 'W'
+ endif
+
+ call add(l:output, {
+ \ 'filename': l:error.range.filename,
+ \ 'lnum': l:error.range.start.line,
+ \ 'col': l:error.range.start.column,
+ \ 'end_lnum': l:error.range.end.line,
+ \ 'end_col': l:error.range.end.column,
+ \ 'text': l:error.message,
+ \ 'code': l:error.rule.name,
+ \ 'type': l:type,
+ \})
+ endfor
+ endif
return l:output
endfunction
diff --git a/ale_linters/typescript/standard.vim b/ale_linters/typescript/standard.vim
new file mode 100644
index 00000000..da8f14eb
--- /dev/null
+++ b/ale_linters/typescript/standard.vim
@@ -0,0 +1,31 @@
+" Author: Ahmed El Gabri <@ahmedelgabri>
+" Description: standardjs for typescript files
+
+call ale#Set('typescript_standard_executable', 'standard')
+call ale#Set('typescript_standard_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('typescript_standard_options', '')
+
+function! ale_linters#typescript#standard#GetExecutable(buffer) abort
+ return ale#node#FindExecutable(a:buffer, 'typescript_standard', [
+ \ 'node_modules/standardx/bin/cmd.js',
+ \ 'node_modules/standard/bin/cmd.js',
+ \ 'node_modules/.bin/standard',
+ \])
+endfunction
+
+function! ale_linters#typescript#standard#GetCommand(buffer) abort
+ let l:executable = ale_linters#typescript#standard#GetExecutable(a:buffer)
+ let l:options = ale#Var(a:buffer, 'typescript_standard_options')
+
+ return ale#node#Executable(a:buffer, l:executable)
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' --stdin %s'
+endfunction
+
+" standard uses eslint and the output format is the same
+call ale#linter#Define('typescript', {
+\ 'name': 'standard',
+\ 'executable': function('ale_linters#typescript#standard#GetExecutable'),
+\ 'command': function('ale_linters#typescript#standard#GetCommand'),
+\ 'callback': 'ale#handlers#eslint#Handle',
+\})
diff --git a/ale_linters/verilog/hdl_checker.vim b/ale_linters/verilog/hdl_checker.vim
new file mode 100644
index 00000000..b05d8565
--- /dev/null
+++ b/ale_linters/verilog/hdl_checker.vim
@@ -0,0 +1,5 @@
+" Author: suoto <andre820@gmail.com>
+" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
+" or xvhdl. More info on https://github.com/suoto/hdl_checker
+
+call ale#handlers#hdl_checker#DefineLinter('verilog')
diff --git a/ale_linters/verilog/verilator.vim b/ale_linters/verilog/verilator.vim
index 64bb6e41..029dd4c9 100644
--- a/ale_linters/verilog/verilator.vim
+++ b/ale_linters/verilog/verilator.vim
@@ -28,21 +28,30 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
" %Warning-UNDRIVEN: test.v:3: Signal is not driven: clk
" %Warning-UNUSED: test.v:4: Signal is not used: dout
" %Warning-BLKSEQ: test.v:10: Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).
- let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\): \(.\+\)$'
+ " Since version 4.032 (04/2020) verilator linter messages also contain the column number,
+ " and look like:
+ " %Error: /tmp/test.sv:3:1: syntax error, unexpected endmodule, expecting ';'
+ "
+ " to stay compatible with old versions of the tool, the column number is
+ " optional in the researched pattern
+ let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\):\(\d\+\)\?:\? \(.\+\)$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
- let l:line = l:match[3] + 0
- let l:type = l:match[1] is# 'Error' ? 'E' : 'W'
- let l:text = l:match[4]
+ let l:item = {
+ \ 'lnum': str2nr(l:match[3]),
+ \ 'text': l:match[5],
+ \ 'type': l:match[1] is# 'Error' ? 'E' : 'W',
+ \}
+
+ if !empty(l:match[4])
+ let l:item.col = str2nr(l:match[4])
+ endif
+
let l:file = l:match[2]
if l:file =~# '_verilator_linted.v'
- call add(l:output, {
- \ 'lnum': l:line,
- \ 'text': l:text,
- \ 'type': l:type,
- \})
+ call add(l:output, l:item)
endif
endfor
diff --git a/ale_linters/verilog/vlog.vim b/ale_linters/verilog/vlog.vim
index 37d21c4c..45e1977c 100644
--- a/ale_linters/verilog/vlog.vim
+++ b/ale_linters/verilog/vlog.vim
@@ -13,14 +13,30 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"Matches patterns like the following:
"** Warning: add.v(7): (vlog-2623) Undefined variable: C.
"** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: C.
- let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
+ let l:pattern = '^**\s\(\w*\): \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
- \ 'lnum': l:match[2] + 0,
+ \ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
- \ 'text': l:match[3],
+ \ 'text': l:match[4],
+ \ 'filename': l:match[2],
+ \})
+ endfor
+
+ "Matches patterns like the following:
+ "** Warning: (vlog-2623) add.v(7): Undefined variable: C.
+ "** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C.
+ " let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
+ let l:pattern = '^**\s\(\w*\):\s\([^)]*)\) \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'lnum': l:match[4] + 0,
+ \ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
+ \ 'text': l:match[2] . ' ' . l:match[5],
+ \ 'filename': l:match[3],
\})
endfor
diff --git a/ale_linters/vhdl/hdl_checker.vim b/ale_linters/vhdl/hdl_checker.vim
new file mode 100644
index 00000000..c9d306b3
--- /dev/null
+++ b/ale_linters/vhdl/hdl_checker.vim
@@ -0,0 +1,5 @@
+" Author: suoto <andre820@gmail.com>
+" Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl
+" or xvhdl. More info on https://github.com/suoto/hdl_checker
+
+call ale#handlers#hdl_checker#DefineLinter('vhdl')
diff --git a/ale_linters/vim/vimls.vim b/ale_linters/vim/vimls.vim
new file mode 100644
index 00000000..26014d66
--- /dev/null
+++ b/ale_linters/vim/vimls.vim
@@ -0,0 +1,61 @@
+" Author: Jeffrey Lau - https://github.com/zoonfafer
+" Description: Vim Language Server integration for ALE
+
+call ale#Set('vim_vimls_executable', 'vim-language-server')
+call ale#Set('vim_vimls_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('vim_vimls_config', {})
+
+function! ale_linters#vim#vimls#GetProjectRoot(buffer) abort
+ let l:trigger_file_candidates = [
+ \ '.vimrc',
+ \ 'init.vim',
+ \]
+
+ for l:candidate in l:trigger_file_candidates
+ let l:trigger_file = fnamemodify(bufname(a:buffer), ':t')
+
+ if l:trigger_file is# l:candidate
+ return fnamemodify(
+ \ bufname(a:buffer),
+ \ ':h',
+ \)
+ endif
+ endfor
+
+ let l:trigger_dir_candidates = [
+ \ 'autoload',
+ \ 'plugin',
+ \ '.git',
+ \]
+
+ let l:path_upwards = ale#path#Upwards(fnamemodify(bufname(a:buffer), ':p:h'))
+
+ for l:path in l:path_upwards
+ for l:candidate in l:trigger_dir_candidates
+ let l:trigger_dir = ale#path#Simplify(
+ \ l:path . '/' . l:candidate,
+ \)
+
+ if isdirectory(l:trigger_dir)
+ return fnamemodify(
+ \ l:trigger_dir,
+ \ ':p:h:h',
+ \)
+ endif
+ endfor
+ endfor
+
+ return ''
+endfunction
+
+call ale#linter#Define('vim', {
+\ 'name': 'vimls',
+\ 'lsp': 'stdio',
+\ 'lsp_config': {b -> ale#Var(b, 'vim_vimls_config')},
+\ 'executable': {b -> ale#node#FindExecutable(b, 'vim_vimls', [
+\ 'node_modules/.bin/vim-language-server',
+\ ])},
+\ 'command': '%e --stdio',
+\ 'language': 'vim',
+\ 'project_root': function('ale_linters#vim#vimls#GetProjectRoot'),
+\})
diff --git a/ale_linters/zig/zls.vim b/ale_linters/zig/zls.vim
new file mode 100644
index 00000000..1390f6b1
--- /dev/null
+++ b/ale_linters/zig/zls.vim
@@ -0,0 +1,20 @@
+" Author: CherryMan <skipper308@hotmail.ca>
+" Description: A language server for Zig
+
+call ale#Set('zig_zls_executable', 'zls')
+call ale#Set('zig_zls_config', {})
+
+function! ale_linters#zig#zls#GetProjectRoot(buffer) abort
+ let l:build_rs = ale#path#FindNearestFile(a:buffer, 'build.zig')
+
+ return !empty(l:build_rs) ? fnamemodify(l:build_rs, ':h') : ''
+endfunction
+
+call ale#linter#Define('zig', {
+\ 'name': 'zls',
+\ 'lsp': 'stdio',
+\ 'lsp_config': {b -> ale#Var(b, 'zig_zls_config')},
+\ 'executable': {b -> ale#Var(b, 'zig_zls_executable')},
+\ 'command': '%e',
+\ 'project_root': function('ale_linters#zig#zls#GetProjectRoot'),
+\})