diff options
Diffstat (limited to 'ale_linters')
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'), +\}) |