summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CONTRIBUTING.md2
-rw-r--r--.github/ISSUE_TEMPLATE/report-a-bug.md16
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md5
-rw-r--r--README.md160
-rw-r--r--ale_linters/ada/gcc.vim54
-rw-r--r--ale_linters/ansible/ansible_lint.vim13
-rw-r--r--ale_linters/apiblueprint/drafter.vim2
-rw-r--r--ale_linters/asciidoc/vale.vim9
-rw-r--r--ale_linters/asm/gcc.vim13
-rw-r--r--ale_linters/awk/gawk.vim18
-rw-r--r--ale_linters/c/ccls.vim14
-rw-r--r--ale_linters/c/clang.vim17
-rw-r--r--ale_linters/c/clangd.vim12
-rw-r--r--ale_linters/c/clangtidy.vim30
-rw-r--r--ale_linters/c/cppcheck.vim9
-rw-r--r--ale_linters/c/cquery.vim28
-rw-r--r--ale_linters/c/flawfinder.vim12
-rw-r--r--ale_linters/c/gcc.vim17
-rw-r--r--ale_linters/chef/foodcritic.vim11
-rw-r--r--ale_linters/clojure/joker.vim4
-rw-r--r--ale_linters/cpp/ccls.vim14
-rw-r--r--ale_linters/cpp/clang.vim17
-rw-r--r--ale_linters/cpp/clangcheck.vim13
-rw-r--r--ale_linters/cpp/clangd.vim23
-rw-r--r--ale_linters/cpp/clangtidy.vim30
-rw-r--r--ale_linters/cpp/clazy.vim32
-rw-r--r--ale_linters/cpp/cppcheck.vim9
-rw-r--r--ale_linters/cpp/cpplint.vim10
-rw-r--r--ale_linters/cpp/cquery.vim17
-rw-r--r--ale_linters/cpp/flawfinder.vim10
-rw-r--r--ale_linters/cpp/gcc.vim17
-rw-r--r--ale_linters/css/stylelint.vim13
-rw-r--r--ale_linters/cucumber/cucumber.vim1
-rw-r--r--ale_linters/cuda/nvcc.vim17
-rw-r--r--ale_linters/d/dls.vim22
-rw-r--r--ale_linters/d/dmd.vim16
-rw-r--r--ale_linters/dafny/dafny.vim1
-rw-r--r--ale_linters/dart/dartanalyzer.vim9
-rw-r--r--ale_linters/dart/language_server.vim8
-rw-r--r--ale_linters/dockerfile/dockerfile_lint.vim61
-rw-r--r--ale_linters/dockerfile/hadolint.vim2
-rw-r--r--ale_linters/elixir/credo.vim23
-rw-r--r--ale_linters/elixir/dialyxir.vim9
-rw-r--r--ale_linters/elixir/dogma.vim9
-rw-r--r--ale_linters/elixir/elixir_ls.vim21
-rw-r--r--ale_linters/elixir/mix.vim15
-rw-r--r--ale_linters/elm/make.vim28
-rw-r--r--ale_linters/erlang/syntaxerl.vim24
-rw-r--r--ale_linters/eruby/ruumba.vim62
-rw-r--r--ale_linters/fortran/gcc.vim28
-rw-r--r--ale_linters/fortran/language_server.vim12
-rw-r--r--ale_linters/fuse/fusionlint.vim9
-rw-r--r--ale_linters/gitcommit/gitlint.vim23
-rw-r--r--ale_linters/glsl/glslang.vim14
-rw-r--r--ale_linters/glsl/glslls.vim11
-rw-r--r--ale_linters/go/gobuild.vim40
-rw-r--r--ale_linters/go/golangci_lint.vim56
-rw-r--r--ale_linters/go/golint.vim15
-rw-r--r--ale_linters/go/gometalinter.vim11
-rw-r--r--ale_linters/go/govet.vim12
-rw-r--r--ale_linters/go/langserver.vim28
-rw-r--r--ale_linters/hack/hack.vim22
-rw-r--r--ale_linters/hack/hhast.vim40
-rw-r--r--ale_linters/haml/hamllint.vim10
-rw-r--r--ale_linters/handlebars/embertemplatelint.vim17
-rw-r--r--ale_linters/haskell/ghc-mod.vim18
-rw-r--r--ale_linters/haskell/ghc_mod.vim19
-rw-r--r--ale_linters/haskell/hdevtools.vim14
-rw-r--r--ale_linters/haskell/hie.vim47
-rw-r--r--ale_linters/haskell/hlint.vim16
-rw-r--r--ale_linters/haskell/stack_build.vim2
-rw-r--r--ale_linters/haskell/stack_ghc.vim2
-rw-r--r--ale_linters/html/htmlhint.vim14
-rw-r--r--ale_linters/html/stylelint.vim27
-rw-r--r--ale_linters/html/tidy.vim8
-rw-r--r--ale_linters/idris/idris.vim14
-rw-r--r--ale_linters/ispc/ispc.vim45
-rw-r--r--ale_linters/java/checkstyle.vim18
-rw-r--r--ale_linters/java/javac.vim12
-rw-r--r--ale_linters/java/javalsp.vim23
-rw-r--r--ale_linters/java/pmd.vim2
-rwxr-xr-xale_linters/javascript/flow.vim3
-rw-r--r--ale_linters/javascript/flow_ls.vim18
-rw-r--r--ale_linters/javascript/jscs.vim14
-rw-r--r--ale_linters/javascript/jshint.vim15
-rw-r--r--ale_linters/javascript/tsserver.vim19
-rw-r--r--ale_linters/json/jsonlint.vim1
-rw-r--r--ale_linters/julia/languageserver.vim21
-rw-r--r--ale_linters/kotlin/kotlinc.vim7
-rw-r--r--ale_linters/kotlin/languageserver.vim13
-rwxr-xr-xale_linters/less/lessc.vim21
-rw-r--r--ale_linters/less/stylelint.vim15
-rw-r--r--ale_linters/llvm/llc.vim16
-rw-r--r--ale_linters/lua/luac.vim13
-rw-r--r--ale_linters/lua/luacheck.vim16
-rw-r--r--ale_linters/make/checkmake.vim1
-rw-r--r--ale_linters/markdown/remark_lint.vim17
-rw-r--r--ale_linters/matlab/mlint.vim17
-rw-r--r--ale_linters/mercury/mmc.vim9
-rw-r--r--ale_linters/nasm/nasm.vim26
-rw-r--r--ale_linters/objc/ccls.vim14
-rw-r--r--ale_linters/objc/clang.vim2
-rw-r--r--ale_linters/objc/clangd.vim23
-rw-r--r--ale_linters/objcpp/clang.vim2
-rw-r--r--ale_linters/objcpp/clangd.vim23
-rw-r--r--ale_linters/perl/perl.vim22
-rw-r--r--ale_linters/perl/perlcritic.vim25
-rw-r--r--ale_linters/perl6/perl6.vim166
-rw-r--r--ale_linters/php/hack.vim28
-rw-r--r--ale_linters/php/langserver.vim16
-rw-r--r--ale_linters/php/php.vim6
-rw-r--r--ale_linters/php/phpcs.vim21
-rw-r--r--ale_linters/php/phpmd.vim13
-rw-r--r--ale_linters/php/phpstan.vim31
-rw-r--r--ale_linters/php/psalm.vim21
-rw-r--r--ale_linters/pony/ponyc.vim9
-rw-r--r--ale_linters/prolog/swipl.vim100
-rw-r--r--ale_linters/pug/puglint.vim14
-rw-r--r--ale_linters/puppet/languageserver.vim16
-rw-r--r--ale_linters/puppet/puppet.vim14
-rw-r--r--ale_linters/puppet/puppetlint.vim16
-rw-r--r--ale_linters/pyrex/cython.vim11
-rw-r--r--ale_linters/python/flake8.vim7
-rw-r--r--ale_linters/python/mypy.vim6
-rw-r--r--ale_linters/python/prospector.vim7
-rw-r--r--ale_linters/python/pycodestyle.vim6
-rw-r--r--ale_linters/python/pyflakes.vim6
-rw-r--r--ale_linters/python/pylint.vim6
-rw-r--r--ale_linters/python/pyls.vim6
-rw-r--r--ale_linters/python/pyre.vim6
-rw-r--r--ale_linters/python/vulture.vim85
-rw-r--r--ale_linters/qml/qmlfmt.vim33
-rw-r--r--ale_linters/rst/rstcheck.vim1
-rw-r--r--ale_linters/ruby/brakeman.vim12
-rw-r--r--ale_linters/ruby/rails_best_practices.vim14
-rw-r--r--ale_linters/ruby/reek.vim13
-rw-r--r--ale_linters/ruby/rubocop.vim12
-rw-r--r--ale_linters/ruby/ruby.vim14
-rw-r--r--ale_linters/ruby/solargraph.vim22
-rw-r--r--ale_linters/rust/cargo.vim15
-rw-r--r--ale_linters/rust/rls.vim13
-rw-r--r--ale_linters/rust/rustc.vim2
-rw-r--r--ale_linters/sass/stylelint.vim17
-rw-r--r--ale_linters/scala/fsc.vim23
-rw-r--r--ale_linters/scala/sbtserver.vim31
-rw-r--r--ale_linters/scala/scalac.vim23
-rw-r--r--ale_linters/scala/scalastyle.vim2
-rw-r--r--ale_linters/scss/stylelint.vim13
-rw-r--r--ale_linters/sh/shellcheck.vim11
-rw-r--r--ale_linters/sml/smlnj_cm.vim1
-rw-r--r--ale_linters/solidity/solhint.vim1
-rw-r--r--ale_linters/spec/rpmlint.vim17
-rw-r--r--ale_linters/stylus/stylelint.vim14
-rw-r--r--ale_linters/tcl/nagelfar.vim11
-rw-r--r--ale_linters/terraform/tflint.vim12
-rw-r--r--ale_linters/tex/lacheck.vim16
-rw-r--r--ale_linters/thrift/thrift.vim13
-rw-r--r--ale_linters/typescript/tsserver.vim19
-rw-r--r--ale_linters/vim/ale_custom_linting_rules.vim65
-rw-r--r--ale_linters/vue/vls.vim18
-rw-r--r--ale_linters/xml/xmllint.vim12
-rw-r--r--ale_linters/yaml/swaglint.vim17
-rw-r--r--ale_linters/yaml/yamllint.vim16
-rw-r--r--ale_linters/yang/yang_lsp.vim15
-rw-r--r--autoload/ale.vim125
-rw-r--r--autoload/ale/assert.vim70
-rw-r--r--autoload/ale/c.vim175
-rw-r--r--autoload/ale/completion.vim141
-rw-r--r--autoload/ale/cursor.vim102
-rw-r--r--autoload/ale/d.vim16
-rw-r--r--autoload/ale/debugging.vim5
-rw-r--r--autoload/ale/definition.vim74
-rw-r--r--autoload/ale/engine.vim58
-rw-r--r--autoload/ale/engine/ignore.vim4
-rw-r--r--autoload/ale/events.vim16
-rw-r--r--autoload/ale/fix.vim24
-rw-r--r--autoload/ale/fix/registry.vim60
-rw-r--r--autoload/ale/fixers/brittany.vim10
-rw-r--r--autoload/ale/fixers/eslint.vim2
-rw-r--r--autoload/ale/fixers/fixjson.vim1
-rw-r--r--autoload/ale/fixers/generic_python.vim17
-rw-r--r--autoload/ale/fixers/gomod.vim10
-rw-r--r--autoload/ale/fixers/google_java_format.vim10
-rw-r--r--autoload/ale/fixers/hackfmt.vim8
-rw-r--r--autoload/ale/fixers/hfmt.vim2
-rw-r--r--autoload/ale/fixers/hlint.vim13
-rw-r--r--autoload/ale/fixers/importjs.vim5
-rw-r--r--autoload/ale/fixers/jq.vim9
-rw-r--r--autoload/ale/fixers/ocamlformat.vim18
-rw-r--r--autoload/ale/fixers/php_cs_fixer.vim1
-rw-r--r--autoload/ale/fixers/phpcbf.vim1
-rw-r--r--autoload/ale/fixers/prettier.vim42
-rw-r--r--autoload/ale/fixers/puppetlint.vim1
-rw-r--r--autoload/ale/fixers/rubocop.vim13
-rw-r--r--autoload/ale/fixers/scalafmt.vim1
-rw-r--r--autoload/ale/fixers/shfmt.vim18
-rw-r--r--autoload/ale/fixers/sqlfmt.vim13
-rw-r--r--autoload/ale/fixers/stylish_haskell.vim21
-rw-r--r--autoload/ale/fixers/terraform.vim17
-rw-r--r--autoload/ale/fixers/uncrustify.vim16
-rw-r--r--autoload/ale/fixers/xmllint.vim29
-rw-r--r--autoload/ale/go.vim27
-rw-r--r--autoload/ale/handlers/ccls.vim17
-rw-r--r--autoload/ale/handlers/elixir.vim28
-rw-r--r--autoload/ale/handlers/eslint.vim7
-rw-r--r--autoload/ale/handlers/gawk.vim2
-rw-r--r--autoload/ale/handlers/gcc.vim86
-rw-r--r--autoload/ale/handlers/go.vim1
-rw-r--r--autoload/ale/handlers/haskell.vim10
-rw-r--r--autoload/ale/handlers/haskell_stack.vim7
-rw-r--r--autoload/ale/handlers/hlint.vim8
-rw-r--r--autoload/ale/handlers/ols.vim1
-rw-r--r--autoload/ale/handlers/pony.vim1
-rw-r--r--autoload/ale/handlers/redpen.vim11
-rw-r--r--autoload/ale/handlers/rubocop.vim6
-rw-r--r--autoload/ale/handlers/ruby.vim9
-rw-r--r--autoload/ale/handlers/rust.vim10
-rw-r--r--autoload/ale/handlers/sml.vim5
-rw-r--r--autoload/ale/handlers/vale.vim1
-rw-r--r--autoload/ale/hover.vim87
-rw-r--r--autoload/ale/java.vim20
-rw-r--r--autoload/ale/job.vim7
-rw-r--r--autoload/ale/julia.vim19
-rw-r--r--autoload/ale/linter.vim67
-rw-r--r--autoload/ale/list.vim3
-rw-r--r--autoload/ale/loclist_jumping.vim2
-rw-r--r--autoload/ale/lsp.vim464
-rw-r--r--autoload/ale/lsp/message.vim12
-rw-r--r--autoload/ale/lsp/reset.vim2
-rw-r--r--autoload/ale/lsp/response.vim33
-rw-r--r--autoload/ale/lsp_linter.vim62
-rw-r--r--autoload/ale/node.vim5
-rw-r--r--autoload/ale/other_source.vim21
-rw-r--r--autoload/ale/path.vim21
-rw-r--r--autoload/ale/preview.vim7
-rw-r--r--autoload/ale/python.vim8
-rw-r--r--autoload/ale/references.vim60
-rw-r--r--autoload/ale/ruby.vim22
-rw-r--r--autoload/ale/sign.vim2
-rw-r--r--autoload/ale/socket.vim12
-rw-r--r--autoload/ale/symbol.vim109
-rw-r--r--autoload/ale/toggle.vim20
-rw-r--r--autoload/ale/util.vim34
-rw-r--r--autoload/ale/virtualtext.vim136
-rw-r--r--doc/ale-ada.txt25
-rw-r--r--doc/ale-ansible.txt16
-rw-r--r--doc/ale-c.txt101
-rw-r--r--doc/ale-cpp.txt90
-rw-r--r--doc/ale-cs.txt10
-rw-r--r--doc/ale-d.txt23
-rw-r--r--doc/ale-development.txt3
-rw-r--r--doc/ale-dockerfile.txt23
-rw-r--r--doc/ale-elixir.txt33
-rw-r--r--doc/ale-eruby.txt26
-rw-r--r--doc/ale-go.txt94
-rw-r--r--doc/ale-hack.txt51
-rw-r--r--doc/ale-haskell.txt50
-rw-r--r--doc/ale-hcl.txt11
-rw-r--r--doc/ale-html.txt33
-rw-r--r--doc/ale-ispc.txt24
-rw-r--r--doc/ale-java.txt29
-rw-r--r--doc/ale-json.txt7
-rw-r--r--doc/ale-julia.txt20
-rw-r--r--doc/ale-objc.txt56
-rw-r--r--doc/ale-objcpp.txt25
-rw-r--r--doc/ale-ocaml.txt17
-rw-r--r--doc/ale-pawn.txt12
-rw-r--r--doc/ale-perl6.txt43
-rw-r--r--doc/ale-php.txt45
-rw-r--r--doc/ale-prolog.txt56
-rw-r--r--doc/ale-puppet.txt20
-rw-r--r--doc/ale-python.txt111
-rw-r--r--doc/ale-ruby.txt39
-rw-r--r--doc/ale-rust.txt60
-rw-r--r--doc/ale-scala.txt33
-rw-r--r--doc/ale-scss.txt6
-rw-r--r--doc/ale-sql.txt25
-rw-r--r--doc/ale-terraform.txt18
-rw-r--r--doc/ale-thrift.txt2
-rw-r--r--doc/ale-typescript.txt12
-rw-r--r--doc/ale-vala.txt12
-rw-r--r--doc/ale-xml.txt8
-rw-r--r--doc/ale-yaml.txt14
-rw-r--r--doc/ale-yang.txt17
-rw-r--r--doc/ale.txt502
-rw-r--r--plugin/ale.vim24
-rw-r--r--run-tests.bat4
-rw-r--r--test/command_callback/ccls_paths/with_ccls-root/.ccls-root (renamed from test/hack_files/testfile.php)0
-rw-r--r--test/command_callback/ccls_paths/with_ccls/.ccls0
-rw-r--r--test/command_callback/ccls_paths/with_compile_commands_json/compile_commands.json0
-rw-r--r--test/command_callback/cquery_paths/with_compile_commands_json/compile_commands.json0
-rw-r--r--test/command_callback/cquery_paths/with_cquery/.cquery0
-rw-r--r--test/command_callback/elixir_paths/mix_project/lib/app.ex0
-rw-r--r--test/command_callback/elixir_paths/mix_project/mix.exs3
-rw-r--r--test/command_callback/elixir_paths/umbrella_project/apps/app1/lib/app.ex0
-rw-r--r--test/command_callback/elixir_paths/umbrella_project/apps/app1/mix.exs0
-rw-r--r--test/command_callback/elixir_paths/umbrella_project/apps/app2/lib/app.ex0
-rw-r--r--test/command_callback/elixir_paths/umbrella_project/apps/app2/mix.exs0
-rw-r--r--test/command_callback/elixir_paths/umbrella_project/mix.exs0
-rw-r--r--test/command_callback/go_paths/go1/prj1/file.go0
-rw-r--r--test/command_callback/go_paths/go2/prj2/file.go0
-rw-r--r--test/command_callback/julia-languageserver-project/REQUIRE0
-rw-r--r--test/command_callback/julia-languageserver-project/test.jl0
-rw-r--r--test/command_callback/mix_paths/wrapped_project/mix.exs1
-rwxr-xr-xtest/command_callback/psalm-project/vendor/bin/psalm-language-server0
-rw-r--r--test/command_callback/stack_build_paths/stack.yaml0
-rw-r--r--test/command_callback/stack_ghc_paths/stack.yaml0
-rw-r--r--test/command_callback/test_ada_gcc_command_callbacks.vader44
-rw-r--r--test/command_callback/test_ansible_lint_command_callback.vader17
-rw-r--r--test/command_callback/test_brakeman_command_callback.vader17
-rw-r--r--test/command_callback/test_c_ccls_command_callbacks.vader43
-rw-r--r--test/command_callback/test_c_clang_command_callbacks.vader3
-rw-r--r--test/command_callback/test_c_clang_tidy_command_callback.vader7
-rw-r--r--test/command_callback/test_c_cppcheck_command_callbacks.vader2
-rw-r--r--test/command_callback/test_c_cquery_command_callbacks.vader33
-rw-r--r--test/command_callback/test_c_flawfinder_command_callbacks.vader2
-rw-r--r--test/command_callback/test_c_gcc_command_callbacks.vader3
-rw-r--r--test/command_callback/test_c_import_paths.vader223
-rw-r--r--test/command_callback/test_cargo_command_callbacks.vader24
-rw-r--r--test/command_callback/test_clang_tidy_command_callback.vader21
-rw-r--r--test/command_callback/test_cpp_ccls_command_callbacks.vader43
-rw-r--r--test/command_callback/test_cpp_clang_command_callbacks.vader3
-rw-r--r--test/command_callback/test_cpp_clazy_command_callback.vader54
-rw-r--r--test/command_callback/test_cpp_cppcheck_command_callbacks.vader2
-rw-r--r--test/command_callback/test_cpp_cquery_command_callbacks.vader14
-rw-r--r--test/command_callback/test_cpp_gcc_command_callbacks.vader3
-rw-r--r--test/command_callback/test_cs_mcsc_command_callbacks.vader14
-rw-r--r--test/command_callback/test_cuda_nvcc_command_callbacks.vader6
-rw-r--r--test/command_callback/test_d_dls_callbacks.vader19
-rw-r--r--test/command_callback/test_dart_language_server_command_callback.vader8
-rw-r--r--test/command_callback/test_dockerfile_lint_command_callback.vader19
-rw-r--r--test/command_callback/test_elixir_ls_command_callbacks.vader35
-rw-r--r--test/command_callback/test_elixir_mix_command_callbacks.vader18
-rw-r--r--test/command_callback/test_elm_make_command_callback.vader32
-rw-r--r--test/command_callback/test_flake8_command_callback.vader11
-rw-r--r--test/command_callback/test_fsc_command_callback.vader2
-rw-r--r--test/command_callback/test_gawk_command_callback.vader6
-rw-r--r--test/command_callback/test_gfortran_command_callback.vader8
-rw-r--r--test/command_callback/test_gobuild_command_callback.vader37
-rw-r--r--test/command_callback/test_golangci_lint_command_callback.vader38
-rw-r--r--test/command_callback/test_golangserver_command_callback.vader68
-rw-r--r--test/command_callback/test_golint_command_callbacks.vader18
-rw-r--r--test/command_callback/test_gometalinter_command_callback.vader8
-rw-r--r--test/command_callback/test_gosimple_command_callback.vader2
-rw-r--r--test/command_callback/test_gotype_command_callback.vader2
-rw-r--r--test/command_callback/test_govet_command_callback.vader13
-rw-r--r--test/command_callback/test_haml_hamllint_command_callback.vader4
-rw-r--r--test/command_callback/test_haskell_ghc_mod_command_callbacks.vader10
-rw-r--r--test/command_callback/test_haskell_hie_callbacks.vader27
-rw-r--r--test/command_callback/test_haskell_hlint_command_callbacks.vader17
-rw-r--r--test/command_callback/test_haskell_stack_build_command_callback.vader13
-rw-r--r--test/command_callback/test_haskell_stack_ghc_command_callback.vader14
-rw-r--r--test/command_callback/test_html_stylelint_command_callback.vader60
-rw-r--r--test/command_callback/test_ispc_ispc_command_callbacks.vader20
-rw-r--r--test/command_callback/test_javac_command_callback.vader12
-rw-r--r--test/command_callback/test_javalsp_command_callback.vader10
-rw-r--r--test/command_callback/test_javascript_tsserver_command_callback.vader8
-rw-r--r--test/command_callback/test_jshint_command_callback.vader17
-rw-r--r--test/command_callback/test_julia_languageserver_callbacks.vader30
-rw-r--r--test/command_callback/test_kotlin_languageserver_command_callback.vader8
-rw-r--r--test/command_callback/test_lintr_command_callback.vader6
-rw-r--r--test/command_callback/test_luac_command_callback.vader4
-rw-r--r--test/command_callback/test_luacheck_command_callback.vader4
-rw-r--r--test/command_callback/test_mercury_mmc_command_callback.vader6
-rw-r--r--test/command_callback/test_mypy_command_callback.vader26
-rw-r--r--test/command_callback/test_nasm_nasm_command_callbacks.vader6
-rw-r--r--test/command_callback/test_objc_ccls_command_callbacks.vader40
-rw-r--r--test/command_callback/test_perl6_command_callback.vader14
-rw-r--r--test/command_callback/test_php_command_callback.vader15
-rw-r--r--test/command_callback/test_phpcs_command_callback.vader35
-rw-r--r--test/command_callback/test_phpstan_command_callbacks.vader10
-rw-r--r--test/command_callback/test_prospector_command_callback.vader8
-rw-r--r--test/command_callback/test_psalm_command_callbacks.vader29
-rw-r--r--test/command_callback/test_pycodestyle_command_callback.vader7
-rw-r--r--test/command_callback/test_pyflakes_command_callback.vader7
-rw-r--r--test/command_callback/test_pylint_command_callback.vader9
-rw-r--r--test/command_callback/test_pyls_command_callback.vader7
-rw-r--r--test/command_callback/test_pyre_command_callback.vader7
-rw-r--r--test/command_callback/test_reek_command_callback.vader30
-rw-r--r--test/command_callback/test_ruby_solargraph.vader44
-rw-r--r--test/command_callback/test_rustc_command_callback.vader4
-rw-r--r--test/command_callback/test_ruumba_command_callback.vader29
-rw-r--r--test/command_callback/test_sasslint_command_callback.vader2
-rw-r--r--test/command_callback/test_scala_sbtserver.vader21
-rw-r--r--test/command_callback/test_scalac_command_callback.vader4
-rw-r--r--test/command_callback/test_scss_stylelint_command_callback.vader31
-rw-r--r--test/command_callback/test_shellcheck_command_callback.vader2
-rw-r--r--test/command_callback/test_staticcheck_command_callback.vader6
-rw-r--r--test/command_callback/test_swaglint_command_callback.vader8
-rw-r--r--test/command_callback/test_terraform_tflint_command_callback.vader9
-rw-r--r--test/command_callback/test_thrift_command_callback.vader10
-rw-r--r--test/command_callback/test_tslint_command_callback.vader6
-rw-r--r--test/command_callback/test_typescript_tsserver_command_callback.vader8
-rw-r--r--test/command_callback/test_yang_lsp_command_callbacks.vader12
-rw-r--r--test/completion/test_completion_events.vader14
-rw-r--r--test/completion/test_completion_filtering.vader26
-rw-r--r--test/completion/test_completion_prefixes.vader20
-rw-r--r--test/completion/test_lsp_completion_messages.vader26
-rw-r--r--test/completion/test_lsp_completion_parsing.vader24
-rw-r--r--test/completion/test_tsserver_completion_parsing.vader18
-rw-r--r--test/fix/test_ale_fix.vader42
-rw-r--r--test/fixers/test_eslint_fixer_callback.vader7
-rw-r--r--test/fixers/test_gomod_fixer_callback.vader24
-rw-r--r--test/fixers/test_goofle_java_format_fixer_callback.vader8
-rw-r--r--test/fixers/test_hackfmt_fixer_callback.vader14
-rw-r--r--test/fixers/test_hlint_fixer_callback.vader20
-rw-r--r--test/fixers/test_importjs_fixer_callback.vader8
-rw-r--r--test/fixers/test_isort_fixer_callback.vader4
-rw-r--r--test/fixers/test_jq_fixer_callback.vader14
-rw-r--r--test/fixers/test_ocamlformat_fixer_callback.vader38
-rw-r--r--test/fixers/test_prettier_eslint_fixer.callback.vader4
-rw-r--r--test/fixers/test_prettier_fixer_callback.vader70
-rw-r--r--test/fixers/test_python_add_blank_lines_fixer.vader56
-rw-r--r--test/fixers/test_rubocop_fixer_callback.vader6
-rw-r--r--test/fixers/test_shfmt_fixer_callback.vader37
-rw-r--r--test/fixers/test_sqlfmt_fixer_callback.vader26
-rw-r--r--test/fixers/test_stylish_haskell_fixer_callback.vader24
-rw-r--r--test/fixers/test_terraform_fmt_fixer_callback.vader34
-rw-r--r--test/fixers/test_uncrustify_fixer_callback.vader36
-rw-r--r--test/fixers/test_xmllint_fixer_callback.vader46
-rw-r--r--test/go_files/go.mod1
-rw-r--r--test/handler/test_ada_gcc_handler.vader36
-rw-r--r--test/handler/test_checkstyle_handler.vader13
-rw-r--r--test/handler/test_clang_handler.vader15
-rw-r--r--test/handler/test_credo_handler.vader26
-rw-r--r--test/handler/test_dockerfile_lint_handler.vader108
-rw-r--r--test/handler/test_eslint_handler.vader12
-rw-r--r--test/handler/test_flake8_handler.vader14
-rw-r--r--test/handler/test_gcc_handler.vader81
-rw-r--r--test/handler/test_gitlint_handler.vader19
-rw-r--r--test/handler/test_golangci_lint_handler.vader55
-rw-r--r--test/handler/test_haskell_stack_handler.vader7
-rw-r--r--test/handler/test_ispc_ispc_handler.vader90
-rw-r--r--test/handler/test_perl6_handler.vader277
-rw-r--r--test/handler/test_perl_handler.vader5
-rw-r--r--test/handler/test_pmd_handler.vader15
-rw-r--r--test/handler/test_rust_handler.vader145
-rw-r--r--test/handler/test_swipl_handler.vader95
-rw-r--r--test/handler/test_vulture_handler.vader92
-rw-r--r--test/lsp/test_did_save_event.vader15
-rw-r--r--test/lsp/test_lsp_client_messages.vader27
-rw-r--r--test/lsp/test_lsp_command_formatting.vader6
-rw-r--r--test/lsp/test_lsp_connections.vader54
-rw-r--r--test/lsp/test_other_initialize_message_handling.vader132
-rw-r--r--test/lsp/test_read_lsp_diagnostics.vader57
-rw-r--r--test/lsp/test_update_config.vader17
-rw-r--r--test/ocaml-test-files/testfile.ml0
-rw-r--r--test/python_fixtures/pipenv/Pipfile.lock0
-rw-r--r--test/ruby_fixtures/valid_ruby_app1/Rakefile0
-rw-r--r--test/ruby_fixtures/valid_ruby_app1/lib/file.rb0
-rw-r--r--test/ruby_fixtures/valid_ruby_app2/Gemfile0
-rw-r--r--test/ruby_fixtures/valid_ruby_app2/lib/file.rb0
-rw-r--r--test/ruby_fixtures/valid_ruby_app3/.solargraph.yml0
-rw-r--r--test/ruby_fixtures/valid_ruby_app3/lib/file.rb0
-rw-r--r--test/scala_fixtures/invalid_sbt_project/Main.scala0
-rw-r--r--test/scala_fixtures/valid_sbt_project/Main.scala0
-rw-r--r--test/scala_fixtures/valid_sbt_project/build.sbt0
-rwxr-xr-xtest/script/block-padding-checker117
-rwxr-xr-xtest/script/custom-linting-rules38
-rw-r--r--test/smoke_test.vader8
-rw-r--r--test/test_ale_info.vader5
-rw-r--r--test/test_alejobstarted_autocmd.vader11
-rw-r--r--test/test_alelint_autocmd.vader19
-rw-r--r--test/test_autocmd_commands.vader17
-rw-r--r--test/test_c_flag_parsing.vader179
-rw-r--r--test/test_c_import_paths.vader252
-rw-r--r--test/test_c_parse_makefile.vader184
-rw-r--r--test/test_checkingbuffer_autocmd.vader6
-rw-r--r--test/test_command_chain.vader2
-rw-r--r--test/test_elm_executable_detection.vader36
-rw-r--r--test/test_engine_lsp_response_handling.vader6
-rw-r--r--test/test_find_references.vader22
-rw-r--r--test/test_go_to_definition.vader44
-rw-r--r--test/test_gradle_build_classpath_command.vader8
-rw-r--r--test/test_history_saving.vader6
-rw-r--r--test/test_ignoring_linters.vader9
-rw-r--r--test/test_lint_file_linters.vader1
-rw-r--r--test/test_linter_defintion_processing.vader54
-rw-r--r--test/test_linter_retrieval.vader11
-rw-r--r--test/test_linter_type_mapping.vader12
-rw-r--r--test/test_linting_blacklist.vader2
-rw-r--r--test/test_loclist_corrections.vader45
-rw-r--r--test/test_other_sources.vader153
-rw-r--r--test/test_path_dirname.vader8
-rw-r--r--test/test_phpcs_executable_detection.vader39
-rw-r--r--test/test_python_pipenv.vader13
-rw-r--r--test/test_redundant_tsserver_rendering_avoided.vader136
-rw-r--r--test/test_sandbox_execution.vader1
-rw-r--r--test/test_setting_problems_found_in_previous_buffers.vader4
-rw-r--r--test/test_should_do_nothing_conditions.vader18
-rw-r--r--test/test_symbol_search.vader173
-rw-r--r--test/test_temporary_file_management.vader4
-rw-r--r--test/test_tflint_config_detection.vader18
-rw-r--r--test/test_verilog_verilator_options.vader2
-rw-r--r--test/test_writefile_function.vader21
-rw-r--r--test/util/test_cd_string_commands.vader6
496 files changed, 10013 insertions, 2945 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index e59f8326..f2e7474c 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -3,7 +3,7 @@
Have fun, and work on whatever floats your boat. Take It Easy :tm:.
For help with contributing to ALE, see `:help ale-development` in Vim, or view
-the help file online [here](/w0rp/ale/blob/master/doc/ale-development.txt).
+the help file online [here](/doc/ale-development.txt).
## Creating Issues
diff --git a/.github/ISSUE_TEMPLATE/report-a-bug.md b/.github/ISSUE_TEMPLATE/report-a-bug.md
index cf335c11..e617893f 100644
--- a/.github/ISSUE_TEMPLATE/report-a-bug.md
+++ b/.github/ISSUE_TEMPLATE/report-a-bug.md
@@ -23,14 +23,12 @@ about: Report a bug with ALE.
Operating System: <!-- Describe your operating system version. -->
-### :ALEInfo
-
-<!-- Paste the output of :ALEInfo here. Try :ALEInfoToClipboard -->
-<!-- Make sure to run :ALEInfo from the buffer where the bug occurred. -->
-
## What went wrong
-<!-- Describe what went wrong here. -->
+<!-- Describe what went wrong here. Be specific. -->
+
+Something went wrong in specifically this place, and I also searched through
+both open and closed issues for the same problem before reporting a bug here.
## Reproducing the bug
@@ -38,3 +36,9 @@ Operating System: <!-- Describe your operating system version. -->
1. I did this.
2. Then this happened.
+
+### :ALEInfo
+
+<!-- Paste the output of :ALEInfo here. Try :ALEInfoToClipboard -->
+<!-- Make sure to run :ALEInfo from the buffer where the bug occurred. -->
+<!-- Read the output. You might figure out what went wrong yourself. -->
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 8e1b5c57..a73f67ba 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -6,3 +6,8 @@ Before creating a pull request, do the following.
Have fun!
-->
+
+Where are the tests? Have you added tests? Have you updated the tests? Read the
+comment above and the documentation referenced in it first. Write tests!
+
+Seriously, read `:help ale-development` and write tests.
diff --git a/README.md b/README.md
index 66a30bf2..ad55e255 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ ALE (Asynchronous Lint Engine) is a plugin for providing linting in NeoVim
0.2.0+ and Vim 8 while you edit your text files, and acts as a Vim
[Language Server Protocol](https://langserver.org/) client.
-![linting example](img/example.gif?raw=true)
+<img src="img/example.gif?raw=true" alt="A linting example with the darkspectrum color scheme in GVim." title="A linting example with the darkspectrum color scheme in GVim.">
ALE makes use of NeoVim and Vim 8 job control functions and timers to
run linters on the contents of text buffers and return errors as
@@ -26,14 +26,18 @@ features, including:
* Diagnostics (via Language Server Protocol linters)
* Go To Definition (`:ALEGoToDefinition`)
-* Completion (`let g:ale_completion_enabled = 1`)
+* Completion (`let g:ale_completion_enabled = 1` before ALE is loaded)
* Finding references (`:ALEFindReferences`)
* Hover information (`:ALEHover`)
+* Symbol search (`:ALESymbolSearch`)
If you don't care about Language Server Protocol, ALE won't load any of the code
for working with it unless needed. One of ALE's general missions is that you
won't pay for the features that you don't use.
+If you enjoy this plugin, feel free to contribute or check out the author's
+other content at [w0rp.com](https://w0rp.com).
+
## Table of Contents
1. [Supported Languages and Tools](#supported-languages)
@@ -44,10 +48,12 @@ won't pay for the features that you don't use.
4. [Go To Definition](#usage-go-to-definition)
5. [Find References](#usage-find-references)
6. [Hovering](#usage-hover)
+ 7. [Symbol Search](#usage-symbol-search)
3. [Installation](#installation)
1. [Installation with Vim package management](#standard-installation)
2. [Installation with Pathogen](#installation-with-pathogen)
3. [Installation with Vundle](#installation-with-vundle)
+ 4. [Installation with Vim-Plug](#installation-with-vim-plug)
4. [Contributing](#contributing)
5. [FAQ](#faq)
1. [How do I disable particular linters?](#faq-disable-linters)
@@ -62,10 +68,11 @@ won't pay for the features that you don't use.
10. [How can I run linters only when I save files?](#faq-lint-on-save)
11. [How can I use the quickfix list instead of the loclist?](#faq-quickfix)
12. [How can I check JSX files with both stylelint and eslint?](#faq-jsx-stylelint-eslint)
- 13. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
- 14. [How can I configure my C or C++ project?](#faq-c-configuration)
- 15. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
- 16. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
+ 13. [How can I check Vue files with ESLint?](#faq-vue-eslint)
+ 14. [Will this plugin eat all of my laptop battery power?](#faq-my-battery-is-sad)
+ 15. [How can I configure my C or C++ project?](#faq-c-configuration)
+ 16. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
+ 17. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
<a name="supported-languages"></a>
@@ -90,17 +97,18 @@ formatting.
| Language | Tools |
| -------- | ----- |
+| Ada | [gcc](https://gcc.gnu.org) |
| ASM | [gcc](https://gcc.gnu.org) |
| Ansible | [ansible-lint](https://github.com/willthames/ansible-lint) |
| API Blueprint | [drafter](https://github.com/apiaryio/drafter) |
-| AsciiDoc | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [write-good](https://github.com/btford/write-good) |
+| AsciiDoc | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [write-good](https://github.com/btford/write-good), [vale](https://github.com/ValeLint/vale) |
| Awk | [gawk](https://www.gnu.org/software/gawk/)|
| Bash | [language-server](https://github.com/mads-hartmann/bash-language-server), shell [-n flag](https://www.gnu.org/software/bash/manual/bash.html#index-set), [shellcheck](https://www.shellcheck.net/), [shfmt](https://github.com/mvdan/sh) |
| Bourne Shell | shell [-n flag](http://linux.die.net/man/1/sh), [shellcheck](https://www.shellcheck.net/), [shfmt](https://github.com/mvdan/sh) |
-| C | [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [clang](http://clang.llvm.org/), [clangd](https://clang.llvm.org/extra/clangd.html), [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/) |
-| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) !!, [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) !!, [cquery](https://github.com/cquery-project/cquery), [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/) |
+| C | [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint), [clang](http://clang.llvm.org/), [clangd](https://clang.llvm.org/extra/clangd.html), [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [cquery](https://github.com/cquery-project/cquery), [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/), [uncrustify](https://github.com/uncrustify/uncrustify), [ccls](https://github.com/MaskRay/ccls) |
+| C++ (filetype cpp) | [clang](http://clang.llvm.org/), [clangd](https://clang.llvm.org/extra/clangd.html), [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) !!, [clangtidy](http://clang.llvm.org/extra/clang-tidy/) !!, [clang-format](https://clang.llvm.org/docs/ClangFormat.html), [clazy](https://github.com/KDE/clazy) !!, [cppcheck](http://cppcheck.sourceforge.net), [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) !!, [cquery](https://github.com/cquery-project/cquery), [flawfinder](https://www.dwheeler.com/flawfinder/), [gcc](https://gcc.gnu.org/), [uncrustify](https://github.com/uncrustify/uncrustify), [ccls](https://github.com/MaskRay/ccls) |
| CUDA | [nvcc](http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html) |
-| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) see:`help ale-cs-mcs` for details, [mcsc](http://www.mono-project.com/docs/about-mono/languages/csharp/) !! see:`help ale-cs-mcsc` for details and configuration|
+| C# | [mcs](http://www.mono-project.com/docs/about-mono/languages/csharp/) see:`help ale-cs-mcs` for details, [mcsc](http://www.mono-project.com/docs/about-mono/languages/csharp/) !! see:`help ale-cs-mcsc` for details and configuration, [uncrustify](https://github.com/uncrustify/uncrustify) |
| Chef | [foodcritic](http://www.foodcritic.io/) |
| Clojure | [joker](https://github.com/candid82/joker) |
| CloudFormation | [cfn-python-lint](https://github.com/awslabs/cfn-python-lint) |
@@ -110,13 +118,13 @@ formatting.
| CSS | [csslint](http://csslint.net/), [prettier](https://github.com/prettier/prettier), [stylelint](https://github.com/stylelint/stylelint) |
| Cucumber | [cucumber](https://cucumber.io/) |
| Cython (pyrex filetype) | [cython](http://cython.org/) |
-| D | [dmd](https://dlang.org/dmd-linux.html) |
+| D | [dls](https://github.com/d-language-server/dls), [dmd](https://dlang.org/dmd-linux.html), [uncrustify](https://github.com/uncrustify/uncrustify) |
| Dafny | [dafny](https://rise4fun.com/Dafny) !! |
| Dart | [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) !!, [language_server](https://github.com/natebosch/dart_language_server), [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) |
-| Dockerfile | [hadolint](https://github.com/hadolint/hadolint) |
-| Elixir | [credo](https://github.com/rrrene/credo), [dialyxir](https://github.com/jeremyjh/dialyxir), [dogma](https://github.com/lpil/dogma), [mix](https://hexdocs.pm/mix/Mix.html) !!|
+| Dockerfile | [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint), [hadolint](https://github.com/hadolint/hadolint) |
+| Elixir | [credo](https://github.com/rrrene/credo), [dialyxir](https://github.com/jeremyjh/dialyxir), [dogma](https://github.com/lpil/dogma), [mix](https://hexdocs.pm/mix/Mix.html) !!, [elixir-ls](https://github.com/JakeBecker/elixir-ls) |
| Elm | [elm-format](https://github.com/avh4/elm-format), [elm-make](https://github.com/elm-lang/elm-make) |
-| Erb | [erb](https://apidock.com/ruby/ERB), [erubi](https://github.com/jeremyevans/erubi), [erubis](https://github.com/kwatch/erubis) |
+| Erb | [erb](https://apidock.com/ruby/ERB), [erubi](https://github.com/jeremyevans/erubi), [erubis](https://github.com/kwatch/erubis), [ruumba](https://github.com/ericqweinstein/ruumba) |
| Erlang | [erlc](http://erlang.org/doc/man/erlc.html), [SyntaxErl](https://github.com/ten0s/syntaxerl) |
| Fish | fish [-n flag](https://linux.die.net/man/1/fish)
| Fortran | [gcc](https://gcc.gnu.org/), [language_server](https://github.com/hansec/fortran-language-server) |
@@ -124,16 +132,20 @@ formatting.
| FusionScript | [fusion-lint](https://github.com/RyanSquared/fusionscript) |
| Git Commit Messages | [gitlint](https://github.com/jorisroovers/gitlint) |
| GLSL | [glslang](https://github.com/KhronosGroup/glslang), [glslls](https://github.com/svenstaro/glsl-language-server) |
-| Go | [gofmt](https://golang.org/cmd/gofmt/), [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports), [go vet](https://golang.org/cmd/vet/) !!, [golint](https://godoc.org/github.com/golang/lint), [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype) !!, [gometalinter](https://github.com/alecthomas/gometalinter) !!, [go build](https://golang.org/cmd/go/) !!, [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) !!, [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) !! |
+| Go | [gofmt](https://golang.org/cmd/gofmt/), [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports), [go mod](https://golang.org/cmd/go/) !!, [go vet](https://golang.org/cmd/vet/) !!, [golint](https://godoc.org/github.com/golang/lint), [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype) !!, [gometalinter](https://github.com/alecthomas/gometalinter) !!, [go build](https://golang.org/cmd/go/) !!, [gosimple](https://github.com/dominikh/go-tools/tree/master/cmd/gosimple) !!, [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) !!, [golangserver](https://github.com/sourcegraph/go-langserver), [golangci-lint](https://github.com/golangci/golangci-lint) !! |
| GraphQL | [eslint](http://eslint.org/), [gqlint](https://github.com/happylinks/gqlint), [prettier](https://github.com/prettier/prettier) |
+| Hack | [hack](http://hacklang.org/), [hackfmt](https://github.com/facebook/hhvm/tree/master/hphp/hack/hackfmt), [hhast](https://github.com/hhvm/hhast) (disabled by default; see `:help ale-integration-hack`) |
| Haml | [haml-lint](https://github.com/brigade/haml-lint) |
| Handlebars | [ember-template-lint](https://github.com/rwjblue/ember-template-lint) |
-| Haskell | [brittany](https://github.com/lspitzner/brittany), [ghc](https://www.haskell.org/ghc/), [cabal-ghc](https://www.haskell.org/cabal/), [stack-ghc](https://haskellstack.org/), [stack-build](https://haskellstack.org/) !!, [ghc-mod](https://github.com/DanielG/ghc-mod), [stack-ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools), [hfmt](https://github.com/danstiner/hfmt) |
-| HTML | [alex](https://github.com/wooorm/alex) !!, [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/), [write-good](https://github.com/btford/write-good) |
+| Haskell | [brittany](https://github.com/lspitzner/brittany), [ghc](https://www.haskell.org/ghc/), [cabal-ghc](https://www.haskell.org/cabal/), [stylish-haskell](https://github.com/jaspervdj/stylish-haskell), [stack-ghc](https://haskellstack.org/), [stack-build](https://haskellstack.org/) !!, [ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools), [hfmt](https://github.com/danstiner/hfmt), [hie](https://github.com/haskell/haskell-ide-engine) |
+| HCL | [terraform-fmt](https://github.com/hashicorp/terraform) |
+| HTML | [alex](https://github.com/wooorm/alex) !!, [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/), [prettier](https://github.com/prettier/prettier), [write-good](https://github.com/btford/write-good) |
| Idris | [idris](http://www.idris-lang.org/) |
-| Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [google-java-format](https://github.com/google/google-java-format), [PMD](https://pmd.github.io/) |
+| ISPC | [ispc](https://ispc.github.io/) !! |
+| Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [google-java-format](https://github.com/google/google-java-format), [PMD](https://pmd.github.io/), [javalsp](https://github.com/georgewfraser/vscode-javac), [uncrustify](https://github.com/uncrustify/uncrustify) |
| JavaScript | [eslint](http://eslint.org/), [flow](https://flowtype.org/), [jscs](http://jscs.info/), [jshint](http://jshint.com/), [prettier](https://github.com/prettier/prettier), [prettier-eslint](https://github.com/prettier/prettier-eslint-cli), [prettier-standard](https://github.com/sheerun/prettier-standard), [standard](http://standardjs.com/), [xo](https://github.com/sindresorhus/xo)
| JSON | [fixjson](https://github.com/rhysd/fixjson), [jsonlint](http://zaa.ch/jsonlint/), [jq](https://stedolan.github.io/jq/), [prettier](https://github.com/prettier/prettier) |
+| Julia | [languageserver](https://github.com/JuliaEditorSupport/LanguageServer.jl) |
| Kotlin | [kotlinc](https://kotlinlang.org) !!, [ktlint](https://ktlint.github.io) !!, [languageserver](https://github.com/fwcd/KotlinLanguageServer) see `:help ale-integration-kotlin` for configuration instructions |
| LaTeX | [alex](https://github.com/wooorm/alex) !!, [chktex](http://www.nongnu.org/chktex/), [lacheck](https://www.ctan.org/pkg/lacheck), [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [vale](https://github.com/ValeLint/vale), [write-good](https://github.com/btford/write-good) |
| Less | [lessc](https://www.npmjs.com/package/less), [prettier](https://github.com/prettier/prettier), [stylelint](https://github.com/stylelint/stylelint) |
@@ -148,48 +160,53 @@ formatting.
| Nim | [nim check](https://nim-lang.org/docs/nimc.html) !! |
| nix | [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate) |
| nroff | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good)|
-| Objective-C | [clang](http://clang.llvm.org/) |
-| Objective-C++ | [clang](http://clang.llvm.org/) |
-| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions, [ols](https://github.com/freebroccolo/ocaml-language-server) |
+| Objective-C | [clang](http://clang.llvm.org/), [clangd](https://clang.llvm.org/extra/clangd.html), [uncrustify](https://github.com/uncrustify/uncrustify), [ccls](https://github.com/MaskRay/ccls) |
+| Objective-C++ | [clang](http://clang.llvm.org/), [clangd](https://clang.llvm.org/extra/clangd.html), [uncrustify](https://github.com/uncrustify/uncrustify) |
+| OCaml | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions, [ols](https://github.com/freebroccolo/ocaml-language-server), [ocamlformat](https://github.com/ocaml-ppx/ocamlformat) |
+| Pawn | [uncrustify](https://github.com/uncrustify/uncrustify) |
| Perl | [perl -c](https://perl.org/), [perl-critic](https://metacpan.org/pod/Perl::Critic), [perltidy](https://metacpan.org/pod/distribution/Perl-Tidy/bin/perltidy) |
-| PHP | [hack](http://hacklang.org/), [hackfmt](https://github.com/facebook/flow/tree/master/hack/hackfmt), [langserver](https://github.com/felixfbecker/php-language-server), [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions, [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer), [php-cs-fixer](http://cs.sensiolabs.org/) |
+| Perl6 | [perl6 -c](https://perl6.org) |
+| PHP | [langserver](https://github.com/felixfbecker/php-language-server), [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions, [php -l](https://secure.php.net/), [phpcs](https://github.com/squizlabs/PHP_CodeSniffer), [phpmd](https://phpmd.org), [phpstan](https://github.com/phpstan/phpstan), [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer), [php-cs-fixer](http://cs.sensiolabs.org/), [psalm](https://getpsalm.org) !! |
| PO | [alex](https://github.com/wooorm/alex) !!, [msgfmt](https://www.gnu.org/software/gettext/manual/html_node/msgfmt-Invocation.html), [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) |
| Pod | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) |
| Pony | [ponyc](https://github.com/ponylang/ponyc) |
+| Prolog | [swipl](https://github.com/SWI-Prolog/swipl-devel) |
| proto | [protoc-gen-lint](https://github.com/ckaznocha/protoc-gen-lint) |
| Pug | [pug-lint](https://github.com/pugjs/pug-lint) |
| Puppet | [languageserver](https://github.com/lingua-pupuli/puppet-editor-services), [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) |
-| Python | [autopep8](https://github.com/hhatto/autopep8), [black](https://github.com/ambv/black), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [prospector](http://github.com/landscapeio/prospector), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pyls](https://github.com/palantir/python-language-server), [pyre](https://github.com/facebook/pyre-check), [pylint](https://www.pylint.org/) !!, [yapf](https://github.com/google/yapf) |
+| Python | [autopep8](https://github.com/hhatto/autopep8), [black](https://github.com/ambv/black), [flake8](http://flake8.pycqa.org/en/latest/), [isort](https://github.com/timothycrosley/isort), [mypy](http://mypy-lang.org/), [prospector](https://github.com/PyCQA/prospector), [pycodestyle](https://github.com/PyCQA/pycodestyle), [pyls](https://github.com/palantir/python-language-server), [pyre](https://github.com/facebook/pyre-check), [pylint](https://www.pylint.org/) !!, [vulture](https://github.com/jendrikseipp/vulture) !!, [yapf](https://github.com/google/yapf) |
| QML | [qmlfmt](https://github.com/jesperhh/qmlfmt), [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint) |
| R | [lintr](https://github.com/jimhester/lintr) |
| ReasonML | [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-reasonml-ols` for configuration instructions, [ols](https://github.com/freebroccolo/ocaml-language-server), [refmt](https://github.com/reasonml/reason-cli) |
| reStructuredText | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [rstcheck](https://github.com/myint/rstcheck), [vale](https://github.com/ValeLint/vale), [write-good](https://github.com/btford/write-good) |
| Re:VIEW | [redpen](http://redpen.cc/) |
| RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) (disabled by default; see `:help ale-integration-spec`) |
-| Ruby | [brakeman](http://brakemanscanner.org/) !!, [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) !!, [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org), [rufo](https://github.com/ruby-formatter/rufo) |
-| Rust | cargo !! (see `:help ale-integration-rust` for configuration instructions), [rls](https://github.com/rust-lang-nursery/rls), [rustc](https://www.rust-lang.org/), [rustfmt](https://github.com/rust-lang-nursery/rustfmt) |
+| Ruby | [brakeman](http://brakemanscanner.org/) !!, [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) !!, [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org), [rufo](https://github.com/ruby-formatter/rufo), [solargraph](https://solargraph.org) |
+| Rust | [cargo](https://github.com/rust-lang/cargo) !! (see `:help ale-integration-rust` for configuration instructions), [rls](https://github.com/rust-lang-nursery/rls), [rustc](https://www.rust-lang.org/), [rustfmt](https://github.com/rust-lang-nursery/rustfmt) |
| SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) |
| SCSS | [prettier](https://github.com/prettier/prettier), [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) |
-| Scala | [fsc](https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/tools/fsc.html), [scalac](http://scala-lang.org), [scalafmt](https://scalameta.org/scalafmt/), [scalastyle](http://www.scalastyle.org) |
+| Scala | [fsc](https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/tools/fsc.html), [sbtserver](https://www.scala-sbt.org/1.x/docs/sbt-server.html), [scalac](http://scala-lang.org), [scalafmt](https://scalameta.org/scalafmt/), [scalastyle](http://www.scalastyle.org)|
| Slim | [slim-lint](https://github.com/sds/slim-lint) |
| SML | [smlnj](http://www.smlnj.org/) |
| Solidity | [solhint](https://github.com/protofire/solhint), [solium](https://github.com/duaraghav8/Solium) |
| Stylus | [stylelint](https://github.com/stylelint/stylelint) |
-| SQL | [sqlint](https://github.com/purcell/sqlint) |
+| SQL | [sqlint](https://github.com/purcell/sqlint), [sqlfmt](https://github.com/jackc/sqlfmt) |
| Swift | [swiftlint](https://github.com/realm/SwiftLint), [swiftformat](https://github.com/nicklockwood/SwiftFormat) |
| Tcl | [nagelfar](http://nagelfar.sourceforge.net) !! |
-| Terraform | [tflint](https://github.com/wata727/tflint) |
+| Terraform | [fmt](https://github.com/hashicorp/terraform), [tflint](https://github.com/wata727/tflint) |
| Texinfo | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good)|
| Text^ | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [redpen](http://redpen.cc/), [textlint](https://textlint.github.io/), [vale](https://github.com/ValeLint/vale), [write-good](https://github.com/btford/write-good) |
| Thrift | [thrift](http://thrift.apache.org/) |
-| TypeScript | [eslint](http://eslint.org/), [prettier](https://github.com/prettier/prettier), [tslint](https://github.com/palantir/tslint), tsserver, typecheck |
+| TypeScript | [eslint](http://eslint.org/), [prettier](https://github.com/prettier/prettier), [tslint](https://github.com/palantir/tslint), [tsserver](https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-%28tsserver%29), typecheck |
+| VALA | [uncrustify](https://github.com/uncrustify/uncrustify) |
| Verilog | [iverilog](https://github.com/steveicarus/iverilog), [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) |
| Vim | [vint](https://github.com/Kuniwak/vint) |
| Vim help^ | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) |
| Vue | [prettier](https://github.com/prettier/prettier), [vls](https://github.com/vuejs/vetur/tree/master/server) |
| XHTML | [alex](https://github.com/wooorm/alex) !!, [proselint](http://proselint.com/), [write-good](https://github.com/btford/write-good) |
| XML | [xmllint](http://xmlsoft.org/xmllint.html) |
-| YAML | [swaglint](https://github.com/byCedric/swaglint), [yamllint](https://yamllint.readthedocs.io/) |
+| YAML | [prettier](https://github.com/prettier/prettier), [swaglint](https://github.com/byCedric/swaglint), [yamllint](https://yamllint.readthedocs.io/) |
+| YANG | [yang-lsp](https://github.com/theia-ide/yang-lsp) |
<a name="usage"></a>
@@ -229,12 +246,18 @@ let b:ale_fixers = ['prettier', 'eslint']
let b:ale_fixers = {'javascript': ['prettier', 'eslint']}
```
-You can also configure your fixers from vimrc using `g:ale_fixers`, before
-or after ALE has been loaded.
+You can also configure your fixers from vimrc using `g:ale_fixers`, before or
+after ALE has been loaded.
+
+A `*` in place of the filetype will apply a List of fixers to all files which
+do not match some filetype in the Dictionary.
+
+Note that using a plain List for `g:ale_fixers` is not supported.
```vim
" In ~/.vim/vimrc, or somewhere similar.
let g:ale_fixers = {
+\ '*': ['remove_trailing_lines', 'trim_whitespace'],
\ 'javascript': ['eslint'],
\}
```
@@ -263,6 +286,7 @@ Protocol linters, or from `tsserver` for TypeScript.
```vim
" Enable completion where available.
+" This setting must be set before ALE is loaded.
let g:ale_completion_enabled = 1
```
@@ -296,11 +320,24 @@ ALE supports "hover" information for printing brief information about symbols at
the cursor taken from Language Server Protocol linters and `tsserver` with the
`ALEHover` command.
-On vim/gvim with `balloon` support you can see the information in a tooltip
-that appears under the mouse when you mouseover a symbol.
+The information can be displayed in a `balloon` tooltip in Vim or GVim by
+hovering your mouse over symbols. Mouse hovering is enabled by default in GVim,
+and needs to be configured for Vim 8.1+ in terminals.
See `:help ale-hover` for more information.
+<a name="usage-symbol-search"></a>
+
+### 2.vii Symbol Search
+
+ALE supports searching for workspace symbols via Language Server Protocol
+linters with the `ALESymbolSearch` command.
+
+Search queries can be performed to find functions, types, and more which are
+similar to a given query string.
+
+See `:help ale-symbol-search` for more information.
+
<a name="installation"></a>
## 3. Installation
@@ -384,6 +421,18 @@ Plugin 'w0rp/ale'
See the Vundle documentation for more information.
+<a name="installation-with-vim-plug"></a>
+
+### 3.iiii. Installation with Vim-Plug
+
+You can install this plugin using [Vim-Plug](https://github.com/junegunn/vim-plug)
+by adding the GitHub path for this repository to your `~/.vimrc`
+and running `:PlugInstall`.
+
+```vim
+Plug 'w0rp/ale'
+```
+
<a name="contributing"></a>
## 4. Contributing
@@ -702,16 +751,16 @@ options in a jsx.vim ftplugin file.
```vim
" In ~/.vim/ftplugin/jsx.vim, or somewhere similar.
+let b:ale_linter_aliases = ['css', 'javascript']
let b:ale_linters = ['stylelint', 'eslint']
-let b:ale_linter_aliases = ['css']
```
Or if you want, you can configure the linters from your vimrc file.
```vim
" In ~/.vim/vimrc, or somewhere similar.
+let g:ale_linter_aliases = {'jsx': ['css, 'javascript']}
let g:ale_linters = {'jsx': ['stylelint', 'eslint']}
-let g:ale_linter_aliases = {'jsx': 'css'}
```
ALE will alias the `jsx` filetype so it uses the `css` filetype linters, and
@@ -719,9 +768,40 @@ use the original Array of selected linters for `jsx` from the `g:ale_linters`
object. All available linters will be used for the filetype `javascript`, and
no linter will be run twice for the same file.
+<a name="faq-vue-eslint"></a>
+
+### 5.xiii. How can I check Vue files with ESLint?
+
+To check Vue files with ESLint, your ESLint project configuration file must be
+configured to use the [Vue plugin](https://github.com/vuejs/eslint-plugin-vue).
+After that, you need to configure ALE so it will run the JavaScript ESLint
+linter on your files. The settings you need are similar to the settings needed
+for checking JSX code with both stylelint and ESLint, in the previous section.
+
+```vim
+" In ~/.vim/ftplugin/vue.vim, or somewhere similar.
+
+" Run both javascript and vue linters for vue files.
+let b:ale_linter_aliases = ['javascript', 'vue']
+" Select the eslint and vls linters.
+let b:ale_linters = ['eslint', 'vls']
+```
+
+Run `:ALEInfo` to see which linters are available after telling ALE to run
+JavaScript linters on Vue files. Not all linters support checking Vue files.
+
+If you don't want to configure your linters in ftplugin files for some reason,
+you can configure them from your vimrc file instead.
+
+```vim
+" In ~/.vim/vimrc, or somewhere similar.
+let g:ale_linter_aliases = {'vue': ['vue', 'javascript']}
+let g:ale_linters = {'vue': ['eslint', 'vls']}
+```
+
<a name="faq-my-battery-is-sad"></a>
-### 5.xiii. Will this plugin eat all of my laptop battery power?
+### 5.xiv. Will this plugin eat all of my laptop battery power?
ALE takes advantage of the power of various tools to check your code. This of
course means that CPU time will be used to continuously check your code. If you
@@ -746,7 +826,7 @@ including the option `g:ale_lint_on_enter`, and you can run ALE manually with
<a name="faq-c-configuration"></a>
-### 5.xiv. How can I configure my C or C++ project?
+### 5.xv. How can I configure my C or C++ project?
The structure of C and C++ projects varies wildly from project to project, with
many different build tools being used for building them, and many different
@@ -772,7 +852,7 @@ used for executing local vimrc files which can be shared in your project.
<a name="faq-buffer-configuration"></a>
-### 5.xv. How can I configure ALE differently for different buffers?
+### 5.xvi. How can I configure ALE differently for different buffers?
ALE offers various ways to configure which linters or fixers are run, and
other settings. For the majority of ALE's settings, they can either be
@@ -808,7 +888,7 @@ Buffer-local variables for settings always override the global settings.
<a name="faq-list-window-height"></a>
-### 5.xvi. How can I configure the height of the list in which ALE displays errors?
+### 5.xvii. How can I configure the height of the list in which ALE displays errors?
To set a default height for the error list, use the `g:ale_list_window_size` variable.
diff --git a/ale_linters/ada/gcc.vim b/ale_linters/ada/gcc.vim
new file mode 100644
index 00000000..d6f973ae
--- /dev/null
+++ b/ale_linters/ada/gcc.vim
@@ -0,0 +1,54 @@
+" Author: Martino Pilia <martino.pilia@gmail.com>
+" Description: Lint Ada files with GCC
+
+call ale#Set('ada_gcc_executable', 'gcc')
+
+" -gnatwa: activate most optional warnings
+" -gnatq: try semantic analysis even if syntax errors have been found
+call ale#Set('ada_gcc_options', '-gnatwa -gnatq')
+
+function! ale_linters#ada#gcc#GetCommand(buffer) abort
+ " Build a suitable output file name. The output file is specified because
+ " the .ali file may be created even if no code generation is attempted.
+ " The output file name must match the source file name (except for the
+ " extension), so here we cannot use the null file as output.
+ let l:tmp_dir = fnamemodify(ale#engine#CreateDirectory(a:buffer), ':p')
+ let l:out_file = l:tmp_dir . fnamemodify(bufname(a:buffer), ':t:r') . '.o'
+
+ " -gnatc: Check syntax and semantics only (no code generation attempted)
+ return '%e -x ada -c -gnatc'
+ \ . ' -o ' . ale#Escape(l:out_file)
+ \ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
+ \ . ' %t'
+endfunction
+
+" For the message format please refer to:
+" https://gcc.gnu.org/onlinedocs/gnat_ugn/Output-and-Error-Message-Control.html
+" https://gcc.gnu.org/onlinedocs/gnat_ugn/Warning-Message-Control.html
+function! ale_linters#ada#gcc#Handle(buffer, lines) abort
+ " Error format: <filename>:<lnum>:<col>: <text>
+ " Warning format: <filename>:<lnum>:<col>: warning: <text>
+ let l:re = '\v(.+):([0-9]+):([0-9]+):\s+(warning:)?\s*(.+)\s*'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:re)
+ call add(l:output, {
+ \ 'bufnr': a:buffer,
+ \ 'lnum': str2nr(l:match[2]),
+ \ 'col': str2nr(l:match[3]),
+ \ 'type': l:match[4] is# 'warning:' ? 'W' : 'E',
+ \ 'text': l:match[5],
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('ada', {
+\ 'name': 'gcc',
+\ 'output_stream': 'stderr',
+\ 'executable_callback': ale#VarFunc('ada_gcc_executable'),
+\ 'command_callback': 'ale_linters#ada#gcc#GetCommand',
+\ 'callback': 'ale_linters#ada#gcc#Handle',
+\})
diff --git a/ale_linters/ansible/ansible_lint.vim b/ale_linters/ansible/ansible_lint.vim
index 0b3b39c8..99fff6c3 100644
--- a/ale_linters/ansible/ansible_lint.vim
+++ b/ale_linters/ansible/ansible_lint.vim
@@ -1,6 +1,12 @@
" Author: Bjorn Neergaard <bjorn@neersighted.com>
" Description: ansible-lint for ansible-yaml files
+call ale#Set('ansible_ansible_lint_executable', 'ansible-lint')
+
+function! ale_linters#ansible#ansible_lint#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'ansible_ansible_lint_executable')
+endfunction
+
function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
for l:line in a:lines[:10]
if match(l:line, '^Traceback') >= 0
@@ -42,8 +48,9 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
endfunction
call ale#linter#Define('ansible', {
-\ 'name': 'ansible',
-\ 'executable': 'ansible',
-\ 'command': 'ansible-lint -p %t',
+\ 'name': 'ansible_lint',
+\ 'aliases': ['ansible', 'ansible-lint'],
+\ 'executable_callback': 'ale_linters#ansible#ansible_lint#GetExecutable',
+\ 'command': '%e -p %t',
\ 'callback': 'ale_linters#ansible#ansible_lint#Handle',
\})
diff --git a/ale_linters/apiblueprint/drafter.vim b/ale_linters/apiblueprint/drafter.vim
index 198709f9..5d40c53a 100644
--- a/ale_linters/apiblueprint/drafter.vim
+++ b/ale_linters/apiblueprint/drafter.vim
@@ -16,10 +16,12 @@ function! ale_linters#apiblueprint#drafter#HandleErrors(buffer, lines) abort
\ 'lnum': l:match[3] + 0,
\ 'col': l:match[4] + 0,
\}
+
if l:match[5] isnot# ''
let l:item.end_lnum = l:match[6] + 0
let l:item.end_col = l:match[7] + 0
endif
+
call add(l:output, l:item)
endfor
diff --git a/ale_linters/asciidoc/vale.vim b/ale_linters/asciidoc/vale.vim
new file mode 100644
index 00000000..b3cf4547
--- /dev/null
+++ b/ale_linters/asciidoc/vale.vim
@@ -0,0 +1,9 @@
+" Author: Jeff Kreeftmeijer https://github.com/jeffkreeftmeijer
+" Description: vale for AsciiDoc files
+
+call ale#linter#Define('asciidoc', {
+\ 'name': 'vale',
+\ 'executable': 'vale',
+\ 'command': 'vale --output=line %t',
+\ 'callback': 'ale#handlers#unix#HandleAsWarning',
+\})
diff --git a/ale_linters/asm/gcc.vim b/ale_linters/asm/gcc.vim
index 4ac876f8..fdd0ee83 100644
--- a/ale_linters/asm/gcc.vim
+++ b/ale_linters/asm/gcc.vim
@@ -4,15 +4,10 @@
call ale#Set('asm_gcc_executable', 'gcc')
call ale#Set('asm_gcc_options', '-Wall')
-function! ale_linters#asm#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'asm_gcc_executable')
-endfunction
-
function! ale_linters#asm#gcc#GetCommand(buffer) abort
- return ale#Escape(ale_linters#asm#gcc#GetExecutable(a:buffer))
- \ . ' -x assembler -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
- \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
+ return '%e -x assembler -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction
function! ale_linters#asm#gcc#Handle(buffer, lines) abort
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('asm', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#asm#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('asm_gcc_executable'),
\ 'command_callback': 'ale_linters#asm#gcc#GetCommand',
\ 'callback': 'ale_linters#asm#gcc#Handle',
\})
diff --git a/ale_linters/awk/gawk.vim b/ale_linters/awk/gawk.vim
index 8b60815f..eb92e45e 100644
--- a/ale_linters/awk/gawk.vim
+++ b/ale_linters/awk/gawk.vim
@@ -1,29 +1,21 @@
" Author: kmarc <korondi.mark@gmail.com>
" Description: This file adds support for using GNU awk with sripts.
-let g:ale_awk_gawk_executable =
-\ get(g:, 'ale_awk_gawk_executable', 'gawk')
-
-let g:ale_awk_gawk_options =
-\ get(g:, 'ale_awk_gawk_options', '')
-
-function! ale_linters#awk#gawk#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'awk_gawk_executable')
-endfunction
+call ale#Set('awk_gawk_executable', 'gawk')
+call ale#Set('awk_gawk_options', '')
function! ale_linters#awk#gawk#GetCommand(buffer) abort
" note the --source 'BEGIN ...' is to prevent
" gawk from attempting to execute the body of the script
" it is linting.
- return ale#Escape(ale_linters#awk#gawk#GetExecutable(a:buffer))
- \ . " --source 'BEGIN { exit } END { exit 1 }'"
+ return '%e --source ' . ale#Escape('BEGIN { exit } END { exit 1 }')
\ . ale#Pad(ale#Var(a:buffer, 'awk_gawk_options'))
- \ . ' ' . '-f %t --lint /dev/null'
+ \ . ' -f %t --lint /dev/null'
endfunction
call ale#linter#Define('awk', {
\ 'name': 'gawk',
-\ 'executable_callback': 'ale_linters#awk#gawk#GetExecutable',
+\ 'executable_callback': ale#VarFunc('awk_gawk_executable'),
\ 'command_callback': 'ale_linters#awk#gawk#GetCommand',
\ 'callback': 'ale#handlers#gawk#HandleGawkFormat',
\ 'output_stream': 'both'
diff --git a/ale_linters/c/ccls.vim b/ale_linters/c/ccls.vim
new file mode 100644
index 00000000..5dc2339f
--- /dev/null
+++ b/ale_linters/c/ccls.vim
@@ -0,0 +1,14 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for C
+
+call ale#Set('c_ccls_executable', 'ccls')
+call ale#Set('c_ccls_init_options', {})
+
+call ale#linter#Define('c', {
+\ 'name': 'ccls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('c_ccls_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
+\ 'initialization_options_callback':ale#VarFunc('c_ccls_init_options'),
+\})
diff --git a/ale_linters/c/clang.vim b/ale_linters/c/clang.vim
index ddec4fcb..f1bd675b 100644
--- a/ale_linters/c/clang.vim
+++ b/ale_linters/c/clang.vim
@@ -4,29 +4,24 @@
call ale#Set('c_clang_executable', 'clang')
call ale#Set('c_clang_options', '-std=c11 -Wall')
-function! ale_linters#c#clang#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_clang_executable')
-endfunction
-
function! ale_linters#c#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#c#clang#GetExecutable(a:buffer))
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'c_clang_options') . ' -'
+ return '%e -S -x c -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#c#clang#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_clang_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#c#clang#GetCommand'}
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/c/clangd.vim b/ale_linters/c/clangd.vim
index 5aa2e221..6cad601a 100644
--- a/ale_linters/c/clangd.vim
+++ b/ale_linters/c/clangd.vim
@@ -6,24 +6,18 @@ call ale#Set('c_clangd_options', '')
function! ale_linters#c#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
- return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
-endfunction
-function! ale_linters#c#clangd#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_clangd_executable')
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#c#clangd#GetCommand(buffer) abort
- let l:executable = ale_linters#c#clangd#GetExecutable(a:buffer)
- let l:options = ale#Var(a:buffer, 'c_clangd_options')
-
- return ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
endfunction
call ale#linter#Define('c', {
\ 'name': 'clangd',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#c#clangd#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_clangd_executable'),
\ 'command_callback': 'ale_linters#c#clangd#GetCommand',
\ 'project_root_callback': 'ale_linters#c#clangd#GetProjectRoot',
\})
diff --git a/ale_linters/c/clangtidy.vim b/ale_linters/c/clangtidy.vim
index 47faa1ef..4f334655 100644
--- a/ale_linters/c/clangtidy.vim
+++ b/ale_linters/c/clangtidy.vim
@@ -10,44 +10,22 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy')
" Consult the check list in clang-tidy's documentation:
" http://clang.llvm.org/extra/clang-tidy/checks/list.html
-call ale#Set('c_clangtidy_checks', ['*'])
+call ale#Set('c_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection.
call ale#Set('c_clangtidy_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#c#clangtidy#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_clangtidy_executable')
-endfunction
-
-function! s:GetBuildDirectory(buffer) abort
- " Don't include build directory for header files, as compile_commands.json
- " files don't consider headers to be translation units, and provide no
- " commands for compiling header files.
- if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
- return ''
- endif
-
- let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
-
- " c_build_dir has the priority if defined
- if !empty(l:build_dir)
- return l:build_dir
- endif
-
- return ale#c#FindCompileCommands(a:buffer)
-endfunction
-
function! ale_linters#c#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'c_clangtidy_checks'), ',')
- let l:build_dir = s:GetBuildDirectory(a:buffer)
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
" Get the extra options if we couldn't find a build directory.
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'c_clangtidy_options')
\ : ''
- return ale#Escape(ale_linters#c#clangtidy#GetExecutable(a:buffer))
+ return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
@@ -57,7 +35,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#c#clangtidy#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_clangtidy_executable'),
\ 'command_callback': 'ale_linters#c#clangtidy#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
diff --git a/ale_linters/c/cppcheck.vim b/ale_linters/c/cppcheck.vim
index 4db93f74..5e8c7936 100644
--- a/ale_linters/c/cppcheck.vim
+++ b/ale_linters/c/cppcheck.vim
@@ -4,10 +4,6 @@
call ale#Set('c_cppcheck_executable', 'cppcheck')
call ale#Set('c_cppcheck_options', '--enable=style')
-function! ale_linters#c#cppcheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_cppcheck_executable')
-endfunction
-
function! ale_linters#c#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json.
"
@@ -23,8 +19,7 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
\ : ''
return l:cd_command
- \ . ale#Escape(ale_linters#c#cppcheck#GetExecutable(a:buffer))
- \ . ' -q --language=c '
+ \ . '%e -q --language=c '
\ . l:compile_commands_option
\ . ale#Var(a:buffer, 'c_cppcheck_options')
\ . ' %t'
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale_linters#c#cppcheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_cppcheck_executable'),
\ 'command_callback': 'ale_linters#c#cppcheck#GetCommand',
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\})
diff --git a/ale_linters/c/cquery.vim b/ale_linters/c/cquery.vim
new file mode 100644
index 00000000..a20782a2
--- /dev/null
+++ b/ale_linters/c/cquery.vim
@@ -0,0 +1,28 @@
+" Author: Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for C
+
+call ale#Set('c_cquery_executable', 'cquery')
+call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery'))
+
+function! ale_linters#c#cquery#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ if empty(l:project_root)
+ let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
+ endif
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort
+ return {'cacheDirectory': ale#Var(a:buffer, 'c_cquery_cache_directory')}
+endfunction
+
+call ale#linter#Define('c', {
+\ 'name': 'cquery',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('c_cquery_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale_linters#c#cquery#GetProjectRoot',
+\ 'initialization_options_callback': 'ale_linters#c#cquery#GetInitializationOptions',
+\})
diff --git a/ale_linters/c/flawfinder.vim b/ale_linters/c/flawfinder.vim
index df6fbebe..7e1f6769 100644
--- a/ale_linters/c/flawfinder.vim
+++ b/ale_linters/c/flawfinder.vim
@@ -6,18 +6,12 @@ call ale#Set('c_flawfinder_options', '')
call ale#Set('c_flawfinder_minlevel', 1)
call ale#Set('c_flawfinder_error_severity', 6)
-function! ale_linters#c#flawfinder#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_flawfinder_executable')
-endfunction
-
function! ale_linters#c#flawfinder#GetCommand(buffer) abort
-
" Set the minimum vulnerability level for flawfinder to bother with
let l:minlevel = ' --minlevel=' . ale#Var(a:buffer, 'c_flawfinder_minlevel')
- return ale#Escape(ale_linters#c#flawfinder#GetExecutable(a:buffer))
- \ . ' -CDQS'
- \ . ale#Var(a:buffer, 'c_flawfinder_options')
+ return '%e -CDQS'
+ \ . ale#Pad(ale#Var(a:buffer, 'c_flawfinder_options'))
\ . l:minlevel
\ . ' %t'
endfunction
@@ -25,7 +19,7 @@ endfunction
call ale#linter#Define('c', {
\ 'name': 'flawfinder',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#c#flawfinder#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_flawfinder_executable'),
\ 'command_callback': 'ale_linters#c#flawfinder#GetCommand',
\ 'callback': 'ale#handlers#flawfinder#HandleFlawfinderFormat',
\})
diff --git a/ale_linters/c/gcc.vim b/ale_linters/c/gcc.vim
index 98563952..60ecb712 100644
--- a/ale_linters/c/gcc.vim
+++ b/ale_linters/c/gcc.vim
@@ -4,29 +4,24 @@
call ale#Set('c_gcc_executable', 'gcc')
call ale#Set('c_gcc_options', '-std=c11 -Wall')
-function! ale_linters#c#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'c_gcc_executable')
-endfunction
-
function! ale_linters#c#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#c#gcc#GetExecutable(a:buffer))
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'c_gcc_options') . ' -'
+ return '%e -S -x c -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#c#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('c_gcc_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#c#gcc#GetCommand'}
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/chef/foodcritic.vim b/ale_linters/chef/foodcritic.vim
index 2c28246c..c86336d6 100644
--- a/ale_linters/chef/foodcritic.vim
+++ b/ale_linters/chef/foodcritic.vim
@@ -6,17 +6,10 @@
call ale#Set('chef_foodcritic_executable', 'foodcritic')
call ale#Set('chef_foodcritic_options', '')
-function! ale_linters#chef#foodcritic#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'chef_foodcritic_executable')
-endfunction
-
function! ale_linters#chef#foodcritic#GetCommand(buffer) abort
- let l:executable = ale_linters#chef#foodcritic#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'chef_foodcritic_options')
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . escape(l:options, '~') : '')
- \ . ' %s'
+ return '%e' . ale#Pad(escape(l:options, '~')) . ' %s'
endfunction
function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort
@@ -41,7 +34,7 @@ endfunction
call ale#linter#Define('chef', {
\ 'name': 'foodcritic',
-\ 'executable_callback': 'ale_linters#chef#foodcritic#GetExecutable',
+\ 'executable_callback': ale#VarFunc('chef_foodcritic_executable'),
\ 'command_callback': 'ale_linters#chef#foodcritic#GetCommand',
\ 'callback': 'ale_linters#chef#foodcritic#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/clojure/joker.vim b/ale_linters/clojure/joker.vim
index e78066fe..2f61148b 100644
--- a/ale_linters/clojure/joker.vim
+++ b/ale_linters/clojure/joker.vim
@@ -9,9 +9,11 @@ function! ale_linters#clojure#joker#HandleJokerFormat(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:type = 'E'
+
if l:match[4] is? 'Parse warning'
let l:type = 'W'
endif
+
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
@@ -27,6 +29,6 @@ call ale#linter#Define('clojure', {
\ 'name': 'joker',
\ 'output_stream': 'stderr',
\ 'executable': 'joker',
-\ 'command': 'joker --lint %t',
+\ 'command': 'joker --working-dir %s --lint %t',
\ 'callback': 'ale_linters#clojure#joker#HandleJokerFormat',
\})
diff --git a/ale_linters/cpp/ccls.vim b/ale_linters/cpp/ccls.vim
new file mode 100644
index 00000000..501fd685
--- /dev/null
+++ b/ale_linters/cpp/ccls.vim
@@ -0,0 +1,14 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for C++
+
+call ale#Set('cpp_ccls_executable', 'ccls')
+call ale#Set('cpp_ccls_init_options', {})
+
+call ale#linter#Define('cpp', {
+\ 'name': 'ccls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('cpp_ccls_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
+\ 'initialization_options_callback': ale#VarFunc('cpp_ccls_init_options'),
+\})
diff --git a/ale_linters/cpp/clang.vim b/ale_linters/cpp/clang.vim
index e8d96187..649c5993 100644
--- a/ale_linters/cpp/clang.vim
+++ b/ale_linters/cpp/clang.vim
@@ -4,29 +4,24 @@
call ale#Set('cpp_clang_executable', 'clang++')
call ale#Set('cpp_clang_options', '-std=c++14 -Wall')
-function! ale_linters#cpp#clang#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_clang_executable')
-endfunction
-
function! ale_linters#cpp#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#cpp#clang#GetExecutable(a:buffer))
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'cpp_clang_options') . ' -'
+ return '%e -S -x c++ -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#clang#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_clang_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#cpp#clang#GetCommand'},
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/cpp/clangcheck.vim b/ale_linters/cpp/clangcheck.vim
index a109d5d3..c66d6702 100644
--- a/ale_linters/cpp/clangcheck.vim
+++ b/ale_linters/cpp/clangcheck.vim
@@ -5,10 +5,6 @@ call ale#Set('cpp_clangcheck_executable', 'clang-check')
call ale#Set('cpp_clangcheck_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#cpp#clangcheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_clangcheck_executable')
-endfunction
-
function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:user_options = ale#Var(a:buffer, 'cpp_clangcheck_options')
@@ -16,23 +12,22 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:build_dir)
- let l:build_dir = ale#c#FindCompileCommands(a:buffer)
+ let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
endif
" The extra arguments in the command are used to prevent .plist files from
" being generated. These are only added if no build directory can be
" detected.
- return ale#Escape(ale_linters#cpp#clangcheck#GetExecutable(a:buffer))
- \ . ' -analyze %s'
+ return '%e -analyze %s'
\ . (empty(l:build_dir) ? ' -extra-arg -Xclang -extra-arg -analyzer-output=text' : '')
- \ . (!empty(l:user_options) ? ' ' . l:user_options : '')
+ \ . ale#Pad(l:user_options)
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangcheck',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#clangcheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_clangcheck_executable'),
\ 'command_callback': 'ale_linters#cpp#clangcheck#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
diff --git a/ale_linters/cpp/clangd.vim b/ale_linters/cpp/clangd.vim
new file mode 100644
index 00000000..9139f054
--- /dev/null
+++ b/ale_linters/cpp/clangd.vim
@@ -0,0 +1,23 @@
+" Author: Andrey Melentyev <andrey.melentyev@protonmail.com>
+" Description: Clangd language server
+
+call ale#Set('cpp_clangd_executable', 'clangd')
+call ale#Set('cpp_clangd_options', '')
+
+function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#cpp#clangd#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
+endfunction
+
+call ale#linter#Define('cpp', {
+\ 'name': 'clangd',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('cpp_clangd_executable'),
+\ 'command_callback': 'ale_linters#cpp#clangd#GetCommand',
+\ 'project_root_callback': 'ale_linters#cpp#clangd#GetProjectRoot',
+\})
diff --git a/ale_linters/cpp/clangtidy.vim b/ale_linters/cpp/clangtidy.vim
index 1d5fb77a..9c3da8db 100644
--- a/ale_linters/cpp/clangtidy.vim
+++ b/ale_linters/cpp/clangtidy.vim
@@ -4,44 +4,22 @@
call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" Set this option to check the checks clang-tidy will apply.
-call ale#Set('cpp_clangtidy_checks', ['*'])
+call ale#Set('cpp_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy.
" This will disable compile_commands.json detection.
call ale#Set('cpp_clangtidy_options', '')
call ale#Set('c_build_dir', '')
-function! ale_linters#cpp#clangtidy#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_clangtidy_executable')
-endfunction
-
-function! s:GetBuildDirectory(buffer) abort
- " Don't include build directory for header files, as compile_commands.json
- " files don't consider headers to be translation units, and provide no
- " commands for compiling header files.
- if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
- return ''
- endif
-
- let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
-
- " c_build_dir has the priority if defined
- if !empty(l:build_dir)
- return l:build_dir
- endif
-
- return ale#c#FindCompileCommands(a:buffer)
-endfunction
-
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',')
- let l:build_dir = s:GetBuildDirectory(a:buffer)
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
" Get the extra options if we couldn't find a build directory.
let l:options = empty(l:build_dir)
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
\ : ''
- return ale#Escape(ale_linters#cpp#clangtidy#GetExecutable(a:buffer))
+ return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
@@ -51,7 +29,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clangtidy',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#cpp#clangtidy#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_clangtidy_executable'),
\ 'command_callback': 'ale_linters#cpp#clangtidy#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'lint_file': 1,
diff --git a/ale_linters/cpp/clazy.vim b/ale_linters/cpp/clazy.vim
new file mode 100644
index 00000000..cbbd0ccf
--- /dev/null
+++ b/ale_linters/cpp/clazy.vim
@@ -0,0 +1,32 @@
+" Description: clazy linter for cpp files (clang-based and Qt-oriented)
+
+call ale#Set('cpp_clazy_executable', 'clazy-standalone')
+" Set this option to check the checks clazy will apply.
+call ale#Set('cpp_clazy_checks', ['level1'])
+" Set this option to manually set some options for clazy.
+" This will disable compile_commands.json detection.
+call ale#Set('cpp_clazy_options', '')
+call ale#Set('c_build_dir', '')
+
+function! ale_linters#cpp#clazy#GetCommand(buffer) abort
+ let l:checks = join(ale#Var(a:buffer, 'cpp_clazy_checks'), ',')
+ let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
+
+ " Get the extra options if we couldn't find a build directory.
+ let l:options = ale#Var(a:buffer, 'cpp_clazy_options')
+
+ return '%e'
+ \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
+ \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' %s'
+endfunction
+
+call ale#linter#Define('cpp', {
+\ 'name': 'clazy',
+\ 'output_stream': 'stderr',
+\ 'executable_callback': ale#VarFunc('cpp_clazy_executable'),
+\ 'command_callback': 'ale_linters#cpp#clazy#GetCommand',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/cpp/cppcheck.vim b/ale_linters/cpp/cppcheck.vim
index 8b2aa802..229d6133 100644
--- a/ale_linters/cpp/cppcheck.vim
+++ b/ale_linters/cpp/cppcheck.vim
@@ -4,10 +4,6 @@
call ale#Set('cpp_cppcheck_executable', 'cppcheck')
call ale#Set('cpp_cppcheck_options', '--enable=style')
-function! ale_linters#cpp#cppcheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_cppcheck_executable')
-endfunction
-
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json.
"
@@ -23,8 +19,7 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
\ : ''
return l:cd_command
- \ . ale#Escape(ale_linters#cpp#cppcheck#GetExecutable(a:buffer))
- \ . ' -q --language=c++ '
+ \ . '%e -q --language=c++ '
\ . l:compile_commands_option
\ . ale#Var(a:buffer, 'cpp_cppcheck_options')
\ . ' %t'
@@ -33,7 +28,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cppcheck',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale_linters#cpp#cppcheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_cppcheck_executable'),
\ 'command_callback': 'ale_linters#cpp#cppcheck#GetCommand',
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\})
diff --git a/ale_linters/cpp/cpplint.vim b/ale_linters/cpp/cpplint.vim
index 346ac815..d135fa79 100644
--- a/ale_linters/cpp/cpplint.vim
+++ b/ale_linters/cpp/cpplint.vim
@@ -4,22 +4,16 @@
call ale#Set('cpp_cpplint_executable', 'cpplint')
call ale#Set('cpp_cpplint_options', '')
-function! ale_linters#cpp#cpplint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_cpplint_executable')
-endfunction
-
function! ale_linters#cpp#cpplint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'cpp_cpplint_options')
- return ale#Escape(ale_linters#cpp#cpplint#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' %s'
+ return '%e' . ale#Pad(l:options) . ' %s'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cpplint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#cpplint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_cpplint_executable'),
\ 'command_callback': 'ale_linters#cpp#cpplint#GetCommand',
\ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat',
\ 'lint_file': 1,
diff --git a/ale_linters/cpp/cquery.vim b/ale_linters/cpp/cquery.vim
index 7997c843..b1c81989 100644
--- a/ale_linters/cpp/cquery.vim
+++ b/ale_linters/cpp/cquery.vim
@@ -7,16 +7,11 @@ call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
- return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
-endfunction
+ if empty(l:project_root)
+ let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery')
+ endif
-function! ale_linters#cpp#cquery#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_cquery_executable')
-endfunction
-
-function! ale_linters#cpp#cquery#GetCommand(buffer) abort
- let l:executable = ale_linters#cpp#cquery#GetExecutable(a:buffer)
- return ale#Escape(l:executable)
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort
@@ -26,8 +21,8 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cquery',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#cpp#cquery#GetExecutable',
-\ 'command_callback': 'ale_linters#cpp#cquery#GetCommand',
+\ 'executable_callback': ale#VarFunc('cpp_cquery_executable'),
+\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#cpp#cquery#GetProjectRoot',
\ 'initialization_options_callback': 'ale_linters#cpp#cquery#GetInitializationOptions',
\})
diff --git a/ale_linters/cpp/flawfinder.vim b/ale_linters/cpp/flawfinder.vim
index 5a7092cf..4f669bff 100644
--- a/ale_linters/cpp/flawfinder.vim
+++ b/ale_linters/cpp/flawfinder.vim
@@ -6,17 +6,11 @@ call ale#Set('cpp_flawfinder_options', '')
call ale#Set('cpp_flawfinder_minlevel', 1)
call ale#Set('c_flawfinder_error_severity', 6)
-function! ale_linters#cpp#flawfinder#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_flawfinder_executable')
-endfunction
-
function! ale_linters#cpp#flawfinder#GetCommand(buffer) abort
-
" Set the minimum vulnerability level for flawfinder to bother with
let l:minlevel = ' --minlevel=' . ale#Var(a:buffer, 'cpp_flawfinder_minlevel')
- return ale#Escape(ale_linters#cpp#flawfinder#GetExecutable(a:buffer))
- \ . ' -CDQS'
+ return '%e -CDQS'
\ . ale#Var(a:buffer, 'cpp_flawfinder_options')
\ . l:minlevel
\ . ' %t'
@@ -25,7 +19,7 @@ endfunction
call ale#linter#Define('cpp', {
\ 'name': 'flawfinder',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#cpp#flawfinder#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_flawfinder_executable'),
\ 'command_callback': 'ale_linters#cpp#flawfinder#GetCommand',
\ 'callback': 'ale#handlers#flawfinder#HandleFlawfinderFormat',
\})
diff --git a/ale_linters/cpp/gcc.vim b/ale_linters/cpp/gcc.vim
index a663eaa3..9935b0bb 100644
--- a/ale_linters/cpp/gcc.vim
+++ b/ale_linters/cpp/gcc.vim
@@ -4,30 +4,25 @@
call ale#Set('cpp_gcc_executable', 'gcc')
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
-function! ale_linters#cpp#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cpp_gcc_executable')
-endfunction
-
function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
- return ale#Escape(ale_linters#cpp#gcc#GetExecutable(a:buffer))
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) . ' '
- \ . l:cflags
- \ . ale#Var(a:buffer, 'cpp_gcc_options') . ' -'
+ return '%e -S -x c++ -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
+ \ . ale#Pad(l:cflags)
+ \ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'gcc',
\ 'aliases': ['g++'],
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cpp#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cpp_gcc_executable'),
\ 'command_chain': [
\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#cpp#gcc#GetCommand'},
\ ],
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/css/stylelint.vim b/ale_linters/css/stylelint.vim
index a16dfde2..6f8bef68 100644
--- a/ale_linters/css/stylelint.vim
+++ b/ale_linters/css/stylelint.vim
@@ -4,21 +4,16 @@ call ale#Set('css_stylelint_executable', 'stylelint')
call ale#Set('css_stylelint_options', '')
call ale#Set('css_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#css#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'css_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#css#stylelint#GetCommand(buffer) abort
- return ale_linters#css#stylelint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'css_stylelint_options')
+ return '%e ' . ale#Pad(ale#Var(a:buffer, 'css_stylelint_options'))
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('css', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#css#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('css_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': 'ale_linters#css#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/cucumber/cucumber.vim b/ale_linters/cucumber/cucumber.vim
index 6708d32f..e8ae09ff 100644
--- a/ale_linters/cucumber/cucumber.vim
+++ b/ale_linters/cucumber/cucumber.vim
@@ -22,6 +22,7 @@ function! ale_linters#cucumber#cucumber#Handle(buffer, lines) abort
endtry
let l:output = []
+
for l:element in get(l:json, 'elements', [])
for l:step in l:element['steps']
if l:step['result']['status'] is# 'undefined'
diff --git a/ale_linters/cuda/nvcc.vim b/ale_linters/cuda/nvcc.vim
index 3764fe9d..f4442cb8 100644
--- a/ale_linters/cuda/nvcc.vim
+++ b/ale_linters/cuda/nvcc.vim
@@ -4,20 +4,14 @@
call ale#Set('cuda_nvcc_executable', 'nvcc')
call ale#Set('cuda_nvcc_options', '-std=c++11')
-function! ale_linters#cuda#nvcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'cuda_nvcc_executable')
-endfunction
-
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#engine#ManageFile(a:buffer, l:output_file)
-
- return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer))
- \ . ' -cuda '
- \ . ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
- \ . ale#Var(a:buffer, 'cuda_nvcc_options') . ' %s'
- \ . ' -o ' . g:ale#util#nul_file
+ return '%e -cuda'
+ \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
+ \ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))
+ \ . ' %s -o ' . g:ale#util#nul_file
endfunction
function! ale_linters#cuda#nvcc#HandleNVCCFormat(buffer, lines) abort
@@ -28,7 +22,6 @@ function! ale_linters#cuda#nvcc#HandleNVCCFormat(buffer, lines) abort
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
-
let l:item = {
\ 'lnum': str2nr(l:match[2]),
\ 'type': l:match[4] =~# 'error' ? 'E' : 'W',
@@ -49,7 +42,7 @@ endfunction
call ale#linter#Define('cuda', {
\ 'name': 'nvcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#cuda#nvcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('cuda_nvcc_executable'),
\ 'command_callback': 'ale_linters#cuda#nvcc#GetCommand',
\ 'callback': 'ale_linters#cuda#nvcc#HandleNVCCFormat',
\ 'lint_file': 1,
diff --git a/ale_linters/d/dls.vim b/ale_linters/d/dls.vim
new file mode 100644
index 00000000..7210d21e
--- /dev/null
+++ b/ale_linters/d/dls.vim
@@ -0,0 +1,22 @@
+" Author: aurieh <me@aurieh.me>
+" Description: A Language Server implementation for D
+
+call ale#Set('d_dls_executable', 'dls')
+
+function! ale_linters#d#dls#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'd_dls_executable')
+endfunction
+
+function! ale_linters#d#dls#FindProjectRoot(buffer) abort
+ " Note: this will return . if dub config is empty
+ " dls can run outside DUB projects just fine
+ return fnamemodify(ale#d#FindDUBConfig(a:buffer), ':h')
+endfunction
+
+call ale#linter#Define('d', {
+\ 'name': 'dls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#d#dls#GetExecutable',
+\ 'command_callback': 'ale_linters#d#dls#GetExecutable',
+\ 'project_root_callback': 'ale_linters#d#dls#FindProjectRoot',
+\})
diff --git a/ale_linters/d/dmd.vim b/ale_linters/d/dmd.vim
index d64b6c3d..c816d592 100644
--- a/ale_linters/d/dmd.vim
+++ b/ale_linters/d/dmd.vim
@@ -1,20 +1,6 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: "dmd for D files"
-function! s:FindDUBConfig(buffer) abort
- " Find a DUB configuration file in ancestor paths.
- " The most DUB-specific names will be tried first.
- for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
- let l:dub_file = ale#path#FindNearestFile(a:buffer, l:possible_filename)
-
- if !empty(l:dub_file)
- return l:dub_file
- endif
- endfor
-
- return ''
-endfunction
-
function! ale_linters#d#dmd#DUBCommand(buffer) abort
" If we can't run dub, then skip this command.
if !executable('dub')
@@ -22,7 +8,7 @@ function! ale_linters#d#dmd#DUBCommand(buffer) abort
return ''
endif
- let l:dub_file = s:FindDUBConfig(a:buffer)
+ let l:dub_file = ale#d#FindDUBConfig(a:buffer)
if empty(l:dub_file)
return ''
diff --git a/ale_linters/dafny/dafny.vim b/ale_linters/dafny/dafny.vim
index 8bbf1b13..b5b90675 100644
--- a/ale_linters/dafny/dafny.vim
+++ b/ale_linters/dafny/dafny.vim
@@ -13,6 +13,7 @@ function! ale_linters#dafny#dafny#Handle(buffer, lines) abort
\ 'type': l:match[4] =~# '^Error' ? 'E' : 'W'
\ })
endfor
+
return l:output
endfunction
diff --git a/ale_linters/dart/dartanalyzer.vim b/ale_linters/dart/dartanalyzer.vim
index ef33c9d4..26817df5 100644
--- a/ale_linters/dart/dartanalyzer.vim
+++ b/ale_linters/dart/dartanalyzer.vim
@@ -3,15 +3,10 @@
call ale#Set('dart_dartanalyzer_executable', 'dartanalyzer')
-function! ale_linters#dart#dartanalyzer#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'dart_dartanalyzer_executable')
-endfunction
-
function! ale_linters#dart#dartanalyzer#GetCommand(buffer) abort
- let l:executable = ale_linters#dart#dartanalyzer#GetExecutable(a:buffer)
let l:path = ale#path#FindNearestFile(a:buffer, '.packages')
- return ale#Escape(l:executable)
+ return '%e'
\ . (!empty(l:path) ? ' --packages ' . ale#Escape(l:path) : '')
\ . ' %s'
endfunction
@@ -34,7 +29,7 @@ endfunction
call ale#linter#Define('dart', {
\ 'name': 'dartanalyzer',
-\ 'executable_callback': 'ale_linters#dart#dartanalyzer#GetExecutable',
+\ 'executable_callback': ale#VarFunc('dart_dartanalyzer_executable'),
\ 'command_callback': 'ale_linters#dart#dartanalyzer#GetCommand',
\ 'callback': 'ale_linters#dart#dartanalyzer#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/dart/language_server.vim b/ale_linters/dart/language_server.vim
index 2265e37a..8e0c139b 100644
--- a/ale_linters/dart/language_server.vim
+++ b/ale_linters/dart/language_server.vim
@@ -3,10 +3,6 @@
call ale#Set('dart_language_server_executable', 'dart_language_server')
-function! ale_linters#dart#language_server#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'dart_language_server_executable')
-endfunction
-
function! ale_linters#dart#language_server#GetProjectRoot(buffer) abort
" Note: pub only looks for pubspec.yaml, there's no point in adding
" support for pubspec.yml
@@ -18,7 +14,7 @@ endfunction
call ale#linter#Define('dart', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#dart#language_server#GetExecutable',
-\ 'command_callback': 'ale_linters#dart#language_server#GetExecutable',
+\ 'executable_callback': ale#VarFunc('dart_language_server_executable'),
+\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#dart#language_server#GetProjectRoot',
\})
diff --git a/ale_linters/dockerfile/dockerfile_lint.vim b/ale_linters/dockerfile/dockerfile_lint.vim
new file mode 100644
index 00000000..a5a846f2
--- /dev/null
+++ b/ale_linters/dockerfile/dockerfile_lint.vim
@@ -0,0 +1,61 @@
+" Author: Alexander Olofsson <alexander.olofsson@liu.se>
+
+call ale#Set('dockerfile_dockerfile_lint_executable', 'dockerfile_lint')
+call ale#Set('dockerfile_dockerfile_lint_options', '')
+
+function! ale_linters#dockerfile#dockerfile_lint#GetType(type) abort
+ if a:type is? 'error'
+ return 'E'
+ elseif a:type is? 'warn'
+ return 'W'
+ endif
+
+ return 'I'
+endfunction
+
+function! ale_linters#dockerfile#dockerfile_lint#Handle(buffer, lines) abort
+ try
+ let l:data = json_decode(join(a:lines, ''))
+ catch
+ return []
+ endtry
+
+ if empty(l:data)
+ " Should never happen, but it's better to be on the safe side
+ return []
+ endif
+
+ let l:messages = []
+
+ for l:type in ['error', 'warn', 'info']
+ for l:object in l:data[l:type]['data']
+ let l:line = get(l:object, 'line', -1)
+ let l:message = l:object['message']
+
+ if get(l:object, 'description', 'None') isnot# 'None'
+ let l:message = l:message . '. ' . l:object['description']
+ endif
+
+ call add(l:messages, {
+ \ 'lnum': l:line,
+ \ 'text': l:message,
+ \ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type),
+ \})
+ endfor
+ endfor
+
+ return l:messages
+endfunction
+
+function! ale_linters#dockerfile#dockerfile_lint#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'dockerfile_dockerfile_lint_options'))
+ \ . ' -p -j -f'
+ \ . ' %t'
+endfunction
+
+call ale#linter#Define('dockerfile', {
+\ 'name': 'dockerfile_lint',
+\ 'executable_callback': ale#VarFunc('dockerfile_dockerfile_lint_executable'),
+\ 'command_callback': 'ale_linters#dockerfile#dockerfile_lint#GetCommand',
+\ 'callback': 'ale_linters#dockerfile#dockerfile_lint#Handle',
+\})
diff --git a/ale_linters/dockerfile/hadolint.vim b/ale_linters/dockerfile/hadolint.vim
index 7772afbd..dc0f5b9e 100644
--- a/ale_linters/dockerfile/hadolint.vim
+++ b/ale_linters/dockerfile/hadolint.vim
@@ -82,9 +82,11 @@ endfunction
function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort
let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer)
+
if l:command is# 'docker'
return 'docker run --rm -i ' . ale#Var(a:buffer, 'dockerfile_hadolint_docker_image')
endif
+
return 'hadolint -'
endfunction
diff --git a/ale_linters/elixir/credo.vim b/ale_linters/elixir/credo.vim
index af2ff48a..d778471c 100644
--- a/ale_linters/elixir/credo.vim
+++ b/ale_linters/elixir/credo.vim
@@ -11,10 +11,18 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
let l:type = l:match[3]
let l:text = l:match[4]
- if l:type is# 'C'
- let l:type = 'E'
- elseif l:type is# 'R'
+ " Refactoring opportunities
+ if l:type is# 'F'
+ let l:type = 'W'
+ " Consistency
+ elseif l:type is# 'C'
let l:type = 'W'
+ " Software Design
+ elseif l:type is# 'D'
+ let l:type = 'I'
+ " Code Readability
+ elseif l:type is# 'R'
+ let l:type = 'I'
endif
call add(l:output, {
@@ -29,9 +37,16 @@ function! ale_linters#elixir#credo#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#elixir#credo#GetCommand(buffer) abort
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+
+ return ale#path#CdString(l:project_root)
+ \ . ' mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
+endfunction
+
call ale#linter#Define('elixir', {
\ 'name': 'credo',
\ 'executable': 'mix',
-\ 'command': 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s',
+\ 'command_callback': 'ale_linters#elixir#credo#GetCommand',
\ 'callback': 'ale_linters#elixir#credo#Handle',
\})
diff --git a/ale_linters/elixir/dialyxir.vim b/ale_linters/elixir/dialyxir.vim
index bba0ae14..d28d3c70 100644
--- a/ale_linters/elixir/dialyxir.vim
+++ b/ale_linters/elixir/dialyxir.vim
@@ -25,10 +25,17 @@ function! ale_linters#elixir#dialyxir#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#elixir#dialyxir#GetCommand(buffer) abort
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+
+ return ale#path#CdString(l:project_root)
+ \ . ' mix help dialyzer && mix dialyzer'
+endfunction
+
call ale#linter#Define('elixir', {
\ 'name': 'dialyxir',
\ 'executable': 'mix',
-\ 'command': 'mix help dialyzer && mix dialyzer',
+\ 'command_callback': 'ale_linters#elixir#dialyxir#GetCommand',
\ 'callback': 'ale_linters#elixir#dialyxir#Handle',
\})
diff --git a/ale_linters/elixir/dogma.vim b/ale_linters/elixir/dogma.vim
index 71cf4f4c..dcfb6f28 100644
--- a/ale_linters/elixir/dogma.vim
+++ b/ale_linters/elixir/dogma.vim
@@ -29,10 +29,17 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#elixir#dogma#GetCommand(buffer) abort
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+
+ return ale#path#CdString(l:project_root)
+ \ . ' mix help dogma && mix dogma %s --format=flycheck'
+endfunction
+
call ale#linter#Define('elixir', {
\ 'name': 'dogma',
\ 'executable': 'mix',
-\ 'command': 'mix help dogma && mix dogma %s --format=flycheck',
+\ 'command_callback': 'ale_linters#elixir#dogma#GetCommand',
\ 'lint_file': 1,
\ 'callback': 'ale_linters#elixir#dogma#Handle',
\})
diff --git a/ale_linters/elixir/elixir_ls.vim b/ale_linters/elixir/elixir_ls.vim
new file mode 100644
index 00000000..3b299ec6
--- /dev/null
+++ b/ale_linters/elixir/elixir_ls.vim
@@ -0,0 +1,21 @@
+" Author: Jon Parise <jon@indelible.org>
+" Description: ElixirLS integration (https://github.com/JakeBecker/elixir-ls)
+
+call ale#Set('elixir_elixir_ls_release', 'elixir-ls')
+call ale#Set('elixir_elixir_ls_config', {})
+
+function! ale_linters#elixir#elixir_ls#GetExecutable(buffer) abort
+ let l:dir = ale#path#Simplify(ale#Var(a:buffer, 'elixir_elixir_ls_release'))
+ let l:cmd = ale#Has('win32') ? '\language_server.bat' : '/language_server.sh'
+
+ return l:dir . l:cmd
+endfunction
+
+call ale#linter#Define('elixir', {
+\ 'name': 'elixir-ls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#elixir#elixir_ls#GetExecutable',
+\ 'command_callback': 'ale_linters#elixir#elixir_ls#GetExecutable',
+\ 'project_root_callback': 'ale#handlers#elixir#FindMixUmbrellaRoot',
+\ 'lsp_config_callback': ale#VarFunc('elixir_elixir_ls_config'),
+\})
diff --git a/ale_linters/elixir/mix.vim b/ale_linters/elixir/mix.vim
index 1a95e37f..dc3c1818 100644
--- a/ale_linters/elixir/mix.vim
+++ b/ale_linters/elixir/mix.vim
@@ -10,7 +10,6 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort
"
" TODO: Warning format
" warning: variable "foobar" does not exist and is being expanded to "foobar()", please use parentheses to remove the ambiguity or change the variable name
-
let l:pattern = '\v\(([^\)]+Error)\) ([^:]+):([^:]+): (.+)$'
let l:output = []
@@ -30,16 +29,8 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#elixir#mix#FindProjectRoot(buffer) abort
- let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs')
- if !empty(l:mix_file)
- return fnamemodify(l:mix_file, ':p:h')
- endif
- return '.'
-endfunction
-
function! ale_linters#elixir#mix#GetCommand(buffer) abort
- let l:project_root = ale_linters#elixir#mix#FindProjectRoot(a:buffer)
+ let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:temp_dir = ale#engine#CreateDirectory(a:buffer)
@@ -48,8 +39,8 @@ function! ale_linters#elixir#mix#GetCommand(buffer) abort
\ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir)
return ale#path#CdString(l:project_root)
- \ . l:mix_build_path
- \ . ' mix compile %s'
+ \ . l:mix_build_path
+ \ . ' mix compile %s'
endfunction
call ale#linter#Define('elixir', {
diff --git a/ale_linters/elm/make.vim b/ale_linters/elm/make.vim
index d5bc19eb..ddea983f 100644
--- a/ale_linters/elm/make.vim
+++ b/ale_linters/elm/make.vim
@@ -4,12 +4,6 @@
call ale#Set('elm_make_executable', 'elm')
call ale#Set('elm_make_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#elm#make#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'elm_make', [
- \ 'node_modules/.bin/elm',
- \])
-endfunction
-
function! ale_linters#elm#make#Handle(buffer, lines) abort
let l:output = []
let l:unparsed_lines = []
@@ -136,7 +130,7 @@ function! ale_linters#elm#make#ParseMessage(message) abort
endfunction
function! ale_linters#elm#make#ParseMessageItem(item) abort
- if type(a:item) == type('')
+ if type(a:item) is v:t_string
return a:item
else
return a:item.string
@@ -147,7 +141,6 @@ endfunction
" If it doesn't, then this will fail when imports are needed.
function! ale_linters#elm#make#GetCommand(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
- let l:elm_exe = ale_linters#elm#make#GetExecutable(a:buffer)
if empty(l:elm_json)
" Fallback to Elm 0.18
@@ -165,18 +158,15 @@ function! ale_linters#elm#make#GetCommand(buffer) abort
" a sort of flag to tell the compiler not to generate an output file,
" which is why this is hard coded here.
" Source: https://github.com/elm-lang/elm-compiler/blob/19d5a769b30ec0b2fc4475985abb4cd94cd1d6c3/builder/src/Generate/Output.hs#L253
- let l:elm_cmd = ale#Escape(l:elm_exe)
- \ . ' make'
- \ . ' --report=json'
- \ . ' --output=/dev/null'
-
- return l:dir_set_cmd . ' ' . l:elm_cmd . ' %t'
+ return l:dir_set_cmd . '%e make --report=json --output=/dev/null %t'
endfunction
call ale#linter#Define('elm', {
-\ 'name': 'make',
-\ 'executable_callback': 'ale_linters#elm#make#GetExecutable',
-\ 'output_stream': 'both',
-\ 'command_callback': 'ale_linters#elm#make#GetCommand',
-\ 'callback': 'ale_linters#elm#make#Handle'
+\ 'name': 'make',
+\ 'executable_callback': ale#node#FindExecutableFunc('elm_make', [
+\ 'node_modules/.bin/elm',
+\ ]),
+\ 'output_stream': 'both',
+\ 'command_callback': 'ale_linters#elm#make#GetCommand',
+\ 'callback': 'ale_linters#elm#make#Handle'
\})
diff --git a/ale_linters/erlang/syntaxerl.vim b/ale_linters/erlang/syntaxerl.vim
index 46ecdcb7..5b679743 100644
--- a/ale_linters/erlang/syntaxerl.vim
+++ b/ale_linters/erlang/syntaxerl.vim
@@ -3,24 +3,12 @@
call ale#Set('erlang_syntaxerl_executable', 'syntaxerl')
-
-function! ale_linters#erlang#syntaxerl#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'erlang_syntaxerl_executable')
-endfunction
-
-
-function! ale_linters#erlang#syntaxerl#FeatureCheck(buffer) abort
- return s:GetEscapedExecutable(a:buffer) . ' -h'
-endfunction
-
-
function! ale_linters#erlang#syntaxerl#GetCommand(buffer, output) abort
let l:use_b_option = match(a:output, '\C\V-b, --base\>') > -1
- return s:GetEscapedExecutable(a:buffer) . (l:use_b_option ? ' -b %s %t' : ' %t')
+ return '%e' . (l:use_b_option ? ' -b %s %t' : ' %t')
endfunction
-
function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort
let l:pattern = '\v\C:(\d+):( warning:)? (.+)'
let l:loclist = []
@@ -36,17 +24,11 @@ function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort
return l:loclist
endfunction
-
-function! s:GetEscapedExecutable(buffer) abort
- return ale#Escape(ale_linters#erlang#syntaxerl#GetExecutable(a:buffer))
-endfunction
-
-
call ale#linter#Define('erlang', {
\ 'name': 'syntaxerl',
-\ 'executable_callback': 'ale_linters#erlang#syntaxerl#GetExecutable',
+\ 'executable_callback': ale#VarFunc('erlang_syntaxerl_executable'),
\ 'command_chain': [
-\ {'callback': 'ale_linters#erlang#syntaxerl#FeatureCheck'},
+\ {'callback': {-> '%e -h'}},
\ {'callback': 'ale_linters#erlang#syntaxerl#GetCommand'},
\ ],
\ 'callback': 'ale_linters#erlang#syntaxerl#Handle',
diff --git a/ale_linters/eruby/ruumba.vim b/ale_linters/eruby/ruumba.vim
new file mode 100644
index 00000000..24f112e4
--- /dev/null
+++ b/ale_linters/eruby/ruumba.vim
@@ -0,0 +1,62 @@
+" Author: aclemons - https://github.com/aclemons
+" based on the ale rubocop linter
+" Description: Ruumba, RuboCop linting for ERB templates.
+
+call ale#Set('eruby_ruumba_executable', 'ruumba')
+call ale#Set('eruby_ruumba_options', '')
+
+function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'eruby_ruumba_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'ruumba')
+ \ . ' --format json --force-exclusion '
+ \ . ale#Var(a:buffer, 'eruby_ruumba_options')
+ \ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
+endfunction
+
+function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort
+ try
+ let l:errors = json_decode(a:lines[0])
+ catch
+ return []
+ endtry
+
+ if !has_key(l:errors, 'summary')
+ \|| l:errors['summary']['offense_count'] == 0
+ \|| empty(l:errors['files'])
+ return []
+ endif
+
+ let l:output = []
+
+ for l:error in l:errors['files'][0]['offenses']
+ let l:start_col = l:error['location']['column'] + 0
+ call add(l:output, {
+ \ 'lnum': l:error['location']['line'] + 0,
+ \ 'col': l:start_col,
+ \ 'end_col': l:start_col + l:error['location']['length'] - 1,
+ \ 'code': l:error['cop_name'],
+ \ 'text': l:error['message'],
+ \ 'type': ale_linters#eruby#ruumba#GetType(l:error['severity']),
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+function! ale_linters#eruby#ruumba#GetType(severity) abort
+ if a:severity is? 'convention'
+ \|| a:severity is? 'warning'
+ \|| a:severity is? 'refactor'
+ return 'W'
+ endif
+
+ return 'E'
+endfunction
+
+call ale#linter#Define('eruby', {
+\ 'name': 'ruumba',
+\ 'executable_callback': ale#VarFunc('eruby_ruumba_executable'),
+\ 'command_callback': 'ale_linters#eruby#ruumba#GetCommand',
+\ 'callback': 'ale_linters#eruby#ruumba#Handle',
+\})
diff --git a/ale_linters/fortran/gcc.vim b/ale_linters/fortran/gcc.vim
index 5f2ac018..f1595789 100644
--- a/ale_linters/fortran/gcc.vim
+++ b/ale_linters/fortran/gcc.vim
@@ -2,18 +2,10 @@
" Description: gcc for Fortran files
" This option can be set to 0 to use -ffixed-form
-if !exists('g:ale_fortran_gcc_use_free_form')
- let g:ale_fortran_gcc_use_free_form = 1
-endif
-
-if !exists('g:ale_fortran_gcc_executable')
- let g:ale_fortran_gcc_executable = 'gcc'
-endif
-
+call ale#Set('fortran_gcc_use_free_form', 1)
+call ale#Set('fortran_gcc_executable', 'gcc')
" Set this option to change the GCC options for warnings for Fortran.
-if !exists('g:ale_fortran_gcc_options')
- let g:ale_fortran_gcc_options = '-Wall'
-endif
+call ale#Set('fortran_gcc_options', '-Wall')
function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
" We have to match a starting line and a later ending line together,
@@ -61,26 +53,20 @@ function! ale_linters#fortran#gcc#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#fortran#gcc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'fortran_gcc_executable')
-endfunction
-
function! ale_linters#fortran#gcc#GetCommand(buffer) abort
let l:layout_option = ale#Var(a:buffer, 'fortran_gcc_use_free_form')
\ ? '-ffree-form'
\ : '-ffixed-form'
- return ale_linters#fortran#gcc#GetExecutable(a:buffer)
- \ . ' -S -x f95 -fsyntax-only '
- \ . l:layout_option . ' '
- \ . ale#Var(a:buffer, 'fortran_gcc_options') . ' '
- \ . '-'
+ return '%e -S -x f95 -fsyntax-only ' . l:layout_option
+ \ . ale#Pad(ale#Var(a:buffer, 'fortran_gcc_options'))
+ \ . ' -'
endfunction
call ale#linter#Define('fortran', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#fortran#gcc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('fortran_gcc_executable'),
\ 'command_callback': 'ale_linters#fortran#gcc#GetCommand',
\ 'callback': 'ale_linters#fortran#gcc#Handle',
\})
diff --git a/ale_linters/fortran/language_server.vim b/ale_linters/fortran/language_server.vim
index fd763fcf..4e5f5dc4 100644
--- a/ale_linters/fortran/language_server.vim
+++ b/ale_linters/fortran/language_server.vim
@@ -4,14 +4,6 @@
call ale#Set('fortran_language_server_executable', 'fortls')
call ale#Set('fortran_language_server_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#fortran#language_server#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'fortran_language_server_executable')
-endfunction
-
-function! ale_linters#fortran#language_server#GetCommand(buffer) abort
- return ale#Escape(ale_linters#fortran#language_server#GetExecutable(a:buffer))
-endfunction
-
function! ale_linters#fortran#language_server#GetProjectRoot(buffer) abort
let l:fortls_file = ale#path#FindNearestFile(a:buffer, '.fortls')
@@ -21,7 +13,7 @@ endfunction
call ale#linter#Define('fortran', {
\ 'name': 'language_server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#fortran#language_server#GetExecutable',
-\ 'command_callback': 'ale_linters#fortran#language_server#GetCommand',
+\ 'executable_callback': ale#VarFunc('fortran_language_server_executable'),
+\ 'command': '%e',
\ 'project_root_callback': 'ale_linters#fortran#language_server#GetProjectRoot',
\})
diff --git a/ale_linters/fuse/fusionlint.vim b/ale_linters/fuse/fusionlint.vim
index cf20e1b4..ab8f143b 100644
--- a/ale_linters/fuse/fusionlint.vim
+++ b/ale_linters/fuse/fusionlint.vim
@@ -4,13 +4,8 @@
call ale#Set('fuse_fusionlint_executable', 'fusion-lint')
call ale#Set('fuse_fusionlint_options', '')
-function! ale_linters#fuse#fusionlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'fuse_fusionlint_executable')
-endfunction
-
function! ale_linters#fuse#fusionlint#GetCommand(buffer) abort
- return ale#Escape(ale_linters#fuse#fusionlint#GetExecutable(a:buffer))
- \ . ale#Pad(ale#Var(a:buffer, 'fuse_fusionlint_options'))
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'fuse_fusionlint_options'))
\ . ' --filename %s -i'
endfunction
@@ -32,7 +27,7 @@ endfunction
call ale#linter#Define('fuse', {
\ 'name': 'fusionlint',
-\ 'executable_callback': 'ale_linters#fuse#fusionlint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('fuse_fusionlint_executable'),
\ 'command_callback': 'ale_linters#fuse#fusionlint#GetCommand',
\ 'callback': 'ale_linters#fuse#fusionlint#Handle',
\})
diff --git a/ale_linters/gitcommit/gitlint.vim b/ale_linters/gitcommit/gitlint.vim
index 64731055..a9c4822d 100644
--- a/ale_linters/gitcommit/gitlint.vim
+++ b/ale_linters/gitcommit/gitlint.vim
@@ -1,11 +1,9 @@
" Author: Nick Yamane <nick.diego@gmail.com>
" Description: gitlint for git commit message files
-let g:ale_gitcommit_gitlint_executable =
-\ get(g:, 'ale_gitcommit_gitlint_executable', 'gitlint')
-let g:ale_gitcommit_gitlint_options = get(g:, 'ale_gitcommit_gitlint_options', '')
-let g:ale_gitcommit_gitlint_use_global = get(g:, 'ale_gitcommit_gitlint_use_global', get(g:, 'ale_use_global_executables', 0))
-
+call ale#Set('gitcommit_gitlint_executable', 'gitlint')
+call ale#Set('gitcommit_gitlint_options', '')
+call ale#Set('gitcommit_gitlint_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#gitcommit#gitlint#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'gitcommit_gitlint', ['gitlint'])
@@ -13,12 +11,9 @@ endfunction
function! ale_linters#gitcommit#gitlint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'gitcommit_gitlint_options')
- let l:executable = ale_linters#gitcommit#gitlint#GetExecutable(a:buffer)
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' lint'
-endfunction
+ return '%e' . ale#Pad(l:options) . ' lint'
+endfunction
function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
" Matches patterns line the following:
@@ -28,8 +23,10 @@ function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:code = l:match[2]
- if l:code is# 'T2' && !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
- continue
+ if !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
+ if l:code is# 'T2' || l:code is# 'B2'
+ continue
+ endif
endif
let l:item = {
@@ -45,7 +42,6 @@ function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort
return l:output
endfunction
-
call ale#linter#Define('gitcommit', {
\ 'name': 'gitlint',
\ 'output_stream': 'stderr',
@@ -53,4 +49,3 @@ call ale#linter#Define('gitcommit', {
\ 'command_callback': 'ale_linters#gitcommit#gitlint#GetCommand',
\ 'callback': 'ale_linters#gitcommit#gitlint#Handle',
\})
-
diff --git a/ale_linters/glsl/glslang.vim b/ale_linters/glsl/glslang.vim
index d494df0e..d55a5e7c 100644
--- a/ale_linters/glsl/glslang.vim
+++ b/ale_linters/glsl/glslang.vim
@@ -4,17 +4,11 @@
" TODO: Once https://github.com/KhronosGroup/glslang/pull/1047 is accepted,
" we can use stdin.
-let g:ale_glsl_glslang_executable =
-\ get(g:, 'ale_glsl_glslang_executable', 'glslangValidator')
-
-let g:ale_glsl_glslang_options = get(g:, 'ale_glsl_glslang_options', '')
-
-function! ale_linters#glsl#glslang#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'glsl_glslang_executable')
-endfunction
+call ale#Set('glsl_glslang_executable', 'glslangValidator')
+call ale#Set('glsl_glslang_options', '')
function! ale_linters#glsl#glslang#GetCommand(buffer) abort
- return ale#Escape(ale_linters#glsl#glslang#GetExecutable(a:buffer))
+ return '%e'
\ . ale#Pad(ale#Var(a:buffer, 'glsl_glslang_options'))
\ . ' -C %t'
endfunction
@@ -40,7 +34,7 @@ endfunction
call ale#linter#Define('glsl', {
\ 'name': 'glslang',
-\ 'executable_callback': 'ale_linters#glsl#glslang#GetExecutable',
+\ 'executable_callback': ale#VarFunc('glsl_glslang_executable'),
\ 'command_callback': 'ale_linters#glsl#glslang#GetCommand',
\ 'callback': 'ale_linters#glsl#glslang#Handle',
\})
diff --git a/ale_linters/glsl/glslls.vim b/ale_linters/glsl/glslls.vim
index 77e30f9c..8c6d9bd9 100644
--- a/ale_linters/glsl/glslls.vim
+++ b/ale_linters/glsl/glslls.vim
@@ -4,18 +4,15 @@
call ale#Set('glsl_glslls_executable', 'glslls')
call ale#Set('glsl_glslls_logfile', '')
-function! ale_linters#glsl#glslls#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'glsl_glslls_executable')
-endfunction
-
function! ale_linters#glsl#glslls#GetCommand(buffer) abort
- let l:executable = ale_linters#glsl#glslls#GetExecutable(a:buffer)
let l:logfile = ale#Var(a:buffer, 'glsl_glslls_logfile')
let l:logfile_args = ''
+
if l:logfile isnot# ''
let l:logfile_args = ' --verbose -l ' . l:logfile
endif
- return ale#Escape(l:executable) . l:logfile_args . ' --stdin'
+
+ return '%e' . l:logfile_args . ' --stdin'
endfunction
function! ale_linters#glsl#glslls#GetProjectRoot(buffer) abort
@@ -27,7 +24,7 @@ endfunction
call ale#linter#Define('glsl', {
\ 'name': 'glslls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#glsl#glslls#GetExecutable',
+\ 'executable_callback': ale#VarFunc('glsl_glslls_executable'),
\ 'command_callback': 'ale_linters#glsl#glslls#GetCommand',
\ 'project_root_callback': 'ale_linters#glsl#glslls#GetProjectRoot',
\})
diff --git a/ale_linters/go/gobuild.vim b/ale_linters/go/gobuild.vim
index c4608071..cef1ff88 100644
--- a/ale_linters/go/gobuild.vim
+++ b/ale_linters/go/gobuild.vim
@@ -3,38 +3,15 @@
" Description: go build for Go files
" inspired by work from dzhou121 <dzhou121@gmail.com>
+call ale#Set('go_go_executable', 'go')
call ale#Set('go_gobuild_options', '')
-function! ale_linters#go#gobuild#ResetEnv() abort
- unlet! s:go_env
-endfunction
-
-function! ale_linters#go#gobuild#GoEnv(buffer) abort
- if exists('s:go_env')
- return ''
- endif
-
- return 'go env GOPATH GOROOT'
-endfunction
-
-function! ale_linters#go#gobuild#GetCommand(buffer, goenv_output) abort
+function! ale_linters#go#gobuild#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_gobuild_options')
- if !exists('s:go_env')
- let s:go_env = {
- \ 'GOPATH': a:goenv_output[0],
- \ 'GOROOT': a:goenv_output[1],
- \}
- endif
-
- let l:gopath_env_command = has('win32')
- \ ? 'set GOPATH=' . ale#Escape(s:go_env.GOPATH) . ' && '
- \ : 'GOPATH=' . ale#Escape(s:go_env.GOPATH) . ' '
-
" Run go test in local directory with relative path
- return l:gopath_env_command
- \ . ale#path#BufferCdString(a:buffer)
- \ . 'go test'
+ return ale#path#BufferCdString(a:buffer)
+ \ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./'
endfunction
@@ -45,7 +22,6 @@ function! ale_linters#go#gobuild#GetMatches(lines) abort
" file.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args
" file.go:53:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
" file.go:5:2: expected declaration, found 'STRING' "log"
-
" go test returns relative paths so use tail of filename as part of pattern matcher
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? (.+)$'
@@ -72,11 +48,9 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gobuild',
\ 'aliases': ['go build'],
-\ 'executable': 'go',
-\ 'command_chain': [
-\ {'callback': 'ale_linters#go#gobuild#GoEnv', 'output_stream': 'stdout'},
-\ {'callback': 'ale_linters#go#gobuild#GetCommand', 'output_stream': 'stderr'},
-\ ],
+\ 'executable_callback': ale#VarFunc('go_go_executable'),
+\ 'command_callback': 'ale_linters#go#gobuild#GetCommand',
+\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#go#gobuild#Handler',
\ 'lint_file': 1,
\})
diff --git a/ale_linters/go/golangci_lint.vim b/ale_linters/go/golangci_lint.vim
new file mode 100644
index 00000000..dd9a3c64
--- /dev/null
+++ b/ale_linters/go/golangci_lint.vim
@@ -0,0 +1,56 @@
+" Author: Sascha Grunert <mail@saschagrunert.de>
+" Description: Adds support of golangci-lint
+
+call ale#Set('go_golangci_lint_options', '--enable-all')
+call ale#Set('go_golangci_lint_executable', 'golangci-lint')
+call ale#Set('go_golangci_lint_package', 0)
+
+function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
+ let l:filename = expand('#' . a:buffer . ':t')
+ let l:options = ale#Var(a:buffer, 'go_golangci_lint_options')
+ let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package')
+
+ if l:lint_package
+ return ale#path#BufferCdString(a:buffer)
+ \ . '%e run '
+ \ . l:options
+ endif
+
+ return ale#path#BufferCdString(a:buffer)
+ \ . '%e run '
+ \ . ale#Escape(l:filename)
+ \ . ' ' . l:options
+endfunction
+
+function! ale_linters#go#golangci_lint#GetMatches(lines) abort
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:?:?:?\s\*?(.+)$'
+
+ return ale#util#GetMatches(a:lines, l:pattern)
+endfunction
+
+function! ale_linters#go#golangci_lint#Handler(buffer, lines) abort
+ let l:dir = expand('#' . a:buffer . ':p:h')
+ let l:output = []
+
+ for l:match in ale_linters#go#golangci_lint#GetMatches(a:lines)
+ " l:match[1] will already be an absolute path, output from
+ " golangci_lint
+ call add(l:output, {
+ \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
+ \ 'lnum': l:match[2] + 0,
+ \ 'col': l:match[3] + 0,
+ \ 'type': 'E',
+ \ 'text': l:match[4],
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('go', {
+\ 'name': 'golangci-lint',
+\ 'executable_callback': ale#VarFunc('go_golangci_lint_executable'),
+\ 'command_callback': 'ale_linters#go#golangci_lint#GetCommand',
+\ 'callback': 'ale_linters#go#golangci_lint#Handler',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/go/golint.vim b/ale_linters/go/golint.vim
index d580fda2..4bf14fcc 100644
--- a/ale_linters/go/golint.vim
+++ b/ale_linters/go/golint.vim
@@ -1,10 +1,21 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: golint for Go files
+call ale#Set('go_golint_executable', 'golint')
+call ale#Set('go_golint_options', '')
+
+function! ale_linters#go#golint#GetCommand(buffer) abort
+ let l:options = ale#Var(a:buffer, 'go_golint_options')
+
+ return '%e'
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' %t'
+endfunction
+
call ale#linter#Define('go', {
\ 'name': 'golint',
\ 'output_stream': 'both',
-\ 'executable': 'golint',
-\ 'command': 'golint %t',
+\ 'executable_callback': ale#VarFunc('go_golint_executable'),
+\ 'command_callback': 'ale_linters#go#golint#GetCommand',
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
\})
diff --git a/ale_linters/go/gometalinter.vim b/ale_linters/go/gometalinter.vim
index 375a8b0f..d005e1d2 100644
--- a/ale_linters/go/gometalinter.vim
+++ b/ale_linters/go/gometalinter.vim
@@ -5,12 +5,7 @@ call ale#Set('go_gometalinter_options', '')
call ale#Set('go_gometalinter_executable', 'gometalinter')
call ale#Set('go_gometalinter_lint_package', 0)
-function! ale_linters#go#gometalinter#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'go_gometalinter_executable')
-endfunction
-
function! ale_linters#go#gometalinter#GetCommand(buffer) abort
- let l:executable = ale_linters#go#gometalinter#GetExecutable(a:buffer)
let l:filename = expand('#' . a:buffer . ':t')
let l:options = ale#Var(a:buffer, 'go_gometalinter_options')
let l:lint_package = ale#Var(a:buffer, 'go_gometalinter_lint_package')
@@ -19,12 +14,12 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
" be calculated to absolute paths in the Handler
if l:lint_package
return ale#path#BufferCdString(a:buffer)
- \ . ale#Escape(l:executable)
+ \ . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif
return ale#path#BufferCdString(a:buffer)
- \ . ale#Escape(l:executable)
+ \ . '%e'
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endfunction
@@ -55,7 +50,7 @@ endfunction
call ale#linter#Define('go', {
\ 'name': 'gometalinter',
-\ 'executable_callback': 'ale_linters#go#gometalinter#GetExecutable',
+\ 'executable_callback': ale#VarFunc('go_gometalinter_executable'),
\ 'command_callback': 'ale_linters#go#gometalinter#GetCommand',
\ 'callback': 'ale_linters#go#gometalinter#Handler',
\ 'lint_file': 1,
diff --git a/ale_linters/go/govet.vim b/ale_linters/go/govet.vim
index e94e6ecd..3d0d2adf 100644
--- a/ale_linters/go/govet.vim
+++ b/ale_linters/go/govet.vim
@@ -4,15 +4,23 @@
" Author: John Eikenberry <jae@zhar.net>
" Description: updated to work with go1.10
+call ale#Set('go_go_executable', 'go')
+call ale#Set('go_govet_options', '')
+
function! ale_linters#go#govet#GetCommand(buffer) abort
- return ale#path#BufferCdString(a:buffer) . ' go vet .'
+ let l:options = ale#Var(a:buffer, 'go_govet_options')
+
+ return ale#path#BufferCdString(a:buffer) . ' '
+ \ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' .'
endfunction
call ale#linter#Define('go', {
\ 'name': 'govet',
\ 'aliases': ['go vet'],
\ 'output_stream': 'stderr',
-\ 'executable': 'go',
+\ 'executable_callback': ale#VarFunc('go_go_executable'),
\ 'command_callback': 'ale_linters#go#govet#GetCommand',
\ 'callback': 'ale#handlers#go#Handler',
\ 'lint_file': 1,
diff --git a/ale_linters/go/langserver.vim b/ale_linters/go/langserver.vim
new file mode 100644
index 00000000..df956483
--- /dev/null
+++ b/ale_linters/go/langserver.vim
@@ -0,0 +1,28 @@
+" Author: Horacio Sanson <https://github.com/hsanson>
+" Description: Support for go-langserver https://github.com/sourcegraph/go-langserver
+
+call ale#Set('go_langserver_executable', 'go-langserver')
+call ale#Set('go_langserver_options', '')
+
+function! ale_linters#go#langserver#GetCommand(buffer) abort
+ let l:executable = [ale#Escape(ale#Var(a:buffer, 'go_langserver_executable'))]
+ let l:options = ale#Var(a:buffer, 'go_langserver_options')
+ let l:options = substitute(l:options, '-gocodecompletion', '', 'g')
+ let l:options = filter(split(l:options, ' '), 'empty(v:val) != 1')
+
+ if(ale#Var(a:buffer, 'completion_enabled') == 1)
+ call add(l:options, '-gocodecompletion')
+ endif
+
+ let l:options = uniq(sort(l:options))
+
+ return join(extend(l:executable, l:options), ' ')
+endfunction
+
+call ale#linter#Define('go', {
+\ 'name': 'golangserver',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('go_langserver_executable'),
+\ 'command_callback': 'ale_linters#go#langserver#GetCommand',
+\ 'project_root_callback': 'ale#go#FindProjectRoot',
+\})
diff --git a/ale_linters/hack/hack.vim b/ale_linters/hack/hack.vim
new file mode 100644
index 00000000..aea428cc
--- /dev/null
+++ b/ale_linters/hack/hack.vim
@@ -0,0 +1,22 @@
+" Author: Fred Emmott <fe@fb.com>
+" Description: Hack support via `hack lsp`
+
+call ale#Set('hack_hack_executable', 'hh_client')
+
+function! ale_linters#hack#hack#GetProjectRoot(buffer) abort
+ let l:hhconfig = ale#path#FindNearestFile(a:buffer, '.hhconfig')
+
+ return !empty(l:hhconfig) ? fnamemodify(l:hhconfig, ':h') : ''
+endfunction
+
+function! ale_linters#hack#hack#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'hack_hack_executable')
+endfunction
+
+call ale#linter#Define('hack', {
+\ 'name': 'hack',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#hack#hack#GetExecutable',
+\ 'command': '%e lsp --from vim-ale',
+\ 'project_root_callback': 'ale_linters#hack#hack#GetProjectRoot',
+\})
diff --git a/ale_linters/hack/hhast.vim b/ale_linters/hack/hhast.vim
new file mode 100644
index 00000000..710b7b25
--- /dev/null
+++ b/ale_linters/hack/hhast.vim
@@ -0,0 +1,40 @@
+" Author: Fred Emmott <fe@fb.com>
+" Description: Hack support via `hhast lsp`
+
+call ale#Set('hack_hhast_executable', 'vendor/bin/hhast-lint')
+
+function! ale_linters#hack#hhast#GetProjectRoot(buffer) abort
+ " Find the hack root, then figure out if it's also an HHAST root.
+ " Don't try to use lint configurations from vendor/foo/bar/hhast-lint.json
+ let l:hhconfig = ale#path#FindNearestFile(a:buffer, '.hhconfig')
+
+ if empty(l:hhconfig)
+ return ''
+ endif
+
+ let l:root = fnamemodify(l:hhconfig, ':h')
+ let l:hhast_config = findfile('hhast-lint.json', l:root)
+
+ return !empty(l:hhast_config) ? l:root : ''
+endfunction
+
+function! ale_linters#hack#hhast#GetExecutable(buffer) abort
+ let l:root = ale_linters#hack#hhast#GetProjectRoot(a:buffer)
+ let l:relative = ale#Var(a:buffer, 'hack_hhast_executable')
+ let l:absolute = findfile(l:relative, l:root)
+
+ return !empty(l:absolute) ? l:absolute : ''
+endfunction
+
+function! ale_linters#hack#hhast#GetInitializationOptions(buffer) abort
+ return {'lintMode': 'open-files'}
+endfunction
+
+call ale#linter#Define('hack', {
+\ 'name': 'hhast',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#hack#hhast#GetExecutable',
+\ 'command': '%e --mode lsp --from vim-ale',
+\ 'project_root_callback': 'ale_linters#hack#hhast#GetProjectRoot',
+\ 'initialization_options_callback': 'ale_linters#hack#hhast#GetInitializationOptions',
+\})
diff --git a/ale_linters/haml/hamllint.vim b/ale_linters/haml/hamllint.vim
index d6633599..6598f81a 100644
--- a/ale_linters/haml/hamllint.vim
+++ b/ale_linters/haml/hamllint.vim
@@ -1,6 +1,12 @@
" Author: Patrick Lewis - https://github.com/patricklewis, thenoseman - https://github.com/thenoseman
" Description: haml-lint for Haml files
+call ale#Set('haml_hamllint_executable', 'haml-lint')
+
+function! ale_linters#haml#hamllint#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'haml_hamllint_executable')
+endfunction
+
function! ale_linters#haml#hamllint#GetCommand(buffer) abort
let l:prefix = ''
@@ -21,7 +27,7 @@ function! ale_linters#haml#hamllint#GetCommand(buffer) abort
endif
return (!empty(l:prefix) ? l:prefix . ' ' : '')
- \ . 'haml-lint'
+ \ . ale_linters#haml#hamllint#GetExecutable(a:buffer)
\ . (!empty(l:hamllint_config_file_path) ? ' --config ' . ale#Escape(l:hamllint_config_file_path) : '')
\ . ' %t'
endfunction
@@ -45,7 +51,7 @@ endfunction
call ale#linter#Define('haml', {
\ 'name': 'hamllint',
-\ 'executable': 'haml-lint',
+\ 'executable_callback': 'ale_linters#haml#hamllint#GetExecutable',
\ 'command_callback': 'ale_linters#haml#hamllint#GetCommand',
\ 'callback': 'ale_linters#haml#hamllint#Handle'
\})
diff --git a/ale_linters/handlebars/embertemplatelint.vim b/ale_linters/handlebars/embertemplatelint.vim
index 162a033c..4fc0f20d 100644
--- a/ale_linters/handlebars/embertemplatelint.vim
+++ b/ale_linters/handlebars/embertemplatelint.vim
@@ -4,17 +4,6 @@
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#handlebars#embertemplatelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [
- \ 'node_modules/.bin/ember-template-lint',
- \])
-endfunction
-
-function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer) abort
- return ale_linters#handlebars#embertemplatelint#GetExecutable(a:buffer)
- \ . ' --json %t'
-endfunction
-
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
@@ -42,7 +31,9 @@ endfunction
call ale#linter#Define('handlebars', {
\ 'name': 'ember-template-lint',
-\ 'executable_callback': 'ale_linters#handlebars#embertemplatelint#GetExecutable',
-\ 'command_callback': 'ale_linters#handlebars#embertemplatelint#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('handlebars_embertemplatelint', [
+\ 'node_modules/.bin/ember-template-lint',
+\ ]),
+\ 'command': '%e --json %t',
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\})
diff --git a/ale_linters/haskell/ghc-mod.vim b/ale_linters/haskell/ghc-mod.vim
deleted file mode 100644
index eb032f50..00000000
--- a/ale_linters/haskell/ghc-mod.vim
+++ /dev/null
@@ -1,18 +0,0 @@
-" Author: wizzup <wizzup@gmail.com>
-" Description: ghc-mod for Haskell files
-
-call ale#linter#Define('haskell', {
-\ 'name': 'ghc_mod',
-\ 'aliases': ['ghc-mod'],
-\ 'executable': 'ghc-mod',
-\ 'command': 'ghc-mod --map-file %s=%t check %s',
-\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
-\})
-
-call ale#linter#Define('haskell', {
-\ 'name': 'stack_ghc_mod',
-\ 'aliases': ['stack-ghc-mod'],
-\ 'executable': 'stack',
-\ 'command': 'stack exec ghc-mod -- --map-file %s=%t check %s',
-\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
-\})
diff --git a/ale_linters/haskell/ghc_mod.vim b/ale_linters/haskell/ghc_mod.vim
new file mode 100644
index 00000000..9762be7a
--- /dev/null
+++ b/ale_linters/haskell/ghc_mod.vim
@@ -0,0 +1,19 @@
+" Author: wizzup <wizzup@gmail.com>
+" Description: ghc-mod for Haskell files
+
+call ale#Set('haskell_ghc_mod_executable', 'ghc-mod')
+
+function! ale_linters#haskell#ghc_mod#GetCommand (buffer) abort
+ let l:executable = ale#Var(a:buffer, 'haskell_ghc_mod_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'ghc-mod')
+ \ . ' --map-file %s=%t check %s'
+endfunction
+
+call ale#linter#Define('haskell', {
+\ 'name': 'ghc_mod',
+\ 'aliases': ['ghc-mod'],
+\ 'executable_callback': ale#VarFunc('haskell_ghc_mod_executable'),
+\ 'command_callback': 'ale_linters#haskell#ghc_mod#GetCommand',
+\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
+\})
diff --git a/ale_linters/haskell/hdevtools.vim b/ale_linters/haskell/hdevtools.vim
index dc902152..cc5ce56f 100644
--- a/ale_linters/haskell/hdevtools.vim
+++ b/ale_linters/haskell/hdevtools.vim
@@ -4,19 +4,17 @@
call ale#Set('haskell_hdevtools_executable', 'hdevtools')
call ale#Set('haskell_hdevtools_options', get(g:, 'hdevtools_options', '-g -Wall'))
-function! ale_linters#haskell#hdevtools#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'haskell_hdevtools_executable')
-endfunction
-
function! ale_linters#haskell#hdevtools#GetCommand(buffer) abort
- return ale#Escape(ale_linters#haskell#hdevtools#GetExecutable(a:buffer))
- \ . ' check ' . ale#Var(a:buffer, 'haskell_hdevtools_options')
- \ . ' -p %s %t'
+ let l:executable = ale#Var(a:buffer, 'haskell_hdevtools_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hdevtools')
+ \ . ' check' . ale#Pad(ale#Var(a:buffer, 'haskell_hdevtools_options'))
+ \ . ' -p %s %t'
endfunction
call ale#linter#Define('haskell', {
\ 'name': 'hdevtools',
-\ 'executable_callback': 'ale_linters#haskell#hdevtools#GetExecutable',
+\ 'executable_callback': ale#VarFunc('haskell_hdevtools_executable'),
\ 'command_callback': 'ale_linters#haskell#hdevtools#GetCommand',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/haskell/hie.vim b/ale_linters/haskell/hie.vim
new file mode 100644
index 00000000..3ff1180a
--- /dev/null
+++ b/ale_linters/haskell/hie.vim
@@ -0,0 +1,47 @@
+" Author: Luxed <devildead13@gmail.com>
+" Description: A language server for Haskell
+
+call ale#Set('haskell_hie_executable', 'hie')
+
+function! ale_linters#haskell#hie#GetProjectRoot(buffer) abort
+ " Search for the stack file first
+ let l:project_file = ale#path#FindNearestFile(a:buffer, 'stack.yaml')
+
+ " If it's empty, search for the cabal file
+ if empty(l:project_file)
+ let l:cabal_file = fnamemodify(bufname(a:buffer), ':p:h')
+ let l:paths = ''
+
+ while empty(matchstr(l:cabal_file, '^\(\/\|\(\w:\\\)\)$'))
+ let l:cabal_file = fnamemodify(l:cabal_file, ':h')
+ let l:paths = l:paths . l:cabal_file . ','
+ endwhile
+
+ let l:project_file = globpath(l:paths, '*.cabal')
+ endif
+
+ " Either extract the project directory or take the current working
+ " directory
+ if !empty(l:project_file)
+ let l:project_file = fnamemodify(l:project_file, ':h')
+ else
+ let l:project_file = expand('#' . a:buffer . ':p:h')
+ endif
+
+ return l:project_file
+endfunction
+
+function! ale_linters#haskell#hie#GetCommand(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'haskell_hie_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hie')
+\ . ' --lsp'
+endfunction
+
+call ale#linter#Define('haskell', {
+\ 'name': 'hie',
+\ 'lsp': 'stdio',
+\ 'command_callback': 'ale_linters#haskell#hie#GetCommand',
+\ 'executable_callback': ale#VarFunc('haskell_hie_executable'),
+\ 'project_root_callback': 'ale_linters#haskell#hie#GetProjectRoot',
+\})
diff --git a/ale_linters/haskell/hlint.vim b/ale_linters/haskell/hlint.vim
index be40d92c..0cc7437f 100644
--- a/ale_linters/haskell/hlint.vim
+++ b/ale_linters/haskell/hlint.vim
@@ -1,6 +1,9 @@
" Author: jparoz <jesse.paroz@gmail.com>
" Description: hlint for Haskell files
+call ale#Set('haskell_hlint_executable', 'hlint')
+call ale#Set('haskell_hlint_options', get(g:, 'hlint_options', ''))
+
function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
let l:output = []
@@ -26,9 +29,18 @@ function! ale_linters#haskell#hlint#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#haskell#hlint#GetCommand(buffer) abort
+ let l:hlintopts = '--color=never --json'
+
+ return ale#handlers#hlint#GetExecutable(a:buffer)
+ \ . ' ' . ale#Var(a:buffer, 'haskell_hlint_options')
+ \ . ' ' . l:hlintopts
+ \ . ' -'
+endfunction
+
call ale#linter#Define('haskell', {
\ 'name': 'hlint',
-\ 'executable': 'hlint',
-\ 'command': 'hlint --color=never --json -',
+\ 'executable_callback': ale#VarFunc('haskell_hlint_executable'),
+\ 'command_callback': 'ale_linters#haskell#hlint#GetCommand' ,
\ 'callback': 'ale_linters#haskell#hlint#Handle',
\})
diff --git a/ale_linters/haskell/stack_build.vim b/ale_linters/haskell/stack_build.vim
index f5bdf4b8..95a54587 100644
--- a/ale_linters/haskell/stack_build.vim
+++ b/ale_linters/haskell/stack_build.vim
@@ -16,7 +16,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_build',
\ 'aliases': ['stack-build'],
\ 'output_stream': 'stderr',
-\ 'executable': 'stack',
+\ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
\ 'command_callback': 'ale_linters#haskell#stack_build#GetCommand',
\ 'lint_file': 1,
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
diff --git a/ale_linters/haskell/stack_ghc.vim b/ale_linters/haskell/stack_ghc.vim
index d702aa68..8f42b96c 100644
--- a/ale_linters/haskell/stack_ghc.vim
+++ b/ale_linters/haskell/stack_ghc.vim
@@ -5,7 +5,7 @@ call ale#linter#Define('haskell', {
\ 'name': 'stack_ghc',
\ 'aliases': ['stack-ghc'],
\ 'output_stream': 'stderr',
-\ 'executable': 'stack',
+\ 'executable_callback': 'ale#handlers#haskell#GetStackExecutable',
\ 'command': 'stack ghc -- -fno-code -v0 %t',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
diff --git a/ale_linters/html/htmlhint.vim b/ale_linters/html/htmlhint.vim
index caa15bbb..234c1176 100644
--- a/ale_linters/html/htmlhint.vim
+++ b/ale_linters/html/htmlhint.vim
@@ -5,12 +5,6 @@ call ale#Set('html_htmlhint_options', '')
call ale#Set('html_htmlhint_executable', 'htmlhint')
call ale#Set('html_htmlhint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#html#htmlhint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'html_htmlhint', [
- \ 'node_modules/.bin/htmlhint',
- \])
-endfunction
-
function! ale_linters#html#htmlhint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'html_htmlhint_options')
let l:config = l:options !~# '--config'
@@ -25,14 +19,14 @@ function! ale_linters#html#htmlhint#GetCommand(buffer) abort
let l:options = substitute(l:options, '--format=unix', '', '')
endif
- return ale#Escape(ale_linters#html#htmlhint#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --format=unix %t'
+ return '%e' . ale#Pad(l:options) . ' --format=unix %t'
endfunction
call ale#linter#Define('html', {
\ 'name': 'htmlhint',
-\ 'executable_callback': 'ale_linters#html#htmlhint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('html_htmlhint', [
+\ 'node_modules/.bin/htmlhint',
+\ ]),
\ 'command_callback': 'ale_linters#html#htmlhint#GetCommand',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/html/stylelint.vim b/ale_linters/html/stylelint.vim
new file mode 100644
index 00000000..908c4b02
--- /dev/null
+++ b/ale_linters/html/stylelint.vim
@@ -0,0 +1,27 @@
+" Author: Filipe Kiss <hello@filipekiss.com.br> http://github.com/filipekiss
+
+call ale#Set('html_stylelint_executable', 'stylelint')
+call ale#Set('html_stylelint_options', '')
+call ale#Set('html_stylelint_use_global', 0)
+
+function! ale_linters#html#stylelint#GetExecutable(buffer) abort
+ return ale#node#FindExecutable(a:buffer, 'html_stylelint', [
+ \ 'node_modules/.bin/stylelint',
+ \])
+endfunction
+
+function! ale_linters#html#stylelint#GetCommand(buffer) abort
+ let l:executable = ale_linters#html#stylelint#GetExecutable(a:buffer)
+ let l:options = ale#Var(a:buffer, 'html_stylelint_options')
+
+ return ale#Escape(l:executable)
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' --stdin-filename %s'
+endfunction
+
+call ale#linter#Define('html', {
+\ 'name': 'stylelint',
+\ 'executable_callback': 'ale_linters#html#stylelint#GetExecutable',
+\ 'command_callback': 'ale_linters#html#stylelint#GetCommand',
+\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
+\})
diff --git a/ale_linters/html/tidy.vim b/ale_linters/html/tidy.vim
index 913cdade..4ec29091 100644
--- a/ale_linters/html/tidy.vim
+++ b/ale_linters/html/tidy.vim
@@ -25,6 +25,7 @@ function! ale_linters#html#tidy#GetCommand(buffer) abort
" On macOS, old tidy (released on 31 Oct 2006) is installed. It does not
" consider HTML5 so we should avoid it.
let l:executable = ale#Var(a:buffer, 'html_tidy_executable')
+
if has('mac') && l:executable is# 'tidy' && exists('*exepath')
\ && exepath(l:executable) is# '/usr/bin/tidy'
return ''
@@ -37,14 +38,9 @@ function! ale_linters#html#tidy#GetCommand(buffer) abort
\)
endfunction
-function! ale_linters#html#tidy#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'html_tidy_executable')
-endfunction
-
function! ale_linters#html#tidy#Handle(buffer, lines) abort
" Matches patterns lines like the following:
" line 7 column 5 - Warning: missing </title> before </head>
-
let l:pattern = '^line \(\d\+\) column \(\d\+\) - \(Warning\|Error\): \(.\+\)$'
let l:output = []
@@ -67,7 +63,7 @@ endfunction
call ale#linter#Define('html', {
\ 'name': 'tidy',
-\ 'executable_callback': 'ale_linters#html#tidy#GetExecutable',
+\ 'executable_callback': ale#VarFunc('html_tidy_executable'),
\ 'output_stream': 'stderr',
\ 'command_callback': 'ale_linters#html#tidy#GetCommand',
\ 'callback': 'ale_linters#html#tidy#Handle',
diff --git a/ale_linters/idris/idris.vim b/ale_linters/idris/idris.vim
index 115d04fc..feac0f10 100644
--- a/ale_linters/idris/idris.vim
+++ b/ale_linters/idris/idris.vim
@@ -4,21 +4,15 @@
call ale#Set('idris_idris_executable', 'idris')
call ale#Set('idris_idris_options', '--total --warnpartial --warnreach --warnipkg')
-function! ale_linters#idris#idris#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'idris_idris_executable')
-endfunction
-
function! ale_linters#idris#idris#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'idris_idris_options')
- return ale#Escape(ale_linters#idris#idris#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --check %s'
+ return '%e' . ale#Pad(l:options) . ' --check %s'
endfunction
function! ale_linters#idris#idris#Handle(buffer, lines) abort
" This was copied almost verbatim from ale#handlers#haskell#HandleGHCFormat
-
+ "
" Look for lines like the following:
" foo.idr:2:6:When checking right hand side of main with expected type
" bar.idr:11:11-13:
@@ -36,6 +30,7 @@ function! ale_linters#idris#idris#Handle(buffer, lines) abort
else
let l:corrected_lines[-1] .= l:line
endif
+
let l:corrected_lines[-1] = substitute(l:corrected_lines[-1], '\s\+', ' ', 'g')
endif
endfor
@@ -80,8 +75,7 @@ endfunction
call ale#linter#Define('idris', {
\ 'name': 'idris',
-\ 'executable_callback': 'ale_linters#idris#idris#GetExecutable',
+\ 'executable_callback': ale#VarFunc('idris_idris_executable'),
\ 'command_callback': 'ale_linters#idris#idris#GetCommand',
\ 'callback': 'ale_linters#idris#idris#Handle',
\})
-
diff --git a/ale_linters/ispc/ispc.vim b/ale_linters/ispc/ispc.vim
new file mode 100644
index 00000000..de7ceafa
--- /dev/null
+++ b/ale_linters/ispc/ispc.vim
@@ -0,0 +1,45 @@
+" Author: Martino Pilia <martino.pilia@gmail.com>
+" Description: Lint ispc files with the Intel(R) SPMD Program Compiler
+
+call ale#Set('ispc_ispc_executable', 'ispc')
+call ale#Set('ispc_ispc_options', '')
+
+function! ale_linters#ispc#ispc#GetCommand(buffer) abort
+ " --nowrap: do not wrap message lines
+ return '%e --nowrap'
+ \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
+ \ . ale#Pad(ale#Var(a:buffer, 'ispc_ispc_options'))
+ \ . ' %s'
+endfunction
+
+" Note that we ignore the two warnings in the beginning of the compiler output
+" ('no output file specified' and 'no --target specified'), since they have
+" nothing to do with linting.
+function! ale_linters#ispc#ispc#Handle(buffer, lines) abort
+ " Message format: <filename>:<lnum>:<col> <type>: <text>
+ " As far as I know, <type> can be any of:
+ " 'error', 'Error', 'fatal error', 'Warning', 'Performance Warning'
+ let l:re = '\v.+:([0-9]+):([0-9]+):\s+([^:]+):\s+(.+)'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:re)
+ call add(l:output, {
+ \ 'bufnr': a:buffer,
+ \ 'lnum': str2nr(l:match[1]),
+ \ 'col': str2nr(l:match[2]),
+ \ 'type': l:match[3] =~? 'error' ? 'E' : 'W',
+ \ 'text': l:match[4],
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('ispc', {
+\ 'name': 'ispc',
+\ 'output_stream': 'stderr',
+\ 'executable_callback': ale#VarFunc('ispc_ispc_executable'),
+\ 'command_callback': 'ale_linters#ispc#ispc#GetCommand',
+\ 'callback': 'ale_linters#ispc#ispc#Handle',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/java/checkstyle.vim b/ale_linters/java/checkstyle.vim
index 8155170a..c07b65d0 100644
--- a/ale_linters/java/checkstyle.vim
+++ b/ale_linters/java/checkstyle.vim
@@ -2,9 +2,11 @@
" Description: checkstyle for Java files
function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
- let l:pattern = '\v\[(WARN|ERROR)\] [a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.*) \[(.+)\]$'
let l:output = []
+ " modern checkstyle versions
+ let l:pattern = '\v\[(WARN|ERROR)\] [a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.*) \[(.+)\]$'
+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'type': l:match[1] is? 'WARN' ? 'W' : 'E',
@@ -15,13 +17,24 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
\})
endfor
+ " old checkstyle versions
+ let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$'
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'type': l:match[3] is? 'warning' ? 'W' : 'E',
+ \ 'lnum': l:match[2] + 0,
+ \ 'text': l:match[4],
+ \})
+ endfor
+
return l:output
endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort
return 'checkstyle '
\ . ale#Var(a:buffer, 'java_checkstyle_options')
- \ . ' %t'
+ \ . ' %s'
endfunction
if !exists('g:ale_java_checkstyle_options')
@@ -33,4 +46,5 @@ call ale#linter#Define('java', {
\ 'executable': 'checkstyle',
\ 'command_callback': 'ale_linters#java#checkstyle#GetCommand',
\ 'callback': 'ale_linters#java#checkstyle#Handle',
+\ 'lint_file': 1,
\})
diff --git a/ale_linters/java/javac.vim b/ale_linters/java/javac.vim
index d7a39aa7..63dcdd94 100644
--- a/ale_linters/java/javac.vim
+++ b/ale_linters/java/javac.vim
@@ -16,6 +16,7 @@ function! ale_linters#java#javac#GetImportPaths(buffer) abort
endif
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
+
if !empty(l:classpath_command)
return l:classpath_command
endif
@@ -36,10 +37,6 @@ function! s:BuildClassPathOption(buffer, import_paths) abort
\ : ''
endfunction
-function! ale_linters#java#javac#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'java_javac_executable')
-endfunction
-
function! ale_linters#java#javac#GetCommand(buffer, import_paths) abort
let l:cp_option = s:BuildClassPathOption(a:buffer, a:import_paths)
let l:sp_option = ''
@@ -77,13 +74,11 @@ function! ale_linters#java#javac#GetCommand(buffer, import_paths) abort
" Create .class files in a temporary directory, which we will delete later.
let l:class_file_directory = ale#engine#CreateDirectory(a:buffer)
- let l:executable = ale_linters#java#javac#GetExecutable(a:buffer)
" Always run javac from the directory the file is in, so we can resolve
" relative paths correctly.
return ale#path#BufferCdString(a:buffer)
- \ . ale#Escape(l:executable)
- \ . ' -Xlint'
+ \ . '%e -Xlint'
\ . ale#Pad(l:cp_option)
\ . ale#Pad(l:sp_option)
\ . ' -d ' . ale#Escape(l:class_file_directory)
@@ -96,7 +91,6 @@ function! ale_linters#java#javac#Handle(buffer, lines) abort
"
" Main.java:13: warning: [deprecation] donaught() in Testclass has been deprecated
" Main.java:16: error: ';' expected
-
let l:directory = expand('#' . a:buffer . ':p:h')
let l:pattern = '\v^(.*):(\d+): (.+):(.+)$'
let l:col_pattern = '\v^(\s*\^)$'
@@ -126,7 +120,7 @@ endfunction
call ale#linter#Define('java', {
\ 'name': 'javac',
-\ 'executable_callback': 'ale_linters#java#javac#GetExecutable',
+\ 'executable_callback': ale#VarFunc('java_javac_executable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#java#javac#GetImportPaths', 'output_stream': 'stdout'},
\ {'callback': 'ale_linters#java#javac#GetCommand', 'output_stream': 'stderr'},
diff --git a/ale_linters/java/javalsp.vim b/ale_linters/java/javalsp.vim
new file mode 100644
index 00000000..5d1a0c63
--- /dev/null
+++ b/ale_linters/java/javalsp.vim
@@ -0,0 +1,23 @@
+" Author: Horacio Sanson <https://github.com/hsanson>
+" Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac
+
+call ale#Set('java_javalsp_jar', 'javacs.jar')
+
+function! ale_linters#java#javalsp#Executable(buffer) abort
+ return 'java'
+endfunction
+
+function! ale_linters#java#javalsp#Command(buffer) abort
+ let l:jar = ale#Var(a:buffer, 'java_javalsp_jar')
+
+ return ale#Escape('java -cp ' . l:jar . ' -Xverify:none org.javacs.Main')
+endfunction
+
+call ale#linter#Define('java', {
+\ 'name': 'javalsp',
+\ 'lsp': 'stdio',
+\ 'executable_callback': 'ale_linters#java#javalsp#Executable',
+\ 'command_callback': 'ale_linters#java#javalsp#Command',
+\ 'language': 'java',
+\ 'project_root_callback': 'ale#java#FindProjectRoot',
+\})
diff --git a/ale_linters/java/pmd.vim b/ale_linters/java/pmd.vim
index d461e094..b530ad09 100644
--- a/ale_linters/java/pmd.vim
+++ b/ale_linters/java/pmd.vim
@@ -2,7 +2,7 @@
" Description: PMD for Java files
function! ale_linters#java#pmd#Handle(buffer, lines) abort
- let l:pattern = '"\(\d\+\)",".\+","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
+ let l:pattern = '"\(\d\+\)",".*","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim
index d555184e..cdb289c7 100755
--- a/ale_linters/javascript/flow.vim
+++ b/ale_linters/javascript/flow.vim
@@ -91,7 +91,6 @@ function! s:GetDetails(error) abort
let l:detail = ''
for l:extra_error in a:error.extra
-
if has_key(l:extra_error, 'message')
for l:extra_message in l:extra_error.message
let l:detail = s:ExtraErrorMsg(l:detail, l:extra_message.descr)
@@ -105,7 +104,6 @@ function! s:GetDetails(error) abort
endfor
endfor
endif
-
endfor
return l:detail
@@ -161,7 +159,6 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort
endif
call add(l:output, l:errorToAdd)
-
endfor
return l:output
diff --git a/ale_linters/javascript/flow_ls.vim b/ale_linters/javascript/flow_ls.vim
index 20fc2217..75377183 100644
--- a/ale_linters/javascript/flow_ls.vim
+++ b/ale_linters/javascript/flow_ls.vim
@@ -6,18 +6,6 @@ call ale#Set('javascript_flow_ls_use_global',
\ get(g:, 'ale_use_global_executables', 0)
\)
-function! ale_linters#javascript#flow_ls#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_flow_ls', [
- \ 'node_modules/.bin/flow',
- \])
-endfunction
-
-function! ale_linters#javascript#flow_ls#GetCommand(buffer) abort
- let l:executable = ale_linters#javascript#flow_ls#GetExecutable(a:buffer)
-
- return ale#Escape(l:executable) . ' lsp --from ale-lsp'
-endfunction
-
function! ale_linters#javascript#flow_ls#FindProjectRoot(buffer) abort
let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig')
@@ -31,8 +19,10 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'flow-language-server',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#javascript#flow_ls#GetExecutable',
-\ 'command_callback': 'ale_linters#javascript#flow_ls#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_flow_ls', [
+\ 'node_modules/.bin/flow',
+\ ]),
+\ 'command': '%e lsp --from ale-lsp',
\ 'project_root_callback': 'ale_linters#javascript#flow_ls#FindProjectRoot',
\ 'language': 'javascript',
\})
diff --git a/ale_linters/javascript/jscs.vim b/ale_linters/javascript/jscs.vim
index 60044037..a38766a6 100644
--- a/ale_linters/javascript/jscs.vim
+++ b/ale_linters/javascript/jscs.vim
@@ -4,12 +4,6 @@
call ale#Set('javascript_jscs_executable', 'jscs')
call ale#Set('javascript_jscs_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#javascript#jscs#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_jscs', [
- \ 'node_modules/.bin/jscs',
- \])
-endfunction
-
function! ale_linters#javascript#jscs#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jscs_config = ale#path#ResolveLocalPath(
@@ -18,8 +12,7 @@ function! ale_linters#javascript#jscs#GetCommand(buffer) abort
\ get(g:, 'ale_jscs_config_loc', '')
\)
- let l:command = ale#Escape(ale_linters#javascript#jscs#GetExecutable(a:buffer))
- let l:command .= ' --reporter inline --no-colors'
+ let l:command = '%e --reporter inline --no-colors'
if !empty(l:jscs_config)
let l:command .= ' --config ' . ale#Escape(l:jscs_config)
@@ -60,8 +53,9 @@ endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jscs',
-\ 'executable_callback': 'ale_linters#javascript#jscs#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_jscs', [
+\ 'node_modules/.bin/jscs',
+\ ]),
\ 'command_callback': 'ale_linters#javascript#jscs#GetCommand',
\ 'callback': 'ale_linters#javascript#jscs#Handle',
\})
-
diff --git a/ale_linters/javascript/jshint.vim b/ale_linters/javascript/jshint.vim
index 2e9bb9fd..cb7f66fc 100644
--- a/ale_linters/javascript/jshint.vim
+++ b/ale_linters/javascript/jshint.vim
@@ -4,12 +4,6 @@
call ale#Set('javascript_jshint_executable', 'jshint')
call ale#Set('javascript_jshint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#javascript#jshint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_jshint', [
- \ 'node_modules/.bin/jshint',
- \])
-endfunction
-
function! ale_linters#javascript#jshint#GetCommand(buffer) abort
" Search for a local JShint config locaation, and default to a global one.
let l:jshint_config = ale#path#ResolveLocalPath(
@@ -18,21 +12,22 @@ function! ale_linters#javascript#jshint#GetCommand(buffer) abort
\ get(g:, 'ale_jshint_config_loc', '')
\)
- let l:command = ale#Escape(ale_linters#javascript#jshint#GetExecutable(a:buffer))
- let l:command .= ' --reporter unix --extract auto'
+ let l:command = '%e --reporter unix --extract auto'
if !empty(l:jshint_config)
let l:command .= ' --config ' . ale#Escape(l:jshint_config)
endif
- let l:command .= ' -'
+ let l:command .= ' --filename %s -'
return l:command
endfunction
call ale#linter#Define('javascript', {
\ 'name': 'jshint',
-\ 'executable_callback': 'ale_linters#javascript#jshint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_jshint', [
+\ 'node_modules/.bin/jshint',
+\ ]),
\ 'command_callback': 'ale_linters#javascript#jshint#GetCommand',
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})
diff --git a/ale_linters/javascript/tsserver.vim b/ale_linters/javascript/tsserver.vim
index 62dded10..6cf08dd6 100644
--- a/ale_linters/javascript/tsserver.vim
+++ b/ale_linters/javascript/tsserver.vim
@@ -5,22 +5,13 @@ call ale#Set('javascript_tsserver_executable', 'tsserver')
call ale#Set('javascript_tsserver_config_path', '')
call ale#Set('javascript_tsserver_use_global', get(g:, 'ale_use_global_executables', 0))
-" These functions need to be defined just to comply with the API for LSP.
-function! ale_linters#javascript#tsserver#GetProjectRoot(buffer) abort
- return ''
-endfunction
-
-function! ale_linters#javascript#tsserver#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'javascript_tsserver', [
- \ 'node_modules/.bin/tsserver',
- \])
-endfunction
-
call ale#linter#Define('javascript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
-\ 'executable_callback': 'ale_linters#javascript#tsserver#GetExecutable',
-\ 'command_callback': 'ale_linters#javascript#tsserver#GetExecutable',
-\ 'project_root_callback': 'ale_linters#javascript#tsserver#GetProjectRoot',
+\ 'executable_callback': ale#node#FindExecutableFunc('javascript_tsserver', [
+\ 'node_modules/.bin/tsserver',
+\ ]),
+\ 'command': '%e',
+\ 'project_root_callback': {-> ''},
\ 'language': '',
\})
diff --git a/ale_linters/json/jsonlint.vim b/ale_linters/json/jsonlint.vim
index 75f47088..f01553d6 100644
--- a/ale_linters/json/jsonlint.vim
+++ b/ale_linters/json/jsonlint.vim
@@ -3,7 +3,6 @@
function! ale_linters#json#jsonlint#Handle(buffer, lines) abort
" Matches patterns like the following:
" line 2, col 15, found: 'STRING' - expected: 'EOF', '}', ',', ']'.
-
let l:pattern = '^line \(\d\+\), col \(\d*\), \(.\+\)$'
let l:output = []
diff --git a/ale_linters/julia/languageserver.vim b/ale_linters/julia/languageserver.vim
new file mode 100644
index 00000000..cd2000de
--- /dev/null
+++ b/ale_linters/julia/languageserver.vim
@@ -0,0 +1,21 @@
+" Author: Bartolomeo Stellato <bartolomeo.stellato@gmail.com>
+" Description: A language server for Julia
+
+" Set julia executable variable
+call ale#Set('julia_executable', 'julia')
+
+function! ale_linters#julia#languageserver#GetCommand(buffer) abort
+ let l:julia_executable = ale#Var(a:buffer, 'julia_executable')
+ let l:cmd_string = 'using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);'
+
+ return ale#Escape(l:julia_executable) . ' --startup-file=no --history-file=no -e ' . ale#Escape(l:cmd_string)
+endfunction
+
+call ale#linter#Define('julia', {
+\ 'name': 'languageserver',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('julia_executable'),
+\ 'command_callback': 'ale_linters#julia#languageserver#GetCommand',
+\ 'language': 'julia',
+\ 'project_root_callback': 'ale#julia#FindProjectRoot',
+\})
diff --git a/ale_linters/kotlin/kotlinc.vim b/ale_linters/kotlin/kotlinc.vim
index 00f94be5..4a993986 100644
--- a/ale_linters/kotlin/kotlinc.vim
+++ b/ale_linters/kotlin/kotlinc.vim
@@ -17,12 +17,14 @@ function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort
return ''
else
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml')
+
if !empty(l:pom_path) && executable('mvn')
return ale#path#CdString(fnamemodify(l:pom_path, ':h'))
\ . 'mvn dependency:build-classpath'
endif
let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer)
+
if !empty(l:classpath_command)
return l:classpath_command
endif
@@ -78,12 +80,13 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
endif
let l:fname = ''
+
if ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath') isnot# ''
let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' '
else
" Find the src directory for files in this project.
-
let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
+
if !empty(l:project_root)
let l:src_dir = l:project_root
else
@@ -93,6 +96,7 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort
let l:fname .= expand(l:src_dir, 1) . ' '
endif
+
let l:fname .= ale#Escape(expand('#' . a:buffer . ':p'))
let l:command .= l:kotlinc_opts . ' ' . l:fname
@@ -124,6 +128,7 @@ function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort
if l:buf_abspath isnot# l:curbuf_abspath
continue
endif
+
let l:type_marker_str = l:type is# 'warning' ? 'W' : 'E'
call add(l:output, {
diff --git a/ale_linters/kotlin/languageserver.vim b/ale_linters/kotlin/languageserver.vim
index 0ab673ec..aea817ba 100644
--- a/ale_linters/kotlin/languageserver.vim
+++ b/ale_linters/kotlin/languageserver.vim
@@ -3,15 +3,6 @@
call ale#Set('kotlin_languageserver_executable', 'kotlin-language-server')
-function! ale_linters#kotlin#languageserver#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'kotlin_languageserver_executable')
-endfunction
-
-function! ale_linters#kotlin#languageserver#GetCommand(buffer) abort
- let l:executable = ale_linters#kotlin#languageserver#GetExecutable(a:buffer)
- return ale#Escape(l:executable)
-endfunction
-
function! ale_linters#kotlin#languageserver#GetProjectRoot(buffer) abort
let l:gradle_root = ale#gradle#FindProjectRoot(a:buffer)
@@ -31,8 +22,8 @@ endfunction
call ale#linter#Define('kotlin', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#kotlin#languageserver#GetExecutable',
-\ 'command_callback': 'ale_linters#kotlin#languageserver#GetCommand',
+\ 'executable_callback': ale#VarFunc('kotlin_languageserver_executable'),
+\ 'command': '%e',
\ 'language': 'kotlin',
\ 'project_root_callback': 'ale_linters#kotlin#languageserver#GetProjectRoot',
\})
diff --git a/ale_linters/less/lessc.vim b/ale_linters/less/lessc.vim
index 5fd9a383..37600649 100755
--- a/ale_linters/less/lessc.vim
+++ b/ale_linters/less/lessc.vim
@@ -5,21 +5,10 @@ call ale#Set('less_lessc_executable', 'lessc')
call ale#Set('less_lessc_options', '')
call ale#Set('less_lessc_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#less#lessc#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'less_lessc', [
- \ 'node_modules/.bin/lessc',
- \])
-endfunction
-
function! ale_linters#less#lessc#GetCommand(buffer) abort
- let l:executable = ale_linters#less#lessc#GetExecutable(a:buffer)
- let l:dir = expand('#' . a:buffer . ':p:h')
- let l:options = ale#Var(a:buffer, 'less_lessc_options')
-
- return ale#Escape(l:executable)
- \ . ' --no-color --lint'
- \ . ' --include-path=' . ale#Escape(l:dir)
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ return '%e --no-color --lint'
+ \ . ' --include-path=' . ale#Escape(expand('#' . a:buffer . ':p:h'))
+ \ . ale#Pad(ale#Var(a:buffer, 'less_lessc_options'))
\ . ' -'
endfunction
@@ -49,7 +38,9 @@ endfunction
call ale#linter#Define('less', {
\ 'name': 'lessc',
-\ 'executable_callback': 'ale_linters#less#lessc#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('less_lessc', [
+\ 'node_modules/.bin/lessc',
+\ ]),
\ 'command_callback': 'ale_linters#less#lessc#GetCommand',
\ 'callback': 'ale_linters#less#lessc#Handle',
\ 'output_stream': 'stderr',
diff --git a/ale_linters/less/stylelint.vim b/ale_linters/less/stylelint.vim
index 8e16a098..479808c2 100644
--- a/ale_linters/less/stylelint.vim
+++ b/ale_linters/less/stylelint.vim
@@ -4,24 +4,17 @@ call ale#Set('less_stylelint_executable', 'stylelint')
call ale#Set('less_stylelint_options', '')
call ale#Set('less_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#less#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'less_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#less#stylelint#GetCommand(buffer) abort
- let l:executable = ale_linters#less#stylelint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'less_stylelint_options')
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --stdin-filename %s'
+ return '%e' . ale#Pad(l:options) . ' --stdin-filename %s'
endfunction
call ale#linter#Define('less', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#less#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('less_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': 'ale_linters#less#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/llvm/llc.vim b/ale_linters/llvm/llc.vim
index 15201cbe..044f8c44 100644
--- a/ale_linters/llvm/llc.vim
+++ b/ale_linters/llvm/llc.vim
@@ -3,21 +3,11 @@
call ale#Set('llvm_llc_executable', 'llc')
-function! ale_linters#llvm#llc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'llvm_llc_executable')
-endfunction
-
-function! ale_linters#llvm#llc#GetCommand(buffer) abort
- return ale#Escape(ale_linters#llvm#llc#GetExecutable(a:buffer))
- \ . ' -filetype=null -o=' . g:ale#util#nul_file
-endfunction
-
function! ale_linters#llvm#llc#HandleErrors(buffer, lines) abort
" Handle '{path}: {file}:{line}:{col}: error: {message}' format
let l:pattern = '\v^[a-zA-Z]?:?[^:]+: [^:]+:(\d+):(\d+): (.+)$'
- let l:matches = ale#util#GetMatches(a:lines, l:pattern)
- return map(l:matches, "{
+ return map(ale#util#GetMatches(a:lines, l:pattern), "{
\ 'lnum': str2nr(v:val[1]),
\ 'col': str2nr(v:val[2]),
\ 'text': v:val[3],
@@ -27,8 +17,8 @@ endfunction
call ale#linter#Define('llvm', {
\ 'name': 'llc',
-\ 'executable_callback': 'ale_linters#llvm#llc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('llvm_llc_executable'),
\ 'output_stream': 'stderr',
-\ 'command_callback': 'ale_linters#llvm#llc#GetCommand',
+\ 'command_callback': {-> '%e -filetype=null -o=' . g:ale#util#nul_file},
\ 'callback': 'ale_linters#llvm#llc#HandleErrors',
\})
diff --git a/ale_linters/lua/luac.vim b/ale_linters/lua/luac.vim
index 4a6bb403..bca2cd8d 100644
--- a/ale_linters/lua/luac.vim
+++ b/ale_linters/lua/luac.vim
@@ -3,15 +3,6 @@
call ale#Set('lua_luac_executable', 'luac')
-function! ale_linters#lua#luac#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'lua_luac_executable')
-endfunction
-
-function! ale_linters#lua#luac#GetCommand(buffer) abort
- let l:executable = ale_linters#lua#luac#GetExecutable(a:buffer)
- return ale#Escape(l:executable) . ' -p - '
-endfunction
-
function! ale_linters#lua#luac#Handle(buffer, lines) abort
" Matches patterns line the following:
"
@@ -33,8 +24,8 @@ endfunction
call ale#linter#Define('lua', {
\ 'name': 'luac',
-\ 'executable_callback': 'ale_linters#lua#luac#GetExecutable',
-\ 'command_callback': 'ale_linters#lua#luac#GetCommand',
+\ 'executable_callback': ale#VarFunc('lua_luac_executable'),
+\ 'command': '%e -p -',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#lua#luac#Handle',
\})
diff --git a/ale_linters/lua/luacheck.vim b/ale_linters/lua/luacheck.vim
index 725153c6..669103b8 100644
--- a/ale_linters/lua/luacheck.vim
+++ b/ale_linters/lua/luacheck.vim
@@ -1,19 +1,11 @@
" Author: Sol Bekic https://github.com/s-ol
" Description: luacheck linter for lua files
-let g:ale_lua_luacheck_executable =
-\ get(g:, 'ale_lua_luacheck_executable', 'luacheck')
-
-let g:ale_lua_luacheck_options =
-\ get(g:, 'ale_lua_luacheck_options', '')
-
-function! ale_linters#lua#luacheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'lua_luacheck_executable')
-endfunction
+call ale#Set('lua_luacheck_executable', 'luacheck')
+call ale#Set('lua_luacheck_options', '')
function! ale_linters#lua#luacheck#GetCommand(buffer) abort
- return ale#Escape(ale_linters#lua#luacheck#GetExecutable(a:buffer))
- \ . ' ' . ale#Var(a:buffer, 'lua_luacheck_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'lua_luacheck_options'))
\ . ' --formatter plain --codes --filename %s -'
endfunction
@@ -46,7 +38,7 @@ endfunction
call ale#linter#Define('lua', {
\ 'name': 'luacheck',
-\ 'executable_callback': 'ale_linters#lua#luacheck#GetExecutable',
+\ 'executable_callback': ale#VarFunc('lua_luacheck_executable'),
\ 'command_callback': 'ale_linters#lua#luacheck#GetCommand',
\ 'callback': 'ale_linters#lua#luacheck#Handle',
\})
diff --git a/ale_linters/make/checkmake.vim b/ale_linters/make/checkmake.vim
index 63c35db3..5ebdf91e 100644
--- a/ale_linters/make/checkmake.vim
+++ b/ale_linters/make/checkmake.vim
@@ -13,6 +13,7 @@ function! ale_linters#make#checkmake#Handle(buffer, lines) abort
\ 'text': l:match[3],
\})
endfor
+
return l:output
endfunction
diff --git a/ale_linters/markdown/remark_lint.vim b/ale_linters/markdown/remark_lint.vim
index d9c2efb6..4f8d48fa 100644
--- a/ale_linters/markdown/remark_lint.vim
+++ b/ale_linters/markdown/remark_lint.vim
@@ -5,19 +5,10 @@ call ale#Set('markdown_remark_lint_executable', 'remark')
call ale#Set('markdown_remark_lint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('markdown_remark_lint_options', '')
-function! ale_linters#markdown#remark_lint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'markdown_remark_lint', [
- \ 'node_modules/.bin/remark',
- \])
-endfunction
-
function! ale_linters#markdown#remark_lint#GetCommand(buffer) abort
- let l:executable = ale_linters#markdown#remark_lint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options')
- return ale#node#Executable(a:buffer, l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --no-stdout --no-color'
+ return '%e' . ale#Pad(l:options) . ' --no-stdout --no-color'
endfunction
function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort
@@ -33,10 +24,12 @@ function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort
\ 'type': l:match[6] is# 'error' ? 'E' : 'W',
\ 'text': l:match[7],
\}
+
if l:match[3] isnot# ''
let l:item.end_lnum = l:match[4] + 0
let l:item.end_col = l:match[5] + 0
endif
+
call add(l:output, l:item)
endfor
@@ -46,7 +39,9 @@ endfunction
call ale#linter#Define('markdown', {
\ 'name': 'remark_lint',
\ 'aliases': ['remark-lint'],
-\ 'executable_callback': 'ale_linters#markdown#remark_lint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('markdown_remark_lint', [
+\ 'node_modules/.bin/remark',
+\ ]),
\ 'command_callback': 'ale_linters#markdown#remark_lint#GetCommand',
\ 'callback': 'ale_linters#markdown#remark_lint#Handle',
\ 'output_stream': 'stderr',
diff --git a/ale_linters/matlab/mlint.vim b/ale_linters/matlab/mlint.vim
index 32766334..3435045e 100644
--- a/ale_linters/matlab/mlint.vim
+++ b/ale_linters/matlab/mlint.vim
@@ -1,18 +1,7 @@
" Author: awlayton <alex@layton.in>
" Description: mlint for MATLAB files
-let g:ale_matlab_mlint_executable =
-\ get(g:, 'ale_matlab_mlint_executable', 'mlint')
-
-function! ale_linters#matlab#mlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'matlab_mlint_executable')
-endfunction
-
-function! ale_linters#matlab#mlint#GetCommand(buffer) abort
- let l:executable = ale_linters#matlab#mlint#GetExecutable(a:buffer)
-
- return l:executable . ' -id %t'
-endfunction
+call ale#Set('matlab_mlint_executable', 'mlint')
function! ale_linters#matlab#mlint#Handle(buffer, lines) abort
" Matches patterns like the following:
@@ -48,8 +37,8 @@ endfunction
call ale#linter#Define('matlab', {
\ 'name': 'mlint',
-\ 'executable_callback': 'ale_linters#matlab#mlint#GetExecutable',
-\ 'command_callback': 'ale_linters#matlab#mlint#GetCommand',
+\ 'executable_callback': ale#VarFunc('matlab_mlint_executable'),
+\ 'command': '%e -id %t',
\ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#matlab#mlint#Handle',
\})
diff --git a/ale_linters/mercury/mmc.vim b/ale_linters/mercury/mmc.vim
index c7bfc59d..76d357f0 100644
--- a/ale_linters/mercury/mmc.vim
+++ b/ale_linters/mercury/mmc.vim
@@ -4,16 +4,11 @@
call ale#Set('mercury_mmc_executable', 'mmc')
call ale#Set('mercury_mmc_options', '--make --output-compile-error-lines 100')
-function! ale_linters#mercury#mmc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'mercury_mmc_executable')
-endfunction
-
function! ale_linters#mercury#mmc#GetCommand(buffer) abort
let l:module_name = expand('#' . a:buffer . ':t:r')
return ale#path#BufferCdString(a:buffer)
- \ . ale_linters#mercury#mmc#GetExecutable(a:buffer)
- \ . ' --errorcheck-only '
+ \ . '%e --errorcheck-only '
\ . ale#Var(a:buffer, 'mercury_mmc_options')
\ . ' ' . l:module_name
endfunction
@@ -38,7 +33,7 @@ endfunction
call ale#linter#Define('mercury', {
\ 'name': 'mmc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#mercury#mmc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('mercury_mmc_executable'),
\ 'command_callback': 'ale_linters#mercury#mmc#GetCommand',
\ 'callback': 'ale_linters#mercury#mmc#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/nasm/nasm.vim b/ale_linters/nasm/nasm.vim
index 77d57e18..cb2119a6 100644
--- a/ale_linters/nasm/nasm.vim
+++ b/ale_linters/nasm/nasm.vim
@@ -4,32 +4,23 @@
call ale#Set('nasm_nasm_executable', 'nasm')
call ale#Set('nasm_nasm_options', '')
-function! ale_linters#nasm#nasm#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'nasm_nasm_executable')
-endfunction
-
-function! ale_linters#nasm#nasm#GetOptions(buffer) abort
- return ale#Var(a:buffer, 'nasm_nasm_options')
-endfunction
-
function! ale_linters#nasm#nasm#GetCommand(buffer) abort
- " Note that NASM require a trailing slash to the -I option.
- let l:executable = ale#Escape(ale_linters#nasm#nasm#GetExecutable(a:buffer))
+ " Note that NASM requires a trailing slash for the -I option.
let l:separator = has('win32') ? '\' : '/'
- let l:path = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h') . l:separator)
- let l:options = ale_linters#nasm#nasm#GetOptions(a:buffer)
+ let l:path = fnamemodify(bufname(a:buffer), ':p:h') . l:separator
+ let l:output_null = has('win32') ? 'NUL' : '/dev/null'
- return l:executable
- \ . ' -X gnu'
- \ . ' -I ' . l:path
- \ . ' ' . l:options
+ return '%e -X gnu -I ' . ale#Escape(l:path)
+ \ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
\ . ' %s'
+ \ . ' -o ' . l:output_null
endfunction
function! ale_linters#nasm#nasm#Handle(buffer, lines) abort
" Note that we treat 'fatal' as errors.
let l:pattern = '^.\+:\(\d\+\): \([^:]\+\): \(.\+\)$'
let l:output = []
+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
@@ -37,6 +28,7 @@ function! ale_linters#nasm#nasm#Handle(buffer, lines) abort
\ 'text': l:match[3],
\})
endfor
+
return l:output
endfunction
@@ -44,7 +36,7 @@ call ale#linter#Define('nasm', {
\ 'name': 'nasm',
\ 'output_stream': 'stderr',
\ 'lint_file': 1,
-\ 'executable_callback': 'ale_linters#nasm#nasm#GetExecutable',
+\ 'executable_callback': ale#VarFunc('nasm_nasm_executable'),
\ 'command_callback': 'ale_linters#nasm#nasm#GetCommand',
\ 'callback': 'ale_linters#nasm#nasm#Handle',
\})
diff --git a/ale_linters/objc/ccls.vim b/ale_linters/objc/ccls.vim
new file mode 100644
index 00000000..0aa6a5e5
--- /dev/null
+++ b/ale_linters/objc/ccls.vim
@@ -0,0 +1,14 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>, jtalowell <jtalowell@protonmail.com>
+" Description: A language server for Objective-C
+
+call ale#Set('objc_ccls_executable', 'ccls')
+call ale#Set('objc_ccls_init_options', {})
+
+call ale#linter#Define('objc', {
+\ 'name': 'ccls',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('objc_ccls_executable'),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale#handlers#ccls#GetProjectRoot',
+\ 'initialization_options_callback': ale#VarFunc('objc_ccls_init_options'),
+\})
diff --git a/ale_linters/objc/clang.vim b/ale_linters/objc/clang.vim
index f4725a0e..4e80ac5c 100644
--- a/ale_linters/objc/clang.vim
+++ b/ale_linters/objc/clang.vim
@@ -19,5 +19,5 @@ call ale#linter#Define('objc', {
\ 'output_stream': 'stderr',
\ 'executable': 'clang',
\ 'command_callback': 'ale_linters#objc#clang#GetCommand',
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/objc/clangd.vim b/ale_linters/objc/clangd.vim
new file mode 100644
index 00000000..f090e6ce
--- /dev/null
+++ b/ale_linters/objc/clangd.vim
@@ -0,0 +1,23 @@
+" Author: Andrey Melentyev <andrey.melentyev@protonmail.com>
+" Description: Clangd language server
+
+call ale#Set('objc_clangd_executable', 'clangd')
+call ale#Set('objc_clangd_options', '')
+
+function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#objc#clangd#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options'))
+endfunction
+
+call ale#linter#Define('objc', {
+\ 'name': 'clangd',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('objc_clangd_executable'),
+\ 'command_callback': 'ale_linters#objc#clangd#GetCommand',
+\ 'project_root_callback': 'ale_linters#objc#clangd#GetProjectRoot',
+\})
diff --git a/ale_linters/objcpp/clang.vim b/ale_linters/objcpp/clang.vim
index 0e9cefe9..d1474f17 100644
--- a/ale_linters/objcpp/clang.vim
+++ b/ale_linters/objcpp/clang.vim
@@ -19,5 +19,5 @@ call ale#linter#Define('objcpp', {
\ 'output_stream': 'stderr',
\ 'executable': 'clang++',
\ 'command_callback': 'ale_linters#objcpp#clang#GetCommand',
-\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
+\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})
diff --git a/ale_linters/objcpp/clangd.vim b/ale_linters/objcpp/clangd.vim
new file mode 100644
index 00000000..a09753be
--- /dev/null
+++ b/ale_linters/objcpp/clangd.vim
@@ -0,0 +1,23 @@
+" Author: Andrey Melentyev <andrey.melentyev@protonmail.com>
+" Description: Clangd language server
+
+call ale#Set('objcpp_clangd_executable', 'clangd')
+call ale#Set('objcpp_clangd_options', '')
+
+function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+function! ale_linters#objcpp#clangd#GetCommand(buffer) abort
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options'))
+endfunction
+
+call ale#linter#Define('objcpp', {
+\ 'name': 'clangd',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('objcpp_clangd_executable'),
+\ 'command_callback': 'ale_linters#objcpp#clangd#GetCommand',
+\ 'project_root_callback': 'ale_linters#objcpp#clangd#GetProjectRoot',
+\})
diff --git a/ale_linters/perl/perl.vim b/ale_linters/perl/perl.vim
index 1b9aa95e..1cb20fa7 100644
--- a/ale_linters/perl/perl.vim
+++ b/ale_linters/perl/perl.vim
@@ -1,20 +1,11 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>
" Description: This file adds support for checking perl syntax
-let g:ale_perl_perl_executable =
-\ get(g:, 'ale_perl_perl_executable', 'perl')
-
-let g:ale_perl_perl_options =
-\ get(g:, 'ale_perl_perl_options', '-c -Mwarnings -Ilib')
-
-function! ale_linters#perl#perl#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'perl_perl_executable')
-endfunction
+call ale#Set('perl_perl_executable', 'perl')
+call ale#Set('perl_perl_options', '-c -Mwarnings -Ilib')
function! ale_linters#perl#perl#GetCommand(buffer) abort
- return ale#Escape(ale_linters#perl#perl#GetExecutable(a:buffer))
- \ . ' ' . ale#Var(a:buffer, 'perl_perl_options')
- \ . ' %t'
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'perl_perl_options')) . ' %t'
endfunction
let s:begin_failed_skip_pattern = '\v' . join([
@@ -23,11 +14,16 @@ let s:begin_failed_skip_pattern = '\v' . join([
\], '|')
function! ale_linters#perl#perl#Handle(buffer, lines) abort
+ if empty(a:lines)
+ return []
+ endif
+
let l:pattern = '\(.\+\) at \(.\+\) line \(\d\+\)'
let l:output = []
let l:basename = expand('#' . a:buffer . ':t')
let l:type = 'E'
+
if a:lines[-1] =~# 'syntax OK'
let l:type = 'W'
endif
@@ -61,7 +57,7 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perl',
-\ 'executable_callback': 'ale_linters#perl#perl#GetExecutable',
+\ 'executable_callback': ale#VarFunc('perl_perl_executable'),
\ 'output_stream': 'both',
\ 'command_callback': 'ale_linters#perl#perl#GetCommand',
\ 'callback': 'ale_linters#perl#perl#Handle',
diff --git a/ale_linters/perl/perlcritic.vim b/ale_linters/perl/perlcritic.vim
index e91c8a03..8619a404 100644
--- a/ale_linters/perl/perlcritic.vim
+++ b/ale_linters/perl/perlcritic.vim
@@ -1,21 +1,10 @@
" Author: Vincent Lequertier <https://github.com/SkySymbol>, Chris Weyl <cweyl@alumni.drew.edu>
" Description: This file adds support for checking perl with perl critic
-let g:ale_perl_perlcritic_executable =
-\ get(g:, 'ale_perl_perlcritic_executable', 'perlcritic')
-
-let g:ale_perl_perlcritic_profile =
-\ get(g:, 'ale_perl_perlcritic_profile', '.perlcriticrc')
-
-let g:ale_perl_perlcritic_options =
-\ get(g:, 'ale_perl_perlcritic_options', '')
-
-let g:ale_perl_perlcritic_showrules =
-\ get(g:, 'ale_perl_perlcritic_showrules', 0)
-
-function! ale_linters#perl#perlcritic#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'perl_perlcritic_executable')
-endfunction
+call ale#Set('perl_perlcritic_executable', 'perlcritic')
+call ale#Set('perl_perlcritic_profile', '.perlcriticrc')
+call ale#Set('perl_perlcritic_options', '')
+call ale#Set('perl_perlcritic_showrules', 0)
function! ale_linters#perl#perlcritic#GetProfile(buffer) abort
" first see if we've been overridden
@@ -39,11 +28,11 @@ function! ale_linters#perl#perlcritic#GetCommand(buffer) abort
let l:profile = ale_linters#perl#perlcritic#GetProfile(a:buffer)
let l:options = ale#Var(a:buffer, 'perl_perlcritic_options')
- return ale#Escape(ale_linters#perl#perlcritic#GetExecutable(a:buffer))
+ return '%e'
\ . ' --verbose ' . ale#Escape(l:critic_verbosity)
\ . ' --nocolor'
\ . (!empty(l:profile) ? ' --profile ' . ale#Escape(l:profile) : '')
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ale#Pad(l:options)
endfunction
@@ -66,7 +55,7 @@ endfunction
call ale#linter#Define('perl', {
\ 'name': 'perlcritic',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#perl#perlcritic#GetExecutable',
+\ 'executable_callback': ale#VarFunc('perl_perlcritic_executable'),
\ 'command_callback': 'ale_linters#perl#perlcritic#GetCommand',
\ 'callback': 'ale_linters#perl#perlcritic#Handle',
\})
diff --git a/ale_linters/perl6/perl6.vim b/ale_linters/perl6/perl6.vim
new file mode 100644
index 00000000..b33a0c51
--- /dev/null
+++ b/ale_linters/perl6/perl6.vim
@@ -0,0 +1,166 @@
+" Author:Travis Gibson <https://github.com/Garland-g>
+" Description: This file adds support for checking perl6 syntax
+
+let g:ale_perl6_perl6_executable =
+\ get(g:, 'ale_perl6_perl6_executable', 'perl6')
+
+let g:ale_perl6_perl6_options =
+\ get(g:, 'ale_perl6_perl6_options', '-c -Ilib')
+
+let $PERL6_EXCEPTIONS_HANDLER = 'JSON'
+
+let $RAKUDO_ERROR_COLOR = 0
+
+function! ale_linters#perl6#perl6#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'perl6_perl6_executable')
+endfunction
+
+function! ale_linters#perl6#perl6#GetCommand(buffer) abort
+ return ale_linters#perl6#perl6#GetExecutable(a:buffer)
+ \ . ' ' . ale#Var(a:buffer, 'perl6_perl6_options')
+ \ . ' %t'
+endfunction
+
+function! ale_linters#perl6#perl6#ExtractError(dict, item, type, buffer) abort
+ let l:file = ''
+ let l:line = 1
+ let l:column = ''
+ let l:text = ''
+ let l:pre = ''
+ let l:counter = 2
+ let l:end_line = ''
+ let l:linepatternmessage = 'at\s\+line\s\+\(\d\+\)'
+
+ if has_key(a:dict[a:item], 'filename') && !empty(a:dict[a:item]['filename'])
+ let l:file = a:dict[a:item]['filename']
+ endif
+
+ if has_key(a:dict[a:item], 'line') && !empty(a:dict[a:item]['line'])
+ let l:line = a:dict[a:item]['line']
+ let l:counter -= 1
+ endif
+
+ if has_key(a:dict[a:item], 'column') && !empty(a:dict[a:item]['column'])
+ let l:column = a:dict[a:item]['column']
+ endif
+
+ if has_key(a:dict[a:item], 'message') && !empty(a:dict[a:item]['message'])
+ let l:text = substitute(a:dict[a:item]['message'], '\s*\n\s*', ' ', 'g')
+ let l:counter -= 1
+ endif
+
+ if has_key(a:dict[a:item], 'line-real') && !empty(a:dict[a:item]['line-real'])
+ let l:end_line = l:line
+ let l:line = a:dict[a:item]['line-real']
+ endif
+
+ for l:match in ale#util#GetMatches(l:text, l:linepatternmessage)
+ let l:line = l:match[1]
+ let l:counter -= 1
+ endfor
+
+" Currently, filenames and line numbers are not always given in the error output
+ if l:counter < 2
+ \&& ( ale#path#IsBufferPath(a:buffer, l:file) || l:file is# '' )
+ return {
+ \ 'lnum': '' . l:line,
+ \ 'text': l:text,
+ \ 'type': a:type,
+ \ 'col': l:column,
+ \ 'end_lnum': l:end_line,
+ \ 'code': a:item,
+ \}
+ endif
+
+ return ''
+endfunction
+
+function! ale_linters#perl6#perl6#Handle(buffer, lines) abort
+ let l:output = []
+
+ if empty(a:lines)
+ return l:output
+ endif
+
+ if a:lines[0] is# 'Syntax OK'
+ return l:output
+ endif
+
+ try
+ let l:json = json_decode(join(a:lines, ''))
+ catch /E474/
+ call add(l:output, {
+ \ 'lnum': '1',
+ \ 'text': 'Received output in the default Perl6 error format. See :ALEDetail for details',
+ \ 'detail': join(a:lines, "\n"),
+ \ 'type': 'W',
+ \ })
+
+ return l:output
+ endtry
+
+ if type(l:json) is v:t_dict
+ for l:key in keys(l:json)
+ if has_key(l:json[l:key], 'sorrows') &&
+ \ has_key(l:json[l:key], 'worries')
+ if !empty(l:json[l:key]['sorrows'])
+ for l:dictionary in get(l:json[l:key], 'sorrows')
+ for l:item in keys(l:dictionary)
+ let l:result =
+ \ ale_linters#perl6#perl6#ExtractError(
+ \ l:dictionary,
+ \ l:item,
+ \ 'E',
+ \ a:buffer,
+ \ )
+
+ if l:result isnot# ''
+ call add(l:output, l:result)
+ endif
+ endfor
+ endfor
+ endif
+
+ if !empty(l:json[l:key]['worries'])
+ for l:dictionary in get(l:json[l:key], 'worries')
+ for l:item in keys(l:dictionary)
+ let l:result =
+ \ ale_linters#perl6#perl6#ExtractError(
+ \ l:dictionary,
+ \ l:item,
+ \ 'W',
+ \ a:buffer,
+ \ )
+
+ if l:result isnot# ''
+ call add(l:output, l:result)
+ endif
+ endfor
+ endfor
+ endif
+ else
+ let l:result = ale_linters#perl6#perl6#ExtractError(
+ \ l:json,
+ \ l:key,
+ \ 'E',
+ \ a:buffer,
+ \ )
+
+ if l:result isnot# ''
+ call add(l:output, l:result)
+ endif
+ endif
+ endfor
+ endif
+
+ return l:output
+endfunction
+
+call ale#linter#Define('perl6', {
+\ 'name': 'perl6',
+\ 'executable_callback': 'ale_linters#perl6#perl6#GetExecutable',
+\ 'output_stream': 'both',
+\ 'command_callback': 'ale_linters#perl6#perl6#GetCommand',
+\ 'callback': 'ale_linters#perl6#perl6#Handle',
+\})
+
diff --git a/ale_linters/php/hack.vim b/ale_linters/php/hack.vim
deleted file mode 100644
index 77d3a588..00000000
--- a/ale_linters/php/hack.vim
+++ /dev/null
@@ -1,28 +0,0 @@
-" Author: Zefei Xuan <https://github.com/zefei>
-" Description: Hack type checking (http://hacklang.org/)
-
-function! ale_linters#php#hack#Handle(buffer, lines) abort
- let l:pattern = '^\(.*\):\(\d\+\):\(\d\+\),\(\d\+\): \(.\+])\)$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- if a:buffer != bufnr(l:match[1])
- continue
- endif
-
- call add(l:output, {
- \ 'lnum': l:match[2] + 0,
- \ 'col': l:match[3] + 0,
- \ 'text': l:match[5],
- \})
- endfor
-
- return l:output
-endfunction
-
-call ale#linter#Define('php', {
-\ 'name': 'hack',
-\ 'executable': 'hh_client',
-\ 'command': 'hh_client --retries 0 --retry-if-init false',
-\ 'callback': 'ale_linters#php#hack#Handle',
-\})
diff --git a/ale_linters/php/langserver.vim b/ale_linters/php/langserver.vim
index 38b42df9..ca91db4c 100644
--- a/ale_linters/php/langserver.vim
+++ b/ale_linters/php/langserver.vim
@@ -4,16 +4,6 @@
call ale#Set('php_langserver_executable', 'php-language-server.php')
call ale#Set('php_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#php#langserver#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'php_langserver', [
- \ 'vendor/bin/php-language-server.php',
- \])
-endfunction
-
-function! ale_linters#php#langserver#GetCommand(buffer) abort
- return 'php ' . ale#Escape(ale_linters#php#langserver#GetExecutable(a:buffer))
-endfunction
-
function! ale_linters#php#langserver#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
@@ -23,7 +13,9 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'langserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#php#langserver#GetExecutable',
-\ 'command_callback': 'ale_linters#php#langserver#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('php_langserver', [
+\ 'vendor/bin/php-language-server.php',
+\ ]),
+\ 'command': 'php %e',
\ 'project_root_callback': 'ale_linters#php#langserver#GetProjectRoot',
\})
diff --git a/ale_linters/php/php.vim b/ale_linters/php/php.vim
index 6470383b..5d87196c 100644
--- a/ale_linters/php/php.vim
+++ b/ale_linters/php/php.vim
@@ -1,6 +1,8 @@
" Author: Spencer Wood <https://github.com/scwood>, Adriaan Zonnenberg <amz@adriaan.xyz>
" Description: This file adds support for checking PHP with php-cli
+call ale#Set('php_php_executable', 'php')
+
function! ale_linters#php#php#Handle(buffer, lines) abort
" Matches patterns like the following:
"
@@ -30,8 +32,8 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'php',
-\ 'executable': 'php',
+\ 'executable_callback': ale#VarFunc('php_php_executable'),
\ 'output_stream': 'stdout',
-\ 'command': 'php -l -d error_reporting=E_ALL -d display_errors=1 -d log_errors=0 --',
+\ 'command': '%e -l -d error_reporting=E_ALL -d display_errors=1 -d log_errors=0 --',
\ 'callback': 'ale_linters#php#php#Handle',
\})
diff --git a/ale_linters/php/phpcs.vim b/ale_linters/php/phpcs.vim
index faf8ad55..408c2652 100644
--- a/ale_linters/php/phpcs.vim
+++ b/ale_linters/php/phpcs.vim
@@ -3,26 +3,20 @@
let g:ale_php_phpcs_standard = get(g:, 'ale_php_phpcs_standard', '')
+call ale#Set('php_phpcs_options', '')
call ale#Set('php_phpcs_executable', 'phpcs')
call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#php#phpcs#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'php_phpcs', [
- \ 'vendor/bin/phpcs',
- \ 'phpcs'
- \])
-endfunction
-
function! ale_linters#php#phpcs#GetCommand(buffer) abort
- let l:executable = ale_linters#php#phpcs#GetExecutable(a:buffer)
-
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
let l:standard_option = !empty(l:standard)
\ ? '--standard=' . l:standard
\ : ''
+ let l:options = ale#Var(a:buffer, 'php_phpcs_options')
- return ale#Escape(l:executable)
- \ . ' -s --report=emacs --stdin-path=%s ' . l:standard_option
+ return '%e -s --report=emacs --stdin-path=%s'
+ \ . ale#Pad(l:standard_option)
+ \ . ale#Pad(l:options)
endfunction
function! ale_linters#php#phpcs#Handle(buffer, lines) abort
@@ -50,7 +44,10 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpcs',
-\ 'executable_callback': 'ale_linters#php#phpcs#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('php_phpcs', [
+\ 'vendor/bin/phpcs',
+\ 'phpcs'
+\ ]),
\ 'command_callback': 'ale_linters#php#phpcs#GetCommand',
\ 'callback': 'ale_linters#php#phpcs#Handle',
\})
diff --git a/ale_linters/php/phpmd.vim b/ale_linters/php/phpmd.vim
index e9450752..65f1cc3c 100644
--- a/ale_linters/php/phpmd.vim
+++ b/ale_linters/php/phpmd.vim
@@ -6,16 +6,9 @@ let g:ale_php_phpmd_executable = get(g:, 'ale_php_phpmd_executable', 'phpmd')
" Set to change the ruleset
let g:ale_php_phpmd_ruleset = get(g:, 'ale_php_phpmd_ruleset', 'cleancode,codesize,controversial,design,naming,unusedcode')
-function! ale_linters#php#phpmd#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'php_phpmd_executable')
-endfunction
-
function! ale_linters#php#phpmd#GetCommand(buffer) abort
- let l:executable = ale_linters#php#phpmd#GetExecutable(a:buffer)
-
- return ale#Escape(l:executable)
- \ . ' %s text '
- \ . ale#Var(a:buffer, 'php_phpmd_ruleset')
+ return '%e %s text'
+ \ . ale#Pad(ale#Var(a:buffer, 'php_phpmd_ruleset'))
\ . ' --ignore-violations-on-exit %t'
endfunction
@@ -39,7 +32,7 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpmd',
-\ 'executable_callback': 'ale_linters#php#phpmd#GetExecutable',
+\ 'executable_callback': ale#VarFunc('php_phpmd_executable'),
\ 'command_callback': 'ale_linters#php#phpmd#GetCommand',
\ 'callback': 'ale_linters#php#phpmd#Handle',
\})
diff --git a/ale_linters/php/phpstan.vim b/ale_linters/php/phpstan.vim
index 24762086..1c831e1b 100644
--- a/ale_linters/php/phpstan.vim
+++ b/ale_linters/php/phpstan.vim
@@ -10,18 +10,36 @@ function! ale_linters#php#phpstan#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'php_phpstan_executable')
endfunction
-function! ale_linters#php#phpstan#GetCommand(buffer) abort
+function! ale_linters#php#phpstan#VersionCheck(buffer) abort
let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer)
+ " If we have previously stored the version number in a cache, then
+ " don't look it up again.
+ if ale#semver#HasVersion(l:executable)
+ " Returning an empty string skips this command.
+ return ''
+ endif
+
+ let l:executable = ale#Escape(l:executable)
+
+ return l:executable . ' --version'
+endfunction
+
+function! ale_linters#php#phpstan#GetCommand(buffer, version_output) abort
let l:configuration = ale#Var(a:buffer, 'php_phpstan_configuration')
let l:configuration_option = !empty(l:configuration)
\ ? ' -c ' . l:configuration
\ : ''
- return ale#Escape(l:executable)
- \ . ' analyze -l'
+ let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer)
+ let l:version = ale#semver#GetVersion(l:executable, a:version_output)
+ let l:error_format = ale#semver#GTE(l:version, [0, 10, 3])
+ \ ? ' --error-format raw'
+ \ : ' --errorFormat raw'
+
+ return '%e analyze -l'
\ . ale#Var(a:buffer, 'php_phpstan_level')
- \ . ' --errorFormat raw'
+ \ . l:error_format
\ . l:configuration_option
\ . ' %s'
endfunction
@@ -48,6 +66,9 @@ endfunction
call ale#linter#Define('php', {
\ 'name': 'phpstan',
\ 'executable_callback': 'ale_linters#php#phpstan#GetExecutable',
-\ 'command_callback': 'ale_linters#php#phpstan#GetCommand',
+\ 'command_chain': [
+\ {'callback': 'ale_linters#php#phpstan#VersionCheck'},
+\ {'callback': 'ale_linters#php#phpstan#GetCommand'},
+\ ],
\ 'callback': 'ale_linters#php#phpstan#Handle',
\})
diff --git a/ale_linters/php/psalm.vim b/ale_linters/php/psalm.vim
new file mode 100644
index 00000000..dce59178
--- /dev/null
+++ b/ale_linters/php/psalm.vim
@@ -0,0 +1,21 @@
+" Author: Matt Brown <https://github.com/muglug>
+" Description: plugin for Psalm, static analyzer for PHP
+
+call ale#Set('psalm_langserver_executable', 'psalm-language-server')
+call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
+
+function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
+ let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
+
+ return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
+endfunction
+
+call ale#linter#Define('php', {
+\ 'name': 'psalm',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#node#FindExecutableFunc('psalm_langserver', [
+\ 'vendor/bin/psalm-language-server',
+\ ]),
+\ 'command': '%e',
+\ 'project_root_callback': 'ale_linters#php#psalm#GetProjectRoot',
+\})
diff --git a/ale_linters/pony/ponyc.vim b/ale_linters/pony/ponyc.vim
index b3329053..19e7e828 100644
--- a/ale_linters/pony/ponyc.vim
+++ b/ale_linters/pony/ponyc.vim
@@ -3,19 +3,14 @@
call ale#Set('pony_ponyc_executable', 'ponyc')
call ale#Set('pony_ponyc_options', '--pass paint')
-function! ale_linters#pony#ponyc#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'pony_ponyc_executable')
-endfunction
-
function! ale_linters#pony#ponyc#GetCommand(buffer) abort
- return ale#Escape(ale_linters#pony#ponyc#GetExecutable(a:buffer))
- \ . ' ' . ale#Var(a:buffer, 'pony_ponyc_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'pony_ponyc_options'))
endfunction
call ale#linter#Define('pony', {
\ 'name': 'ponyc',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#pony#ponyc#GetExecutable',
+\ 'executable_callback': ale#VarFunc('pony_ponyc_executable'),
\ 'command_callback': 'ale_linters#pony#ponyc#GetCommand',
\ 'callback': 'ale#handlers#pony#HandlePonycFormat',
\})
diff --git a/ale_linters/prolog/swipl.vim b/ale_linters/prolog/swipl.vim
new file mode 100644
index 00000000..401e52b6
--- /dev/null
+++ b/ale_linters/prolog/swipl.vim
@@ -0,0 +1,100 @@
+" Author: Takuya Fujiwara <tyru.exe@gmail.com>
+" Description: swipl syntax / semantic check for Prolog files
+
+call ale#Set('prolog_swipl_executable', 'swipl')
+call ale#Set('prolog_swipl_load', 'current_prolog_flag(argv, [File]), load_files(File, [sandboxed(true)]), halt.')
+call ale#Set('prolog_swipl_timeout', 3)
+call ale#Set('prolog_swipl_alarm', 'alarm(%t, (%h), _, [])')
+call ale#Set('prolog_swipl_alarm_handler', 'writeln(user_error, "ERROR: Exceeded %t seconds, Please change g:prolog_swipl_timeout to modify the limit."), halt(1)')
+
+function! ale_linters#prolog#swipl#GetCommand(buffer) abort
+ let l:goals = ale#Var(a:buffer, 'prolog_swipl_load')
+ let l:goals = l:goals =~# '^\s*$' ? 'halt' : l:goals
+ let l:timeout = ale#Var(a:buffer, 'prolog_swipl_timeout') + 0
+
+ if l:timeout > 0
+ let l:goals = s:GetAlarm(a:buffer, l:timeout) . ', ' . l:goals
+ endif
+
+ return '%e -g ' . ale#Escape(l:goals) . ' -- %s'
+endfunction
+
+function! s:GetAlarm(buffer, timeout) abort
+ let l:handler = ale#Var(a:buffer, 'prolog_swipl_alarm_handler')
+ let l:handler = s:Subst(l:handler, {'t': a:timeout})
+ let l:alarm = ale#Var(a:buffer, 'prolog_swipl_alarm')
+ let l:alarm = s:Subst(l:alarm, {'t': a:timeout, 'h': l:handler})
+
+ return l:alarm
+endfunction
+
+function! s:Subst(format, vars) abort
+ let l:vars = extend(copy(a:vars), {'%': '%'})
+
+ return substitute(a:format, '%\(.\)', '\=get(l:vars, submatch(1), "")', 'g')
+endfunction
+
+function! ale_linters#prolog#swipl#Handle(buffer, lines) abort
+ let l:pattern = '\v^(ERROR|Warning)+%(:\s*[^:]+:(\d+)%(:(\d+))?)?:\s*(.*)$'
+ let l:output = []
+ let l:i = 0
+
+ while l:i < len(a:lines)
+ let l:match = matchlist(a:lines[l:i], l:pattern)
+
+ if empty(l:match)
+ let l:i += 1
+ continue
+ endif
+
+ let [l:i, l:text] = s:GetErrMsg(l:i, a:lines, l:match[4])
+ let l:item = {
+ \ 'lnum': (l:match[2] + 0 ? l:match[2] + 0 : 1),
+ \ 'col': l:match[3] + 0,
+ \ 'text': l:text,
+ \ 'type': (l:match[1] is# 'ERROR' ? 'E' : 'W'),
+ \}
+
+ if !s:Ignore(l:item)
+ call add(l:output, l:item)
+ endif
+ endwhile
+
+ return l:output
+endfunction
+
+" This returns [<next line number>, <error message string>]
+function! s:GetErrMsg(i, lines, text) abort
+ if a:text !~# '^\s*$'
+ return [a:i + 1, a:text]
+ endif
+
+ let l:i = a:i + 1
+ let l:text = []
+
+ while l:i < len(a:lines) && a:lines[l:i] =~# '^\s'
+ call add(l:text, s:Trim(a:lines[l:i]))
+ let l:i += 1
+ endwhile
+
+ return [l:i, join(l:text, '. ')]
+endfunction
+
+function! s:Trim(str) abort
+ return substitute(a:str, '\v^\s+|\s+$', '', 'g')
+endfunction
+
+" Skip sandbox error which is caused by directives
+" because what we want is syntactic or semantic check.
+function! s:Ignore(item) abort
+ return a:item.type is# 'E' &&
+ \ a:item.text =~# '\vNo permission to (call|directive|assert) sandboxed'
+endfunction
+
+call ale#linter#Define('prolog', {
+\ 'name': 'swipl',
+\ 'output_stream': 'stderr',
+\ 'executable_callback': ale#VarFunc('prolog_swipl_executable'),
+\ 'command_callback': 'ale_linters#prolog#swipl#GetCommand',
+\ 'callback': 'ale_linters#prolog#swipl#Handle',
+\})
diff --git a/ale_linters/pug/puglint.vim b/ale_linters/pug/puglint.vim
index 165e68b7..63208986 100644
--- a/ale_linters/pug/puglint.vim
+++ b/ale_linters/pug/puglint.vim
@@ -5,12 +5,6 @@ call ale#Set('pug_puglint_options', '')
call ale#Set('pug_puglint_executable', 'pug-lint')
call ale#Set('pug_puglint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#pug#puglint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'pug_puglint', [
- \ 'node_modules/.bin/pug-lint',
- \])
-endfunction
-
function! s:FindConfig(buffer) abort
for l:filename in [
\ '.pug-lintrc',
@@ -29,19 +23,19 @@ function! s:FindConfig(buffer) abort
endfunction
function! ale_linters#pug#puglint#GetCommand(buffer) abort
- let l:executable = ale_linters#pug#puglint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'pug_puglint_options')
let l:config = s:FindConfig(a:buffer)
- return ale#Escape(l:executable)
- \ . (!empty(l:options) ? ' ' . l:options : '')
+ return '%e' . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' -r inline %t'
endfunction
call ale#linter#Define('pug', {
\ 'name': 'puglint',
-\ 'executable_callback': 'ale_linters#pug#puglint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('pug_puglint', [
+\ 'node_modules/.bin/pug-lint',
+\ ]),
\ 'output_stream': 'stderr',
\ 'command_callback': 'ale_linters#pug#puglint#GetCommand',
\ 'callback': 'ale#handlers#unix#HandleAsError',
diff --git a/ale_linters/puppet/languageserver.vim b/ale_linters/puppet/languageserver.vim
index 52880f32..a3060e65 100644
--- a/ale_linters/puppet/languageserver.vim
+++ b/ale_linters/puppet/languageserver.vim
@@ -3,21 +3,12 @@
call ale#Set('puppet_languageserver_executable', 'puppet-languageserver')
-function! ale_linters#puppet#languageserver#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'puppet_languageserver_executable')
-endfunction
-
-function! ale_linters#puppet#languageserver#GetCommand(buffer) abort
- let l:exe = ale#Escape(ale_linters#puppet#languageserver#GetExecutable(a:buffer))
-
- return l:exe . ' --stdio'
-endfunction
-
function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort
" Note: The metadata.json file is recommended for Puppet 4+ modules, but
" there's no requirement to have it, so fall back to the other possible
" Puppet module directories
let l:root_path = ale#path#FindNearestFile(a:buffer, 'metadata.json')
+
if !empty(l:root_path)
return fnamemodify(l:root_path, ':h')
endif
@@ -27,6 +18,7 @@ function! ale_linters#puppet#languageserver#GetProjectRoot(buffer) abort
\ 'templates',
\]
let l:root_path = ale#path#FindNearestDirectory(a:buffer, l:test_path)
+
if !empty(l:root_path)
return fnamemodify(l:root_path, ':h:h')
endif
@@ -38,8 +30,8 @@ endfunction
call ale#linter#Define('puppet', {
\ 'name': 'languageserver',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#puppet#languageserver#GetExecutable',
-\ 'command_callback': 'ale_linters#puppet#languageserver#GetCommand',
+\ 'executable_callback': ale#VarFunc('puppet_languageserver_executable'),
+\ 'command': '%e --stdio',
\ 'language': 'puppet',
\ 'project_root_callback': 'ale_linters#puppet#languageserver#GetProjectRoot',
\})
diff --git a/ale_linters/puppet/puppet.vim b/ale_linters/puppet/puppet.vim
index 4ca0dd55..0e37bdbd 100644
--- a/ale_linters/puppet/puppet.vim
+++ b/ale_linters/puppet/puppet.vim
@@ -1,11 +1,13 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>
+call ale#Set('puppet_puppet_executable', 'puppet')
+call ale#Set('puppet_puppet_options', '')
+
function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
" Matches patterns like the following:
" Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12
" Error: Could not parse for environment production: Syntax error at '='; expected '}' at /root/puppetcode/modules/pancakes/manifests/init.pp:5"
" Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 4, column: 5)
-
let l:pattern = '^Error: .*: \(.\+\) \((file:\|at\) .\+\.pp\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)'
let l:output = []
@@ -20,10 +22,16 @@ function! ale_linters#puppet#puppet#Handle(buffer, lines) abort
return l:output
endfunction
+function! ale_linters#puppet#puppet#GetCommand(buffer) abort
+ return '%e parser validate --color=false '
+ \ . ale#Pad(ale#Var(a:buffer, 'puppet_puppet_options'))
+ \ . ' %t'
+endfunction
+
call ale#linter#Define('puppet', {
\ 'name': 'puppet',
-\ 'executable': 'puppet',
+\ 'executable_callback': ale#VarFunc('puppet_puppet_executable'),
\ 'output_stream': 'stderr',
-\ 'command': 'puppet parser validate --color=false %t',
+\ 'command_callback': 'ale_linters#puppet#puppet#GetCommand',
\ 'callback': 'ale_linters#puppet#puppet#Handle',
\})
diff --git a/ale_linters/puppet/puppetlint.vim b/ale_linters/puppet/puppetlint.vim
index 13da511b..c9c16f5e 100644
--- a/ale_linters/puppet/puppetlint.vim
+++ b/ale_linters/puppet/puppetlint.vim
@@ -1,26 +1,18 @@
" Author: Alexander Olofsson <alexander.olofsson@liu.se>, Robert Flechtner <flechtner@chemmedia.de>
" Description: puppet-lint for puppet files
-let g:ale_puppet_puppetlint_executable =
-\ get(g:, 'ale_puppet_puppetlint_executable', 'puppet-lint')
-
-let g:ale_puppet_puppetlint_options =
-\ get(g:, 'ale_puppet_puppetlint_options', '--no-autoloader_layout-check')
-
-function! ale_linters#puppet#puppetlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'puppet_puppetlint_executable')
-endfunction
+call ale#Set('puppet_puppetlint_executable', 'puppet-lint')
+call ale#Set('puppet_puppetlint_options', '--no-autoloader_layout-check')
function! ale_linters#puppet#puppetlint#GetCommand(buffer) abort
- return ale_linters#puppet#puppetlint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'puppet_puppetlint_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'puppet_puppetlint_options'))
\ . ' --log-format "-:%{line}:%{column}: %{kind}: [%{check}] %{message}"'
\ . ' %t'
endfunction
call ale#linter#Define('puppet', {
\ 'name': 'puppetlint',
-\ 'executable_callback': 'ale_linters#puppet#puppetlint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('puppet_puppetlint_executable'),
\ 'command_callback': 'ale_linters#puppet#puppetlint#GetCommand',
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\})
diff --git a/ale_linters/pyrex/cython.vim b/ale_linters/pyrex/cython.vim
index 9b6b39d7..d260698c 100644
--- a/ale_linters/pyrex/cython.vim
+++ b/ale_linters/pyrex/cython.vim
@@ -5,16 +5,11 @@
call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra')
-function! ale_linters#pyrex#cython#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'pyrex_cython_executable')
-endfunction
-
function! ale_linters#pyrex#cython#GetCommand(buffer) abort
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
- return ale#Escape(ale_linters#pyrex#cython#GetExecutable(a:buffer))
- \ . ' --working ' . l:local_dir . ' --include-dir ' . l:local_dir
- \ . ' ' . ale#Var(a:buffer, 'pyrex_cython_options')
+ return '%e --working ' . l:local_dir . ' --include-dir ' . l:local_dir
+ \ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
\ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction
@@ -37,7 +32,7 @@ endfunction
call ale#linter#Define('pyrex', {
\ 'name': 'cython',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#pyrex#cython#GetExecutable',
+\ 'executable_callback': ale#VarFunc('pyrex_cython_executable'),
\ 'command_callback': 'ale_linters#pyrex#cython#GetCommand',
\ 'callback': 'ale_linters#pyrex#cython#Handle',
\})
diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim
index 358f51a4..14b67d77 100644
--- a/ale_linters/python/flake8.vim
+++ b/ale_linters/python/flake8.vim
@@ -5,12 +5,18 @@ call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '')
call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_flake8_change_directory', 1)
+call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort
return ale#Var(a:buffer, 'python_flake8_options') =~# ' *-m flake8'
endfunction
function! ale_linters#python#flake8#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_flake8_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
if !s:UsingModule(a:buffer)
return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8'])
endif
@@ -104,6 +110,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines) abort
let l:item = {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
+ \ 'vcol': 1,
\ 'text': l:match[4],
\ 'code': l:code,
\ 'type': 'W',
diff --git a/ale_linters/python/mypy.vim b/ale_linters/python/mypy.vim
index b38ccdeb..0c90a3c7 100644
--- a/ale_linters/python/mypy.vim
+++ b/ale_linters/python/mypy.vim
@@ -5,8 +5,14 @@ call ale#Set('python_mypy_executable', 'mypy')
call ale#Set('python_mypy_ignore_invalid_syntax', 0)
call ale#Set('python_mypy_options', '')
call ale#Set('python_mypy_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_mypy_auto_pipenv', 0)
function! ale_linters#python#mypy#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_mypy_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy'])
endfunction
diff --git a/ale_linters/python/prospector.vim b/ale_linters/python/prospector.vim
index fff37147..b01cec87 100644
--- a/ale_linters/python/prospector.vim
+++ b/ale_linters/python/prospector.vim
@@ -1,6 +1,8 @@
" Author: chocoelho <carlospecter@gmail.com>
" Description: prospector linter python files
+call ale#Set('python_prospector_auto_pipenv', 0)
+
let g:ale_python_prospector_executable =
\ get(g:, 'ale_python_prospector_executable', 'prospector')
@@ -10,6 +12,11 @@ let g:ale_python_prospector_options =
let g:ale_python_prospector_use_global = get(g:, 'ale_python_prospector_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#python#prospector#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_prospector_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_prospector', ['prospector'])
endfunction
diff --git a/ale_linters/python/pycodestyle.vim b/ale_linters/python/pycodestyle.vim
index de96363f..f0269585 100644
--- a/ale_linters/python/pycodestyle.vim
+++ b/ale_linters/python/pycodestyle.vim
@@ -4,8 +4,14 @@
call ale#Set('python_pycodestyle_executable', 'pycodestyle')
call ale#Set('python_pycodestyle_options', '')
call ale#Set('python_pycodestyle_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pycodestyle_auto_pipenv', 0)
function! ale_linters#python#pycodestyle#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycodestyle_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pycodestyle', ['pycodestyle'])
endfunction
diff --git a/ale_linters/python/pyflakes.vim b/ale_linters/python/pyflakes.vim
index 86ff8773..091408d5 100644
--- a/ale_linters/python/pyflakes.vim
+++ b/ale_linters/python/pyflakes.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyflakes_executable', 'pyflakes')
call ale#Set('python_pyflakes_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyflakes_auto_pipenv', 0)
function! ale_linters#python#pyflakes#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyflakes_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyflakes', ['pyflakes'])
endfunction
diff --git a/ale_linters/python/pylint.vim b/ale_linters/python/pylint.vim
index 9239f835..01c3cb37 100644
--- a/ale_linters/python/pylint.vim
+++ b/ale_linters/python/pylint.vim
@@ -5,8 +5,14 @@ call ale#Set('python_pylint_executable', 'pylint')
call ale#Set('python_pylint_options', '')
call ale#Set('python_pylint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_pylint_change_directory', 1)
+call ale#Set('python_pylint_auto_pipenv', 0)
function! ale_linters#python#pylint#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylint_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
endfunction
diff --git a/ale_linters/python/pyls.vim b/ale_linters/python/pyls.vim
index ae71f022..83fe8066 100644
--- a/ale_linters/python/pyls.vim
+++ b/ale_linters/python/pyls.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyls_executable', 'pyls')
call ale#Set('python_pyls_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyls_auto_pipenv', 0)
function! ale_linters#python#pyls#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyls_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyls', ['pyls'])
endfunction
diff --git a/ale_linters/python/pyre.vim b/ale_linters/python/pyre.vim
index 5efef409..adc185f2 100644
--- a/ale_linters/python/pyre.vim
+++ b/ale_linters/python/pyre.vim
@@ -3,8 +3,14 @@
call ale#Set('python_pyre_executable', 'pyre')
call ale#Set('python_pyre_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_pyre_auto_pipenv', 0)
function! ale_linters#python#pyre#GetExecutable(buffer) abort
+ if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyre_auto_pipenv'))
+ \ && ale#python#PipenvPresent(a:buffer)
+ return 'pipenv'
+ endif
+
return ale#python#FindExecutable(a:buffer, 'python_pyre', ['pyre'])
endfunction
diff --git a/ale_linters/python/vulture.vim b/ale_linters/python/vulture.vim
new file mode 100644
index 00000000..80828013
--- /dev/null
+++ b/ale_linters/python/vulture.vim
@@ -0,0 +1,85 @@
+" Author: Yauheni Kirylau <actionless.loveless@gmail.com>
+" Description: vulture linting for python files
+
+call ale#Set('python_vulture_executable', 'vulture')
+call ale#Set('python_vulture_options', '')
+call ale#Set('python_vulture_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('python_vulture_change_directory', 1)
+
+
+" The directory to change to before running vulture
+function! s:GetDir(buffer) abort
+ let l:project_root = ale#python#FindProjectRoot(a:buffer)
+
+ return !empty(l:project_root)
+ \ ? l:project_root
+ \ : expand('#' . a:buffer . ':p:h')
+endfunction
+
+
+function! ale_linters#python#vulture#GetExecutable(buffer) abort
+ return ale#python#FindExecutable(a:buffer, 'python_vulture', ['vulture'])
+endfunction
+
+
+function! ale_linters#python#vulture#GetCommand(buffer) abort
+ let l:change_dir = ale#Var(a:buffer, 'python_vulture_change_directory')
+ \ ? ale#path#CdString(s:GetDir(a:buffer))
+ \ : ''
+
+ let l:executable = ale_linters#python#vulture#GetExecutable(a:buffer)
+
+ let l:exec_args = l:executable =~? 'pipenv$'
+ \ ? ' run vulture'
+ \ : ''
+
+ let l:lint_dest = ale#Var(a:buffer, 'python_vulture_change_directory')
+ \ ? ' .'
+ \ : ' %s'
+
+ return l:change_dir
+ \ . ale#Escape(l:executable) . l:exec_args
+ \ . ' '
+ \ . ale#Var(a:buffer, 'python_vulture_options')
+ \ . l:lint_dest
+endfunction
+
+
+function! ale_linters#python#vulture#Handle(buffer, lines) abort
+ for l:line in a:lines[:10]
+ if match(l:line, '^Traceback') >= 0
+ return [{
+ \ 'lnum': 1,
+ \ 'text': 'An exception was thrown. See :ALEDetail',
+ \ 'detail': join(a:lines, "\n"),
+ \}]
+ endif
+ endfor
+
+ " Matches patterns line the following:
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+): (.*)$'
+ let l:output = []
+ let l:dir = s:GetDir(a:buffer)
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ let l:abspath = ale#path#GetAbsPath(l:dir, l:match[1])
+ let l:item = {
+ \ 'filename': l:abspath,
+ \ 'lnum': l:match[2] + 0,
+ \ 'text': l:match[3],
+ \ 'type': 'W',
+ \}
+ call add(l:output, l:item)
+ endfor
+
+ return l:output
+endfunction
+
+
+call ale#linter#Define('python', {
+\ 'name': 'vulture',
+\ 'executable_callback': 'ale_linters#python#vulture#GetExecutable',
+\ 'command_callback': 'ale_linters#python#vulture#GetCommand',
+\ 'callback': 'ale_linters#python#vulture#Handle',
+\ 'lint_file': 1,
+\})
diff --git a/ale_linters/qml/qmlfmt.vim b/ale_linters/qml/qmlfmt.vim
index 85b131fd..12f3e97b 100644
--- a/ale_linters/qml/qmlfmt.vim
+++ b/ale_linters/qml/qmlfmt.vim
@@ -1,40 +1,25 @@
" Author: pylipp (www.github.com/pylipp)
" Description: qmlfmt for QML files
-let g:ale_qml_qmlfmt_executable = get(g:, 'ale_qml_qmlfmt_executable', 'qmlfmt')
-
-function! ale_linters#qml#qmlfmt#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'qml_qmlfmt_executable')
-endfunction
-
-function! ale_linters#qml#qmlfmt#GetCommand(buffer) abort
- return ale#Escape(ale_linters#qml#qmlfmt#GetExecutable(a:buffer))
- \ . ' -e'
-endfunction
+call ale#Set('qml_qmlfmt_executable', 'qmlfmt')
" Find lines like
" Error:11:1: Expected token `}'
function! ale_linters#qml#qmlfmt#Handle(buffer, lines) abort
let l:pattern = '\v^(Error|Warning):(\d+):(\d+): (.+)$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- let l:item = {
- \ 'lnum': l:match[2] + 0,
- \ 'col': l:match[3] + 0,
- \ 'text': l:match[4],
- \ 'type': l:match[1] is# 'Warning' ? 'W' : 'E',
- \}
- call add(l:output, l:item)
- endfor
- return l:output
+ return map(ale#util#GetMatches(a:lines, l:pattern), "{
+ \ 'lnum': v:val[2] + 0,
+ \ 'col': v:val[3] + 0,
+ \ 'text': v:val[4],
+ \ 'type': v:val[1] is# 'Warning' ? 'W' : 'E',
+ \}")
endfunction
call ale#linter#Define('qml', {
\ 'name': 'qmlfmt',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#qml#qmlfmt#GetExecutable',
-\ 'command_callback': 'ale_linters#qml#qmlfmt#GetCommand',
+\ 'executable_callback': ale#VarFunc('qml_qmlfmt_executable'),
+\ 'command': '%e -e',
\ 'callback': 'ale_linters#qml#qmlfmt#Handle',
\})
diff --git a/ale_linters/rst/rstcheck.vim b/ale_linters/rst/rstcheck.vim
index b660627f..8504738b 100644
--- a/ale_linters/rst/rstcheck.vim
+++ b/ale_linters/rst/rstcheck.vim
@@ -8,6 +8,7 @@ function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort
let l:pattern = '\v^(.+):(\d*): \(([a-zA-Z]*)/\d*\) (.+)$'
let l:dir = expand('#' . a:buffer . ':p:h')
let l:output = []
+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
diff --git a/ale_linters/ruby/brakeman.vim b/ale_linters/ruby/brakeman.vim
index 85cfc184..122e0b5b 100644
--- a/ale_linters/ruby/brakeman.vim
+++ b/ale_linters/ruby/brakeman.vim
@@ -1,8 +1,9 @@
" Author: Eddie Lebow https://github.com/elebow
" Description: Brakeman, a static analyzer for Rails security
-let g:ale_ruby_brakeman_options =
-\ get(g:, 'ale_ruby_brakeman_options', '')
+call ale#Set('ruby_brakeman_options', '')
+call ale#Set('ruby_brakeman_executable', 'brakeman')
+call ale#Set('ruby_brakeman_options', '')
function! ale_linters#ruby#brakeman#Handle(buffer, lines) abort
let l:output = []
@@ -33,14 +34,17 @@ function! ale_linters#ruby#brakeman#GetCommand(buffer) abort
return ''
endif
- return 'brakeman -f json -q '
+ let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'brakeman')
+ \ . ' -f json -q '
\ . ale#Var(a:buffer, 'ruby_brakeman_options')
\ . ' -p ' . ale#Escape(l:rails_root)
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'brakeman',
-\ 'executable': 'brakeman',
+\ 'executable_callback': ale#VarFunc('ruby_brakeman_executable'),
\ 'command_callback': 'ale_linters#ruby#brakeman#GetCommand',
\ 'callback': 'ale_linters#ruby#brakeman#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/ruby/rails_best_practices.vim b/ale_linters/ruby/rails_best_practices.vim
index 4ba1f3fe..20cadca8 100644
--- a/ale_linters/ruby/rails_best_practices.vim
+++ b/ale_linters/ruby/rails_best_practices.vim
@@ -22,26 +22,18 @@ function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#ruby#rails_best_practices#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
-endfunction
-
function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort
- let l:executable = ale_linters#ruby#rails_best_practices#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rails_best_practices'
- \ : ''
-
let l:rails_root = ale#ruby#FindRailsRoot(a:buffer)
if l:rails_root is? ''
return ''
endif
+ let l:executable = ale#Var(a:buffer, 'ruby_rails_best_practices_executable')
let l:output_file = ale#Has('win32') ? '%t ' : '/dev/stdout '
let l:cat_file = ale#Has('win32') ? '; type %t' : ''
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rails_best_practices')
\ . ' --silent -f json --output-file ' . l:output_file
\ . ale#Var(a:buffer, 'ruby_rails_best_practices_options')
\ . ale#Escape(l:rails_root)
@@ -50,7 +42,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rails_best_practices',
-\ 'executable_callback': 'ale_linters#ruby#rails_best_practices#GetExecutable',
+\ 'executable_callback': ale#VarFunc('ruby_rails_best_practices_executable'),
\ 'command_callback': 'ale_linters#ruby#rails_best_practices#GetCommand',
\ 'callback': 'ale_linters#ruby#rails_best_practices#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/ruby/reek.vim b/ale_linters/ruby/reek.vim
index aa5d8d70..53363d31 100644
--- a/ale_linters/ruby/reek.vim
+++ b/ale_linters/ruby/reek.vim
@@ -3,6 +3,8 @@
call ale#Set('ruby_reek_show_context', 0)
call ale#Set('ruby_reek_show_wiki_link', 0)
+call ale#Set('ruby_reek_options', '')
+call ale#Set('ruby_reek_executable', 'reek')
function! ale_linters#ruby#reek#VersionCheck(buffer) abort
" If we have previously stored the version number in a cache, then
@@ -12,18 +14,23 @@ function! ale_linters#ruby#reek#VersionCheck(buffer) abort
return ''
endif
- return 'reek --version'
+ let l:executable = ale#Var(a:buffer, 'ruby_reek_executable')
+
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ \ . ' --version'
endfunction
function! ale_linters#ruby#reek#GetCommand(buffer, version_output) abort
let l:version = ale#semver#GetVersion('reek', a:version_output)
+ let l:executable = ale#Var(a:buffer, 'ruby_reek_executable')
" Tell reek what the filename is if the version of reek is new enough.
let l:display_name_args = ale#semver#GTE(l:version, [5, 0, 0])
\ ? ' --stdin-filename %s'
\ : ''
- return 'reek -f json --no-progress --no-color'
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek')
+ \ . ' -f json --no-progress --no-color --force-exclusion'
\ . l:display_name_args
endfunction
@@ -62,7 +69,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'reek',
-\ 'executable': 'reek',
+\ 'executable_callback': ale#VarFunc('ruby_reek_executable'),
\ 'command_chain': [
\ {'callback': 'ale_linters#ruby#reek#VersionCheck'},
\ {'callback': 'ale_linters#ruby#reek#GetCommand'},
diff --git a/ale_linters/ruby/rubocop.vim b/ale_linters/ruby/rubocop.vim
index 777f457a..45218394 100644
--- a/ale_linters/ruby/rubocop.vim
+++ b/ale_linters/ruby/rubocop.vim
@@ -1,13 +1,13 @@
" Author: ynonp - https://github.com/ynonp, Eddie Lebow https://github.com/elebow
" Description: RuboCop, a code style analyzer for Ruby files
+call ale#Set('ruby_rubocop_executable', 'rubocop')
+call ale#Set('ruby_rubocop_options', '')
+
function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
- let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rubocop'
- \ : ''
+ let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
@@ -55,7 +55,7 @@ endfunction
call ale#linter#Define('ruby', {
\ 'name': 'rubocop',
-\ 'executable_callback': 'ale#handlers#rubocop#GetExecutable',
+\ 'executable_callback': ale#VarFunc('ruby_rubocop_executable'),
\ 'command_callback': 'ale_linters#ruby#rubocop#GetCommand',
\ 'callback': 'ale_linters#ruby#rubocop#Handle',
\})
diff --git a/ale_linters/ruby/ruby.vim b/ale_linters/ruby/ruby.vim
index 1aa88851..2bc4ec4b 100644
--- a/ale_linters/ruby/ruby.vim
+++ b/ale_linters/ruby/ruby.vim
@@ -3,20 +3,10 @@
call ale#Set('ruby_ruby_executable', 'ruby')
-function! ale_linters#ruby#ruby#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_ruby_executable')
-endfunction
-
-function! ale_linters#ruby#ruby#GetCommand(buffer) abort
- let l:executable = ale_linters#ruby#ruby#GetExecutable(a:buffer)
-
- return ale#Escape(l:executable) . ' -w -c -T1 %t'
-endfunction
-
call ale#linter#Define('ruby', {
\ 'name': 'ruby',
-\ 'executable_callback': 'ale_linters#ruby#ruby#GetExecutable',
-\ 'command_callback': 'ale_linters#ruby#ruby#GetCommand',
+\ 'executable_callback': ale#VarFunc('ruby_ruby_executable'),
+\ 'command': '%e -w -c -T1 %t',
\ 'output_stream': 'stderr',
\ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors',
\})
diff --git a/ale_linters/ruby/solargraph.vim b/ale_linters/ruby/solargraph.vim
new file mode 100644
index 00000000..5ff0a759
--- /dev/null
+++ b/ale_linters/ruby/solargraph.vim
@@ -0,0 +1,22 @@
+" Author: Horacio Sanson - https://github.com/hsanson
+" Description: Solargraph Language Server https://solargraph.org/
+"
+" Author: Devon Meunier <devon.meunier@gmail.com>
+" Description: updated to use stdio
+
+call ale#Set('ruby_solargraph_executable', 'solargraph')
+call ale#Set('ruby_solargraph_options', {})
+
+function! ale_linters#ruby#solargraph#GetCommand(buffer) abort
+ return '%e' . ale#Pad('stdio')
+endfunction
+
+call ale#linter#Define('ruby', {
+\ 'name': 'solargraph',
+\ 'lsp': 'stdio',
+\ 'language': 'ruby',
+\ 'executable_callback': ale#VarFunc('ruby_solargraph_executable'),
+\ 'command_callback': 'ale_linters#ruby#solargraph#GetCommand',
+\ 'project_root_callback': 'ale#ruby#FindProjectRoot',
+\ 'initialization_options_callback': ale#VarFunc('ruby_solargraph_options'),
+\})
diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim
index e6c3870a..cf6187f8 100644
--- a/ale_linters/rust/cargo.vim
+++ b/ale_linters/rust/cargo.vim
@@ -9,6 +9,8 @@ call ale#Set('rust_cargo_check_tests', 0)
call ale#Set('rust_cargo_avoid_whole_workspace', 1)
call ale#Set('rust_cargo_default_feature_behavior', 'default')
call ale#Set('rust_cargo_include_features', '')
+call ale#Set('rust_cargo_use_clippy', 0)
+call ale#Set('rust_cargo_clippy_options', '')
function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# ''
@@ -42,6 +44,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
\ && ale#semver#GTE(l:version, [0, 22, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
+
if !empty(l:include_features)
let l:include_features = ' --features ' . ale#Escape(l:include_features)
endif
@@ -59,6 +62,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
endif
let l:default_feature_behavior = ale#Var(a:buffer, 'rust_cargo_default_feature_behavior')
+
if l:default_feature_behavior is# 'all'
let l:include_features = ''
let l:default_feature = ' --all-features'
@@ -68,14 +72,23 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort
let l:default_feature = ''
endif
+ let l:subcommand = l:use_check ? 'check' : 'build'
+ let l:clippy_options = ''
+
+ if ale#Var(a:buffer, 'rust_cargo_use_clippy')
+ let l:subcommand = 'clippy'
+ let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options')
+ endif
+
return l:nearest_cargo_prefix . 'cargo '
- \ . (l:use_check ? 'check' : 'build')
+ \ . l:subcommand
\ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '')
\ . (l:use_tests ? ' --tests' : '')
\ . ' --frozen --message-format=json -q'
\ . l:default_feature
\ . l:include_features
+ \ . l:clippy_options
endfunction
call ale#linter#Define('rust', {
diff --git a/ale_linters/rust/rls.vim b/ale_linters/rust/rls.vim
index cd13291d..60dd3667 100644
--- a/ale_linters/rust/rls.vim
+++ b/ale_linters/rust/rls.vim
@@ -4,19 +4,10 @@
call ale#Set('rust_rls_executable', 'rls')
call ale#Set('rust_rls_toolchain', 'nightly')
-function! ale_linters#rust#rls#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'rust_rls_executable')
-endfunction
-
function! ale_linters#rust#rls#GetCommand(buffer) abort
- let l:executable = ale_linters#rust#rls#GetExecutable(a:buffer)
let l:toolchain = ale#Var(a:buffer, 'rust_rls_toolchain')
- if empty(l:toolchain)
- return ale#Escape(l:executable)
- else
- return ale#Escape(l:executable) . ' +' . ale#Escape(l:toolchain)
- endif
+ return '%e' . (!empty(l:toolchain) ? ' +' . ale#Escape(l:toolchain) : '')
endfunction
function! ale_linters#rust#rls#GetProjectRoot(buffer) abort
@@ -28,7 +19,7 @@ endfunction
call ale#linter#Define('rust', {
\ 'name': 'rls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#rust#rls#GetExecutable',
+\ 'executable_callback': ale#VarFunc('rust_rls_executable'),
\ 'command_callback': 'ale_linters#rust#rls#GetCommand',
\ 'project_root_callback': 'ale_linters#rust#rls#GetProjectRoot',
\})
diff --git a/ale_linters/rust/rustc.vim b/ale_linters/rust/rustc.vim
index 3cd401b3..33fb72f4 100644
--- a/ale_linters/rust/rustc.vim
+++ b/ale_linters/rust/rustc.vim
@@ -1,7 +1,7 @@
" Author: Daniel Schemala <istjanichtzufassen@gmail.com>
" Description: rustc for rust files
-call ale#Set('rust_rustc_options', '-Z no-trans')
+call ale#Set('rust_rustc_options', '-Z no-codegen')
function! ale_linters#rust#rustc#RustcCommand(buffer) abort
" Try to guess the library search path. If the project is managed by cargo,
diff --git a/ale_linters/sass/stylelint.vim b/ale_linters/sass/stylelint.vim
index fe941d6a..b6286f18 100644
--- a/ale_linters/sass/stylelint.vim
+++ b/ale_linters/sass/stylelint.vim
@@ -3,20 +3,11 @@
call ale#Set('sass_stylelint_executable', 'stylelint')
call ale#Set('sass_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#sass#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'sass_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
-function! ale_linters#sass#stylelint#GetCommand(buffer) abort
- return ale_linters#sass#stylelint#GetExecutable(a:buffer)
- \ . ' --stdin-filename %s'
-endfunction
-
call ale#linter#Define('sass', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#sass#stylelint#GetExecutable',
-\ 'command_callback': 'ale_linters#sass#stylelint#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('sass_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
+\ 'command': '%e --stdin-filename %s',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/scala/fsc.vim b/ale_linters/scala/fsc.vim
index 17b26f0b..fbdce20e 100644
--- a/ale_linters/scala/fsc.vim
+++ b/ale_linters/scala/fsc.vim
@@ -1,29 +1,14 @@
" Author: Nils Leuzinger - https://github.com/PawkyPenguin
" Description: Basic scala support using fsc
-"
-function! ale_linters#scala#fsc#GetExecutable(buffer) abort
- if index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
- " Don't check sbt files
- return ''
- endif
- return 'fsc'
-endfunction
-
-function! ale_linters#scala#fsc#GetCommand(buffer) abort
- let l:executable = ale_linters#scala#fsc#GetExecutable(a:buffer)
-
- if empty(l:executable)
- return ''
- endif
-
- return ale#Escape(l:executable) . ' -Ystop-after:parser %t'
+function! s:IsSbt(buffer) abort
+ return index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
endfunction
call ale#linter#Define('scala', {
\ 'name': 'fsc',
-\ 'executable_callback': 'ale_linters#scala#fsc#GetExecutable',
-\ 'command_callback': 'ale_linters#scala#fsc#GetCommand',
+\ 'executable_callback': {buf -> s:IsSbt(buf) ? '' : 'fsc'},
+\ 'command': '%e -Ystop-after:parser %t',
\ 'callback': 'ale#handlers#scala#HandleScalacLintFormat',
\ 'output_stream': 'stderr',
\})
diff --git a/ale_linters/scala/sbtserver.vim b/ale_linters/scala/sbtserver.vim
new file mode 100644
index 00000000..694241d7
--- /dev/null
+++ b/ale_linters/scala/sbtserver.vim
@@ -0,0 +1,31 @@
+" Author: ophirr33 <coghlan.ty@gmail.com>
+" Description: TCP lsp client for sbt Server
+
+call ale#Set('scala_sbtserver_address', '127.0.0.1:4273')
+call ale#Set('scala_sbtserver_project_root', '')
+
+function! ale_linters#scala#sbtserver#GetProjectRoot(buffer) abort
+ let l:project_root = ale#Var(a:buffer, 'scala_sbtserver_project_root')
+
+ if l:project_root is? ''
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'build.sbt')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+ endif
+
+ return l:project_root
+endfunction
+
+function! ale_linters#scala#sbtserver#GetAddress(buffer) abort
+ let l:address = ale#Var(a:buffer, 'scala_sbtserver_address')
+
+ return l:address
+endfunction
+
+call ale#linter#Define('scala', {
+\ 'name': 'sbtserver',
+\ 'lsp': 'socket',
+\ 'address_callback': 'ale_linters#scala#sbtserver#GetAddress',
+\ 'language': 'scala',
+\ 'project_root_callback': 'ale_linters#scala#sbtserver#GetProjectRoot',
+\})
diff --git a/ale_linters/scala/scalac.vim b/ale_linters/scala/scalac.vim
index 551284af..ba105927 100644
--- a/ale_linters/scala/scalac.vim
+++ b/ale_linters/scala/scalac.vim
@@ -2,29 +2,14 @@
" w0rp <devw0rp@gmail.com>
" Description: Basic scala support using scalac
-function! ale_linters#scala#scalac#GetExecutable(buffer) abort
- if index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
- " Don't check sbt files
- return ''
- endif
-
- return 'scalac'
-endfunction
-
-function! ale_linters#scala#scalac#GetCommand(buffer) abort
- let l:executable = ale_linters#scala#scalac#GetExecutable(a:buffer)
-
- if empty(l:executable)
- return ''
- endif
-
- return ale#Escape(l:executable) . ' -Ystop-after:parser %t'
+function! s:IsSbt(buffer) abort
+ return index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0
endfunction
call ale#linter#Define('scala', {
\ 'name': 'scalac',
-\ 'executable_callback': 'ale_linters#scala#scalac#GetExecutable',
-\ 'command_callback': 'ale_linters#scala#scalac#GetCommand',
+\ 'executable_callback': {buf -> s:IsSbt(buf) ? '' : 'scalac'},
+\ 'command': '%e -Ystop-before:jvm %t',
\ 'callback': 'ale#handlers#scala#HandleScalacLintFormat',
\ 'output_stream': 'stderr',
\})
diff --git a/ale_linters/scala/scalastyle.vim b/ale_linters/scala/scalastyle.vim
index 3232d70b..42228cf6 100644
--- a/ale_linters/scala/scalastyle.vim
+++ b/ale_linters/scala/scalastyle.vim
@@ -53,12 +53,14 @@ function! ale_linters#scala#scalastyle#GetCommand(buffer) abort
\ 'scalastyle_config.xml',
\ 'scalastyle-config.xml'
\]
+
for l:config in l:potential_configs
let l:scalastyle_config = ale#path#ResolveLocalPath(
\ a:buffer,
\ l:config,
\ ''
\)
+
if !empty(l:scalastyle_config)
break
endif
diff --git a/ale_linters/scss/stylelint.vim b/ale_linters/scss/stylelint.vim
index 6bfdd09a..2bffa8e1 100644
--- a/ale_linters/scss/stylelint.vim
+++ b/ale_linters/scss/stylelint.vim
@@ -1,22 +1,19 @@
" Author: diartyz <diartyz@gmail.com>
call ale#Set('scss_stylelint_executable', 'stylelint')
+call ale#Set('scss_stylelint_options', '')
call ale#Set('scss_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#scss#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'scss_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#scss#stylelint#GetCommand(buffer) abort
- return ale_linters#scss#stylelint#GetExecutable(a:buffer)
+ return '%e ' . ale#Pad(ale#Var(a:buffer, 'scss_stylelint_options'))
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('scss', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#scss#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('scss_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': 'ale_linters#scss#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim
index 27c74531..0f68e62c 100644
--- a/ale_linters/sh/shellcheck.vim
+++ b/ale_linters/sh/shellcheck.vim
@@ -6,14 +6,9 @@
" codes to exclude from shellcheck. For example:
"
" let g:ale_sh_shellcheck_exclusions = 'SC2002,SC2004'
-let g:ale_sh_shellcheck_exclusions =
-\ get(g:, 'ale_sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_exclusions', ''))
-
-let g:ale_sh_shellcheck_executable =
-\ get(g:, 'ale_sh_shellcheck_executable', 'shellcheck')
-
-let g:ale_sh_shellcheck_options =
-\ get(g:, 'ale_sh_shellcheck_options', '')
+call ale#Set('sh_shellcheck_exclusions', get(g:, 'ale_linters_sh_shellcheck_exclusions', ''))
+call ale#Set('sh_shellcheck_executable', 'shellcheck')
+call ale#Set('sh_shellcheck_options', '')
function! ale_linters#sh#shellcheck#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'sh_shellcheck_executable')
diff --git a/ale_linters/sml/smlnj_cm.vim b/ale_linters/sml/smlnj_cm.vim
index 7a482307..bfa4bc05 100644
--- a/ale_linters/sml/smlnj_cm.vim
+++ b/ale_linters/sml/smlnj_cm.vim
@@ -3,6 +3,7 @@
function! ale_linters#sml#smlnj_cm#GetCommand(buffer) abort
let l:cmfile = ale#handlers#sml#GetCmFile(a:buffer)
+
return 'sml -m ' . l:cmfile . ' < /dev/null'
endfunction
diff --git a/ale_linters/solidity/solhint.vim b/ale_linters/solidity/solhint.vim
index 519fd49d..8ea33e07 100644
--- a/ale_linters/solidity/solhint.vim
+++ b/ale_linters/solidity/solhint.vim
@@ -4,7 +4,6 @@
function! ale_linters#solidity#solhint#Handle(buffer, lines) abort
" Matches patterns like the following:
" /path/to/file/file.sol: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)
-
let l:pattern = '\v^[^:]+: line (\d+), col (\d+), (Error|Warning) - (.*) \((.*)\)$'
let l:output = []
diff --git a/ale_linters/spec/rpmlint.vim b/ale_linters/spec/rpmlint.vim
index f5308af6..486bef1e 100644
--- a/ale_linters/spec/rpmlint.vim
+++ b/ale_linters/spec/rpmlint.vim
@@ -26,19 +26,12 @@
" And this is always output at the end and should just be ignored:
" 0 packages and 1 specfiles checked; 4 errors, 0 warnings.
-let g:ale_spec_rpmlint_executable =
-\ get(g:, 'ale_spec_rpmlint_executable', 'rpmlint')
-
-let g:ale_spec_rpmlint_options =
-\ get(g:, 'ale_spec_rpmlint_options', '')
-
-function! ale_linters#spec#rpmlint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'spec_rpmlint_executable')
-endfunction
+call ale#Set('spec_rpmlint_executable', 'rpmlint')
+call ale#Set('spec_rpmlint_options', '')
function! ale_linters#spec#rpmlint#GetCommand(buffer) abort
- return ale_linters#spec#rpmlint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'spec_rpmlint_options')
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'spec_rpmlint_options'))
\ . ' -o "NetworkEnabled False"'
\ . ' -v'
\ . ' %t'
@@ -79,7 +72,7 @@ endfunction
call ale#linter#Define('spec', {
\ 'name': 'rpmlint',
-\ 'executable_callback': 'ale_linters#spec#rpmlint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('spec_rpmlint_executable'),
\ 'command_callback': 'ale_linters#spec#rpmlint#GetCommand',
\ 'callback': 'ale_linters#spec#rpmlint#Handle',
\})
diff --git a/ale_linters/stylus/stylelint.vim b/ale_linters/stylus/stylelint.vim
index 1562692a..2256f3c0 100644
--- a/ale_linters/stylus/stylelint.vim
+++ b/ale_linters/stylus/stylelint.vim
@@ -4,21 +4,17 @@ call ale#Set('stylus_stylelint_executable', 'stylelint')
call ale#Set('stylus_stylelint_options', '')
call ale#Set('stylus_stylelint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#stylus#stylelint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'stylus_stylelint', [
- \ 'node_modules/.bin/stylelint',
- \])
-endfunction
-
function! ale_linters#stylus#stylelint#GetCommand(buffer) abort
- return ale_linters#stylus#stylelint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'stylus_stylelint_options')
+ return '%e'
+ \ . ale#Pad(ale#Var(a:buffer, 'stylus_stylelint_options'))
\ . ' --stdin-filename %s'
endfunction
call ale#linter#Define('stylus', {
\ 'name': 'stylelint',
-\ 'executable_callback': 'ale_linters#stylus#stylelint#GetExecutable',
+\ 'executable_callback': ale#node#FindExecutableFunc('stylus_stylelint', [
+\ 'node_modules/.bin/stylelint',
+\ ]),
\ 'command_callback': 'ale_linters#stylus#stylelint#GetCommand',
\ 'callback': 'ale#handlers#css#HandleStyleLintFormat',
\})
diff --git a/ale_linters/tcl/nagelfar.vim b/ale_linters/tcl/nagelfar.vim
index 13b7a549..05fe581b 100644
--- a/ale_linters/tcl/nagelfar.vim
+++ b/ale_linters/tcl/nagelfar.vim
@@ -4,16 +4,10 @@
call ale#Set('tcl_nagelfar_executable', 'nagelfar.tcl')
call ale#Set('tcl_nagelfar_options', '')
-function! ale_linters#tcl#nagelfar#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'tcl_nagelfar_executable')
-endfunction
-
function! ale_linters#tcl#nagelfar#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'tcl_nagelfar_options')
- return ale#Escape(ale_linters#tcl#nagelfar#GetExecutable(a:buffer))
- \ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' %s'
+ return '%e' . ale#Pad(l:options) . ' %s'
endfunction
function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort
@@ -21,7 +15,6 @@ function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort
" Line 5: W Found constant "bepa" which is also a variable.
" Line 13: E Wrong number of arguments (3) to "set"
" Line 93: N Close brace not aligned with line 90 (4 0)
-
let l:pattern = '^Line\s\+\([0-9]\+\): \([NEW]\) \(.*\)$'
let l:output = []
@@ -39,7 +32,7 @@ endfunction
call ale#linter#Define('tcl', {
\ 'name': 'nagelfar',
\ 'output_stream': 'stdout',
-\ 'executable_callback': 'ale_linters#tcl#nagelfar#GetExecutable',
+\ 'executable_callback': ale#VarFunc('tcl_nagelfar_executable'),
\ 'command_callback': 'ale_linters#tcl#nagelfar#GetCommand',
\ 'callback': 'ale_linters#tcl#nagelfar#Handle',
\ 'lint_file': 1,
diff --git a/ale_linters/terraform/tflint.vim b/ale_linters/terraform/tflint.vim
index 93966ff3..0d77835a 100644
--- a/ale_linters/terraform/tflint.vim
+++ b/ale_linters/terraform/tflint.vim
@@ -30,19 +30,17 @@ function! ale_linters#terraform#tflint#Handle(buffer, lines) abort
return l:output
endfunction
-function! ale_linters#terraform#tflint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'terraform_tflint_executable')
-endfunction
-
function! ale_linters#terraform#tflint#GetCommand(buffer) abort
- let l:cmd = ale#Escape(ale#Var(a:buffer, 'terraform_tflint_executable'))
+ let l:cmd = '%e'
let l:config_file = ale#path#FindNearestFile(a:buffer, '.tflint.hcl')
+
if !empty(l:config_file)
let l:cmd .= ' --config ' . ale#Escape(l:config_file)
endif
let l:opts = ale#Var(a:buffer, 'terraform_tflint_options')
+
if !empty(l:opts)
let l:cmd .= ' ' . l:opts
endif
@@ -54,9 +52,7 @@ endfunction
call ale#linter#Define('terraform', {
\ 'name': 'tflint',
-\ 'executable_callback': 'ale_linters#terraform#tflint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('terraform_tflint_executable'),
\ 'command_callback': 'ale_linters#terraform#tflint#GetCommand',
\ 'callback': 'ale_linters#terraform#tflint#Handle',
\})
-
-" vim:sw=4
diff --git a/ale_linters/tex/lacheck.vim b/ale_linters/tex/lacheck.vim
index e5a9632b..5e5a94f1 100644
--- a/ale_linters/tex/lacheck.vim
+++ b/ale_linters/tex/lacheck.vim
@@ -1,23 +1,13 @@
" Author: Andrew Balmos - <andrew@balmos.org>
" Description: lacheck for LaTeX files
-let g:ale_tex_lacheck_executable =
-\ get(g:, 'ale_tex_lacheck_executable', 'lacheck')
-
-function! ale_linters#tex#lacheck#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'tex_lacheck_executable')
-endfunction
-
-function! ale_linters#tex#lacheck#GetCommand(buffer) abort
- return ale#Var(a:buffer, 'tex_lacheck_executable') . ' %t'
-endfunction
+call ale#Set('tex_lacheck_executable', 'lacheck')
function! ale_linters#tex#lacheck#Handle(buffer, lines) abort
" Mattes lines like:
"
" "book.tex", line 37: possible unwanted space at "{"
" "book.tex", line 38: missing `\ ' after "etc."
-
let l:pattern = '^".\+", line \(\d\+\): \(.\+\)$'
let l:output = []
@@ -41,7 +31,7 @@ endfunction
call ale#linter#Define('tex', {
\ 'name': 'lacheck',
-\ 'executable_callback': 'ale_linters#tex#lacheck#GetExecutable',
-\ 'command_callback': 'ale_linters#tex#lacheck#GetCommand',
+\ 'executable_callback': ale#VarFunc('tex_lacheck_executable'),
+\ 'command': '%e %t',
\ 'callback': 'ale_linters#tex#lacheck#Handle'
\})
diff --git a/ale_linters/thrift/thrift.vim b/ale_linters/thrift/thrift.vim
index a8fe10b6..36a8656e 100644
--- a/ale_linters/thrift/thrift.vim
+++ b/ale_linters/thrift/thrift.vim
@@ -2,13 +2,9 @@
call ale#Set('thrift_thrift_executable', 'thrift')
call ale#Set('thrift_thrift_generators', ['cpp'])
-call ale#Set('thrift_thrift_includes', [])
+call ale#Set('thrift_thrift_includes', ['.'])
call ale#Set('thrift_thrift_options', '-strict')
-function! ale_linters#thrift#thrift#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'thrift_thrift_executable')
-endfunction
-
function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:generators = ale#Var(a:buffer, 'thrift_thrift_generators')
let l:includes = ale#Var(a:buffer, 'thrift_thrift_includes')
@@ -22,7 +18,7 @@ function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:output_dir = ale#engine#CreateDirectory(a:buffer)
- return ale#Escape(ale_linters#thrift#thrift#GetExecutable(a:buffer))
+ return '%e'
\ . ale#Pad(join(map(copy(l:generators), "'--gen ' . v:val")))
\ . ale#Pad(join(map(copy(l:includes), "'-I ' . v:val")))
\ . ale#Pad(ale#Var(a:buffer, 'thrift_thrift_options'))
@@ -46,12 +42,14 @@ function! ale_linters#thrift#thrift#Handle(buffer, lines) abort
let l:line = a:lines[l:index]
let l:match = matchlist(l:line, l:pattern)
+
if empty(l:match)
let l:index += 1
continue
endif
let l:severity = l:match[1]
+
if l:severity is# 'WARNING'
let l:type = 'W'
else
@@ -61,6 +59,7 @@ function! ale_linters#thrift#thrift#Handle(buffer, lines) abort
" If our text looks like "(last token was ';')", the *next* line
" should contain a more descriptive error message.
let l:text = l:match[4]
+
if l:text =~# '\(last token was .*\)'
let l:index += 1
let l:text = get(a:lines, l:index, 'Unknown error ' . l:text)
@@ -83,7 +82,7 @@ call ale#linter#Define('thrift', {
\ 'name': 'thrift',
\ 'executable': 'thrift',
\ 'output_stream': 'both',
-\ 'executable_callback': 'ale_linters#thrift#thrift#GetExecutable',
+\ 'executable_callback': ale#VarFunc('thrift_thrift_executable'),
\ 'command_callback': 'ale_linters#thrift#thrift#GetCommand',
\ 'callback': 'ale_linters#thrift#thrift#Handle',
\})
diff --git a/ale_linters/typescript/tsserver.vim b/ale_linters/typescript/tsserver.vim
index 08bd0f41..bac63229 100644
--- a/ale_linters/typescript/tsserver.vim
+++ b/ale_linters/typescript/tsserver.vim
@@ -5,22 +5,13 @@ call ale#Set('typescript_tsserver_executable', 'tsserver')
call ale#Set('typescript_tsserver_config_path', '')
call ale#Set('typescript_tsserver_use_global', get(g:, 'ale_use_global_executables', 0))
-" These functions need to be defined just to comply with the API for LSP.
-function! ale_linters#typescript#tsserver#GetProjectRoot(buffer) abort
- return ''
-endfunction
-
-function! ale_linters#typescript#tsserver#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'typescript_tsserver', [
- \ 'node_modules/.bin/tsserver',
- \])
-endfunction
-
call ale#linter#Define('typescript', {
\ 'name': 'tsserver',
\ 'lsp': 'tsserver',
-\ 'executable_callback': 'ale_linters#typescript#tsserver#GetExecutable',
-\ 'command_callback': 'ale_linters#typescript#tsserver#GetExecutable',
-\ 'project_root_callback': 'ale_linters#typescript#tsserver#GetProjectRoot',
+\ 'executable_callback': ale#node#FindExecutableFunc('typescript_tsserver', [
+\ 'node_modules/.bin/tsserver',
+\ ]),
+\ 'command': '%e',
+\ 'project_root_callback': {-> ''},
\ 'language': '',
\})
diff --git a/ale_linters/vim/ale_custom_linting_rules.vim b/ale_linters/vim/ale_custom_linting_rules.vim
new file mode 100644
index 00000000..3da44206
--- /dev/null
+++ b/ale_linters/vim/ale_custom_linting_rules.vim
@@ -0,0 +1,65 @@
+" Author: w0rp <devw0rp@gmail.com>
+" Description: A linter for checking ALE project code itself.
+
+function! ale_linters#vim#ale_custom_linting_rules#GetExecutable(buffer) abort
+ let l:filename = expand('#' . a:buffer . ':p')
+ let l:dir_list = []
+
+ for l:dir in split(&runtimepath, ',')
+ if l:filename[:len(l:dir) - 1] is# l:dir
+ call add(l:dir_list, l:dir)
+ endif
+ endfor
+
+ return !empty(l:dir_list)
+ \ ? findfile('test/script/custom-linting-rules', join(l:dir_list, ','))
+ \ : ''
+endfunction
+
+function! s:GetALEProjectDir(buffer) abort
+ let l:executable = ale_linters#vim#ale_custom_linting_rules#GetExecutable(a:buffer)
+
+ return ale#path#Dirname(ale#path#Dirname(ale#path#Dirname(l:executable)))
+endfunction
+
+function! ale_linters#vim#ale_custom_linting_rules#GetCommand(buffer) abort
+ let l:dir = s:GetALEProjectDir(a:buffer)
+
+ let l:temp_dir = ale#engine#CreateDirectory(a:buffer)
+ let l:temp_file = l:temp_dir . '/example.vim'
+
+ let l:lines = getbufline(a:buffer, 1, '$')
+ call ale#util#Writefile(a:buffer, l:lines, l:temp_file)
+
+ return ale#path#CdString(l:dir) . '%e ' . ale#Escape(l:temp_dir)
+endfunction
+
+function! ale_linters#vim#ale_custom_linting_rules#Handle(buffer, lines) abort
+ let l:dir = s:GetALEProjectDir(a:buffer)
+ let l:output = []
+ let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+) (.+)$'
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ " Ignore trailing whitespace errors if we've turned them off.
+ if !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
+ \&& l:match[3] is# 'Trailing whitespace'
+ continue
+ endif
+
+ call add(l:output, {
+ \ 'lnum': l:match[2],
+ \ 'text': l:match[3],
+ \ 'type': 'W',
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('vim', {
+\ 'name': 'ale_custom_linting_rules',
+\ 'executable_callback': 'ale_linters#vim#ale_custom_linting_rules#GetExecutable',
+\ 'command_callback': 'ale_linters#vim#ale_custom_linting_rules#GetCommand',
+\ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle',
+\ 'read_buffer': 0,
+\})
diff --git a/ale_linters/vue/vls.vim b/ale_linters/vue/vls.vim
index 0d4bf9f6..7116128b 100644
--- a/ale_linters/vue/vls.vim
+++ b/ale_linters/vue/vls.vim
@@ -4,18 +4,6 @@
call ale#Set('vue_vls_executable', 'vls')
call ale#Set('vue_vls_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#vue#vls#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'vue_vls', [
- \ 'node_modules/.bin/vls',
- \])
-endfunction
-
-function! ale_linters#vue#vls#GetCommand(buffer) abort
- let l:exe = ale#Escape(ale_linters#vue#vls#GetExecutable(a:buffer))
-
- return l:exe . ' --stdio'
-endfunction
-
function! ale_linters#vue#vls#GetProjectRoot(buffer) abort
let l:package_path = ale#path#FindNearestFile(a:buffer, 'package.json')
@@ -25,8 +13,10 @@ endfunction
call ale#linter#Define('vue', {
\ 'name': 'vls',
\ 'lsp': 'stdio',
-\ 'executable_callback': 'ale_linters#vue#vls#GetExecutable',
-\ 'command_callback': 'ale_linters#vue#vls#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('vue_vls', [
+\ 'node_modules/.bin/vls',
+\ ]),
+\ 'command': '%e --stdio',
\ 'language': 'vue',
\ 'project_root_callback': 'ale_linters#vue#vls#GetProjectRoot',
\})
diff --git a/ale_linters/xml/xmllint.vim b/ale_linters/xml/xmllint.vim
index 9d79438e..59f43d16 100644
--- a/ale_linters/xml/xmllint.vim
+++ b/ale_linters/xml/xmllint.vim
@@ -5,12 +5,8 @@
let g:ale_xml_xmllint_executable = get(g:, 'ale_xml_xmllint_executable', 'xmllint')
let g:ale_xml_xmllint_options = get(g:, 'ale_xml_xmllint_options', '')
-function! ale_linters#xml#xmllint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'xml_xmllint_executable')
-endfunction
-
function! ale_linters#xml#xmllint#GetCommand(buffer) abort
- return ale#Escape(ale_linters#xml#xmllint#GetExecutable(a:buffer))
+ return '%e'
\ . ale#Pad(ale#Var(a:buffer, 'xml_xmllint_options'))
\ . ' --noout -'
endfunction
@@ -29,9 +25,9 @@ function! ale_linters#xml#xmllint#Handle(buffer, lines) abort
let l:output = []
for l:line in a:lines
-
" Parse error/warning lines
let l:match_message = matchlist(l:line, l:pattern_message)
+
if !empty(l:match_message)
let l:line = l:match_message[2] + 0
let l:type = l:match_message[4] =~? 'warning' ? 'W' : 'E'
@@ -48,13 +44,13 @@ function! ale_linters#xml#xmllint#Handle(buffer, lines) abort
" Parse column position
let l:match_column_token = matchlist(l:line, l:pattern_column_token)
+
if !empty(l:output) && !empty(l:match_column_token)
let l:previous = l:output[len(l:output) - 1]
let l:previous['col'] = len(l:match_column_token[0])
continue
endif
-
endfor
return l:output
@@ -63,7 +59,7 @@ endfunction
call ale#linter#Define('xml', {
\ 'name': 'xmllint',
\ 'output_stream': 'stderr',
-\ 'executable_callback': 'ale_linters#xml#xmllint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('xml_xmllint_executable'),
\ 'command_callback': 'ale_linters#xml#xmllint#GetCommand',
\ 'callback': 'ale_linters#xml#xmllint#Handle',
\ })
diff --git a/ale_linters/yaml/swaglint.vim b/ale_linters/yaml/swaglint.vim
index 4a22c70f..7362536e 100644
--- a/ale_linters/yaml/swaglint.vim
+++ b/ale_linters/yaml/swaglint.vim
@@ -4,17 +4,6 @@
call ale#Set('yaml_swaglint_executable', 'swaglint')
call ale#Set('yaml_swaglint_use_global', get(g:, 'ale_use_global_executables', 0))
-function! ale_linters#yaml#swaglint#GetExecutable(buffer) abort
- return ale#node#FindExecutable(a:buffer, 'yaml_swaglint', [
- \ 'node_modules/.bin/swaglint',
- \])
-endfunction
-
-function! ale_linters#yaml#swaglint#GetCommand(buffer) abort
- return ale_linters#yaml#swaglint#GetExecutable(a:buffer)
- \ . ' -r compact --stdin'
-endfunction
-
function! ale_linters#yaml#swaglint#Handle(buffer, lines) abort
let l:pattern = ': \([^\s]\+\) @ \(\d\+\):\(\d\+\) - \(.\+\)$'
let l:output = []
@@ -43,7 +32,9 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'swaglint',
-\ 'executable_callback': 'ale_linters#yaml#swaglint#GetExecutable',
-\ 'command_callback': 'ale_linters#yaml#swaglint#GetCommand',
+\ 'executable_callback': ale#node#FindExecutableFunc('yaml_swaglint', [
+\ 'node_modules/.bin/swaglint',
+\ ]),
+\ 'command': '%e -r compact --stdin',
\ 'callback': 'ale_linters#yaml#swaglint#Handle',
\})
diff --git a/ale_linters/yaml/yamllint.vim b/ale_linters/yaml/yamllint.vim
index f100667e..9d2cc7c2 100644
--- a/ale_linters/yaml/yamllint.vim
+++ b/ale_linters/yaml/yamllint.vim
@@ -1,18 +1,10 @@
" Author: KabbAmine <amine.kabb@gmail.com>
-let g:ale_yaml_yamllint_executable =
-\ get(g:, 'ale_yaml_yamllint_executable', 'yamllint')
-
-let g:ale_yaml_yamllint_options =
-\ get(g:, 'ale_yaml_yamllint_options', '')
-
-function! ale_linters#yaml#yamllint#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'yaml_yamllint_executable')
-endfunction
+call ale#Set('yaml_yamllint_executable', 'yamllint')
+call ale#Set('yaml_yamllint_options', '')
function! ale_linters#yaml#yamllint#GetCommand(buffer) abort
- return ale_linters#yaml#yamllint#GetExecutable(a:buffer)
- \ . ' ' . ale#Var(a:buffer, 'yaml_yamllint_options')
+ return '%e' . ale#Pad(ale#Var(a:buffer, 'yaml_yamllint_options'))
\ . ' -f parsable %t'
endfunction
@@ -52,7 +44,7 @@ endfunction
call ale#linter#Define('yaml', {
\ 'name': 'yamllint',
-\ 'executable_callback': 'ale_linters#yaml#yamllint#GetExecutable',
+\ 'executable_callback': ale#VarFunc('yaml_yamllint_executable'),
\ 'command_callback': 'ale_linters#yaml#yamllint#GetCommand',
\ 'callback': 'ale_linters#yaml#yamllint#Handle',
\})
diff --git a/ale_linters/yang/yang_lsp.vim b/ale_linters/yang/yang_lsp.vim
new file mode 100644
index 00000000..45776f98
--- /dev/null
+++ b/ale_linters/yang/yang_lsp.vim
@@ -0,0 +1,15 @@
+call ale#Set('yang_lsp_executable', 'yang-language-server')
+
+function! ale_linters#yang#yang_lsp#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'yang.settings')
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
+
+call ale#linter#Define('yang', {
+\ 'name': 'yang_lsp',
+\ 'lsp': 'stdio',
+\ 'executable_callback': ale#VarFunc('yang_lsp_executable'),
+\ 'project_root_callback': 'ale_linters#yang#yang_lsp#GetProjectRoot',
+\ 'command': '%e',
+\})
diff --git a/autoload/ale.vim b/autoload/ale.vim
index 6d1e8521..f6c23d72 100644
--- a/autoload/ale.vim
+++ b/autoload/ale.vim
@@ -10,8 +10,7 @@ let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
let s:lint_timer = -1
-let s:queued_buffer_number = -1
-let s:should_lint_file_for_buffer = {}
+let s:getcmdwintype_exists = exists('*getcmdwintype')
" Return 1 if a file is too large for ALE to handle.
function! ale#FileTooLarge(buffer) abort
@@ -20,14 +19,12 @@ function! ale#FileTooLarge(buffer) abort
return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0
endfunction
-let s:getcmdwintype_exists = exists('*getcmdwintype')
-
" A function for checking various conditions whereby ALE just shouldn't
" attempt to do anything, say if particular buffer types are open in Vim.
function! ale#ShouldDoNothing(buffer) abort
" The checks are split into separate if statements to make it possible to
" profile each check individually with Vim's profiling tools.
-
+ "
" Do nothing if ALE is disabled.
if !getbufvar(a:buffer, 'ale_enabled', get(g:, 'ale_enabled', 0))
return 1
@@ -62,6 +59,11 @@ function! ale#ShouldDoNothing(buffer) abort
return 1
endif
+ " Don't start linting and so on when an operator is pending.
+ if ale#util#Mode(1) is# 'no'
+ return 1
+ endif
+
" Do nothing if running in the sandbox.
if ale#util#InSandbox()
return 1
@@ -81,21 +83,47 @@ function! ale#ShouldDoNothing(buffer) abort
return 0
endfunction
+function! s:Lint(buffer, should_lint_file, timer_id) abort
+ " Use the filetype from the buffer
+ let l:filetype = getbufvar(a:buffer, '&filetype')
+ let l:linters = ale#linter#Get(l:filetype)
+
+ " Apply ignore lists for linters only if needed.
+ let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
+ let l:linters = !empty(l:ignore_config)
+ \ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
+ \ : l:linters
+
+ " Tell other sources that they can start checking the buffer now.
+ let g:ale_want_results_buffer = a:buffer
+ silent doautocmd <nomodeline> User ALEWantResults
+ unlet! g:ale_want_results_buffer
+
+ " Don't set up buffer data and so on if there are no linters to run.
+ if !has_key(g:ale_buffer_info, a:buffer) && empty(l:linters)
+ return
+ endif
+
+ " Clear lint_file linters, or only run them if the file exists.
+ let l:lint_file = empty(l:linters)
+ \ || (a:should_lint_file && filereadable(expand('#' . a:buffer . ':p')))
+
+ call ale#engine#RunLinters(a:buffer, l:linters, l:lint_file)
+endfunction
+
" (delay, [linting_flag, buffer_number])
function! ale#Queue(delay, ...) abort
if a:0 > 2
throw 'too many arguments!'
endif
- " Default linting_flag to ''
- let l:linting_flag = get(a:000, 0, '')
- let l:buffer = get(a:000, 1, bufnr(''))
+ let l:buffer = get(a:000, 1, v:null)
- if l:linting_flag isnot# '' && l:linting_flag isnot# 'lint_file'
- throw "linting_flag must be either '' or 'lint_file'"
+ if l:buffer is v:null
+ let l:buffer = bufnr('')
endif
- if type(l:buffer) != type(0)
+ if type(l:buffer) isnot v:t_number
throw 'buffer_number must be a Number'
endif
@@ -103,80 +131,24 @@ function! ale#Queue(delay, ...) abort
return
endif
- " Remember that we want to check files for this buffer.
- " We will remember this until we finally run the linters, via any event.
- if l:linting_flag is# 'lint_file'
- let s:should_lint_file_for_buffer[l:buffer] = 1
- endif
+ " Default linting_flag to ''
+ let l:should_lint_file = get(a:000, 0) is# 'lint_file'
if s:lint_timer != -1
call timer_stop(s:lint_timer)
let s:lint_timer = -1
endif
- let l:linters = ale#linter#Get(getbufvar(l:buffer, '&filetype'))
-
- " Don't set up buffer data and so on if there are no linters to run.
- if empty(l:linters)
- " If we have some previous buffer data, then stop any jobs currently
- " running and clear everything.
- if has_key(g:ale_buffer_info, l:buffer)
- call ale#engine#RunLinters(l:buffer, [], 1)
- endif
-
- return
- endif
-
if a:delay > 0
- let s:queued_buffer_number = l:buffer
- let s:lint_timer = timer_start(a:delay, function('ale#Lint'))
+ let s:lint_timer = timer_start(
+ \ a:delay,
+ \ function('s:Lint', [l:buffer, l:should_lint_file])
+ \)
else
- call ale#Lint(-1, l:buffer)
+ call s:Lint(l:buffer, l:should_lint_file, 0)
endif
endfunction
-function! ale#Lint(...) abort
- if a:0 > 1
- " Use the buffer number given as the optional second argument.
- let l:buffer = a:2
- elseif a:0 > 0 && a:1 == s:lint_timer
- " Use the buffer number for the buffer linting was queued for.
- let l:buffer = s:queued_buffer_number
- else
- " Use the current buffer number.
- let l:buffer = bufnr('')
- endif
-
- if ale#ShouldDoNothing(l:buffer)
- return
- endif
-
- " Use the filetype from the buffer
- let l:filetype = getbufvar(l:buffer, '&filetype')
- let l:linters = ale#linter#Get(l:filetype)
- let l:should_lint_file = 0
-
- " Check if we previously requested checking the file.
- if has_key(s:should_lint_file_for_buffer, l:buffer)
- unlet s:should_lint_file_for_buffer[l:buffer]
- " Lint files if they exist.
- let l:should_lint_file = filereadable(expand('#' . l:buffer . ':p'))
- endif
-
- " Apply ignore lists for linters only if needed.
- let l:ignore_config = ale#Var(l:buffer, 'linters_ignore')
- let l:linters = !empty(l:ignore_config)
- \ ? ale#engine#ignore#Exclude(l:filetype, l:linters, l:ignore_config)
- \ : l:linters
-
- call ale#engine#RunLinters(l:buffer, l:linters, l:should_lint_file)
-endfunction
-
-" Reset flags indicating that files should be checked for all buffers.
-function! ale#ResetLintFileMarkers() abort
- let s:should_lint_file_for_buffer = {}
-endfunction
-
let g:ale_has_override = get(g:, 'ale_has_override', {})
" Call has(), but check a global Dictionary so we can force flags on or off
@@ -197,6 +169,11 @@ function! ale#Var(buffer, variable_name) abort
return get(l:vars, l:full_name, g:[l:full_name])
endfunction
+" As above, but curry the arguments so only the buffer number is required.
+function! ale#VarFunc(variable_name) abort
+ return {buf -> ale#Var(buf, a:variable_name)}
+endfunction
+
" Initialize a variable with a default value, if it isn't already set.
"
" Every variable name will be prefixed with 'ale_'.
diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim
index 55c39ee3..ed08ed09 100644
--- a/autoload/ale/assert.vim
+++ b/autoload/ale/assert.vim
@@ -30,7 +30,7 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
let l:callbacks = map(copy(l:linter.command_chain), 'v:val.callback')
" If the expected command is a string, just check the last one.
- if type(a:expected_command) is type('')
+ if type(a:expected_command) is v:t_string
if len(l:callbacks) is 1
let l:command = call(l:callbacks[0], [l:buffer])
else
@@ -54,9 +54,14 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
endif
else
let l:command = ale#linter#GetCommand(l:buffer, l:linter)
+ endif
+
+ if type(l:command) is v:t_string
" Replace %e with the escaped executable, so tests keep passing after
" linters are changed to use %e.
let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g')
+ else
+ call map(l:command, 'substitute(v:val, ''%e'', ''\=ale#Escape(l:executable)'', ''g'')')
endif
AssertEqual
@@ -80,6 +85,14 @@ function! ale#assert#LSPOptions(expected_options) abort
AssertEqual a:expected_options, l:initialization_options
endfunction
+function! ale#assert#LSPConfig(expected_config) abort
+ let l:buffer = bufnr('')
+ let l:linter = s:GetLinter()
+ let l:config = ale#lsp_linter#GetConfig(l:buffer, l:linter)
+
+ AssertEqual a:expected_config, l:config
+endfunction
+
function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
@@ -96,6 +109,14 @@ function! ale#assert#LSPProject(expected_root) abort
AssertEqual a:expected_root, l:root
endfunction
+function! ale#assert#LSPAddress(expected_address) abort
+ let l:buffer = bufnr('')
+ let l:linter = s:GetLinter()
+ let l:address = ale#util#GetFunction(l:linter.address_callback)(l:buffer)
+
+ AssertEqual a:expected_address, l:address
+endfunction
+
" A dummy function for making sure this module is loaded.
function! ale#assert#SetUpLinterTest(filetype, name) abort
" Set up a marker so ALE doesn't create real random temporary filenames.
@@ -126,28 +147,59 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim'
- call ale#test#SetDirectory('/testplugin/test/command_callback')
+ if !exists('g:dir')
+ call ale#test#SetDirectory('/testplugin/test/command_callback')
+ endif
command! -nargs=+ WithChainResults :call ale#assert#WithChainResults(<args>)
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
+ command! -nargs=+ AssertLSPConfig :call ale#assert#LSPConfig(<args>)
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
+ command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
endfunction
function! ale#assert#TearDownLinterTest() abort
unlet! g:ale_create_dummy_temporary_file
let s:chain_results = []
- delcommand WithChainResults
- delcommand AssertLinter
- delcommand AssertLinterNotExecuted
- delcommand AssertLSPOptions
- delcommand AssertLSPLanguage
- delcommand AssertLSPProject
+ if exists(':WithChainResults')
+ delcommand WithChainResults
+ endif
+
+ if exists(':AssertLinter')
+ delcommand AssertLinter
+ endif
+
+ if exists(':AssertLinterNotExecuted')
+ delcommand AssertLinterNotExecuted
+ endif
+
+ if exists(':AssertLSPOptions')
+ delcommand AssertLSPOptions
+ endif
+
+ if exists(':AssertLSPConfig')
+ delcommand AssertLSPConfig
+ endif
- call ale#test#RestoreDirectory()
+ if exists(':AssertLSPLanguage')
+ delcommand AssertLSPLanguage
+ endif
+
+ if exists(':AssertLSPProject')
+ delcommand AssertLSPProject
+ endif
+
+ if exists(':AssertLSPAddress')
+ delcommand AssertLSPAddress
+ endif
+
+ if exists('g:dir')
+ call ale#test#RestoreDirectory()
+ endif
Restore
diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim
index fbfe9509..ce5105b6 100644
--- a/autoload/ale/c.vim
+++ b/autoload/ale/c.vim
@@ -2,11 +2,31 @@
" Description: Functions for integrating with C-family linters.
call ale#Set('c_parse_makefile', 0)
+call ale#Set('c_parse_compile_commands', 0)
let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it.
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt']
+function! ale#c#GetBuildDirectory(buffer) abort
+ " Don't include build directory for header files, as compile_commands.json
+ " files don't consider headers to be translation units, and provide no
+ " commands for compiling header files.
+ if expand('#' . a:buffer) =~# '\v\.(h|hpp)$'
+ return ''
+ endif
+
+ let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
+
+ " c_build_dir has the priority if defined
+ if !empty(l:build_dir)
+ return l:build_dir
+ endif
+
+ return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer))
+endfunction
+
+
function! ale#c#FindProjectRoot(buffer) abort
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
@@ -26,15 +46,21 @@ function! ale#c#FindProjectRoot(buffer) abort
return ''
endfunction
-function! ale#c#ParseCFlagsToList(path_prefix, cflags) abort
+function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
let l:cflags_list = []
let l:previous_options = []
- for l:option in a:cflags
+ let l:split_lines = split(a:cflag_line, '-')
+ let l:option_index = 0
+
+ while l:option_index < len(l:split_lines)
+ let l:option = l:split_lines[l:option_index]
+ let l:option_index = l:option_index + 1
call add(l:previous_options, l:option)
" Check if cflag contained a '-' and should not have been splitted
let l:option_list = split(l:option, '\zs')
- if l:option_list[-1] isnot# ' '
+
+ if len(l:option_list) > 0 && l:option_list[-1] isnot# ' ' && l:option_index < len(l:split_lines)
continue
endif
@@ -60,34 +86,134 @@ function! ale#c#ParseCFlagsToList(path_prefix, cflags) abort
call add(l:cflags_list, l:option)
endif
endif
- endfor
+ endwhile
- return l:cflags_list
+ return join(l:cflags_list, ' ')
endfunction
-function! ale#c#ParseCFlags(buffer, stdout_make) abort
+function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile
- return []
+ return ''
endif
let l:buffer_filename = expand('#' . a:buffer . ':t')
- let l:cflags = []
- for l:lines in split(a:stdout_make, '\\n')
- if stridx(l:lines, l:buffer_filename) >= 0
- let l:cflags = split(l:lines, '-')
+ let l:cflag_line = ''
+
+ " Find a line matching this buffer's filename in the make output.
+ for l:line in a:make_output
+ if stridx(l:line, l:buffer_filename) >= 0
+ let l:cflag_line = l:line
break
endif
endfor
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
- return ale#c#ParseCFlagsToList(fnamemodify(l:makefile_path, ':p:h'), l:cflags)
+ let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h')
+
+ return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
+endfunction
+
+" Given a buffer number, find the build subdirectory with compile commands
+" The subdirectory is returned without the trailing /
+function! ale#c#FindCompileCommands(buffer) abort
+ " Look above the current source file to find compile_commands.json
+ let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+
+ if !empty(l:json_file)
+ return l:json_file
+ endif
+
+ " Search in build directories if we can't find it in the project.
+ for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
+ for l:dirname in ale#Var(a:buffer, 'c_build_dir_names')
+ let l:c_build_dir = l:path . s:sep . l:dirname
+ let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
+
+ if filereadable(l:json_file)
+ return l:json_file
+ endif
+ endfor
+ endfor
+
+ return ''
+endfunction
+
+" Cache compile_commands.json data in a Dictionary, so we don't need to read
+" the same files over and over again. The key in the dictionary will include
+" the last modified time of the file.
+if !exists('s:compile_commands_cache')
+ let s:compile_commands_cache = {}
+endif
+
+function! s:GetListFromCompileCommandsFile(compile_commands_file) abort
+ if empty(a:compile_commands_file)
+ return []
+ endif
+
+ let l:time = getftime(a:compile_commands_file)
+
+ if l:time < 0
+ return []
+ endif
+
+ let l:key = a:compile_commands_file . ':' . l:time
+
+ if has_key(s:compile_commands_cache, l:key)
+ return s:compile_commands_cache[l:key]
+ endif
+
+ let l:data = []
+ silent! let l:data = json_decode(join(readfile(a:compile_commands_file), ''))
+
+ if !empty(l:data)
+ let s:compile_commands_cache[l:key] = l:data
+
+ return l:data
+ endif
+
+ return []
+endfunction
+
+function! ale#c#ParseCompileCommandsFlags(buffer, dir, json_list) abort
+ " Search for an exact file match first.
+ for l:item in a:json_list
+ if bufnr(l:item.file) is a:buffer
+ return ale#c#ParseCFlags(a:dir, l:item.command)
+ endif
+ endfor
+
+ " Look for any file in the same directory if we can't find an exact match.
+ let l:dir = ale#path#Simplify(expand('#' . a:buffer . ':p:h'))
+
+ for l:item in a:json_list
+ if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
+ return ale#c#ParseCFlags(a:dir, l:item.command)
+ endif
+ endfor
+
+ return ''
+endfunction
+
+function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort
+ let l:dir = ale#path#Dirname(a:compile_commands_file)
+ let l:json_list = s:GetListFromCompileCommandsFile(a:compile_commands_file)
+
+ return ale#c#ParseCompileCommandsFlags(a:buffer, l:dir, l:json_list)
endfunction
function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = ' '
- if g:ale_c_parse_makefile && !empty(a:output)
- let l:cflags = join(ale#c#ParseCFlags(a:buffer, join(a:output, '\n')), ' ') . ' '
+ if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
+ let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
+ endif
+
+ if ale#Var(a:buffer, 'c_parse_compile_commands')
+ let l:json_file = ale#c#FindCompileCommands(a:buffer)
+
+ if !empty(l:json_file)
+ let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file)
+ endif
endif
if l:cflags is# ' '
@@ -98,8 +224,9 @@ function! ale#c#GetCFlags(buffer, output) abort
endfunction
function! ale#c#GetMakeCommand(buffer) abort
- if g:ale_c_parse_makefile
+ if ale#Var(a:buffer, 'c_parse_makefile')
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
+
if !empty(l:makefile_path)
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n'
endif
@@ -154,26 +281,10 @@ function! ale#c#IncludeOptions(include_paths) abort
return ''
endif
- return ' ' . join(l:option_list) . ' '
+ return join(l:option_list)
endfunction
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])
-
-" Given a buffer number, find the build subdirectory with compile commands
-" The subdirectory is returned without the trailing /
-function! ale#c#FindCompileCommands(buffer) abort
- for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
- for l:dirname in ale#Var(a:buffer, 'c_build_dir_names')
- let l:c_build_dir = l:path . s:sep . l:dirname
-
- if filereadable(l:c_build_dir . '/compile_commands.json')
- return l:c_build_dir
- endif
- endfor
- endfor
-
- return ''
-endfunction
diff --git a/autoload/ale/completion.vim b/autoload/ale/completion.vim
index 7440f8cd..9dd913f5 100644
--- a/autoload/ale/completion.vim
+++ b/autoload/ale/completion.vim
@@ -39,10 +39,14 @@ let s:LSP_COMPLETION_COLOR_KIND = 16
let s:LSP_COMPLETION_FILE_KIND = 17
let s:LSP_COMPLETION_REFERENCE_KIND = 18
+let s:lisp_regex = '\v[a-zA-Z_\-][a-zA-Z_\-0-9]*$'
+
" Regular expressions for checking the characters in the line before where
" the insert cursor is. If one of these matches, we'll check for completions.
let s:should_complete_map = {
\ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$',
+\ 'clojure': s:lisp_regex,
+\ 'lisp': s:lisp_regex,
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$',
\ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$',
\}
@@ -75,6 +79,7 @@ endfunction
" Check if we should look for completions for a language.
function! ale#completion#GetPrefix(filetype, line, column) abort
let l:regex = s:GetFiletypeValue(s:should_complete_map, a:filetype)
+
" The column we're using completions for is where we are inserting text,
" like so:
" abc
@@ -93,14 +98,15 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
return ''
endfunction
-function! ale#completion#Filter(buffer, suggestions, prefix) abort
+function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
+ let l:triggers = s:GetFiletypeValue(s:trigger_character_map, a:filetype)
" For completing...
" foo.
" ^
" We need to include all of the given suggestions.
- if a:prefix is# '.'
+ if index(l:triggers, a:prefix) >= 0
let l:filtered_suggestions = a:suggestions
else
let l:filtered_suggestions = []
@@ -113,7 +119,7 @@ function! ale#completion#Filter(buffer, suggestions, prefix) abort
for l:item in a:suggestions
" A List of String values or a List of completion item Dictionaries
" is accepted here.
- let l:word = type(l:item) == type('') ? l:item : l:item.word
+ let l:word = type(l:item) is v:t_string ? l:item : l:item.word
" Add suggestions if the suggestion starts with a case-insensitive
" match for the prefix.
@@ -133,7 +139,7 @@ function! ale#completion#Filter(buffer, suggestions, prefix) abort
" Remove suggestions with words in the exclusion List.
call filter(
\ l:filtered_suggestions,
- \ 'index(l:excluded_words, type(v:val) is type('''') ? v:val : v:val.word) < 0',
+ \ 'index(l:excluded_words, type(v:val) is v:t_string ? v:val : v:val.word) < 0',
\)
endif
@@ -214,8 +220,10 @@ function! ale#completion#Show(response, completion_parser) abort
" function, and then start omni-completion.
let b:ale_completion_response = a:response
let b:ale_completion_parser = a:completion_parser
+ " Replace completion options shortly before opening the menu.
call s:ReplaceCompletionOptions()
- call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")
+
+ call timer_start(0, {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")})
endfunction
function! s:CompletionStillValid(request_id) abort
@@ -257,7 +265,7 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
call add(l:documentationParts, l:part.text)
endfor
- if l:suggestion.kind is# 'clasName'
+ if l:suggestion.kind is# 'className'
let l:kind = 'f'
elseif l:suggestion.kind is# 'parameterName'
let l:kind = 'f'
@@ -315,10 +323,10 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:item_list = []
- if type(get(a:response, 'result')) is type([])
+ if type(get(a:response, 'result')) is v:t_list
let l:item_list = a:response.result
- elseif type(get(a:response, 'result')) is type({})
- \&& type(get(a:response.result, 'items')) is type([])
+ elseif type(get(a:response, 'result')) is v:t_dict
+ \&& type(get(a:response.result, 'items')) is v:t_list
let l:item_list = a:response.result.items
endif
@@ -352,17 +360,23 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:kind = 'v'
endif
+ let l:doc = get(l:item, 'documentation', '')
+
+ if type(l:doc) is v:t_dict && has_key(l:doc, 'value')
+ let l:doc = l:doc.value
+ endif
+
call add(l:results, {
\ 'word': l:word,
\ 'kind': l:kind,
\ 'icase': 1,
\ 'menu': get(l:item, 'detail', ''),
- \ 'info': get(l:item, 'documentation', ''),
+ \ 'info': (type(l:doc) is v:t_string ? l:doc : ''),
\})
endfor
if has_key(l:info, 'prefix')
- return ale#completion#Filter(l:buffer, l:results, l:info.prefix)
+ return ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
endif
return l:results
@@ -383,6 +397,7 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
if l:command is# 'completions'
let l:names = ale#completion#Filter(
\ l:buffer,
+ \ &filetype,
\ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix,
\)[: g:ale_completion_max_suggestions - 1]
@@ -422,6 +437,58 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort
\)
endfunction
+function! s:OnReady(linter, lsp_details, ...) abort
+ let l:buffer = a:lsp_details.buffer
+ let l:id = a:lsp_details.connection_id
+
+ " If we have sent a completion request already, don't send another.
+ if b:ale_completion_info.request_id
+ return
+ endif
+
+ let l:Callback = a:linter.lsp is# 'tsserver'
+ \ ? function('ale#completion#HandleTSServerResponse')
+ \ : function('ale#completion#HandleLSPResponse')
+ call ale#lsp#RegisterCallback(l:id, l:Callback)
+
+ if a:linter.lsp is# 'tsserver'
+ let l:message = ale#lsp#tsserver_message#Completions(
+ \ l:buffer,
+ \ b:ale_completion_info.line,
+ \ b:ale_completion_info.column,
+ \ b:ale_completion_info.prefix,
+ \)
+ else
+ " Send a message saying the buffer has changed first, otherwise
+ " completions won't know what text is nearby.
+ call ale#lsp#NotifyForChanges(l:id, l:buffer)
+
+ " For LSP completions, we need to clamp the column to the length of
+ " the line. python-language-server and perhaps others do not implement
+ " this correctly.
+ let l:message = ale#lsp#message#Completion(
+ \ l:buffer,
+ \ b:ale_completion_info.line,
+ \ min([
+ \ b:ale_completion_info.line_length,
+ \ b:ale_completion_info.column,
+ \ ]),
+ \ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix),
+ \)
+ endif
+
+ let l:request_id = ale#lsp#Send(l:id, l:message)
+
+ if l:request_id
+ let b:ale_completion_info.conn_id = l:id
+ let b:ale_completion_info.request_id = l:request_id
+
+ if has_key(a:linter, 'completion_filter')
+ let b:ale_completion_info.completion_filter = a:linter.completion_filter
+ endif
+ endif
+endfunction
+
function! s:GetLSPCompletions(linter) abort
let l:buffer = bufnr('')
let l:lsp_details = ale#lsp_linter#StartLSP(l:buffer, a:linter)
@@ -431,58 +498,10 @@ function! s:GetLSPCompletions(linter) abort
endif
let l:id = l:lsp_details.connection_id
- let l:root = l:lsp_details.project_root
-
- function! OnReady(...) abort closure
- " If we have sent a completion request already, don't send another.
- if b:ale_completion_info.request_id
- return
- endif
-
- let l:Callback = a:linter.lsp is# 'tsserver'
- \ ? function('ale#completion#HandleTSServerResponse')
- \ : function('ale#completion#HandleLSPResponse')
- call ale#lsp#RegisterCallback(l:id, l:Callback)
-
- if a:linter.lsp is# 'tsserver'
- let l:message = ale#lsp#tsserver_message#Completions(
- \ l:buffer,
- \ b:ale_completion_info.line,
- \ b:ale_completion_info.column,
- \ b:ale_completion_info.prefix,
- \)
- else
- " Send a message saying the buffer has changed first, otherwise
- " completions won't know what text is nearby.
- call ale#lsp#NotifyForChanges(l:id, l:root, l:buffer)
-
- " For LSP completions, we need to clamp the column to the length of
- " the line. python-language-server and perhaps others do not implement
- " this correctly.
- let l:message = ale#lsp#message#Completion(
- \ l:buffer,
- \ b:ale_completion_info.line,
- \ min([
- \ b:ale_completion_info.line_length,
- \ b:ale_completion_info.column,
- \ ]),
- \ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix),
- \)
- endif
- let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
-
- if l:request_id
- let b:ale_completion_info.conn_id = l:id
- let b:ale_completion_info.request_id = l:request_id
-
- if has_key(a:linter, 'completion_filter')
- let b:ale_completion_info.completion_filter = a:linter.completion_filter
- endif
- endif
- endfunction
+ let l:OnReady = function('s:OnReady', [a:linter, l:lsp_details])
- call ale#lsp#WaitForCapability(l:id, l:root, 'completion', function('OnReady'))
+ call ale#lsp#WaitForCapability(l:id, 'completion', l:OnReady)
endfunction
function! ale#completion#GetCompletions() abort
diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim
index 73dbebb2..6672c349 100644
--- a/autoload/ale/cursor.vim
+++ b/autoload/ale/cursor.vim
@@ -1,4 +1,6 @@
+scriptencoding utf-8
" Author: w0rp <devw0rp@gmail.com>
+" Author: João Paulo S. de Souza <joao.paulo.silvasouza@hotmail.com>
" Description: Echoes lint message for the current line, if any
" Controls the milliseconds delay before echoing a message.
@@ -24,7 +26,20 @@ function! ale#cursor#TruncatedEcho(original_message) abort
" The message is truncated and saved to the history.
setlocal shortmess+=T
- exec "norm! :echomsg l:message\n"
+
+ try
+ exec "norm! :echomsg l:message\n"
+ catch /^Vim\%((\a\+)\)\=:E523/
+ " Fallback into manual truncate (#1987)
+ let l:winwidth = winwidth(0)
+
+ if l:winwidth < strdisplaywidth(l:message)
+ " Truncate message longer than window width with trailing '...'
+ let l:message = l:message[:l:winwidth - 4] . '...'
+ endif
+
+ exec 'echomsg l:message'
+ endtry
" Reset the cursor position if we moved off the end of the line.
" Using :norm and :echomsg can move the cursor off the end of the
@@ -37,17 +52,6 @@ function! ale#cursor#TruncatedEcho(original_message) abort
endtry
endfunction
-function! s:FindItemAtCursor() abort
- let l:buf = bufnr('')
- let l:info = get(g:ale_buffer_info, l:buf, {})
- let l:loclist = get(l:info, 'loclist', [])
- let l:pos = getcurpos()
- let l:index = ale#util#BinarySearch(l:loclist, l:buf, l:pos[1], l:pos[2])
- let l:loc = l:index >= 0 ? l:loclist[l:index] : {}
-
- return [l:info, l:loc]
-endfunction
-
function! s:StopCursorTimer() abort
if s:cursor_timer != -1
call timer_stop(s:cursor_timer)
@@ -56,42 +60,55 @@ function! s:StopCursorTimer() abort
endfunction
function! ale#cursor#EchoCursorWarning(...) abort
- if !g:ale_echo_cursor
+ let l:buffer = bufnr('')
+
+ if !g:ale_echo_cursor && !g:ale_cursor_detail
return
endif
" Only echo the warnings in normal mode, otherwise we will get problems.
- if mode() isnot# 'n'
+ if mode(1) isnot# 'n'
return
endif
- if ale#ShouldDoNothing(bufnr(''))
+ if ale#ShouldDoNothing(l:buffer)
return
endif
- let l:buffer = bufnr('')
- let [l:info, l:loc] = s:FindItemAtCursor()
+ let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer)
+
+ if g:ale_echo_cursor
+ if !empty(l:loc)
+ let l:format = ale#Var(l:buffer, 'echo_msg_format')
+ let l:msg = ale#GetLocItemMessage(l:loc, l:format)
+ call ale#cursor#TruncatedEcho(l:msg)
+ let l:info.echoed = 1
+ elseif get(l:info, 'echoed')
+ " We'll only clear the echoed message when moving off errors once,
+ " so we don't continually clear the echo line.
+ execute 'echo'
+ let l:info.echoed = 0
+ endif
+ endif
- if !empty(l:loc)
- let l:format = ale#Var(l:buffer, 'echo_msg_format')
- let l:msg = ale#GetLocItemMessage(l:loc, l:format)
- call ale#cursor#TruncatedEcho(l:msg)
- let l:info.echoed = 1
- elseif get(l:info, 'echoed')
- " We'll only clear the echoed message when moving off errors once,
- " so we don't continually clear the echo line.
- execute 'echo'
- let l:info.echoed = 0
+ if g:ale_cursor_detail
+ if !empty(l:loc)
+ call s:ShowCursorDetailForItem(l:loc, {'stay_here': 1})
+ else
+ call ale#preview#CloseIfTypeMatches('ale-preview')
+ endif
endif
endfunction
function! ale#cursor#EchoCursorWarningWithDelay() abort
- if !g:ale_echo_cursor
+ let l:buffer = bufnr('')
+
+ if !g:ale_echo_cursor && !g:ale_cursor_detail
return
endif
" Only echo the warnings in normal mode, otherwise we will get problems.
- if mode() isnot# 'n'
+ if mode(1) isnot# 'n'
return
endif
@@ -104,7 +121,7 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
" we should echo something. Otherwise we can end up doing processing
" the echo message far too frequently.
if l:pos != s:last_pos
- let l:delay = ale#Var(bufnr(''), 'echo_delay')
+ let l:delay = ale#Var(l:buffer, 'echo_delay')
let s:last_pos = l:pos
let s:cursor_timer = timer_start(
@@ -114,24 +131,37 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
endif
endfunction
+function! s:ShowCursorDetailForItem(loc, options) abort
+ let l:stay_here = get(a:options, 'stay_here', 0)
+
+ let s:last_detailed_line = line('.')
+ let l:message = get(a:loc, 'detail', a:loc.text)
+ let l:lines = split(l:message, "\n")
+ call ale#preview#Show(l:lines, {'stay_here': l:stay_here})
+
+ " Clear the echo message if we manually displayed details.
+ if !l:stay_here
+ execute 'echo'
+ endif
+endfunction
+
function! ale#cursor#ShowCursorDetail() abort
+ let l:buffer = bufnr('')
+
" Only echo the warnings in normal mode, otherwise we will get problems.
if mode() isnot# 'n'
return
endif
- if ale#ShouldDoNothing(bufnr(''))
+ if ale#ShouldDoNothing(l:buffer)
return
endif
call s:StopCursorTimer()
- let [l:info, l:loc] = s:FindItemAtCursor()
+ let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer)
if !empty(l:loc)
- let l:message = get(l:loc, 'detail', l:loc.text)
-
- call ale#preview#Show(split(l:message, "\n"))
- execute 'echo'
+ call s:ShowCursorDetailForItem(l:loc, {'stay_here': 0})
endif
endfunction
diff --git a/autoload/ale/d.vim b/autoload/ale/d.vim
new file mode 100644
index 00000000..0e232203
--- /dev/null
+++ b/autoload/ale/d.vim
@@ -0,0 +1,16 @@
+" Author: Auri <me@aurieh.me>
+" Description: Functions for integrating with D linters.
+
+function! ale#d#FindDUBConfig(buffer) abort
+ " Find a DUB configuration file in ancestor paths.
+ " The most DUB-specific names will be tried first.
+ for l:possible_filename in ['dub.sdl', 'dub.json', 'package.json']
+ let l:dub_file = ale#path#FindNearestFile(a:buffer, l:possible_filename)
+
+ if !empty(l:dub_file)
+ return l:dub_file
+ endif
+ endfor
+
+ return ''
+endfunction
diff --git a/autoload/ale/debugging.vim b/autoload/ale/debugging.vim
index 34c13770..6c2bfbee 100644
--- a/autoload/ale/debugging.vim
+++ b/autoload/ale/debugging.vim
@@ -22,14 +22,14 @@ let s:global_variable_list = [
\ 'ale_lint_delay',
\ 'ale_lint_on_enter',
\ 'ale_lint_on_filetype_changed',
+\ 'ale_lint_on_insert_leave',
\ 'ale_lint_on_save',
\ 'ale_lint_on_text_changed',
-\ 'ale_lint_on_insert_leave',
\ 'ale_linter_aliases',
\ 'ale_linters',
\ 'ale_linters_explicit',
-\ 'ale_list_window_size',
\ 'ale_list_vertical',
+\ 'ale_list_window_size',
\ 'ale_loclist_msg_format',
\ 'ale_max_buffer_history_size',
\ 'ale_max_signs',
@@ -52,6 +52,7 @@ let s:global_variable_list = [
\ 'ale_statusline_format',
\ 'ale_type_map',
\ 'ale_use_global_executables',
+\ 'ale_virtualtext_cursor',
\ 'ale_warn_about_trailing_blank_lines',
\ 'ale_warn_about_trailing_whitespace',
\]
diff --git a/autoload/ale/definition.vim b/autoload/ale/definition.vim
index 6c7d7d32..984a4f9d 100644
--- a/autoload/ale/definition.vim
+++ b/autoload/ale/definition.vim
@@ -40,16 +40,16 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
" The result can be a Dictionary item, a List of the same, or null.
let l:result = get(a:response, 'result', v:null)
- if type(l:result) is type({})
+ if type(l:result) is v:t_dict
let l:result = [l:result]
- elseif type(l:result) isnot type([])
+ elseif type(l:result) isnot v:t_list
let l:result = []
endif
for l:item in l:result
let l:filename = ale#path#FromURI(l:item.uri)
let l:line = l:item.range.start.line + 1
- let l:column = l:item.range.start.character
+ let l:column = l:item.range.start.character + 1
call ale#util#Open(l:filename, l:line, l:column, l:options)
break
@@ -57,6 +57,39 @@ function! ale#definition#HandleLSPResponse(conn_id, response) abort
endif
endfunction
+function! s:OnReady(linter, lsp_details, line, column, options, ...) abort
+ let l:buffer = a:lsp_details.buffer
+ let l:id = a:lsp_details.connection_id
+
+ let l:Callback = a:linter.lsp is# 'tsserver'
+ \ ? function('ale#definition#HandleTSServerResponse')
+ \ : function('ale#definition#HandleLSPResponse')
+ call ale#lsp#RegisterCallback(l:id, l:Callback)
+
+ if a:linter.lsp is# 'tsserver'
+ let l:message = ale#lsp#tsserver_message#Definition(
+ \ l:buffer,
+ \ a:line,
+ \ a:column
+ \)
+ else
+ " Send a message saying the buffer has changed first, or the
+ " definition position probably won't make sense.
+ call ale#lsp#NotifyForChanges(l:id, l:buffer)
+
+ " For LSP completions, we need to clamp the column to the length of
+ " the line. python-language-server and perhaps others do not implement
+ " this correctly.
+ let l:message = ale#lsp#message#Definition(l:buffer, a:line, a:column)
+ endif
+
+ let l:request_id = ale#lsp#Send(l:id, l:message)
+
+ let s:go_to_definition_map[l:request_id] = {
+ \ 'open_in_tab': get(a:options, 'open_in_tab', 0),
+ \}
+endfunction
+
function! s:GoToLSPDefinition(linter, options) abort
let l:buffer = bufnr('')
let [l:line, l:column] = getcurpos()[1:2]
@@ -71,39 +104,10 @@ function! s:GoToLSPDefinition(linter, options) abort
endif
let l:id = l:lsp_details.connection_id
- let l:root = l:lsp_details.project_root
-
- function! OnReady(...) abort closure
- let l:Callback = a:linter.lsp is# 'tsserver'
- \ ? function('ale#definition#HandleTSServerResponse')
- \ : function('ale#definition#HandleLSPResponse')
- call ale#lsp#RegisterCallback(l:id, l:Callback)
-
- if a:linter.lsp is# 'tsserver'
- let l:message = ale#lsp#tsserver_message#Definition(
- \ l:buffer,
- \ l:line,
- \ l:column
- \)
- else
- " Send a message saying the buffer has changed first, or the
- " definition position probably won't make sense.
- call ale#lsp#NotifyForChanges(l:id, l:root, l:buffer)
-
- " For LSP completions, we need to clamp the column to the length of
- " the line. python-language-server and perhaps others do not implement
- " this correctly.
- let l:message = ale#lsp#message#Definition(l:buffer, l:line, l:column)
- endif
-
- let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
-
- let s:go_to_definition_map[l:request_id] = {
- \ 'open_in_tab': get(a:options, 'open_in_tab', 0),
- \}
- endfunction
- call ale#lsp#WaitForCapability(l:id, l:root, 'definition', function('OnReady'))
+ call ale#lsp#WaitForCapability(l:id, 'definition', function('s:OnReady', [
+ \ a:linter, l:lsp_details, l:line, l:column, a:options
+ \]))
endfunction
function! ale#definition#GoTo(options) abort
diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim
index ec5ccb6d..b44be73c 100644
--- a/autoload/ale/engine.vim
+++ b/autoload/ale/engine.vim
@@ -18,6 +18,22 @@ if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {}
endif
+
+function! ale#engine#CleanupEveryBuffer() abort
+ for l:key in keys(g:ale_buffer_info)
+ " The key could be a filename or a buffer number, so try and
+ " convert it to a number. We need a number for the other
+ " functions.
+ let l:buffer = str2nr(l:key)
+
+ if l:buffer > 0
+ " Stop all jobs and clear the results for everything, and delete
+ " all of the data we stored for the buffer.
+ call ale#engine#Cleanup(l:buffer)
+ endif
+ endfor
+endfunction
+
function! ale#engine#ResetExecutableCache() abort
let s:executable_cache_map = {}
endfunction
@@ -63,6 +79,7 @@ function! ale#engine#InitBufferInfo(buffer) abort
let g:ale_buffer_info[a:buffer] = {
\ 'job_list': [],
\ 'active_linter_list': [],
+ \ 'active_other_sources_list': [],
\ 'loclist': [],
\ 'temporary_file_list': [],
\ 'temporary_directory_list': [],
@@ -81,6 +98,7 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
return !empty(get(l:info, 'active_linter_list', []))
+ \ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction
" Register a temporary file to be managed with the ALE engine for
@@ -161,20 +179,27 @@ function! s:GatherOutput(job_id, line) abort
endif
endfunction
-function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
+function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
if empty(l:info)
return
endif
- " Remove this linter from the list of active linters.
- " This may have already been done when the job exits.
- call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name')
+ if !a:from_other_source
+ " Remove this linter from the list of active linters.
+ " This may have already been done when the job exits.
+ call filter(l:info.active_linter_list, 'v:val isnot# a:linter_name')
+ endif
" Make some adjustments to the loclists to fix common problems, and also
" to set default values for loclist items.
- let l:linter_loclist = ale#engine#FixLocList(a:buffer, a:linter_name, a:loclist)
+ let l:linter_loclist = ale#engine#FixLocList(
+ \ a:buffer,
+ \ a:linter_name,
+ \ a:from_other_source,
+ \ a:loclist,
+ \)
" Remove previous items for this linter.
call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name')
@@ -231,6 +256,7 @@ function! s:HandleExit(job_id, exit_code) abort
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
call s:InvokeChain(l:buffer, l:executable, l:linter, l:next_chain_index, l:output)
+
return
endif
@@ -246,7 +272,7 @@ function! s:HandleExit(job_id, exit_code) abort
let l:loclist = []
endtry
- call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist)
+ call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0)
endfunction
function! ale#engine#SetResults(buffer, loclist) abort
@@ -278,6 +304,12 @@ function! ale#engine#SetResults(buffer, loclist) abort
call ale#cursor#EchoCursorWarning()
endif
+ if g:ale_virtualtext_cursor
+ " Try and show the warning now.
+ " This will only do something meaningful if we're in normal mode.
+ call ale#virtualtext#ShowCursorWarning()
+ endif
+
" Reset the save event marker, used for opening windows, etc.
call setbufvar(a:buffer, 'ale_save_event_fired', 0)
" Set a marker showing how many times a buffer has been checked.
@@ -318,7 +350,7 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfor
endfunction
-function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
+function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
let l:bufnr_map = {}
let l:new_loclist = []
@@ -351,6 +383,10 @@ function! ale#engine#FixLocList(buffer, linter_name, loclist) abort
\ 'linter_name': a:linter_name,
\}
+ if a:from_other_source
+ let l:item.from_other_source = 1
+ endif
+
if has_key(l:old_item, 'code')
let l:item.code = l:old_item.code
endif
@@ -557,7 +593,7 @@ function! s:RunJob(options) abort
if get(g:, 'ale_run_synchronously') == 1
" Run a command synchronously if this test option is set.
let s:job_info_map[l:job_id].output = systemlist(
- \ type(l:command) == type([])
+ \ type(l:command) is v:t_list
\ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2])
\ : l:command
\)
@@ -595,9 +631,8 @@ function! ale#engine#ProcessChain(buffer, linter, chain_index, input) abort
\)
endif
+ " If we have a command to run, execute that.
if !empty(l:command)
- " We hit a command to run, so we'll execute that
-
" The chain item can override the output_stream option.
if has_key(l:chain_item, 'output_stream')
let l:output_stream = l:chain_item.output_stream
@@ -675,6 +710,7 @@ endfunction
function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
" Figure out which linters are still enabled, and remove
" problems for linters which are no longer enabled.
+ " Problems from other sources will be kept.
let l:name_map = {}
for l:linter in a:linters
@@ -683,7 +719,7 @@ function! s:RemoveProblemsForDisabledLinters(buffer, linters) abort
call filter(
\ get(g:ale_buffer_info[a:buffer], 'loclist', []),
- \ 'get(l:name_map, get(v:val, ''linter_name''))',
+ \ 'get(v:val, ''from_other_source'') || get(l:name_map, get(v:val, ''linter_name''))',
\)
endfunction
diff --git a/autoload/ale/engine/ignore.vim b/autoload/ale/engine/ignore.vim
index 65347e21..2db2c6c1 100644
--- a/autoload/ale/engine/ignore.vim
+++ b/autoload/ale/engine/ignore.vim
@@ -4,11 +4,11 @@
" Given a filetype and a configuration for ignoring linters, return a List of
" Strings for linter names to ignore.
function! ale#engine#ignore#GetList(filetype, config) abort
- if type(a:config) is type([])
+ if type(a:config) is v:t_list
return a:config
endif
- if type(a:config) is type({})
+ if type(a:config) is v:t_dict
let l:names_to_remove = []
for l:part in split(a:filetype , '\.')
diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim
index 300aefcc..c3dbd378 100644
--- a/autoload/ale/events.vim
+++ b/autoload/ale/events.vim
@@ -29,7 +29,7 @@ function! ale#events#SaveEvent(buffer) abort
call setbufvar(a:buffer, 'ale_save_event_fired', 1)
endif
- if ale#Var(a:buffer, 'fix_on_save')
+ if ale#Var(a:buffer, 'fix_on_save') && !ale#events#QuitRecently(a:buffer)
let l:will_fix = ale#fix#Fix(a:buffer, 'save_file')
let l:should_lint = l:should_lint && !l:will_fix
endif
@@ -131,13 +131,25 @@ function! ale#events#Init() abort
autocmd InsertLeave * call ale#Queue(0)
endif
- if g:ale_echo_cursor
+ if g:ale_echo_cursor || g:ale_cursor_detail
autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif
" Look for a warning to echo as soon as we leave Insert mode.
" The script's position variable used when moving the cursor will
" not be changed here.
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif
endif
+
+ if g:ale_virtualtext_cursor
+ autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarningWithDelay() | endif
+ " Look for a warning to echo as soon as we leave Insert mode.
+ " The script's position variable used when moving the cursor will
+ " not be changed here.
+ autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarning() | endif
+ endif
+
+ if g:ale_close_preview_on_insert
+ autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif
+ endif
endif
augroup END
endfunction
diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim
index 8dfdeca8..03652ecf 100644
--- a/autoload/ale/fix.vim
+++ b/autoload/ale/fix.vim
@@ -30,7 +30,14 @@ function! ale#fix#ApplyQueuedFixes() abort
call winrestview(l:save)
endif
- call setline(1, l:data.output)
+ " If the file is in DOS mode, we have to remove carriage returns from
+ " the ends of lines before calling setline(), or we will see them
+ " twice.
+ let l:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos'
+ \ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')')
+ \ : l:data.output
+
+ call setline(1, l:lines_to_set)
if l:data.should_save
if empty(&buftype)
@@ -71,6 +78,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort
if l:data.lines_before != l:lines
call remove(g:ale_fix_buffer_data, a:buffer)
execute 'echoerr ''The file was changed before fixing finished'''
+
return
endif
endif
@@ -275,7 +283,7 @@ function! s:RunJob(options) abort
if get(g:, 'ale_run_synchronously') == 1
" Run a command synchronously if this test option is set.
let l:output = systemlist(
- \ type(l:command) == type([])
+ \ type(l:command) is v:t_list
\ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2])
\ : l:command
\)
@@ -313,10 +321,10 @@ function! s:RunFixer(options) abort
\ : call(l:Function, [l:buffer, copy(l:input)])
endif
- if type(l:result) == type(0) && l:result == 0
+ if type(l:result) is v:t_number && l:result == 0
" When `0` is returned, skip this item.
let l:index += 1
- elseif type(l:result) == type([])
+ elseif type(l:result) is v:t_list
let l:input = l:result
let l:index += 1
else
@@ -351,9 +359,9 @@ function! s:RunFixer(options) abort
endfunction
function! s:AddSubCallbacks(full_list, callbacks) abort
- if type(a:callbacks) == type('')
+ if type(a:callbacks) is v:t_string
call add(a:full_list, a:callbacks)
- elseif type(a:callbacks) == type([])
+ elseif type(a:callbacks) is v:t_list
call extend(a:full_list, a:callbacks)
else
return 0
@@ -365,7 +373,7 @@ endfunction
function! s:GetCallbacks(buffer, fixers) abort
if len(a:fixers)
let l:callback_list = a:fixers
- elseif type(get(b:, 'ale_fixers')) is type([])
+ elseif type(get(b:, 'ale_fixers')) is v:t_list
" Lists can be used for buffer-local variables only
let l:callback_list = b:ale_fixers
else
@@ -396,7 +404,7 @@ function! s:GetCallbacks(buffer, fixers) abort
" Variables with capital characters are needed, or Vim will complain about
" funcref variables.
for l:Item in l:callback_list
- if type(l:Item) == type('')
+ if type(l:Item) is v:t_string
let l:Func = ale#fix#registry#GetFunc(l:Item)
if !empty(l:Func)
diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim
index e148ecd6..a54be420 100644
--- a/autoload/ale/fix/registry.vim
+++ b/autoload/ale/fix/registry.vim
@@ -56,7 +56,7 @@ let s:default_registry = {
\ },
\ 'prettier': {
\ 'function': 'ale#fixers#prettier#Fix',
-\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue'],
+\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue', 'html', 'yaml'],
\ 'description': 'Apply prettier to a file.',
\ },
\ 'prettier_eslint': {
@@ -145,6 +145,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['go'],
\ 'description': 'Fix Go files imports with goimports.',
\ },
+\ 'gomod': {
+\ 'function': 'ale#fixers#gomod#Fix',
+\ 'suggested_filetypes': ['gomod'],
+\ 'description': 'Fix Go module files with go mod edit -fmt.',
+\ },
\ 'tslint': {
\ 'function': 'ale#fixers#tslint#Fix',
\ 'suggested_filetypes': ['typescript'],
@@ -157,7 +162,7 @@ let s:default_registry = {
\ },
\ 'hackfmt': {
\ 'function': 'ale#fixers#hackfmt#Fix',
-\ 'suggested_filetypes': ['php'],
+\ 'suggested_filetypes': ['hack'],
\ 'description': 'Fix Hack files with hackfmt.',
\ },
\ 'hfmt': {
@@ -170,6 +175,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with brittany.',
\ },
+\ 'hlint': {
+\ 'function': 'ale#fixers#hlint#Fix',
+\ 'suggested_filetypes': ['haskell'],
+\ 'description': 'Refactor Haskell files with hlint.',
+\ },
+\ 'stylish-haskell': {
+\ 'function': 'ale#fixers#stylish_haskell#Fix',
+\ 'suggested_filetypes': ['haskell'],
+\ 'description': 'Refactor Haskell files with stylish-haskell.',
+\ },
+\ 'ocamlformat': {
+\ 'function': 'ale#fixers#ocamlformat#Fix',
+\ 'suggested_filetypes': ['ocaml'],
+\ 'description': 'Fix OCaml files with ocamlformat.',
+\ },
\ 'refmt': {
\ 'function': 'ale#fixers#refmt#Fix',
\ 'suggested_filetypes': ['reason'],
@@ -180,6 +200,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['sh'],
\ 'description': 'Fix sh files with shfmt.',
\ },
+\ 'sqlfmt': {
+\ 'function': 'ale#fixers#sqlfmt#Fix',
+\ 'suggested_filetypes': ['sql'],
+\ 'description': 'Fix SQL files with sqlfmt.',
+\ },
\ 'google_java_format': {
\ 'function': 'ale#fixers#google_java_format#Fix',
\ 'suggested_filetypes': ['java'],
@@ -215,6 +240,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['dart'],
\ 'description': 'Fix Dart files with dartfmt.',
\ },
+\ 'xmllint': {
+\ 'function': 'ale#fixers#xmllint#Fix',
+\ 'suggested_filetypes': ['xml'],
+\ 'description': 'Fix XML files with xmllint.',
+\ },
+\ 'uncrustify': {
+\ 'function': 'ale#fixers#uncrustify#Fix',
+\ 'suggested_filetypes': ['c', 'cpp', 'cs', 'objc', 'objcpp', 'd', 'java', 'p', 'vala' ],
+\ 'description': 'Fix C, C++, C#, ObjectiveC, ObjectiveC++, D, Java, Pawn, and VALA files with uncrustify.',
+\ },
+\ 'terraform': {
+\ 'function': 'ale#fixers#terraform#Fix',
+\ 'suggested_filetypes': ['hcl', 'terraform'],
+\ 'description': 'Fix tf and hcl files with terraform fmt.',
+\ },
\}
" Reset the function registry to the default entries.
@@ -243,34 +283,34 @@ endfunction
" (name, func, filetypes, desc, aliases)
function! ale#fix#registry#Add(name, func, filetypes, desc, ...) abort
" This command will throw from the sandbox.
- let &equalprg=&equalprg
+ let &l:equalprg=&l:equalprg
- if type(a:name) != type('')
+ if type(a:name) isnot v:t_string
throw '''name'' must be a String'
endif
- if type(a:func) != type('')
+ if type(a:func) isnot v:t_string
throw '''func'' must be a String'
endif
- if type(a:filetypes) != type([])
+ if type(a:filetypes) isnot v:t_list
throw '''filetypes'' must be a List'
endif
for l:type in a:filetypes
- if type(l:type) != type('')
+ if type(l:type) isnot v:t_string
throw 'Each entry of ''filetypes'' must be a String'
endif
endfor
- if type(a:desc) != type('')
+ if type(a:desc) isnot v:t_string
throw '''desc'' must be a String'
endif
let l:aliases = get(a:000, 0, [])
- if type(l:aliases) != type([])
- \|| !empty(filter(copy(l:aliases), 'type(v:val) != type('''')'))
+ if type(l:aliases) isnot v:t_list
+ \|| !empty(filter(copy(l:aliases), 'type(v:val) isnot v:t_string'))
throw '''aliases'' must be a List of String values'
endif
diff --git a/autoload/ale/fixers/brittany.vim b/autoload/ale/fixers/brittany.vim
index 57c77325..c2448348 100644
--- a/autoload/ale/fixers/brittany.vim
+++ b/autoload/ale/fixers/brittany.vim
@@ -3,11 +3,17 @@
call ale#Set('haskell_brittany_executable', 'brittany')
-function! ale#fixers#brittany#Fix(buffer) abort
+function! ale#fixers#brittany#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'haskell_brittany_executable')
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'brittany')
+endfunction
+
+function! ale#fixers#brittany#Fix(buffer) abort
+ let l:executable = ale#fixers#brittany#GetExecutable(a:buffer)
+
return {
- \ 'command': ale#Escape(l:executable)
+ \ 'command': l:executable
\ . ' --write-mode inplace'
\ . ' %t',
\ 'read_temporary_file': 1,
diff --git a/autoload/ale/fixers/eslint.vim b/autoload/ale/fixers/eslint.vim
index 36f47510..ea5b2a63 100644
--- a/autoload/ale/fixers/eslint.vim
+++ b/autoload/ale/fixers/eslint.vim
@@ -25,7 +25,7 @@ endfunction
function! ale#fixers#eslint#ProcessEslintDOutput(buffer, output) abort
" If the output is an error message, don't use it.
for l:line in a:output[:10]
- if l:line =~# '^Error:'
+ if l:line =~# '\v^Error:|^Could not connect'
return []
endif
endfor
diff --git a/autoload/ale/fixers/fixjson.vim b/autoload/ale/fixers/fixjson.vim
index 64c6ba81..33ce0af3 100644
--- a/autoload/ale/fixers/fixjson.vim
+++ b/autoload/ale/fixers/fixjson.vim
@@ -17,6 +17,7 @@ function! ale#fixers#fixjson#Fix(buffer) abort
let l:command = l:executable . ' --stdin-filename ' . l:filename
let l:options = ale#Var(a:buffer, 'json_fixjson_options')
+
if l:options isnot# ''
let l:command .= ' ' . l:options
endif
diff --git a/autoload/ale/fixers/generic_python.vim b/autoload/ale/fixers/generic_python.vim
index 124146be..d55a23c3 100644
--- a/autoload/ale/fixers/generic_python.vim
+++ b/autoload/ale/fixers/generic_python.vim
@@ -6,13 +6,28 @@ function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, line
let l:new_lines = []
let l:last_indent_size = 0
let l:last_line_is_blank = 0
+ let l:in_docstring = 0
for l:line in a:lines
let l:indent_size = len(matchstr(l:line, '^ *'))
+ if !l:in_docstring
+ " Make sure it is not just a single line docstring and then verify
+ " it's starting a new docstring
+ if match(l:line, '\v^ *("""|'''''').*("""|'''''')') == -1
+ \&& match(l:line, '\v^ *("""|'''''')') >= 0
+ let l:in_docstring = 1
+ endif
+ else
+ if match(l:line, '\v^ *.*("""|'''''')') >= 0
+ let l:in_docstring = 0
+ endif
+ endif
+
if !l:last_line_is_blank
+ \&& !l:in_docstring
\&& l:indent_size <= l:last_indent_size
- \&& match(l:line, '\v^ *(return|if|for|while|break|continue)') >= 0
+ \&& match(l:line, '\v^ *(return|if|for|while|break|continue)(\(| |$)') >= 0
call add(l:new_lines, '')
endif
diff --git a/autoload/ale/fixers/gomod.vim b/autoload/ale/fixers/gomod.vim
new file mode 100644
index 00000000..68895f9b
--- /dev/null
+++ b/autoload/ale/fixers/gomod.vim
@@ -0,0 +1,10 @@
+call ale#Set('go_go_executable', 'go')
+
+function! ale#fixers#gomod#Fix(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'go_go_executable')
+
+ return {
+ \ 'command': ale#Escape(l:executable) . ' mod edit -fmt %t',
+ \ 'read_temporary_file': 1,
+ \}
+endfunction
diff --git a/autoload/ale/fixers/google_java_format.vim b/autoload/ale/fixers/google_java_format.vim
index 6a2f5491..20086c73 100644
--- a/autoload/ale/fixers/google_java_format.vim
+++ b/autoload/ale/fixers/google_java_format.vim
@@ -1,13 +1,13 @@
" Author: butlerx <butlerx@notthe,cloud>
" Description: Integration of Google-java-format with ALE.
-call ale#Set('google_java_format_executable', 'google-java-format')
-call ale#Set('google_java_format_use_global', get(g:, 'ale_use_global_executables', 0))
-call ale#Set('google_java_format_options', '')
+call ale#Set('java_google_java_format_executable', 'google-java-format')
+call ale#Set('java_google_java_format_use_global', get(g:, 'ale_use_global_executables', 0))
+call ale#Set('java_google_java_format_options', '')
function! ale#fixers#google_java_format#Fix(buffer) abort
- let l:options = ale#Var(a:buffer, 'google_java_format_options')
- let l:executable = ale#Var(a:buffer, 'google_java_format_executable')
+ let l:options = ale#Var(a:buffer, 'java_google_java_format_options')
+ let l:executable = ale#Var(a:buffer, 'java_google_java_format_executable')
if !executable(l:executable)
return 0
diff --git a/autoload/ale/fixers/hackfmt.vim b/autoload/ale/fixers/hackfmt.vim
index b5bf0dc5..bf2d4f71 100644
--- a/autoload/ale/fixers/hackfmt.vim
+++ b/autoload/ale/fixers/hackfmt.vim
@@ -1,12 +1,12 @@
" Author: Sam Howie <samhowie@gmail.com>
" Description: Integration of hackfmt with ALE.
-call ale#Set('php_hackfmt_executable', 'hackfmt')
-call ale#Set('php_hackfmt_options', '')
+call ale#Set('hack_hackfmt_executable', 'hackfmt')
+call ale#Set('hack_hackfmt_options', '')
function! ale#fixers#hackfmt#Fix(buffer) abort
- let l:executable = ale#Var(a:buffer, 'php_hackfmt_executable')
- let l:options = ale#Var(a:buffer, 'php_hackfmt_options')
+ let l:executable = ale#Var(a:buffer, 'hack_hackfmt_executable')
+ let l:options = ale#Var(a:buffer, 'hack_hackfmt_options')
return {
\ 'command': ale#Escape(l:executable)
diff --git a/autoload/ale/fixers/hfmt.vim b/autoload/ale/fixers/hfmt.vim
index ea061da4..0407b713 100644
--- a/autoload/ale/fixers/hfmt.vim
+++ b/autoload/ale/fixers/hfmt.vim
@@ -7,7 +7,7 @@ function! ale#fixers#hfmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'haskell_hfmt_executable')
return {
- \ 'command': ale#Escape(l:executable)
+ \ 'command': ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hfmt')
\ . ' -w'
\ . ' %t',
\ 'read_temporary_file': 1,
diff --git a/autoload/ale/fixers/hlint.vim b/autoload/ale/fixers/hlint.vim
new file mode 100644
index 00000000..88779a55
--- /dev/null
+++ b/autoload/ale/fixers/hlint.vim
@@ -0,0 +1,13 @@
+" Author: eborden <evan@evan-borden.com>
+" Description: Integration of hlint refactor with ALE.
+"
+
+function! ale#fixers#hlint#Fix(buffer) abort
+ return {
+ \ 'command': ale#handlers#hlint#GetExecutable(a:buffer)
+ \ . ' --refactor'
+ \ . ' --refactor-options="--inplace"'
+ \ . ' %t',
+ \ 'read_temporary_file': 1,
+ \}
+endfunction
diff --git a/autoload/ale/fixers/importjs.vim b/autoload/ale/fixers/importjs.vim
index e8eedb12..b5487b2c 100644
--- a/autoload/ale/fixers/importjs.vim
+++ b/autoload/ale/fixers/importjs.vim
@@ -1,15 +1,16 @@
" Author: Jeff Willette <jrwillette88@gmail.com>
" Description: Integration of importjs with ALE.
-call ale#Set('js_importjs_executable', 'importjs')
+call ale#Set('javascript_importjs_executable', 'importjs')
function! ale#fixers#importjs#ProcessOutput(buffer, output) abort
let l:result = ale#util#FuzzyJSONDecode(a:output, [])
+
return split(get(l:result, 'fileContent', ''), "\n")
endfunction
function! ale#fixers#importjs#Fix(buffer) abort
- let l:executable = ale#Var(a:buffer, 'js_importjs_executable')
+ let l:executable = ale#Var(a:buffer, 'javascript_importjs_executable')
if !executable(l:executable)
return 0
diff --git a/autoload/ale/fixers/jq.vim b/autoload/ale/fixers/jq.vim
index b0a43fe2..1b743e49 100644
--- a/autoload/ale/fixers/jq.vim
+++ b/autoload/ale/fixers/jq.vim
@@ -1,5 +1,6 @@
call ale#Set('json_jq_executable', 'jq')
call ale#Set('json_jq_options', '')
+call ale#Set('json_jq_filters', '.')
function! ale#fixers#jq#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'json_jq_executable')
@@ -7,9 +8,15 @@ endfunction
function! ale#fixers#jq#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'json_jq_options')
+ let l:filters = ale#Var(a:buffer, 'json_jq_filters')
+
+ if empty(l:filters)
+ return 0
+ endif
return {
\ 'command': ale#Escape(ale#fixers#jq#GetExecutable(a:buffer))
- \ . ' . ' . l:options,
+ \ . ' ' . l:filters . ' '
+ \ . l:options,
\}
endfunction
diff --git a/autoload/ale/fixers/ocamlformat.vim b/autoload/ale/fixers/ocamlformat.vim
new file mode 100644
index 00000000..9b7c3e12
--- /dev/null
+++ b/autoload/ale/fixers/ocamlformat.vim
@@ -0,0 +1,18 @@
+" Author: Stephen Lumenta <@sbl>
+" Description: Integration of ocamlformat with ALE.
+
+call ale#Set('ocaml_ocamlformat_executable', 'ocamlformat')
+call ale#Set('ocaml_ocamlformat_options', '')
+
+function! ale#fixers#ocamlformat#Fix(buffer) abort
+ let l:filename = expand('#' . a:buffer . ':p')
+ let l:executable = ale#Var(a:buffer, 'ocaml_ocamlformat_executable')
+ let l:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options')
+
+ return {
+ \ 'command': ale#Escape(l:executable)
+ \ . (empty(l:options) ? '' : ' ' . l:options)
+ \ . ' --name=' . ale#Escape(l:filename)
+ \ . ' -'
+ \}
+endfunction
diff --git a/autoload/ale/fixers/php_cs_fixer.vim b/autoload/ale/fixers/php_cs_fixer.vim
index 26b8e5de..5c59e262 100644
--- a/autoload/ale/fixers/php_cs_fixer.vim
+++ b/autoload/ale/fixers/php_cs_fixer.vim
@@ -14,6 +14,7 @@ endfunction
function! ale#fixers#php_cs_fixer#Fix(buffer) abort
let l:executable = ale#fixers#php_cs_fixer#GetExecutable(a:buffer)
+
return {
\ 'command': ale#Escape(l:executable)
\ . ' ' . ale#Var(a:buffer, 'php_cs_fixer_options')
diff --git a/autoload/ale/fixers/phpcbf.vim b/autoload/ale/fixers/phpcbf.vim
index 487f369a..f14b8406 100644
--- a/autoload/ale/fixers/phpcbf.vim
+++ b/autoload/ale/fixers/phpcbf.vim
@@ -18,6 +18,7 @@ function! ale#fixers#phpcbf#Fix(buffer) abort
let l:standard_option = !empty(l:standard)
\ ? '--standard=' . l:standard
\ : ''
+
return {
\ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ' -'
\}
diff --git a/autoload/ale/fixers/prettier.vim b/autoload/ale/fixers/prettier.vim
index e8f4e92e..58dea159 100644
--- a/autoload/ale/fixers/prettier.vim
+++ b/autoload/ale/fixers/prettier.vim
@@ -27,6 +27,17 @@ function! ale#fixers#prettier#Fix(buffer) abort
\}
endfunction
+function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
+ " If the output is an error message, don't use it.
+ for l:line in a:output[:10]
+ if l:line =~# '^\w*Error:'
+ return []
+ endif
+ endfor
+
+ return a:output
+endfunction
+
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
@@ -36,12 +47,24 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
" Append the --parser flag depending on the current filetype (unless it's
" already set in g:javascript_prettier_options).
if empty(expand('#' . a:buffer . ':e')) && match(l:options, '--parser') == -1
- let l:prettier_parsers = ['typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue']
- let l:parser = 'babylon'
+ let l:prettier_parsers = {
+ \ 'typescript': 'typescript',
+ \ 'css': 'css',
+ \ 'less': 'less',
+ \ 'scss': 'scss',
+ \ 'json': 'json',
+ \ 'json5': 'json5',
+ \ 'graphql': 'graphql',
+ \ 'markdown': 'markdown',
+ \ 'vue': 'vue',
+ \ 'yaml': 'yaml',
+ \ 'html': 'html',
+ \}
+ let l:parser = ''
for l:filetype in split(getbufvar(a:buffer, '&filetype'), '\.')
- if index(l:prettier_parsers, l:filetype) > -1
- let l:parser = l:filetype
+ if has_key(l:prettier_parsers, l:filetype)
+ let l:parser = l:prettier_parsers[l:filetype]
break
endif
endfor
@@ -51,6 +74,17 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort
let l:options = (!empty(l:options) ? l:options . ' ' : '') . '--parser ' . l:parser
endif
+ " Special error handling needed for prettier_d
+ if l:executable =~# 'prettier_d$'
+ return {
+ \ 'command': ale#path#BufferCdString(a:buffer)
+ \ . ale#Escape(l:executable)
+ \ . (!empty(l:options) ? ' ' . l:options : '')
+ \ . ' --stdin-filepath %s --stdin',
+ \ 'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput',
+ \}
+ endif
+
" 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(l:version, [1, 4, 0])
return {
diff --git a/autoload/ale/fixers/puppetlint.vim b/autoload/ale/fixers/puppetlint.vim
index 81f34e89..bf36e486 100644
--- a/autoload/ale/fixers/puppetlint.vim
+++ b/autoload/ale/fixers/puppetlint.vim
@@ -4,6 +4,7 @@
if !exists('g:ale_puppet_puppetlint_executable')
let g:ale_puppet_puppetlint_executable = 'puppet-lint'
endif
+
if !exists('g:ale_puppet_puppetlint_options')
let g:ale_puppet_puppetlint_options = ''
endif
diff --git a/autoload/ale/fixers/rubocop.vim b/autoload/ale/fixers/rubocop.vim
index 35569b19..33ba6887 100644
--- a/autoload/ale/fixers/rubocop.vim
+++ b/autoload/ale/fixers/rubocop.vim
@@ -1,16 +1,15 @@
+call ale#Set('ruby_rubocop_options', '')
+call ale#Set('ruby_rubocop_executable', 'rubocop')
+
function! ale#fixers#rubocop#GetCommand(buffer) abort
- let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
- let l:exec_args = l:executable =~? 'bundle$'
- \ ? ' exec rubocop'
- \ : ''
+ let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable')
let l:config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml')
let l:options = ale#Var(a:buffer, 'ruby_rubocop_options')
- return ale#Escape(l:executable) . l:exec_args
+ return ale#handlers#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '')
- \ . ' --auto-correct %t'
-
+ \ . ' --auto-correct --force-exclusion %t'
endfunction
function! ale#fixers#rubocop#Fix(buffer) abort
diff --git a/autoload/ale/fixers/scalafmt.vim b/autoload/ale/fixers/scalafmt.vim
index 07d28275..dd0e7745 100644
--- a/autoload/ale/fixers/scalafmt.vim
+++ b/autoload/ale/fixers/scalafmt.vim
@@ -15,7 +15,6 @@ function! ale#fixers#scalafmt#GetCommand(buffer) abort
return ale#Escape(l:executable) . l:exec_args
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t'
-
endfunction
function! ale#fixers#scalafmt#Fix(buffer) abort
diff --git a/autoload/ale/fixers/shfmt.vim b/autoload/ale/fixers/shfmt.vim
index 882cf3a4..06e8da57 100644
--- a/autoload/ale/fixers/shfmt.vim
+++ b/autoload/ale/fixers/shfmt.vim
@@ -5,13 +5,27 @@ scriptencoding utf-8
call ale#Set('sh_shfmt_executable', 'shfmt')
call ale#Set('sh_shfmt_options', '')
+function! s:DefaultOption(buffer) abort
+ if getbufvar(a:buffer, '&expandtab') == 0
+ " Tab is used by default
+ return ''
+ endif
+
+ let l:tabsize = getbufvar(a:buffer, '&shiftwidth')
+
+ if l:tabsize == 0
+ let l:tabsize = getbufvar(a:buffer, '&tabstop')
+ endif
+
+ return ' -i ' . l:tabsize
+endfunction
+
function! ale#fixers#shfmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'sh_shfmt_executable')
let l:options = ale#Var(a:buffer, 'sh_shfmt_options')
return {
\ 'command': ale#Escape(l:executable)
- \ . (empty(l:options) ? '' : ' ' . l:options)
+ \ . (empty(l:options) ? s:DefaultOption(a:buffer) : ' ' . l:options)
\}
-
endfunction
diff --git a/autoload/ale/fixers/sqlfmt.vim b/autoload/ale/fixers/sqlfmt.vim
new file mode 100644
index 00000000..c88a8ec2
--- /dev/null
+++ b/autoload/ale/fixers/sqlfmt.vim
@@ -0,0 +1,13 @@
+call ale#Set('sql_sqlfmt_executable', 'sqlfmt')
+call ale#Set('sql_sqlfmt_options', '')
+
+function! ale#fixers#sqlfmt#Fix(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'sql_sqlfmt_executable')
+ let l:options = ale#Var(a:buffer, 'sql_sqlfmt_options')
+
+ return {
+ \ 'command': ale#Escape(l:executable)
+ \ . ' -w'
+ \ . (empty(l:options) ? '' : ' ' . l:options),
+ \}
+endfunction
diff --git a/autoload/ale/fixers/stylish_haskell.vim b/autoload/ale/fixers/stylish_haskell.vim
new file mode 100644
index 00000000..ce71c1ce
--- /dev/null
+++ b/autoload/ale/fixers/stylish_haskell.vim
@@ -0,0 +1,21 @@
+" Author: eborden <evan@evan-borden.com>
+" Description: Integration of stylish-haskell formatting with ALE.
+"
+call ale#Set('haskell_stylish_haskell_executable', 'stylish-haskell')
+
+function! ale#fixers#stylish_haskell#GetExecutable(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'haskell_stylish_haskell_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'stylish-haskell')
+endfunction
+
+function! ale#fixers#stylish_haskell#Fix(buffer) abort
+ let l:executable = ale#fixers#stylish_haskell#GetExecutable(a:buffer)
+
+ return {
+ \ 'command': l:executable
+ \ . ' --inplace'
+ \ . ' %t',
+ \ 'read_temporary_file': 1,
+ \}
+endfunction
diff --git a/autoload/ale/fixers/terraform.vim b/autoload/ale/fixers/terraform.vim
new file mode 100644
index 00000000..bc05380a
--- /dev/null
+++ b/autoload/ale/fixers/terraform.vim
@@ -0,0 +1,17 @@
+" Author: dsifford <dereksifford@gmail.com>
+" Description: Fixer for terraform and .hcl files
+
+call ale#Set('terraform_fmt_executable', 'terraform')
+call ale#Set('terraform_fmt_options', '')
+
+function! ale#fixers#terraform#Fix(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'terraform_fmt_executable')
+ let l:options = ale#Var(a:buffer, 'terraform_fmt_options')
+
+ return {
+ \ 'command': ale#Escape(l:executable)
+ \ . ' fmt'
+ \ . (empty(l:options) ? '' : ' ' . l:options)
+ \ . ' -'
+ \}
+endfunction
diff --git a/autoload/ale/fixers/uncrustify.vim b/autoload/ale/fixers/uncrustify.vim
new file mode 100644
index 00000000..ffec18ef
--- /dev/null
+++ b/autoload/ale/fixers/uncrustify.vim
@@ -0,0 +1,16 @@
+" Author: Derek P Sifford <dereksifford@gmail.com>
+" Description: Fixer for C, C++, C#, ObjectiveC, D, Java, Pawn, and VALA.
+
+call ale#Set('c_uncrustify_executable', 'uncrustify')
+call ale#Set('c_uncrustify_options', '')
+
+function! ale#fixers#uncrustify#Fix(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'c_uncrustify_executable')
+ let l:options = ale#Var(a:buffer, 'c_uncrustify_options')
+
+ return {
+ \ 'command': ale#Escape(l:executable)
+ \ . ' --no-backup'
+ \ . (empty(l:options) ? '' : ' ' . l:options)
+ \}
+endfunction
diff --git a/autoload/ale/fixers/xmllint.vim b/autoload/ale/fixers/xmllint.vim
new file mode 100644
index 00000000..b14ffd36
--- /dev/null
+++ b/autoload/ale/fixers/xmllint.vim
@@ -0,0 +1,29 @@
+" Author: Cyril Roelandt <tipecaml@gmail.com>
+" Description: Integration of xmllint with ALE.
+
+call ale#Set('xml_xmllint_executable', 'xmllint')
+call ale#Set('xml_xmllint_options', '')
+call ale#Set('xml_xmllint_indentsize', 2)
+
+function! ale#fixers#xmllint#Fix(buffer) abort
+ let l:executable = ale#Escape(ale#Var(a:buffer, 'xml_xmllint_executable'))
+ let l:filename = ale#Escape(bufname(a:buffer))
+ let l:command = l:executable . ' --format ' . l:filename
+
+ let l:indent = ale#Var(a:buffer, 'xml_xmllint_indentsize')
+
+ if l:indent isnot# ''
+ let l:env = ale#Env('XMLLINT_INDENT', repeat(' ', l:indent))
+ let l:command = l:env . l:command
+ endif
+
+ let l:options = ale#Var(a:buffer, 'xml_xmllint_options')
+
+ if l:options isnot# ''
+ let l:command .= ' ' . l:options
+ endif
+
+ return {
+ \ 'command': l:command
+ \}
+endfunction
diff --git a/autoload/ale/go.vim b/autoload/ale/go.vim
new file mode 100644
index 00000000..a166480a
--- /dev/null
+++ b/autoload/ale/go.vim
@@ -0,0 +1,27 @@
+" Author: Horacio Sanson https://github.com/hsanson
+" Description: Functions for integrating with Go tools
+
+" Find the nearest dir listed in GOPATH and assume it the root of the go
+" project.
+function! ale#go#FindProjectRoot(buffer) abort
+ let l:sep = has('win32') ? ';' : ':'
+
+ let l:filename = ale#path#Simplify(expand('#' . a:buffer . ':p'))
+
+ for l:name in split($GOPATH, l:sep)
+ let l:path_dir = ale#path#Simplify(l:name)
+
+ " Use the directory from GOPATH if the current filename starts with it.
+ if l:filename[: len(l:path_dir) - 1] is? l:path_dir
+ return l:path_dir
+ endif
+ endfor
+
+ let l:default_go_path = ale#path#Simplify(expand('~/go'))
+
+ if isdirectory(l:default_go_path)
+ return l:default_go_path
+ endif
+
+ return ''
+endfunction
diff --git a/autoload/ale/handlers/ccls.vim b/autoload/ale/handlers/ccls.vim
new file mode 100644
index 00000000..29dd6aed
--- /dev/null
+++ b/autoload/ale/handlers/ccls.vim
@@ -0,0 +1,17 @@
+scriptencoding utf-8
+" Author: Ye Jingchen <ye.jingchen@gmail.com>
+" Description: Utilities for ccls
+
+function! ale#handlers#ccls#GetProjectRoot(buffer) abort
+ let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls-root')
+
+ if empty(l:project_root)
+ let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
+ endif
+
+ if empty(l:project_root)
+ let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls')
+ endif
+
+ return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
+endfunction
diff --git a/autoload/ale/handlers/elixir.vim b/autoload/ale/handlers/elixir.vim
new file mode 100644
index 00000000..2fddf8e7
--- /dev/null
+++ b/autoload/ale/handlers/elixir.vim
@@ -0,0 +1,28 @@
+" Author: Matteo Centenaro (bugant) - https://github.com/bugant
+" Author: Jon Parise <jon@indelible.org>
+" Description: Functions for working with Elixir projects
+
+" Find the root directory for an elixir project that uses mix.
+function! ale#handlers#elixir#FindMixProjectRoot(buffer) abort
+ let l:mix_file = ale#path#FindNearestFile(a:buffer, 'mix.exs')
+
+ if !empty(l:mix_file)
+ return fnamemodify(l:mix_file, ':p:h')
+ endif
+
+ return '.'
+endfunction
+
+" Similar to ale#handlers#elixir#FindMixProjectRoot but also continue the
+" search upward for a potential umbrella project root. If an umbrella root
+" does not exist, the initial project root will be returned.
+function! ale#handlers#elixir#FindMixUmbrellaRoot(buffer) abort
+ let l:app_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
+ let l:umbrella_root = fnamemodify(l:app_root, ':h:h')
+
+ if filereadable(l:umbrella_root . '/mix.exs')
+ return l:umbrella_root
+ endif
+
+ return l:app_root
+endfunction
diff --git a/autoload/ale/handlers/eslint.vim b/autoload/ale/handlers/eslint.vim
index bc10ec21..eda033e4 100644
--- a/autoload/ale/handlers/eslint.vim
+++ b/autoload/ale/handlers/eslint.vim
@@ -99,6 +99,13 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort
\}]
endif
+ if a:lines == ['Could not connect']
+ return [{
+ \ 'lnum': 1,
+ \ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.',
+ \}]
+ endif
+
" Matches patterns line the following:
"
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
diff --git a/autoload/ale/handlers/gawk.vim b/autoload/ale/handlers/gawk.vim
index 942bc2b2..50bc4c45 100644
--- a/autoload/ale/handlers/gawk.vim
+++ b/autoload/ale/handlers/gawk.vim
@@ -9,9 +9,11 @@ function! ale#handlers#gawk#HandleGawkFormat(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, l:pattern)
let l:ecode = 'E'
+
if l:match[2] is? 'warning:'
let l:ecode = 'W'
endif
+
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': 0,
diff --git a/autoload/ale/handlers/gcc.vim b/autoload/ale/handlers/gcc.vim
index 4b53652a..72d639da 100644
--- a/autoload/ale/handlers/gcc.vim
+++ b/autoload/ale/handlers/gcc.vim
@@ -5,6 +5,13 @@ scriptencoding utf-8
let s:pragma_error = '#pragma once in main file'
+" Look for lines like the following.
+"
+" <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]
+" <stdin>:10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’)
+" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
+let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$'
+
function! s:IsHeaderFile(filename) abort
return a:filename =~? '\v\.(h|hpp)$'
endfunction
@@ -18,16 +25,63 @@ function! s:RemoveUnicodeQuotes(text) abort
return l:text
endfunction
+" Report problems inside of header files just for gcc and clang
+function! s:ParseProblemsInHeaders(buffer, lines) abort
+ let l:output = []
+ let l:include_item = {}
+
+ for l:line in a:lines[: -2]
+ let l:include_match = matchlist(l:line, '\v^In file included from')
+
+ if !empty(l:include_item)
+ let l:pattern_match = matchlist(l:line, s:pattern)
+
+ if !empty(l:pattern_match) && l:pattern_match[1] is# '<stdin>'
+ if has_key(l:include_item, 'lnum')
+ call add(l:output, l:include_item)
+ endif
+
+ let l:include_item = {}
+
+ continue
+ endif
+
+ let l:include_item.detail .= "\n" . l:line
+ endif
+
+ if !empty(l:include_match)
+ if empty(l:include_item)
+ let l:include_item = {
+ \ 'text': 'Error found in header. See :ALEDetail',
+ \ 'detail': l:line,
+ \}
+ endif
+ endif
+
+ if !empty(l:include_item)
+ let l:stdin_match = matchlist(l:line, '\vfrom \<stdin\>:(\d+):(\d*):?$')
+
+ if !empty(l:stdin_match)
+ let l:include_item.lnum = str2nr(l:stdin_match[1])
+
+ if str2nr(l:stdin_match[2])
+ let l:include_item.col = str2nr(l:stdin_match[2])
+ endif
+ endif
+ endif
+ endfor
+
+ if !empty(l:include_item) && has_key(l:include_item, 'lnum')
+ call add(l:output, l:include_item)
+ endif
+
+ return l:output
+endfunction
+
function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
- " Look for lines like the following.
- "
- " <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]
- " <stdin>:10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’)
- " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
- let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$'
let l:output = []
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ for l:match in ale#util#GetMatches(a:lines, s:pattern)
" Filter out the pragma errors
if s:IsHeaderFile(bufname(bufnr('')))
\&& l:match[5][:len(s:pragma_error) - 1] is# s:pragma_error
@@ -38,9 +92,12 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
" the previous error parsed in output
if l:match[4] is# 'note'
if !empty(l:output)
- let l:output[-1]['detail'] =
- \ get(l:output[-1], 'detail', '')
- \ . s:RemoveUnicodeQuotes(l:match[0]) . "\n"
+ if !has_key(l:output[-1], 'detail')
+ let l:output[-1].detail = l:output[-1].text
+ endif
+
+ let l:output[-1].detail = l:output[-1].detail . "\n"
+ \ . s:RemoveUnicodeQuotes(l:match[0])
endif
continue
@@ -67,3 +124,12 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
return l:output
endfunction
+
+" Handle problems with the GCC format, but report problems inside of headers.
+function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort
+ let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines)
+
+ call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines))
+
+ return l:output
+endfunction
diff --git a/autoload/ale/handlers/go.vim b/autoload/ale/handlers/go.vim
index 224df664..f17cd862 100644
--- a/autoload/ale/handlers/go.vim
+++ b/autoload/ale/handlers/go.vim
@@ -21,5 +21,6 @@ function! ale#handlers#go#Handler(buffer, lines) abort
\ 'type': 'E',
\})
endfor
+
return l:output
endfunction
diff --git a/autoload/ale/handlers/haskell.vim b/autoload/ale/handlers/haskell.vim
index 9223b650..9e495b36 100644
--- a/autoload/ale/handlers/haskell.vim
+++ b/autoload/ale/handlers/haskell.vim
@@ -1,5 +1,15 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Error handling for the format GHC outputs.
+"
+function! ale#handlers#haskell#GetStackExecutable(bufnr) abort
+ if ale#path#FindNearestFile(a:bufnr, 'stack.yaml') isnot# ''
+ return 'stack'
+ endif
+
+ " if there is no stack.yaml file, we don't use stack even if it exists,
+ " so we return '', because executable('') apparently always fails
+ return ''
+endfunction
" Remember the directory used for temporary files for Vim.
let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h')
diff --git a/autoload/ale/handlers/haskell_stack.vim b/autoload/ale/handlers/haskell_stack.vim
new file mode 100644
index 00000000..108301a9
--- /dev/null
+++ b/autoload/ale/handlers/haskell_stack.vim
@@ -0,0 +1,7 @@
+function! ale#handlers#haskell_stack#EscapeExecutable(executable, stack_exec) abort
+ let l:exec_args = a:executable =~? 'stack$'
+ \ ? ' exec ' . ale#Escape(a:stack_exec) . ' --'
+ \ : ''
+
+ return ale#Escape(a:executable) . l:exec_args
+endfunction
diff --git a/autoload/ale/handlers/hlint.vim b/autoload/ale/handlers/hlint.vim
new file mode 100644
index 00000000..b9a8c322
--- /dev/null
+++ b/autoload/ale/handlers/hlint.vim
@@ -0,0 +1,8 @@
+call ale#Set('haskell_hlint_executable', 'hlint')
+call ale#Set('haskell_hlint_options', get(g:, 'hlint_options', ''))
+
+function! ale#handlers#hlint#GetExecutable(buffer) abort
+ let l:executable = ale#Var(a:buffer, 'haskell_hlint_executable')
+
+ return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hlint')
+endfunction
diff --git a/autoload/ale/handlers/ols.vim b/autoload/ale/handlers/ols.vim
index 1dda7f92..74130a26 100644
--- a/autoload/ale/handlers/ols.vim
+++ b/autoload/ale/handlers/ols.vim
@@ -3,6 +3,7 @@
function! ale#handlers#ols#GetExecutable(buffer) abort
let l:ols_setting = ale#handlers#ols#GetLanguage(a:buffer) . '_ols'
+
return ale#node#FindExecutable(a:buffer, l:ols_setting, [
\ 'node_modules/.bin/ocaml-language-server',
\])
diff --git a/autoload/ale/handlers/pony.vim b/autoload/ale/handlers/pony.vim
index 0ac18e76..ea84ac4b 100644
--- a/autoload/ale/handlers/pony.vim
+++ b/autoload/ale/handlers/pony.vim
@@ -14,7 +14,6 @@ endfunction
function! ale#handlers#pony#HandlePonycFormat(buffer, lines) abort
" Look for lines like the following.
" /home/code/pony/classes/Wombat.pony:22:30: can't lookup private fields from outside the type
-
let l:pattern = '\v^([^:]+):(\d+):(\d+)?:? (.+)$'
let l:output = []
diff --git a/autoload/ale/handlers/redpen.vim b/autoload/ale/handlers/redpen.vim
index c136789c..84e331ed 100644
--- a/autoload/ale/handlers/redpen.vim
+++ b/autoload/ale/handlers/redpen.vim
@@ -6,15 +6,18 @@ function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort
" element.
let l:res = json_decode(join(a:lines))[0]
let l:output = []
+
for l:err in l:res.errors
let l:item = {
\ 'text': l:err.message,
\ 'type': 'W',
\ 'code': l:err.validator,
\}
+
if has_key(l:err, 'startPosition')
let l:item.lnum = l:err.startPosition.lineNum
let l:item.col = l:err.startPosition.offset + 1
+
if has_key(l:err, 'endPosition')
let l:item.end_lnum = l:err.endPosition.lineNum
let l:item.end_col = l:err.endPosition.offset
@@ -28,29 +31,35 @@ function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort
" Adjust column number for multibyte string
let l:line = getline(l:item.lnum)
+
if l:line is# ''
let l:line = l:err.sentence
endif
+
let l:line = split(l:line, '\zs')
if l:item.col >= 2
let l:col = 0
+
for l:strlen in map(l:line[0:(l:item.col - 2)], 'strlen(v:val)')
let l:col = l:col + l:strlen
endfor
+
let l:item.col = l:col + 1
endif
if has_key(l:item, 'end_col')
let l:col = 0
+
for l:strlen in map(l:line[0:(l:item.end_col - 1)], 'strlen(v:val)')
let l:col = l:col + l:strlen
endfor
+
let l:item.end_col = l:col
endif
call add(l:output, l:item)
endfor
+
return l:output
endfunction
-
diff --git a/autoload/ale/handlers/rubocop.vim b/autoload/ale/handlers/rubocop.vim
deleted file mode 100644
index f6367cf5..00000000
--- a/autoload/ale/handlers/rubocop.vim
+++ /dev/null
@@ -1,6 +0,0 @@
-call ale#Set('ruby_rubocop_options', '')
-call ale#Set('ruby_rubocop_executable', 'rubocop')
-
-function! ale#handlers#rubocop#GetExecutable(buffer) abort
- return ale#Var(a:buffer, 'ruby_rubocop_executable')
-endfunction
diff --git a/autoload/ale/handlers/ruby.vim b/autoload/ale/handlers/ruby.vim
index 555c13b1..c28b8b75 100644
--- a/autoload/ale/handlers/ruby.vim
+++ b/autoload/ale/handlers/ruby.vim
@@ -13,8 +13,10 @@ function! s:HandleSyntaxError(buffer, lines) abort
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
+
if len(l:match) == 0
let l:match = matchlist(l:line, l:column)
+
if len(l:match) != 0
let l:output[len(l:output) - 1]['col'] = len(l:match[1])
endif
@@ -35,3 +37,10 @@ function! ale#handlers#ruby#HandleSyntaxErrors(buffer, lines) abort
return s:HandleSyntaxError(a:buffer, a:lines)
endfunction
+function! ale#handlers#ruby#EscapeExecutable(executable, bundle_exec) abort
+ let l:exec_args = a:executable =~? 'bundle'
+ \ ? ' exec ' . a:bundle_exec
+ \ : ''
+
+ return ale#Escape(a:executable) . l:exec_args
+endfunction
diff --git a/autoload/ale/handlers/rust.vim b/autoload/ale/handlers/rust.vim
index 537bc731..c6a4b670 100644
--- a/autoload/ale/handlers/rust.vim
+++ b/autoload/ale/handlers/rust.vim
@@ -7,6 +7,10 @@ if !exists('g:ale_rust_ignore_error_codes')
let g:ale_rust_ignore_error_codes = []
endif
+if !exists('g:ale_rust_ignore_secondary_spans')
+ let g:ale_rust_ignore_secondary_spans = 0
+endif
+
function! s:FindSpan(buffer, span) abort
if ale#path#IsBufferPath(a:buffer, a:span.file_name) || a:span.file_name is# '<anon>'
return a:span
@@ -32,7 +36,7 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
let l:error = json_decode(l:errorline)
- if has_key(l:error, 'message') && type(l:error.message) == type({})
+ if has_key(l:error, 'message') && type(l:error.message) is v:t_dict
let l:error = l:error.message
endif
@@ -47,6 +51,10 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
for l:root_span in l:error.spans
let l:span = s:FindSpan(a:buffer, l:root_span)
+ if ale#Var(a:buffer, 'rust_ignore_secondary_spans') && !get(l:span, 'is_primary', 1)
+ continue
+ endif
+
if !empty(l:span)
call add(l:output, {
\ 'lnum': l:span.line_start,
diff --git a/autoload/ale/handlers/sml.vim b/autoload/ale/handlers/sml.vim
index 377eade5..92c5f83b 100644
--- a/autoload/ale/handlers/sml.vim
+++ b/autoload/ale/handlers/sml.vim
@@ -11,8 +11,10 @@ function! ale#handlers#sml#GetCmFile(buffer) abort
let l:as_list = 1
let l:cmfile = ''
+
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
let l:results = glob(l:path . '/' . l:pattern, 0, l:as_list)
+
if len(l:results) > 0
" If there is more than one CM file, we take the first one
" See :help ale-sml-smlnj for how to configure this.
@@ -46,6 +48,7 @@ endfunction
function! ale#handlers#sml#GetExecutableSmlnjCm(buffer) abort
return s:GetExecutable(a:buffer, 'smlnj-cm')
endfunction
+
function! ale#handlers#sml#GetExecutableSmlnjFile(buffer) abort
return s:GetExecutable(a:buffer, 'smlnj-file')
endfunction
@@ -53,7 +56,6 @@ endfunction
function! ale#handlers#sml#Handle(buffer, lines) abort
" Try to match basic sml errors
" TODO(jez) We can get better errorfmt strings from Syntastic
-
let l:out = []
let l:pattern = '^.*\:\([0-9\.]\+\)\ \(\w\+\)\:\ \(.*\)'
let l:pattern2 = '^.*\:\([0-9]\+\)\.\?\([0-9]\+\).* \(\(Warning\|Error\): .*\)'
@@ -83,7 +85,6 @@ function! ale#handlers#sml#Handle(buffer, lines) abort
\})
continue
endif
-
endfor
return l:out
diff --git a/autoload/ale/handlers/vale.vim b/autoload/ale/handlers/vale.vim
index 9dc0872f..2da72fc7 100644
--- a/autoload/ale/handlers/vale.vim
+++ b/autoload/ale/handlers/vale.vim
@@ -23,6 +23,7 @@ function! ale#handlers#vale#Handle(buffer, lines) abort
endif
let l:output = []
+
for l:error in l:errors[keys(l:errors)[0]]
call add(l:output, {
\ 'lnum': l:error['Line'],
diff --git a/autoload/ale/hover.vim b/autoload/ale/hover.vim
index 5e97e16e..69db276e 100644
--- a/autoload/ale/hover.vim
+++ b/autoload/ale/hover.vim
@@ -63,19 +63,19 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
let l:result = l:result.contents
- if type(l:result) is type('')
+ if type(l:result) is v:t_string
" The result can be just a string.
let l:result = [l:result]
endif
- if type(l:result) is type({})
+ if type(l:result) is v:t_dict
" If the result is an object, then it's markup content.
let l:result = [l:result.value]
endif
- if type(l:result) is type([])
+ if type(l:result) is v:t_list
" Replace objects with text values.
- call map(l:result, 'type(v:val) is type('''') ? v:val : v:val.value')
+ call map(l:result, 'type(v:val) is v:t_string ? v:val : v:val.value')
let l:str = join(l:result, "\n")
let l:str = substitute(l:str, '^\s*\(.\{-}\)\s*$', '\1', '')
@@ -92,7 +92,44 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
endif
endfunction
-function! s:ShowDetails(linter, buffer, line, column, opt) abort
+function! s:OnReady(linter, lsp_details, line, column, opt, ...) abort
+ let l:buffer = a:lsp_details.buffer
+ let l:id = a:lsp_details.connection_id
+
+ let l:Callback = a:linter.lsp is# 'tsserver'
+ \ ? function('ale#hover#HandleTSServerResponse')
+ \ : function('ale#hover#HandleLSPResponse')
+ call ale#lsp#RegisterCallback(l:id, l:Callback)
+
+ if a:linter.lsp is# 'tsserver'
+ let l:column = a:column
+
+ let l:message = ale#lsp#tsserver_message#Quickinfo(
+ \ l:buffer,
+ \ a:line,
+ \ l:column
+ \)
+ else
+ " Send a message saying the buffer has changed first, or the
+ " hover position probably won't make sense.
+ call ale#lsp#NotifyForChanges(l:id, l:buffer)
+
+ let l:column = min([a:column, len(getbufline(l:buffer, a:line)[0])])
+
+ let l:message = ale#lsp#message#Hover(l:buffer, a:line, l:column)
+ endif
+
+ let l:request_id = ale#lsp#Send(l:id, l:message)
+
+ let s:hover_map[l:request_id] = {
+ \ 'buffer': l:buffer,
+ \ 'line': a:line,
+ \ 'column': l:column,
+ \ 'hover_from_balloonexpr': get(a:opt, 'called_from_balloonexpr', 0),
+ \}
+endfunction
+
+function! s:ShowDetails(linter, buffer, line, column, opt, ...) abort
let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter)
if empty(l:lsp_details)
@@ -100,44 +137,10 @@ function! s:ShowDetails(linter, buffer, line, column, opt) abort
endif
let l:id = l:lsp_details.connection_id
- let l:root = l:lsp_details.project_root
- let l:language_id = l:lsp_details.language_id
-
- function! OnReady(...) abort closure
- let l:Callback = a:linter.lsp is# 'tsserver'
- \ ? function('ale#hover#HandleTSServerResponse')
- \ : function('ale#hover#HandleLSPResponse')
- call ale#lsp#RegisterCallback(l:id, l:Callback)
-
- if a:linter.lsp is# 'tsserver'
- let l:column = a:column
-
- let l:message = ale#lsp#tsserver_message#Quickinfo(
- \ a:buffer,
- \ a:line,
- \ l:column
- \)
- else
- " Send a message saying the buffer has changed first, or the
- " hover position probably won't make sense.
- call ale#lsp#NotifyForChanges(l:id, l:root, a:buffer)
-
- let l:column = min([a:column, len(getbufline(a:buffer, a:line)[0])])
-
- let l:message = ale#lsp#message#Hover(a:buffer, a:line, l:column)
- endif
-
- let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
-
- let s:hover_map[l:request_id] = {
- \ 'buffer': a:buffer,
- \ 'line': a:line,
- \ 'column': l:column,
- \ 'hover_from_balloonexpr': get(a:opt, 'called_from_balloonexpr', 0),
- \}
- endfunction
- call ale#lsp#WaitForCapability(l:id, l:root, 'hover', function('OnReady'))
+ call ale#lsp#WaitForCapability(l:id, 'hover', function('s:OnReady', [
+ \ a:linter, l:lsp_details, a:line, a:column, a:opt
+ \]))
endfunction
" Obtain Hover information for the specified position
diff --git a/autoload/ale/java.vim b/autoload/ale/java.vim
new file mode 100644
index 00000000..b7fd10bd
--- /dev/null
+++ b/autoload/ale/java.vim
@@ -0,0 +1,20 @@
+" Author: Horacio Sanson https://github.com/hsanson
+" Description: Functions for integrating with Java tools
+
+" Find the nearest dir contining a gradle or pom file and asume it
+" the root of a java app.
+function! ale#java#FindProjectRoot(buffer) abort
+ let l:gradle_root = ale#gradle#FindProjectRoot(a:buffer)
+
+ if !empty(l:gradle_root)
+ return l:gradle_root
+ endif
+
+ let l:maven_pom_file = ale#path#FindNearestFile(a:buffer, 'pom.xml')
+
+ if !empty(l:maven_pom_file)
+ return fnamemodify(l:maven_pom_file, ':h')
+ endif
+
+ return ''
+endfunction
diff --git a/autoload/ale/job.vim b/autoload/ale/job.vim
index e0266cba..0117c7dd 100644
--- a/autoload/ale/job.vim
+++ b/autoload/ale/job.vim
@@ -249,6 +249,11 @@ function! ale#job#Start(command, options) abort
let l:job_options.exit_cb = function('s:VimExitCallback')
endif
+ " Use non-blocking writes for Vim versions that support the option.
+ if has('patch-8.1.350')
+ let l:job_options.noblock = 1
+ endif
+
" Vim 8 will read the stdin from the file's buffer.
let l:job_info.job = job_start(a:command, l:job_options)
let l:job_id = ale#job#ParseVim8ProcessID(string(l:job_info.job))
@@ -278,11 +283,13 @@ function! ale#job#IsRunning(job_id) abort
try
" In NeoVim, if the job isn't running, jobpid() will throw.
call jobpid(a:job_id)
+
return 1
catch
endtry
elseif has_key(s:job_map, a:job_id)
let l:job = s:job_map[a:job_id].job
+
return job_status(l:job) is# 'run'
endif
diff --git a/autoload/ale/julia.vim b/autoload/ale/julia.vim
new file mode 100644
index 00000000..18dd9ad7
--- /dev/null
+++ b/autoload/ale/julia.vim
@@ -0,0 +1,19 @@
+" Author: Bartolomeo Stellato bartolomeo.stellato@gmail.com
+" Description: Functions for integrating with Julia tools
+
+" Find the nearest dir containing a julia project
+let s:__ale_julia_project_filenames = ['REQUIRE', 'Manifest.toml', 'Project.toml']
+
+function! ale#julia#FindProjectRoot(buffer) abort
+ for l:project_filename in s:__ale_julia_project_filenames
+ let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
+
+ if !empty(l:full_path)
+ let l:path = fnamemodify(l:full_path, ':p:h')
+
+ return l:path
+ endif
+ endfor
+
+ return ''
+endfunction
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index aa602f7e..1cbc9ffe 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -16,6 +16,7 @@ let s:default_ale_linter_aliases = {
\ 'systemverilog': 'verilog',
\ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'],
\ 'vimwiki': 'markdown',
+\ 'vue': ['vue', 'javascript'],
\ 'zsh': 'sh',
\}
@@ -26,17 +27,22 @@ let s:default_ale_linter_aliases = {
"
" Only cargo is enabled for Rust by default.
" rpmlint is disabled by default because it can result in code execution.
+" hhast is disabled by default because it executes code in the project root.
"
" NOTE: Update the g:ale_linters documentation when modifying this.
let s:default_ale_linters = {
\ 'csh': ['shell'],
+\ 'elixir': ['credo', 'dialyxir', 'dogma', 'elixir-ls'],
\ 'go': ['gofmt', 'golint', 'go vet'],
+\ 'hack': ['hack'],
\ 'help': [],
\ 'perl': ['perlcritic'],
+\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'],
\ 'spec': [],
\ 'text': [],
+\ 'vue': ['eslint', 'vls'],
\ 'zsh': ['shell'],
\}
@@ -51,17 +57,17 @@ endfunction
" Do not call this function.
function! ale#linter#GetLintersLoaded() abort
" This command will throw from the sandbox.
- let &equalprg=&equalprg
+ let &l:equalprg=&l:equalprg
return s:linters
endfunction
function! s:IsCallback(value) abort
- return type(a:value) == type('') || type(a:value) == type(function('type'))
+ return type(a:value) is v:t_string || type(a:value) is v:t_func
endfunction
function! s:IsBoolean(value) abort
- return type(a:value) == type(0) && (a:value == 0 || a:value == 1)
+ return type(a:value) is v:t_number && (a:value == 0 || a:value == 1)
endfunction
function! s:LanguageGetter(buffer) dict abort
@@ -69,7 +75,7 @@ function! s:LanguageGetter(buffer) dict abort
endfunction
function! ale#linter#PreProcess(filetype, linter) abort
- if type(a:linter) != type({})
+ if type(a:linter) isnot v:t_dict
throw 'The linter object must be a Dictionary'
endif
@@ -79,7 +85,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
\ 'lsp': get(a:linter, 'lsp', ''),
\}
- if type(l:obj.name) != type('')
+ if type(l:obj.name) isnot v:t_string
throw '`name` must be defined to name the linter'
endif
@@ -97,7 +103,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
if index(['', 'socket', 'stdio', 'tsserver'], l:obj.lsp) < 0
- throw '`lsp` must be either `''lsp''` or `''tsserver''` if defined'
+ throw '`lsp` must be either `''lsp''`, `''stdio''`, `''socket''` or `''tsserver''` if defined'
endif
if !l:needs_executable
@@ -114,7 +120,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
elseif has_key(a:linter, 'executable')
let l:obj.executable = a:linter.executable
- if type(l:obj.executable) != type('')
+ if type(l:obj.executable) isnot v:t_string
throw '`executable` must be a string if defined'
endif
else
@@ -130,7 +136,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
elseif has_key(a:linter, 'command_chain')
let l:obj.command_chain = a:linter.command_chain
- if type(l:obj.command_chain) != type([])
+ if type(l:obj.command_chain) isnot v:t_list
throw '`command_chain` must be a List'
endif
@@ -148,7 +154,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
if has_key(l:link, 'output_stream')
- if type(l:link.output_stream) != type('')
+ if type(l:link.output_stream) isnot v:t_string
\|| index(['stdout', 'stderr', 'both'], l:link.output_stream) < 0
throw l:err_prefix . '`output_stream` flag must be '
\ . "'stdout', 'stderr', or 'both'"
@@ -170,7 +176,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
elseif has_key(a:linter, 'command')
let l:obj.command = a:linter.command
- if type(l:obj.command) != type('')
+ if type(l:obj.command) isnot v:t_string
throw '`command` must be a string if defined'
endif
else
@@ -217,7 +223,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
" Default to using the filetype as the language.
let l:obj.language = get(a:linter, 'language', a:filetype)
- if type(l:obj.language) != type('')
+ if type(l:obj.language) isnot v:t_string
throw '`language` must be a string'
endif
@@ -253,11 +259,29 @@ function! ale#linter#PreProcess(filetype, linter) abort
elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options
endif
+
+ if has_key(a:linter, 'lsp_config_callback')
+ if has_key(a:linter, 'lsp_config')
+ throw 'Only one of `lsp_config` or `lsp_config_callback` should be set'
+ endif
+
+ let l:obj.lsp_config_callback = a:linter.lsp_config_callback
+
+ if !s:IsCallback(l:obj.lsp_config_callback)
+ throw '`lsp_config_callback` must be a callback if defined'
+ endif
+ elseif has_key(a:linter, 'lsp_config')
+ if type(a:linter.lsp_config) isnot v:t_dict
+ throw '`lsp_config` must be a Dictionary'
+ endif
+
+ let l:obj.lsp_config = a:linter.lsp_config
+ endif
endif
let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout')
- if type(l:obj.output_stream) != type('')
+ if type(l:obj.output_stream) isnot v:t_string
\|| index(['stdout', 'stderr', 'both'], l:obj.output_stream) < 0
throw "`output_stream` must be 'stdout', 'stderr', or 'both'"
endif
@@ -283,8 +307,8 @@ function! ale#linter#PreProcess(filetype, linter) abort
let l:obj.aliases = get(a:linter, 'aliases', [])
- if type(l:obj.aliases) != type([])
- \|| len(filter(copy(l:obj.aliases), 'type(v:val) != type('''')')) > 0
+ if type(l:obj.aliases) isnot v:t_list
+ \|| len(filter(copy(l:obj.aliases), 'type(v:val) isnot v:t_string')) > 0
throw '`aliases` must be a List of String values'
endif
@@ -293,7 +317,7 @@ endfunction
function! ale#linter#Define(filetype, linter) abort
" This command will throw from the sandbox.
- let &equalprg=&equalprg
+ let &l:equalprg=&l:equalprg
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
@@ -335,8 +359,9 @@ endfunction
function! s:GetAliasedFiletype(original_filetype) abort
let l:buffer_aliases = get(b:, 'ale_linter_aliases', {})
- " b:ale_linter_aliases can be set to a List.
- if type(l:buffer_aliases) is type([])
+ " b:ale_linter_aliases can be set to a List or String.
+ if type(l:buffer_aliases) is v:t_list
+ \|| type(l:buffer_aliases) is v:t_string
return l:buffer_aliases
endif
@@ -360,7 +385,7 @@ endfunction
function! ale#linter#ResolveFiletype(original_filetype) abort
let l:filetype = s:GetAliasedFiletype(a:original_filetype)
- if type(l:filetype) != type([])
+ if type(l:filetype) isnot v:t_list
return [l:filetype]
endif
@@ -376,7 +401,7 @@ function! s:GetLinterNames(original_filetype) abort
endif
" b:ale_linters can be set to a List.
- if type(l:buffer_ale_linters) is type([])
+ if type(l:buffer_ale_linters) is v:t_list
return l:buffer_ale_linters
endif
@@ -414,9 +439,9 @@ function! ale#linter#Get(original_filetypes) abort
let l:all_linters = ale#linter#GetAll(l:filetype)
let l:filetype_linters = []
- if type(l:linter_names) == type('') && l:linter_names is# 'all'
+ if type(l:linter_names) is v:t_string && l:linter_names is# 'all'
let l:filetype_linters = l:all_linters
- elseif type(l:linter_names) == type([])
+ elseif type(l:linter_names) is v:t_list
" Select only the linters we or the user has specified.
for l:linter in l:all_linters
let l:name_list = [l:linter.name] + l:linter.aliases
diff --git a/autoload/ale/list.vim b/autoload/ale/list.vim
index 35304a09..3417575c 100644
--- a/autoload/ale/list.vim
+++ b/autoload/ale/list.vim
@@ -25,6 +25,7 @@ function! ale#list#IsQuickfixOpen() abort
return 1
endif
endfor
+
return 0
endfunction
@@ -112,9 +113,11 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort
" open windows vertically instead of default horizontally
let l:open_type = ''
+
if ale#Var(a:buffer, 'list_vertical') == 1
let l:open_type = 'vert '
endif
+
if g:ale_set_quickfix
if !ale#list#IsQuickfixOpen()
silent! execute l:open_type . 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size'))
diff --git a/autoload/ale/loclist_jumping.vim b/autoload/ale/loclist_jumping.vim
index 7ed9e6ba..fd5ff922 100644
--- a/autoload/ale/loclist_jumping.vim
+++ b/autoload/ale/loclist_jumping.vim
@@ -66,6 +66,7 @@ function! ale#loclist_jumping#Jump(direction, wrap) abort
let l:nearest = ale#loclist_jumping#FindNearest(a:direction, a:wrap)
if !empty(l:nearest)
+ normal! m`
call cursor(l:nearest)
endif
endfunction
@@ -82,6 +83,7 @@ function! ale#loclist_jumping#JumpToIndex(index) abort
let l:item = l:loclist[a:index]
if !empty(l:item)
+ normal! m`
call cursor([l:item.lnum, l:item.col])
endif
endfunction
diff --git a/autoload/ale/lsp.vim b/autoload/ale/lsp.vim
index 312319ab..f55096c2 100644
--- a/autoload/ale/lsp.vim
+++ b/autoload/ale/lsp.vim
@@ -1,62 +1,70 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Language Server Protocol client code
-" A List of connections, used for tracking servers which have been connected
-" to, and programs which are run.
-let s:connections = get(s:, 'connections', [])
+" A Dictionary for tracking connections.
+let s:connections = get(s:, 'connections', {})
let g:ale_lsp_next_message_id = 1
-" Exposed only so tests can get at it.
-" Do not call this function basically anywhere.
-function! ale#lsp#NewConnection(initialization_options) abort
- " id: The job ID as a Number, or the server address as a string.
- " data: The message data received so far.
- " executable: An executable only set for program connections.
- " open_documents: A Dictionary mapping buffers to b:changedtick, keeping
- " track of when documents were opened, and when we last changed them.
- " callback_list: A list of callbacks for handling LSP responses.
- " initialization_options: Options to send to the server.
- " capabilities: Features the server supports.
- let l:conn = {
- \ 'is_tsserver': 0,
- \ 'id': '',
- \ 'data': '',
- \ 'projects': {},
- \ 'open_documents': {},
- \ 'callback_list': [],
- \ 'initialization_options': a:initialization_options,
- \ 'capabilities': {
- \ 'hover': 0,
- \ 'references': 0,
- \ 'completion': 0,
- \ 'completion_trigger_characters': [],
- \ 'definition': 0,
- \ },
- \}
-
- call add(s:connections, l:conn)
+" Given an id, which can be an executable or address, and a project path,
+" create a new connection if needed. Return a unique ID for the connection.
+function! ale#lsp#Register(executable_or_address, project, init_options) abort
+ let l:conn_id = a:executable_or_address . ':' . a:project
+
+ if !has_key(s:connections, l:conn_id)
+ " is_tsserver: 1 if the connection is for tsserver.
+ " data: The message data received so far.
+ " root: The project root.
+ " open_documents: A Dictionary mapping buffers to b:changedtick, keeping
+ " track of when documents were opened, and when we last changed them.
+ " initialized: 0 if the connection is ready, 1 otherwise.
+ " init_request_id: The ID for the init request.
+ " init_options: Options to send to the server.
+ " config: Configuration settings to send to the server.
+ " callback_list: A list of callbacks for handling LSP responses.
+ " message_queue: Messages queued for sending to callbacks.
+ " capabilities_queue: The list of callbacks to call with capabilities.
+ " capabilities: Features the server supports.
+ let s:connections[l:conn_id] = {
+ \ 'id': l:conn_id,
+ \ 'is_tsserver': 0,
+ \ 'data': '',
+ \ 'root': a:project,
+ \ 'open_documents': {},
+ \ 'initialized': 0,
+ \ 'init_request_id': 0,
+ \ 'init_options': a:init_options,
+ \ 'config': {},
+ \ 'callback_list': [],
+ \ 'message_queue': [],
+ \ 'capabilities_queue': [],
+ \ 'capabilities': {
+ \ 'hover': 0,
+ \ 'references': 0,
+ \ 'completion': 0,
+ \ 'completion_trigger_characters': [],
+ \ 'definition': 0,
+ \ 'symbol_search': 0,
+ \ },
+ \}
+ endif
- return l:conn
+ return l:conn_id
endfunction
" Remove an LSP connection with a given ID. This is only for tests.
function! ale#lsp#RemoveConnectionWithID(id) abort
- call filter(s:connections, 'v:val.id isnot a:id')
+ if has_key(s:connections, a:id)
+ call remove(s:connections, a:id)
+ endif
endfunction
-function! s:FindConnection(key, value) abort
- for l:conn in s:connections
- if has_key(l:conn, a:key) && get(l:conn, a:key) is# a:value
- return l:conn
- endif
- endfor
-
- return {}
-endfunction
+" This is only needed for tests
+function! ale#lsp#MarkDocumentAsOpen(id, buffer) abort
+ let l:conn = get(s:connections, a:id, {})
-" Get the capabilities for a connection, or an empty Dictionary.
-function! ale#lsp#GetConnectionCapabilities(id) abort
- return get(s:FindConnection('id', a:id), 'capabilities', {})
+ if !empty(l:conn)
+ let l:conn.open_documents[a:buffer] = -1
+ endif
endfunction
function! ale#lsp#GetNextMessageID() abort
@@ -94,13 +102,14 @@ function! s:CreateTSServerMessageData(message) abort
endif
let l:data = json_encode(l:obj) . "\n"
+
return [l:is_notification ? 0 : l:obj.seq, l:data]
endfunction
" Given a List of one or two items, [method_name] or [method_name, params],
" return a List containing [message_id, message_data]
function! ale#lsp#CreateMessageData(message) abort
- if a:message[1] =~# '^ts@'
+ if a:message[1][:2] is# 'ts@'
return s:CreateTSServerMessageData(a:message)
endif
@@ -167,53 +176,10 @@ function! ale#lsp#ReadMessageData(data) abort
return [l:remainder, l:response_list]
endfunction
-function! s:FindProjectWithInitRequestID(conn, init_request_id) abort
- for l:project_root in keys(a:conn.projects)
- let l:project = a:conn.projects[l:project_root]
-
- if l:project.init_request_id == a:init_request_id
- return l:project
- endif
- endfor
-
- return {}
-endfunction
-
-function! s:MarkProjectAsInitialized(conn, project) abort
- let a:project.initialized = 1
-
- " After the server starts, send messages we had queued previously.
- for l:message_data in a:project.message_queue
- call s:SendMessageData(a:conn, l:message_data)
- endfor
-
- " Remove the messages now.
- let a:conn.message_queue = []
-
- " Call capabilities callbacks queued for the project.
- for [l:capability, l:Callback] in a:project.capabilities_queue
- if a:conn.is_tsserver || a:conn.capabilities[l:capability]
- call call(l:Callback, [a:conn.id, a:project.root])
- endif
- endfor
-
- " Clear the queued callbacks now.
- let a:project.capabilities_queue = []
-endfunction
-
-function! s:HandleInitializeResponse(conn, response) abort
- let l:request_id = a:response.request_id
- let l:project = s:FindProjectWithInitRequestID(a:conn, l:request_id)
-
- if !empty(l:project)
- call s:MarkProjectAsInitialized(a:conn, l:project)
- endif
-endfunction
-
" Update capabilities from the server, so we know which features the server
" supports.
function! s:UpdateCapabilities(conn, capabilities) abort
- if type(a:capabilities) != type({})
+ if type(a:capabilities) isnot v:t_dict
return
endif
@@ -229,10 +195,10 @@ function! s:UpdateCapabilities(conn, capabilities) abort
let a:conn.capabilities.completion = 1
endif
- if type(get(a:capabilities, 'completionProvider')) is type({})
+ if type(get(a:capabilities, 'completionProvider')) is v:t_dict
let l:chars = get(a:capabilities.completionProvider, 'triggerCharacters')
- if type(l:chars) is type([])
+ if type(l:chars) is v:t_list
let a:conn.capabilities.completion_trigger_characters = l:chars
endif
endif
@@ -240,180 +206,164 @@ function! s:UpdateCapabilities(conn, capabilities) abort
if get(a:capabilities, 'definitionProvider') is v:true
let a:conn.capabilities.definition = 1
endif
-endfunction
-function! ale#lsp#HandleOtherInitializeResponses(conn, response) abort
- let l:uninitialized_projects = []
+ if get(a:capabilities, 'workspaceSymbolProvider') is v:true
+ let a:conn.capabilities.symbol_search = 1
+ endif
+endfunction
- for [l:key, l:value] in items(a:conn.projects)
- if l:value.initialized == 0
- call add(l:uninitialized_projects, [l:key, l:value])
- endif
- endfor
+" Update a connection's configuration dictionary and notify LSP servers
+" of any changes since the last update. Returns 1 if a configuration
+" update was sent; otherwise 0 will be returned.
+function! ale#lsp#UpdateConfig(conn_id, buffer, config) abort
+ let l:conn = get(s:connections, a:conn_id, {})
- if empty(l:uninitialized_projects)
- return
+ if empty(l:conn) || a:config ==# l:conn.config " no-custom-checks
+ return 0
endif
- if get(a:response, 'method', '') is# ''
- if has_key(get(a:response, 'result', {}), 'capabilities')
- call s:UpdateCapabilities(a:conn, a:response.result.capabilities)
+ let l:conn.config = a:config
+ let l:message = ale#lsp#message#DidChangeConfiguration(a:buffer, a:config)
- for [l:dir, l:project] in l:uninitialized_projects
- call s:MarkProjectAsInitialized(a:conn, l:project)
- endfor
- endif
- elseif get(a:response, 'method', '') is# 'textDocument/publishDiagnostics'
- let l:filename = ale#path#FromURI(a:response.params.uri)
+ call ale#lsp#Send(a:conn_id, l:message)
- for [l:dir, l:project] in l:uninitialized_projects
- if l:filename[:len(l:dir) - 1] is# l:dir
- call s:MarkProjectAsInitialized(a:conn, l:project)
- endif
- endfor
- endif
+ return 1
endfunction
-function! ale#lsp#HandleMessage(conn, message) abort
- if type(a:message) != type('')
- " Ignore messages that aren't strings.
- return
+
+function! ale#lsp#HandleInitResponse(conn, response) abort
+ if get(a:response, 'method', '') is# 'initialize'
+ let a:conn.initialized = 1
+ elseif type(get(a:response, 'result')) is v:t_dict
+ \&& has_key(a:response.result, 'capabilities')
+ call s:UpdateCapabilities(a:conn, a:response.result.capabilities)
+
+ let a:conn.initialized = 1
endif
- let a:conn.data .= a:message
+ if !a:conn.initialized
+ return
+ endif
- " Parse the objects now if we can, and keep the remaining text.
- let [a:conn.data, l:response_list] = ale#lsp#ReadMessageData(a:conn.data)
+ " After the server starts, send messages we had queued previously.
+ for l:message_data in a:conn.message_queue
+ call s:SendMessageData(a:conn, l:message_data)
+ endfor
- " Call our callbacks.
- for l:response in l:response_list
- if get(l:response, 'method', '') is# 'initialize'
- call s:HandleInitializeResponse(a:conn, l:response)
- else
- call ale#lsp#HandleOtherInitializeResponses(a:conn, l:response)
+ " Remove the messages now.
+ let a:conn.message_queue = []
- " Call all of the registered handlers with the response.
- for l:Callback in a:conn.callback_list
- call ale#util#GetFunction(l:Callback)(a:conn.id, l:response)
- endfor
+ " Call capabilities callbacks queued for the project.
+ for [l:capability, l:Callback] in a:conn.capabilities_queue
+ if a:conn.capabilities[l:capability]
+ call call(l:Callback, [a:conn.id])
endif
endfor
+
+ let a:conn.capabilities_queue = []
endfunction
-function! s:HandleChannelMessage(channel_id, message) abort
- let l:address = ale#socket#GetAddress(a:channel_id)
- let l:conn = s:FindConnection('id', l:address)
+function! ale#lsp#HandleMessage(conn_id, message) abort
+ let l:conn = get(s:connections, a:conn_id, {})
- call ale#lsp#HandleMessage(l:conn, a:message)
-endfunction
+ if empty(l:conn)
+ return
+ endif
-function! s:HandleCommandMessage(job_id, message) abort
- let l:conn = s:FindConnection('id', a:job_id)
+ if type(a:message) isnot v:t_string
+ " Ignore messages that aren't strings.
+ return
+ endif
- call ale#lsp#HandleMessage(l:conn, a:message)
-endfunction
+ let l:conn.data .= a:message
-" Given a connection ID, mark it as a tsserver connection, so it will be
-" handled that way.
-function! ale#lsp#MarkConnectionAsTsserver(conn_id) abort
- let l:conn = s:FindConnection('id', a:conn_id)
+ " Parse the objects now if we can, and keep the remaining text.
+ let [l:conn.data, l:response_list] = ale#lsp#ReadMessageData(l:conn.data)
- if !empty(l:conn)
- let l:conn.is_tsserver = 1
+ " Look for initialize responses first.
+ if !l:conn.initialized
+ for l:response in l:response_list
+ call ale#lsp#HandleInitResponse(l:conn, l:response)
+ endfor
endif
-endfunction
-" Register a project for an LSP connection.
-"
-" This function will throw if the connection doesn't exist.
-function! ale#lsp#RegisterProject(conn_id, project_root) abort
- let l:conn = s:FindConnection('id', a:conn_id)
-
- " Empty strings can't be used for Dictionary keys in NeoVim, due to E713.
- " This appears to be a nonsensical bug in NeoVim.
- let l:key = empty(a:project_root) ? '<<EMPTY>>' : a:project_root
-
- if !has_key(l:conn.projects, l:key)
- " Tools without project roots are ready right away, like tsserver.
- let l:conn.projects[l:key] = {
- \ 'root': a:project_root,
- \ 'initialized': empty(a:project_root),
- \ 'init_request_id': 0,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \}
+ " If the connection is marked as initialized, call the callbacks with the
+ " responses.
+ if l:conn.initialized
+ for l:response in l:response_list
+ " Call all of the registered handlers with the response.
+ for l:Callback in l:conn.callback_list
+ call ale#util#GetFunction(l:Callback)(a:conn_id, l:response)
+ endfor
+ endfor
endif
endfunction
-function! ale#lsp#GetProject(conn, project_root) abort
- if empty(a:conn)
- return {}
- endif
-
- let l:key = empty(a:project_root) ? '<<EMPTY>>' : a:project_root
-
- return get(a:conn.projects, l:key, {})
+" Given a connection ID, mark it as a tsserver connection, so it will be
+" handled that way.
+function! ale#lsp#MarkConnectionAsTsserver(conn_id) abort
+ let l:conn = s:connections[a:conn_id]
+ let l:conn.is_tsserver = 1
+ let l:conn.initialized = 1
+ " Set capabilities which are supported by tsserver.
+ let l:conn.capabilities.hover = 1
+ let l:conn.capabilities.references = 1
+ let l:conn.capabilities.completion = 1
+ let l:conn.capabilities.completion_trigger_characters = ['.']
+ let l:conn.capabilities.definition = 1
+ let l:conn.capabilities.symbol_search = 1
endfunction
-" Start a program for LSP servers which run with executables.
+" Start a program for LSP servers.
"
-" The job ID will be returned for for the program if it ran, otherwise
-" 0 will be returned.
-function! ale#lsp#StartProgram(executable, command, init_options) abort
- if !executable(a:executable)
- return 0
- endif
-
- let l:conn = s:FindConnection('executable', a:executable)
+" 1 will be returned if the program is running, or 0 if the program could
+" not be started.
+function! ale#lsp#StartProgram(conn_id, executable, command) abort
+ let l:conn = s:connections[a:conn_id]
- " Get the current connection or a new one.
- let l:conn = !empty(l:conn) ? l:conn : ale#lsp#NewConnection(a:init_options)
- let l:conn.executable = a:executable
-
- if !has_key(l:conn, 'id') || !ale#job#IsRunning(l:conn.id)
+ if !has_key(l:conn, 'job_id') || !ale#job#IsRunning(l:conn.job_id)
let l:options = {
\ 'mode': 'raw',
- \ 'out_cb': function('s:HandleCommandMessage'),
+ \ 'out_cb': {_, message -> ale#lsp#HandleMessage(a:conn_id, message)},
\}
let l:job_id = ale#job#Start(a:command, l:options)
else
- let l:job_id = l:conn.id
+ let l:job_id = l:conn.job_id
endif
- if l:job_id <= 0
- return 0
+ if l:job_id > 0
+ let l:conn.job_id = l:job_id
endif
- let l:conn.id = l:job_id
-
- return l:job_id
+ return l:job_id > 0
endfunction
-" Connect to an address and set up a callback for handling responses.
-function! ale#lsp#ConnectToAddress(address, init_options) abort
- let l:conn = s:FindConnection('id', a:address)
- " Get the current connection or a new one.
- let l:conn = !empty(l:conn) ? l:conn : ale#lsp#NewConnection(a:init_options)
+" Connect to an LSP server via TCP.
+"
+" 1 will be returned if the connection is running, or 0 if the connection could
+" not be opened.
+function! ale#lsp#ConnectToAddress(conn_id, address) abort
+ let l:conn = s:connections[a:conn_id]
if !has_key(l:conn, 'channel_id') || !ale#socket#IsOpen(l:conn.channel_id)
- let l:conn.channel_id = ale#socket#Open(a:address, {
- \ 'callback': function('s:HandleChannelMessage'),
+ let l:channel_id = ale#socket#Open(a:address, {
+ \ 'callback': {_, mess -> ale#lsp#HandleMessage(a:conn_id, mess)},
\})
+ else
+ let l:channel_id = l:conn.channel_id
endif
- if l:conn.channel_id < 0
- return ''
+ if l:channel_id >= 0
+ let l:conn.channel_id = l:channel_id
endif
- let l:conn.id = a:address
-
- return a:address
+ return l:channel_id >= 0
endfunction
" Given a connection ID and a callback, register that callback for handling
" messages if the connection exists.
function! ale#lsp#RegisterCallback(conn_id, callback) abort
- let l:conn = s:FindConnection('id', a:conn_id)
+ let l:conn = get(s:connections, a:conn_id, {})
if !empty(l:conn)
" Add the callback to the List if it's not there already.
@@ -421,23 +371,33 @@ function! ale#lsp#RegisterCallback(conn_id, callback) abort
endif
endfunction
-" Stop all LSP connections, closing all jobs and channels, and removing any
-" queued messages.
-function! ale#lsp#StopAll() abort
- for l:conn in s:connections
+" Stop a single LSP connection.
+function! ale#lsp#Stop(conn_id) abort
+ if has_key(s:connections, a:conn_id)
+ let l:conn = remove(s:connections, a:conn_id)
+
if has_key(l:conn, 'channel_id')
call ale#socket#Close(l:conn.channel_id)
- else
- call ale#job#Stop(l:conn.id)
+ elseif has_key(l:conn, 'job_id')
+ call ale#job#Stop(l:conn.job_id)
endif
- endfor
+ endif
+endfunction
- let s:connections = []
+function! ale#lsp#CloseDocument(conn_id) abort
+endfunction
+
+" Stop all LSP connections, closing all jobs and channels, and removing any
+" queued messages.
+function! ale#lsp#StopAll() abort
+ for l:conn_id in keys(s:connections)
+ call ale#lsp#Stop(l:conn_id)
+ endfor
endfunction
function! s:SendMessageData(conn, data) abort
- if has_key(a:conn, 'executable')
- call ale#job#SendRaw(a:conn.id, a:data)
+ if has_key(a:conn, 'job_id')
+ call ale#job#SendRaw(a:conn.job_id, a:data)
elseif has_key(a:conn, 'channel_id') && ale#socket#IsOpen(a:conn.channel_id)
" Send the message to the server
call ale#socket#Send(a:conn.channel_id, a:data)
@@ -454,38 +414,32 @@ endfunction
" Returns -1 when a message is sent, but no response is expected
" 0 when the message is not sent and
" >= 1 with the message ID when a response is expected.
-function! ale#lsp#Send(conn_id, message, ...) abort
- let l:project_root = get(a:000, 0, '')
+function! ale#lsp#Send(conn_id, message) abort
+ let l:conn = get(s:connections, a:conn_id, {})
- let l:conn = s:FindConnection('id', a:conn_id)
- let l:project = ale#lsp#GetProject(l:conn, l:project_root)
-
- if empty(l:project)
+ if empty(l:conn)
return 0
endif
" If we haven't initialized the server yet, then send the message for it.
- if !l:project.initialized
- " Only send the init message once.
- if !l:project.init_request_id
- let [l:init_id, l:init_data] = ale#lsp#CreateMessageData(
- \ ale#lsp#message#Initialize(l:project_root, l:conn.initialization_options),
- \)
+ if !l:conn.initialized && !l:conn.init_request_id
+ let [l:init_id, l:init_data] = ale#lsp#CreateMessageData(
+ \ ale#lsp#message#Initialize(l:conn.root, l:conn.init_options),
+ \)
- let l:project.init_request_id = l:init_id
+ let l:conn.init_request_id = l:init_id
- call s:SendMessageData(l:conn, l:init_data)
- endif
+ call s:SendMessageData(l:conn, l:init_data)
endif
let [l:id, l:data] = ale#lsp#CreateMessageData(a:message)
- if l:project.initialized
+ if l:conn.initialized
" Send the message now.
call s:SendMessageData(l:conn, l:data)
else
" Add the message we wanted to send to a List to send later.
- call add(l:project.message_queue, l:data)
+ call add(l:conn.message_queue, l:data)
endif
return l:id == 0 ? -1 : l:id
@@ -493,11 +447,10 @@ endfunction
" Notify LSP servers or tsserver if a document is opened, if needed.
" If a document is opened, 1 will be returned, otherwise 0 will be returned.
-function! ale#lsp#OpenDocument(conn_id, project_root, buffer, language_id) abort
- let l:conn = s:FindConnection('id', a:conn_id)
+function! ale#lsp#OpenDocument(conn_id, buffer, language_id) abort
+ let l:conn = get(s:connections, a:conn_id, {})
let l:opened = 0
- " FIXME: Return 1 if the document is already open?
if !empty(l:conn) && !has_key(l:conn.open_documents, a:buffer)
if l:conn.is_tsserver
let l:message = ale#lsp#tsserver_message#Open(a:buffer)
@@ -505,7 +458,7 @@ function! ale#lsp#OpenDocument(conn_id, project_root, buffer, language_id) abort
let l:message = ale#lsp#message#DidOpen(a:buffer, a:language_id)
endif
- call ale#lsp#Send(a:conn_id, l:message, a:project_root)
+ call ale#lsp#Send(a:conn_id, l:message)
let l:conn.open_documents[a:buffer] = getbufvar(a:buffer, 'changedtick')
let l:opened = 1
endif
@@ -515,8 +468,8 @@ endfunction
" Notify LSP servers or tsserver that a document has changed, if needed.
" If a notification is sent, 1 will be returned, otherwise 0 will be returned.
-function! ale#lsp#NotifyForChanges(conn_id, project_root, buffer) abort
- let l:conn = s:FindConnection('id', a:conn_id)
+function! ale#lsp#NotifyForChanges(conn_id, buffer) abort
+ let l:conn = get(s:connections, a:conn_id, {})
let l:notified = 0
if !empty(l:conn) && has_key(l:conn.open_documents, a:buffer)
@@ -529,7 +482,7 @@ function! ale#lsp#NotifyForChanges(conn_id, project_root, buffer) abort
let l:message = ale#lsp#message#DidChange(a:buffer)
endif
- call ale#lsp#Send(a:conn_id, l:message, a:project_root)
+ call ale#lsp#Send(a:conn_id, l:message)
let l:conn.open_documents[a:buffer] = l:new_tick
let l:notified = 1
endif
@@ -540,25 +493,24 @@ endfunction
" Given some LSP details that must contain at least `connection_id` and
" `project_root` keys,
-function! ale#lsp#WaitForCapability(conn_id, project_root, capability, callback) abort
- let l:conn = s:FindConnection('id', a:conn_id)
- let l:project = ale#lsp#GetProject(l:conn, a:project_root)
+function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort
+ let l:conn = get(s:connections, a:conn_id, {})
- if empty(l:project)
- return 0
+ if empty(l:conn)
+ return
endif
- if type(get(l:conn.capabilities, a:capability, v:null)) isnot type(0)
+ if type(get(l:conn.capabilities, a:capability, v:null)) isnot v:t_number
throw 'Invalid capability ' . a:capability
endif
- if l:project.initialized
- if l:conn.is_tsserver || l:conn.capabilities[a:capability]
+ if l:conn.initialized
+ if l:conn.capabilities[a:capability]
" The project has been initialized, so call the callback now.
- call call(a:callback, [a:conn_id, a:project_root])
+ call call(a:callback, [a:conn_id])
endif
else
" Call the callback later, once we have the information we need.
- call add(l:project.capabilities_queue, [a:capability, a:callback])
+ call add(l:conn.capabilities_queue, [a:capability, a:callback])
endif
endfunction
diff --git a/autoload/ale/lsp/message.vim b/autoload/ale/lsp/message.vim
index 9e05156d..9fffb83a 100644
--- a/autoload/ale/lsp/message.vim
+++ b/autoload/ale/lsp/message.vim
@@ -130,6 +130,12 @@ function! ale#lsp#message#References(buffer, line, column) abort
\}]
endfunction
+function! ale#lsp#message#Symbol(query) abort
+ return [0, 'workspace/symbol', {
+ \ 'query': a:query,
+ \}]
+endfunction
+
function! ale#lsp#message#Hover(buffer, line, column) abort
return [0, 'textDocument/hover', {
\ 'textDocument': {
@@ -138,3 +144,9 @@ function! ale#lsp#message#Hover(buffer, line, column) abort
\ 'position': {'line': a:line - 1, 'character': a:column},
\}]
endfunction
+
+function! ale#lsp#message#DidChangeConfiguration(buffer, config) abort
+ return [0, 'workspace/didChangeConfiguration', {
+ \ 'settings': a:config,
+ \}]
+endfunction
diff --git a/autoload/ale/lsp/reset.vim b/autoload/ale/lsp/reset.vim
index c7c97a47..2fc7f0a2 100644
--- a/autoload/ale/lsp/reset.vim
+++ b/autoload/ale/lsp/reset.vim
@@ -17,7 +17,7 @@ function! ale#lsp#reset#StopAllLSPs() abort
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp)
- call ale#engine#HandleLoclist(l:linter.name, l:buffer, [])
+ call ale#engine#HandleLoclist(l:linter.name, l:buffer, [], 0)
endif
endfor
endfor
diff --git a/autoload/ale/lsp/response.vim b/autoload/ale/lsp/response.vim
index a0e1984d..08b36808 100644
--- a/autoload/ale/lsp/response.vim
+++ b/autoload/ale/lsp/response.vim
@@ -47,7 +47,23 @@ function! ale#lsp#response#ReadDiagnostics(response) abort
endif
if has_key(l:diagnostic, 'code')
- let l:loclist_item.nr = l:diagnostic.code
+ if type(l:diagnostic.code) == v:t_string
+ let l:loclist_item.code = l:diagnostic.code
+ elseif type(l:diagnostic.code) == v:t_number && l:diagnostic.code != -1
+ let l:loclist_item.code = string(l:diagnostic.code)
+ let l:loclist_item.nr = l:diagnostic.code
+ endif
+ endif
+
+ if has_key(l:diagnostic, 'relatedInformation')
+ let l:related = deepcopy(l:diagnostic.relatedInformation)
+ call map(l:related, {key, val ->
+ \ ale#path#FromURI(val.location.uri) .
+ \ ':' . (val.location.range.start.line + 1) .
+ \ ':' . (val.location.range.start.character + 1) .
+ \ ":\n\t" . val.message
+ \ })
+ let l:loclist_item.detail = l:diagnostic.message . "\n" . join(l:related, "\n")
endif
if has_key(l:diagnostic, 'source')
@@ -74,7 +90,12 @@ function! ale#lsp#response#ReadTSServerDiagnostics(response) abort
\}
if has_key(l:diagnostic, 'code')
- let l:loclist_item.nr = l:diagnostic.code
+ if type(l:diagnostic.code) == v:t_string
+ let l:loclist_item.code = l:diagnostic.code
+ elseif type(l:diagnostic.code) == v:t_number && l:diagnostic.code != -1
+ let l:loclist_item.code = string(l:diagnostic.code)
+ let l:loclist_item.nr = l:diagnostic.code
+ endif
endif
if get(l:diagnostic, 'category') is# 'warning'
@@ -92,7 +113,7 @@ function! ale#lsp#response#ReadTSServerDiagnostics(response) abort
endfunction
function! ale#lsp#response#GetErrorMessage(response) abort
- if type(get(a:response, 'error', 0)) isnot type({})
+ if type(get(a:response, 'error', 0)) isnot v:t_dict
return ''
endif
@@ -112,12 +133,12 @@ function! ale#lsp#response#GetErrorMessage(response) abort
" Include the traceback or error data as details, if present.
let l:error_data = get(a:response.error, 'data', {})
- if type(l:error_data) is type('')
+ if type(l:error_data) is v:t_string
let l:message .= "\n" . l:error_data
- else
+ elseif type(l:error_data) is v:t_dict
let l:traceback = get(l:error_data, 'traceback', [])
- if type(l:traceback) is type([]) && !empty(l:traceback)
+ if type(l:traceback) is v:t_list && !empty(l:traceback)
let l:message .= "\n" . join(l:traceback, "\n")
endif
endif
diff --git a/autoload/ale/lsp_linter.vim b/autoload/ale/lsp_linter.vim
index 87aee759..42d67398 100644
--- a/autoload/ale/lsp_linter.vim
+++ b/autoload/ale/lsp_linter.vim
@@ -38,7 +38,7 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
- call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
+ call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
@@ -55,20 +55,33 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
endif
let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response)
+ let l:no_changes = 0
" tsserver sends syntax and semantic errors in separate messages, so we
" have to collect the messages separately for each buffer and join them
" back together again.
if a:error_type is# 'syntax'
+ if len(l:thislist) is 0 && len(get(l:info, 'syntax_loclist', [])) is 0
+ let l:no_changes = 1
+ endif
+
let l:info.syntax_loclist = l:thislist
else
+ if len(l:thislist) is 0 && len(get(l:info, 'semantic_loclist', [])) is 0
+ let l:no_changes = 1
+ endif
+
let l:info.semantic_loclist = l:thislist
endif
+ if l:no_changes
+ return
+ endif
+
let l:loclist = get(l:info, 'semantic_loclist', [])
\ + get(l:info, 'syntax_loclist', [])
- call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist)
+ call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0)
endfunction
function! s:HandleLSPErrorMessage(linter_name, response) abort
@@ -99,9 +112,10 @@ endfunction
function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
let l:method = get(a:response, 'method', '')
- let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
+ let l:linter_name = get(s:lsp_linter_map, a:conn_id, '')
+
call s:HandleLSPErrorMessage(l:linter_name, a:response)
elseif l:method is# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:conn_id, a:response)
@@ -126,6 +140,18 @@ function! ale#lsp_linter#GetOptions(buffer, linter) abort
return l:initialization_options
endfunction
+function! ale#lsp_linter#GetConfig(buffer, linter) abort
+ let l:config = {}
+
+ if has_key(a:linter, 'lsp_config_callback')
+ let l:config = ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer)
+ elseif has_key(a:linter, 'lsp_config')
+ let l:config = a:linter.lsp_config
+ endif
+
+ return l:config
+endfunction
+
" Given a buffer, an LSP linter, start up an LSP linter and get ready to
" receive messages for the document.
function! ale#lsp_linter#StartLSP(buffer, linter) abort
@@ -143,7 +169,8 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
if a:linter.lsp is# 'socket'
let l:address = ale#linter#GetAddress(a:buffer, a:linter)
- let l:conn_id = ale#lsp#ConnectToAddress(l:address, l:init_options)
+ let l:conn_id = ale#lsp#Register(l:address, l:root, l:init_options)
+ let l:ready = ale#lsp#ConnectToAddress(l:conn_id, l:address)
else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
@@ -151,18 +178,16 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
return {}
endif
+ let l:conn_id = ale#lsp#Register(l:executable, l:root, l:init_options)
+
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
" Format the command, so %e can be formatted into it.
let l:command = ale#command#FormatCommand(a:buffer, l:executable, l:command, 0)[1]
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
- let l:conn_id = ale#lsp#StartProgram(
- \ l:executable,
- \ l:command,
- \ l:init_options,
- \)
+ let l:ready = ale#lsp#StartProgram(l:conn_id, l:executable, l:command)
endif
- if empty(l:conn_id)
+ if !l:ready
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'failed', l:conn_id, l:command)
endif
@@ -175,9 +200,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif
- " Register the project now the connection is ready.
- call ale#lsp#RegisterProject(l:conn_id, l:root)
-
+ let l:config = ale#lsp_linter#GetConfig(a:buffer, a:linter)
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(a:buffer)
let l:details = {
@@ -188,7 +211,9 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
\ 'language_id': l:language_id,
\}
- if ale#lsp#OpenDocument(l:conn_id, l:root, a:buffer, l:language_id)
+ call ale#lsp#UpdateConfig(l:conn_id, a:buffer, l:config)
+
+ if ale#lsp#OpenDocument(l:conn_id, a:buffer, l:language_id)
if g:ale_history_enabled && !empty(l:command)
call ale#history#Add(a:buffer, 'started', l:conn_id, l:command)
endif
@@ -196,7 +221,7 @@ function! ale#lsp_linter#StartLSP(buffer, linter) abort
" The change message needs to be sent for tsserver before doing anything.
if a:linter.lsp is# 'tsserver'
- call ale#lsp#NotifyForChanges(l:conn_id, l:root, a:buffer)
+ call ale#lsp#NotifyForChanges(l:conn_id, a:buffer)
endif
return l:details
@@ -211,7 +236,6 @@ function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
endif
let l:id = l:lsp_details.connection_id
- let l:root = l:lsp_details.project_root
" Register a callback now for handling errors now.
let l:Callback = function('ale#lsp_linter#HandleLSPResponse')
@@ -222,16 +246,16 @@ function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort
if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Geterr(a:buffer)
- let l:notified = ale#lsp#Send(l:id, l:message, l:root) != 0
+ let l:notified = ale#lsp#Send(l:id, l:message) != 0
else
- let l:notified = ale#lsp#NotifyForChanges(l:id, l:root, a:buffer)
+ let l:notified = ale#lsp#NotifyForChanges(l:id, a:buffer)
endif
" If this was a file save event, also notify the server of that.
if a:linter.lsp isnot# 'tsserver'
\&& getbufvar(a:buffer, 'ale_save_event_fired', 0)
let l:save_message = ale#lsp#message#DidSave(a:buffer)
- let l:notified = ale#lsp#Send(l:id, l:save_message, l:root) != 0
+ let l:notified = ale#lsp#Send(l:id, l:save_message) != 0
endif
if l:notified
diff --git a/autoload/ale/node.vim b/autoload/ale/node.vim
index f75280b7..5c579c75 100644
--- a/autoload/ale/node.vim
+++ b/autoload/ale/node.vim
@@ -23,6 +23,11 @@ function! ale#node#FindExecutable(buffer, base_var_name, path_list) abort
return ale#Var(a:buffer, a:base_var_name . '_executable')
endfunction
+" As above, but curry the arguments so only the buffer number is required.
+function! ale#node#FindExecutableFunc(base_var_name, path_list) abort
+ return {buf -> ale#node#FindExecutable(buf, a:base_var_name, a:path_list)}
+endfunction
+
" Create a executable string which executes a Node.js script command with a
" Node.js executable if needed.
"
diff --git a/autoload/ale/other_source.vim b/autoload/ale/other_source.vim
new file mode 100644
index 00000000..1a092034
--- /dev/null
+++ b/autoload/ale/other_source.vim
@@ -0,0 +1,21 @@
+" Tell ALE that another source has started checking a buffer.
+function! ale#other_source#StartChecking(buffer, linter_name) abort
+ call ale#engine#InitBufferInfo(a:buffer)
+ let l:list = g:ale_buffer_info[a:buffer].active_other_sources_list
+
+ call add(l:list, a:linter_name)
+ call uniq(sort(l:list))
+endfunction
+
+" Show some results, and stop checking a buffer.
+" To clear results or cancel checking a buffer, an empty List can be given.
+function! ale#other_source#ShowResults(buffer, linter_name, loclist) abort
+ call ale#engine#InitBufferInfo(a:buffer)
+ let l:info = g:ale_buffer_info[a:buffer]
+
+ " Remove this linter name from the active list.
+ let l:list = l:info.active_other_sources_list
+ call filter(l:list, 'v:val isnot# a:linter_name')
+
+ call ale#engine#HandleLoclist(a:linter_name, a:buffer, a:loclist, 1)
+endfunction
diff --git a/autoload/ale/path.vim b/autoload/ale/path.vim
index 45da3709..89b119f4 100644
--- a/autoload/ale/path.vim
+++ b/autoload/ale/path.vim
@@ -65,7 +65,11 @@ endfunction
" Output 'cd <directory> && '
" This function can be used changing the directory for a linter command.
function! ale#path#CdString(directory) abort
- return 'cd ' . ale#Escape(a:directory) . ' && '
+ if has('win32')
+ return 'cd /d ' . ale#Escape(a:directory) . ' && '
+ else
+ return 'cd ' . ale#Escape(a:directory) . ' && '
+ endif
endfunction
" Output 'cd <buffer_filename_directory> && '
@@ -105,6 +109,21 @@ function! ale#path#GetAbsPath(base_directory, filename) abort
return ale#path#Simplify(a:base_directory . l:sep . a:filename)
endfunction
+" Given a path, return the directory name for that path, with no trailing
+" slashes. If the argument is empty(), return an empty string.
+function! ale#path#Dirname(path) abort
+ if empty(a:path)
+ return ''
+ endif
+
+ " For /foo/bar/ we need :h:h to get /foo
+ if a:path[-1:] is# '/'
+ return fnamemodify(a:path, ':h:h')
+ endif
+
+ return fnamemodify(a:path, ':h')
+endfunction
+
" Given a buffer number and a relative or absolute path, return 1 if the
" two paths represent the same file on disk.
function! ale#path#IsBufferPath(buffer, complex_filename) abort
diff --git a/autoload/ale/preview.vim b/autoload/ale/preview.vim
index aefbb691..1f50e0ad 100644
--- a/autoload/ale/preview.vim
+++ b/autoload/ale/preview.vim
@@ -15,13 +15,13 @@ function! ale#preview#Show(lines, ...) abort
setlocal modifiable
setlocal noreadonly
setlocal nobuflisted
- let &l:filetype = get(l:options, 'filetype', 'ale-preview')
setlocal buftype=nofile
setlocal bufhidden=wipe
:%d
call setline(1, a:lines)
setlocal nomodifiable
setlocal readonly
+ let &l:filetype = get(l:options, 'filetype', 'ale-preview')
if get(l:options, 'stay_here')
wincmd p
@@ -46,11 +46,14 @@ function! ale#preview#ShowSelection(item_list) abort
" Create lines to display to users.
for l:item in a:item_list
+ let l:match = get(l:item, 'match', '')
+
call add(
\ l:lines,
\ l:item.filename
\ . ':' . l:item.line
- \ . ':' . l:item.column,
+ \ . ':' . l:item.column
+ \ . (!empty(l:match) ? ' ' . l:match : ''),
\)
endfor
diff --git a/autoload/ale/python.vim b/autoload/ale/python.vim
index bc1cc980..8d6bf1f0 100644
--- a/autoload/ale/python.vim
+++ b/autoload/ale/python.vim
@@ -1,6 +1,8 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Functions for integrating with Python linters.
+call ale#Set('python_auto_pipenv', '0')
+
let s:sep = has('win32') ? '\' : '/'
" bin is used for Unix virtualenv directories, and Scripts is for Windows.
let s:bin_dir = has('unix') ? 'bin' : 'Scripts'
@@ -24,6 +26,7 @@ function! ale#python#FindProjectRootIni(buffer) abort
\|| filereadable(l:path . '/mypy.ini')
\|| filereadable(l:path . '/pycodestyle.cfg')
\|| filereadable(l:path . '/flake8.cfg')
+ \|| filereadable(l:path . '/.flake8rc')
\|| filereadable(l:path . '/Pipfile')
\|| filereadable(l:path . '/Pipfile.lock')
return l:path
@@ -106,3 +109,8 @@ function! ale#python#FindExecutable(buffer, base_var_name, path_list) abort
return ale#Var(a:buffer, a:base_var_name . '_executable')
endfunction
+
+" Detects whether a pipenv environment is present.
+function! ale#python#PipenvPresent(buffer) abort
+ return findfile('Pipfile.lock', expand('#' . a:buffer . ':p:h') . ';') isnot# ''
+endfunction
diff --git a/autoload/ale/references.vim b/autoload/ale/references.vim
index 3a710b7b..d00a1fa9 100644
--- a/autoload/ale/references.vim
+++ b/autoload/ale/references.vim
@@ -64,6 +64,35 @@ function! ale#references#HandleLSPResponse(conn_id, response) abort
endif
endfunction
+function! s:OnReady(linter, lsp_details, line, column, ...) abort
+ let l:buffer = a:lsp_details.buffer
+ let l:id = a:lsp_details.connection_id
+
+ let l:Callback = a:linter.lsp is# 'tsserver'
+ \ ? function('ale#references#HandleTSServerResponse')
+ \ : function('ale#references#HandleLSPResponse')
+
+ call ale#lsp#RegisterCallback(l:id, l:Callback)
+
+ if a:linter.lsp is# 'tsserver'
+ let l:message = ale#lsp#tsserver_message#References(
+ \ l:buffer,
+ \ a:line,
+ \ a:column
+ \)
+ else
+ " Send a message saying the buffer has changed first, or the
+ " references position probably won't make sense.
+ call ale#lsp#NotifyForChanges(l:id, l:buffer)
+
+ let l:message = ale#lsp#message#References(l:buffer, a:line, a:column)
+ endif
+
+ let l:request_id = ale#lsp#Send(l:id, l:message)
+
+ let s:references_map[l:request_id] = {}
+endfunction
+
function! s:FindReferences(linter) abort
let l:buffer = bufnr('')
let [l:line, l:column] = getcurpos()[1:2]
@@ -79,35 +108,10 @@ function! s:FindReferences(linter) abort
endif
let l:id = l:lsp_details.connection_id
- let l:root = l:lsp_details.project_root
-
- function! OnReady(...) abort closure
- let l:Callback = a:linter.lsp is# 'tsserver'
- \ ? function('ale#references#HandleTSServerResponse')
- \ : function('ale#references#HandleLSPResponse')
-
- call ale#lsp#RegisterCallback(l:id, l:Callback)
-
- if a:linter.lsp is# 'tsserver'
- let l:message = ale#lsp#tsserver_message#References(
- \ l:buffer,
- \ l:line,
- \ l:column
- \)
- else
- " Send a message saying the buffer has changed first, or the
- " references position probably won't make sense.
- call ale#lsp#NotifyForChanges(l:id, l:root, l:buffer)
-
- let l:message = ale#lsp#message#References(l:buffer, l:line, l:column)
- endif
-
- let l:request_id = ale#lsp#Send(l:id, l:message, l:lsp_details.project_root)
-
- let s:references_map[l:request_id] = {}
- endfunction
- call ale#lsp#WaitForCapability(l:id, l:root, 'references', function('OnReady'))
+ call ale#lsp#WaitForCapability(l:id, 'references', function('s:OnReady', [
+ \ a:linter, l:lsp_details, l:line, l:column
+ \]))
endfunction
function! ale#references#Find() abort
diff --git a/autoload/ale/ruby.vim b/autoload/ale/ruby.vim
index b981ded6..5f0aa50d 100644
--- a/autoload/ale/ruby.vim
+++ b/autoload/ale/ruby.vim
@@ -20,3 +20,25 @@ function! ale#ruby#FindRailsRoot(buffer) abort
return ''
endfunction
+
+" Find the nearest dir containing a potential ruby project.
+function! ale#ruby#FindProjectRoot(buffer) abort
+ let l:dir = ale#ruby#FindRailsRoot(a:buffer)
+
+ if isdirectory(l:dir)
+ return l:dir
+ endif
+
+ for l:name in ['.solargraph.yml', 'Rakefile', 'Gemfile']
+ let l:dir = fnamemodify(
+ \ ale#path#FindNearestFile(a:buffer, l:name),
+ \ ':h'
+ \)
+
+ if l:dir isnot# '.' && isdirectory(l:dir)
+ return l:dir
+ endif
+ endfor
+
+ return ''
+endfunction
diff --git a/autoload/ale/sign.vim b/autoload/ale/sign.vim
index a0dde359..af863682 100644
--- a/autoload/ale/sign.vim
+++ b/autoload/ale/sign.vim
@@ -211,7 +211,7 @@ function! s:BuildSignMap(buffer, current_sign_list, grouped_items) abort
if l:max_signs is 0
let l:selected_grouped_items = []
- elseif type(l:max_signs) is type(0) && l:max_signs > 0
+ elseif type(l:max_signs) is v:t_number && l:max_signs > 0
let l:selected_grouped_items = a:grouped_items[:l:max_signs - 1]
else
let l:selected_grouped_items = a:grouped_items
diff --git a/autoload/ale/socket.vim b/autoload/ale/socket.vim
index 0ca4dea6..7e069fb5 100644
--- a/autoload/ale/socket.vim
+++ b/autoload/ale/socket.vim
@@ -55,11 +55,18 @@ function! ale#socket#Open(address, options) abort
if !has('nvim')
" Vim
- let l:channel_info.channel = ch_open(a:address, {
+ let l:channel_options = {
\ 'mode': l:mode,
\ 'waittime': 0,
\ 'callback': function('s:VimOutputCallback'),
- \})
+ \}
+
+ " Use non-blocking writes for Vim versions that support the option.
+ if has('patch-8.1.350')
+ let l:channel_options.noblock = 1
+ endif
+
+ let l:channel_info.channel = ch_open(a:address, l:channel_options)
let l:vim_info = ch_info(l:channel_info.channel)
let l:channel_id = !empty(l:vim_info) ? l:vim_info.id : -1
elseif exists('*chansend') && exists('*sockconnect')
@@ -104,6 +111,7 @@ function! ale#socket#IsOpen(channel_id) abort
endif
let l:channel = s:channel_map[a:channel_id].channel
+
return ch_status(l:channel) is# 'open'
endfunction
diff --git a/autoload/ale/symbol.vim b/autoload/ale/symbol.vim
new file mode 100644
index 00000000..5180cb86
--- /dev/null
+++ b/autoload/ale/symbol.vim
@@ -0,0 +1,109 @@
+let s:symbol_map = {}
+
+" Used to get the symbol map in tests.
+function! ale#symbol#GetMap() abort
+ return deepcopy(s:symbol_map)
+endfunction
+
+" Used to set the symbol map in tests.
+function! ale#symbol#SetMap(map) abort
+ let s:symbol_map = a:map
+endfunction
+
+function! ale#symbol#ClearLSPData() abort
+ let s:symbol_map = {}
+endfunction
+
+function! ale#symbol#HandleLSPResponse(conn_id, response) abort
+ if has_key(a:response, 'id')
+ \&& has_key(s:symbol_map, a:response.id)
+ let l:options = remove(s:symbol_map, a:response.id)
+
+ let l:result = get(a:response, 'result', v:null)
+ let l:item_list = []
+
+ if type(l:result) is v:t_list
+ " Each item looks like this:
+ " {
+ " 'name': 'foo',
+ " 'kind': 123,
+ " 'deprecated': v:false,
+ " 'location': {
+ " 'uri': 'file://...',
+ " 'range': {
+ " 'start': {'line': 0, 'character': 0},
+ " 'end': {'line': 0, 'character': 0},
+ " },
+ " },
+ " 'containerName': 'SomeContainer',
+ " }
+ for l:response_item in l:result
+ let l:location = l:response_item.location
+
+ call add(l:item_list, {
+ \ 'filename': ale#path#FromURI(l:location.uri),
+ \ 'line': l:location.range.start.line + 1,
+ \ 'column': l:location.range.start.character + 1,
+ \ 'match': l:response_item.name,
+ \})
+ endfor
+ endif
+
+ if empty(l:item_list)
+ call ale#util#Execute('echom ''No symbols found.''')
+ else
+ call ale#preview#ShowSelection(l:item_list)
+ endif
+ endif
+endfunction
+
+function! s:OnReady(linter, lsp_details, query, ...) abort
+ let l:buffer = a:lsp_details.buffer
+
+ " If we already made a request, stop here.
+ if getbufvar(l:buffer, 'ale_symbol_request_made', 0)
+ return
+ endif
+
+ let l:id = a:lsp_details.connection_id
+
+ let l:Callback = function('ale#symbol#HandleLSPResponse')
+ call ale#lsp#RegisterCallback(l:id, l:Callback)
+
+ let l:message = ale#lsp#message#Symbol(a:query)
+ let l:request_id = ale#lsp#Send(l:id, l:message)
+
+ call setbufvar(l:buffer, 'ale_symbol_request_made', 1)
+ let s:symbol_map[l:request_id] = {
+ \ 'buffer': l:buffer,
+ \}
+endfunction
+
+function! s:Search(linter, buffer, query) abort
+ let l:lsp_details = ale#lsp_linter#StartLSP(a:buffer, a:linter)
+
+ if !empty(l:lsp_details)
+ call ale#lsp#WaitForCapability(
+ \ l:lsp_details.connection_id,
+ \ 'symbol_search',
+ \ function('s:OnReady', [a:linter, l:lsp_details, a:query]),
+ \)
+ endif
+endfunction
+
+function! ale#symbol#Search(query) abort
+ if type(a:query) isnot v:t_string || empty(a:query)
+ throw 'A non-empty string must be provided!'
+ endif
+
+ let l:buffer = bufnr('')
+
+ " Set a flag so we only make one request.
+ call setbufvar(l:buffer, 'ale_symbol_request_made', 0)
+
+ for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
+ if !empty(l:linter.lsp) && l:linter.lsp isnot# 'tsserver'
+ call s:Search(l:linter, l:buffer, a:query)
+ endif
+ endfor
+endfunction
diff --git a/autoload/ale/toggle.vim b/autoload/ale/toggle.vim
index da108782..8e642b3f 100644
--- a/autoload/ale/toggle.vim
+++ b/autoload/ale/toggle.vim
@@ -15,21 +15,6 @@ function! s:DisablePostamble() abort
endif
endfunction
-function! s:CleanupEveryBuffer() abort
- for l:key in keys(g:ale_buffer_info)
- " The key could be a filename or a buffer number, so try and
- " convert it to a number. We need a number for the other
- " functions.
- let l:buffer = str2nr(l:key)
-
- if l:buffer > 0
- " Stop all jobs and clear the results for everything, and delete
- " all of the data we stored for the buffer.
- call ale#engine#Cleanup(l:buffer)
- endif
- endfor
-endfunction
-
function! ale#toggle#Toggle() abort
let g:ale_enabled = !get(g:, 'ale_enabled')
@@ -40,7 +25,7 @@ function! ale#toggle#Toggle() abort
call ale#balloon#Enable()
endif
else
- call s:CleanupEveryBuffer()
+ call ale#engine#CleanupEveryBuffer()
call s:DisablePostamble()
if exists('*ale#balloon#Disable')
@@ -64,7 +49,7 @@ function! ale#toggle#Disable() abort
endfunction
function! ale#toggle#Reset() abort
- call s:CleanupEveryBuffer()
+ call ale#engine#CleanupEveryBuffer()
call ale#highlight#UpdateHighlights()
endfunction
@@ -76,6 +61,7 @@ function! ale#toggle#ToggleBuffer(buffer) abort
" linting locally when linting is disabled globally
if l:enabled && !g:ale_enabled
execute 'echom ''ALE cannot be enabled locally when disabled globally'''
+
return
endif
diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim
index fb6dc085..bb478957 100644
--- a/autoload/ale/util.vim
+++ b/autoload/ale/util.vim
@@ -54,6 +54,7 @@ endif
function! ale#util#JoinNeovimOutput(job, last_line, data, mode, callback) abort
if a:mode is# 'raw'
call a:callback(a:job, join(a:data, "\n"))
+
return ''
endif
@@ -79,7 +80,7 @@ function! ale#util#GetLineCount(buffer) abort
endfunction
function! ale#util#GetFunction(string_or_ref) abort
- if type(a:string_or_ref) == type('')
+ if type(a:string_or_ref) is v:t_string
return function(a:string_or_ref)
endif
@@ -88,12 +89,12 @@ endfunction
function! ale#util#Open(filename, line, column, options) abort
if get(a:options, 'open_in_tab', 0)
- call ale#util#Execute('tabedit ' . fnameescape(a:filename))
- else
+ call ale#util#Execute('tabedit +' . a:line . ' ' . fnameescape(a:filename))
+ elseif bufnr(a:filename) isnot bufnr('')
" Open another file only if we need to.
- if bufnr(a:filename) isnot bufnr('')
- call ale#util#Execute('edit ' . fnameescape(a:filename))
- endif
+ call ale#util#Execute('edit +' . a:line . ' ' . fnameescape(a:filename))
+ else
+ normal! m`
endif
call cursor(a:line, a:column)
@@ -268,7 +269,7 @@ endfunction
" See :help sandbox
function! ale#util#InSandbox() abort
try
- let &equalprg=&equalprg
+ let &l:equalprg=&l:equalprg
catch /E48/
" E48 is the sandbox error.
return 1
@@ -303,8 +304,8 @@ endfunction
" Only the first pattern which matches a line will be returned.
function! ale#util#GetMatches(lines, patterns) abort
let l:matches = []
- let l:lines = type(a:lines) == type([]) ? a:lines : [a:lines]
- let l:patterns = type(a:patterns) == type([]) ? a:patterns : [a:patterns]
+ let l:lines = type(a:lines) is v:t_list ? a:lines : [a:lines]
+ let l:patterns = type(a:patterns) is v:t_list ? a:patterns : [a:patterns]
for l:line in l:lines
for l:pattern in l:patterns
@@ -382,7 +383,7 @@ function! ale#util#FuzzyJSONDecode(data, default) abort
return a:default
endif
- let l:str = type(a:data) == type('') ? a:data : join(a:data, '')
+ let l:str = type(a:data) is v:t_string ? a:data : join(a:data, '')
try
let l:result = json_decode(l:str)
@@ -404,7 +405,7 @@ endfunction
" the buffer.
function! ale#util#Writefile(buffer, lines, filename) abort
let l:corrected_lines = getbufvar(a:buffer, '&fileformat') is# 'dos'
- \ ? map(copy(a:lines), 'v:val . "\r"')
+ \ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : a:lines
call writefile(l:corrected_lines, a:filename) " no-custom-checks
@@ -451,3 +452,14 @@ function! ale#util#Col(str, chr) abort
return strlen(join(split(a:str, '\zs')[0:a:chr - 2], '')) + 1
endfunction
+
+function! ale#util#FindItemAtCursor(buffer) abort
+ let l:info = get(g:ale_buffer_info, a:buffer, {})
+ let l:loclist = get(l:info, 'loclist', [])
+ let l:pos = getcurpos()
+ let l:index = ale#util#BinarySearch(l:loclist, a:buffer, l:pos[1], l:pos[2])
+ let l:loc = l:index >= 0 ? l:loclist[l:index] : {}
+
+ return [l:info, l:loc]
+endfunction
+
diff --git a/autoload/ale/virtualtext.vim b/autoload/ale/virtualtext.vim
new file mode 100644
index 00000000..c4ce37dd
--- /dev/null
+++ b/autoload/ale/virtualtext.vim
@@ -0,0 +1,136 @@
+scriptencoding utf-8
+" Author: w0rp <devw0rp@gmail.com>
+" Author: Luan Santos <cfcluan@gmail.com>
+" Description: Shows lint message for the current line as virtualtext, if any
+
+" Controls the milliseconds delay before showing a message.
+let g:ale_virtualtext_delay = get(g:, 'ale_virtualtext_delay', 10)
+let s:cursor_timer = -1
+let s:last_pos = [0, 0, 0]
+
+if has('nvim-0.3.2')
+ let s:ns_id = nvim_create_namespace('ale')
+endif
+
+if !hlexists('ALEVirtualTextError')
+ highlight link ALEVirtualTextError ALEError
+endif
+
+if !hlexists('ALEVirtualTextStyleError')
+ highlight link ALEVirtualTextStyleError ALEVirtualTextError
+endif
+
+if !hlexists('ALEVirtualTextWarning')
+ highlight link ALEVirtualTextWarning ALEWarning
+endif
+
+if !hlexists('ALEVirtualTextStyleWarning')
+ highlight link ALEVirtualTextStyleWarning ALEVirtualTextWarning
+endif
+
+if !hlexists('ALEVirtualTextInfo')
+ highlight link ALEVirtualTextInfo ALEVirtualTextWarning
+endif
+
+function! ale#virtualtext#Clear() abort
+ if !has('nvim-0.3.2')
+ return
+ endif
+
+ let l:buffer = bufnr('')
+
+ call nvim_buf_clear_highlight(l:buffer, s:ns_id, 0, -1)
+endfunction
+
+function! ale#virtualtext#ShowMessage(message, hl_group) abort
+ if !has('nvim-0.3.2')
+ return
+ endif
+
+ let l:cursor_position = getcurpos()
+ let l:line = line('.')
+ let l:buffer = bufnr('')
+ let l:prefix = get(g:, 'ale_virtualtext_prefix', '> ')
+
+ call nvim_buf_set_virtual_text(l:buffer, s:ns_id, l:line-1, [[l:prefix.a:message, a:hl_group]], {})
+endfunction
+
+function! s:StopCursorTimer() abort
+ if s:cursor_timer != -1
+ call timer_stop(s:cursor_timer)
+ let s:cursor_timer = -1
+ endif
+endfunction
+
+function! ale#virtualtext#ShowCursorWarning(...) abort
+ if !g:ale_virtualtext_cursor
+ return
+ endif
+
+ let l:buffer = bufnr('')
+
+ if mode(1) isnot# 'n'
+ return
+ endif
+
+ if ale#ShouldDoNothing(l:buffer)
+ return
+ endif
+
+ let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer)
+
+ call ale#virtualtext#Clear()
+
+ if !empty(l:loc)
+ let l:msg = get(l:loc, 'detail', l:loc.text)
+ let l:hl_group = 'ALEVirtualTextInfo'
+ let l:type = get(l:loc, 'type', 'E')
+
+ if l:type is# 'E'
+ if get(l:loc, 'sub_type', '') is# 'style'
+ let l:hl_group = 'ALEVirtualTextStyleError'
+ else
+ let l:hl_group = 'ALEVirtualTextError'
+ endif
+ elseif l:type is# 'W'
+ if get(l:loc, 'sub_type', '') is# 'style'
+ let l:hl_group = 'ALEVirtualTextStyleWarning'
+ else
+ let l:hl_group = 'ALEVirtualTextWarning'
+ endif
+ endif
+
+ call ale#virtualtext#ShowMessage(l:msg, l:hl_group)
+ endif
+endfunction
+
+function! ale#virtualtext#ShowCursorWarningWithDelay() abort
+ let l:buffer = bufnr('')
+
+ if !g:ale_virtualtext_cursor
+ return
+ endif
+
+ if mode(1) isnot# 'n'
+ return
+ endif
+
+ call s:StopCursorTimer()
+
+ let l:pos = getcurpos()[0:2]
+
+ " Check the current buffer, line, and column number against the last
+ " recorded position. If the position has actually changed, *then*
+ " we should show something. Otherwise we can end up doing processing
+ " the show message far too frequently.
+ if l:pos != s:last_pos
+ let l:delay = ale#Var(l:buffer, 'virtualtext_delay')
+
+ let s:last_pos = l:pos
+ let s:cursor_timer = timer_start(
+ \ l:delay,
+ \ function('ale#virtualtext#ShowCursorWarning')
+ \)
+ endif
+endfunction
+
diff --git a/doc/ale-ada.txt b/doc/ale-ada.txt
new file mode 100644
index 00000000..93e3261a
--- /dev/null
+++ b/doc/ale-ada.txt
@@ -0,0 +1,25 @@
+===============================================================================
+ALE Ada Integration *ale-ada-options*
+
+
+===============================================================================
+gcc *ale-ada-gcc*
+
+g:ale_ada_gcc_executable *g:ale_ada_gcc_executable*
+ *b:ale_ada_gcc_executable*
+ Type: |String|
+ Default: `'gcc'`
+
+This variable can be changed to use a different executable for gcc.
+
+
+g:ale_ada_gcc_options *g:ale_ada_gcc_options*
+ *b:ale_ada_gcc_options*
+ Type: |String|
+ Default: `'-gnatwa -gnatq'`
+
+ This variable can be set to pass additional options to gcc.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-ansible.txt b/doc/ale-ansible.txt
new file mode 100644
index 00000000..3a4efaa5
--- /dev/null
+++ b/doc/ale-ansible.txt
@@ -0,0 +1,16 @@
+===============================================================================
+ALE Ansible Integration *ale-ansible-options*
+
+
+===============================================================================
+ansible-lint *ale-ansible-ansible-lint*
+
+g:ale_ansible_ansible_lint_executable *g:ale_ansible_ansible_lint_executable*
+ *b:ale_ansible_ansible_lint_executable*
+ Type: |String|
+ Default: `'ansible-lint'`
+
+ This variable can be changed to modify the executable used for ansible-lint.
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-c.txt b/doc/ale-c.txt
index acff722c..be0a3d77 100644
--- a/doc/ale-c.txt
+++ b/doc/ale-c.txt
@@ -25,13 +25,28 @@ g:ale_c_build_dir *g:ale_c_build_dir*
Type: |String|
Default: `''`
- A path to the directory containing the `compile_commands.json` file to use
- with c-family linters. Usually setting this option to a non-empty string
- will override the |g:ale_c_build_dir_names| option to impose a compilation
- database (it can be useful if multiple builds are in multiple build
- subdirectories in the project tree).
- This feature is also most useful for the clang tools linters, wrapped
- around LibTooling (namely clang-tidy here)
+ For programs that can read `compile_commands.json` files, this option can be
+ set to the directory containing the file for the project. ALE will try to
+ determine the location of `compile_commands.json` automatically, but if your
+ file exists in some other directory, you can set this option so ALE will
+ know where it is.
+
+ This directory will be searched instead of |g:ale_c_build_dir_names|.
+
+
+g:ale_c_parse_compile_commands *g:ale_c_parse_compile_commands*
+ *b:ale_c_parse_compile_commands*
+ Type: |Number|
+ Default: `0`
+
+ If set to `1`, ALE will parse `compile_commands.json` files to automatically
+ determine flags for C or C++ compilers. ALE will first search for the
+ nearest `compile_commands.json` file, and then look for
+ `compile_commands.json` files in the directories for
+ |g:ale_c_build_dir_names|.
+
+ If |g:ale_c_parse_makefile| or |b:ale_c_parse_makefile| is set to `1`, the
+ output of `make -n` will be preferred over `compile_commands.json` files.
g:ale_c_parse_makefile *g:ale_c_parse_makefile*
@@ -115,7 +130,7 @@ overrides |g:ale_c_build_dir_names|.
g:ale_c_clangtidy_checks *g:ale_c_clangtidy_checks*
*b:ale_c_clangtidy_checks*
Type: |List|
- Default: `['*']`
+ Default: `[]`
The checks to enable for clang-tidy with the `-checks` argument.
@@ -174,6 +189,26 @@ g:ale_c_cppcheck_options *g:ale_c_cppcheck_options*
===============================================================================
+cquery *ale-c-cquery*
+
+g:ale_c_cquery_executable *g:ale_c_cquery_executable*
+ *b:ale_c_cquery_executable*
+ Type: |String|
+ Default: `'cquery'`
+
+ This variable can be changed to use a different executable for cquery.
+
+
+g:ale_cpp_cquery_cache_directory *g:ale_c_cquery_cache_directory*
+ *b:ale_c_cquery_cache_directory*
+ Type: |String|
+ Default: `'~/.cache/cquery'`
+
+ This variable can be changed to decide which directory cquery uses for its
+cache.
+
+
+===============================================================================
flawfinder *ale-c-flawfinder*
g:ale_c_flawfinder_executable *g:ale_c_flawfinder_executable*
@@ -228,4 +263,54 @@ g:ale_c_gcc_options *g:ale_c_gcc_options*
===============================================================================
+uncrustify *ale-c-uncrustify*
+
+g:ale_c_uncrustify_executable *g:ale_c_uncrustify_executable*
+ *b:ale_c_uncrustify_executable*
+ Type: |String|
+ Default: `'uncrustify'`
+
+ This variable can be changed to use a different executable for uncrustify.
+
+
+g:ale_c_uncrustify_options *g:ale_c_uncrustify_options*
+ *b:ale_c_uncrustify_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be change to modify flags given to uncrustify.
+
+
+===============================================================================
+ccls *ale-c-ccls*
+
+g:ale_c_ccls_executable *g:ale_c_ccls_executable*
+ *b:ale_c_ccls_executable*
+ Type: |String|
+ Default: `'ccls'`
+
+ This variable can be changed to use a different executable for ccls.
+
+
+g:ale_c_ccls_init_options *g:ale_c_ccls_init_options*
+ *b:ale_c_ccls_init_options*
+ Type: |Dictionary|
+ Default: `{}`
+
+ This variable can be changed to customize ccls initialization options.
+ Example: >
+ {
+ \ 'cacheDirectory': '/tmp/ccls',
+ \ 'cacheFormat': 'binary',
+ \ 'diagnostics': {
+ \ 'onOpen': 0,
+ \ 'opChange': 1000,
+ \ },
+ \ }
+<
+ Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
+ available options and explanations.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-cpp.txt b/doc/ale-cpp.txt
index 8bd111e4..e1f64ab5 100644
--- a/doc/ale-cpp.txt
+++ b/doc/ale-cpp.txt
@@ -10,6 +10,7 @@ The following C options also apply to some C++ linters too.
* |g:ale_c_build_dir_names|
* |g:ale_c_build_dir|
* |g:ale_c_parse_makefile|
+* |g:ale_c_parse_compile_commands|
===============================================================================
@@ -32,6 +33,25 @@ g:ale_cpp_clang_options *g:ale_cpp_clang_options*
===============================================================================
+clangd *ale-cpp-clangd*
+
+g:ale_cpp_clangd_executable *g:ale_cpp_clangd_executable*
+ *b:ale_cpp_clangd_executable*
+ Type: |String|
+ Default: `'clangd'`
+
+ This variable can be changed to use a different executable for clangd.
+
+
+g:ale_cpp_clangd_options *g:ale_cpp_clangd_options*
+ *b:ale_cpp_clangd_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to modify flags given to clangd.
+
+
+===============================================================================
clangcheck *ale-cpp-clangcheck*
`clang-check` will be run only when files are saved to disk, so that
@@ -83,7 +103,7 @@ overrides |g:ale_c_build_dir_names|.
g:ale_cpp_clangtidy_checks *g:ale_cpp_clangtidy_checks*
*b:ale_cpp_clangtidy_checks*
Type: |List|
- Default: `['*']`
+ Default: `[]`
The checks to enable for clang-tidy with the `-checks` argument.
@@ -119,6 +139,37 @@ g:ale_cpp_clangtidy_options *g:ale_cpp_clangtidy_options*
===============================================================================
+clazy *ale-cpp-clazy*
+
+g:ale_cpp_clazy_executable *g:ale_cpp_clazy_executable*
+ *b:ale_cpp_clazy_executable*
+ Type: |String|
+ Default: `'clazy-standalone'`
+
+ This variable can be changed to use a different executable for clazy.
+
+
+g:ale_cpp_clazy_checks *g:ale_cpp_clazy_checks*
+ *b:ale_cpp_clazy_checks*
+ Type: |List|
+ Default: `['level1']`
+
+ The checks to enable for clazy with the `-checks` argument.
+
+ All options will be joined with commas, and escaped appropriately for
+ the shell. The `-checks` flag can be removed entirely by setting this
+ option to an empty List.
+
+
+g:ale_cpp_clazy_options *g:ale_cpp_clazy_options*
+ *b:ale_cpp_clazy_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to modify flags given to clazy.
+
+
+===============================================================================
cppcheck *ale-cpp-cppcheck*
g:ale_cpp_cppcheck_executable *g:ale_cpp_cppcheck_executable*
@@ -223,4 +274,41 @@ g:ale_cpp_gcc_options *g:ale_cpp_gcc_options*
===============================================================================
+uncrustify *ale-cpp-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
+ccls *ale-cpp-ccls*
+
+g:ale_cpp_ccls_executable *g:ale_cpp_ccls_executable*
+ *b:ale_cpp_ccls_executable*
+ Type: |String|
+ Default: `'ccls'`
+
+ This variable can be changed to use a different executable for ccls.
+
+
+g:ale_cpp_ccls_init_options *g:ale_cpp_ccls_init_options*
+ *b:ale_cpp_ccls_init_options*
+ Type: |Dictionary|
+ Default: `{}`
+
+ This variable can be changed to customize ccls initialization options.
+ Example: >
+ {
+ \ 'cacheDirectory': '/tmp/ccls',
+ \ 'cacheFormat': 'binary',
+ \ 'diagnostics': {
+ \ 'onOpen': 0,
+ \ 'opChange': 1000,
+ \ },
+ \ }
+<
+ Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
+ available options and explanations.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-cs.txt b/doc/ale-cs.txt
index f65b9f39..01e6348f 100644
--- a/doc/ale-cs.txt
+++ b/doc/ale-cs.txt
@@ -2,6 +2,10 @@
ALE C# Integration *ale-cs-options*
+In addition to the linters that are provided with ALE, C# code can be checked
+with the OmniSharp plugin. See here: https://github.com/OmniSharp/omnisharp-vim
+
+
===============================================================================
mcs *ale-cs-mcs*
@@ -99,4 +103,10 @@ g:ale_cs_mcsc_assemblies *g:ale_cs_mcsc_assemblies*
<
===============================================================================
+uncrustify *ale-cs-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-d.txt b/doc/ale-d.txt
new file mode 100644
index 00000000..55596062
--- /dev/null
+++ b/doc/ale-d.txt
@@ -0,0 +1,23 @@
+===============================================================================
+ALE D Integration *ale-d-options*
+
+
+===============================================================================
+dls *ale-d-dls*
+
+g:ale_d_dls_executable *g:ale_d_dls_executable*
+ *b:ale_d_dls_executable*
+ Type: |String|
+ Default: `dls`
+
+See |ale-integrations-local-executables|
+
+
+===============================================================================
+uncrustify *ale-d-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
+vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-development.txt b/doc/ale-development.txt
index 8a4c1d7d..1e168130 100644
--- a/doc/ale-development.txt
+++ b/doc/ale-development.txt
@@ -118,6 +118,7 @@ these are reported with ALE's `custom-linting-rules` script. See
* Use `snake_case` names for linter names, so they can be used as part of
variable names. You can define `aliases` for linters, for other names people
might try to configure linters with.
+* Use |v:t_TYPE| variables instead of `type()`, which are more readable.
Apply the following guidelines when writing Vader test files.
@@ -305,7 +306,9 @@ given the above setup are as follows.
`AssertLinterNotExecuted` - Check that linters will not be executed.
`AssertLSPLanguage language` - Check the language given to an LSP server.
`AssertLSPOptions options_dict` - Check the options given to an LSP server.
+`AssertLSPConfig config_dict` - Check the config given to an LSP server.
`AssertLSPProject project_root` - Check the root given to an LSP server.
+`AssertLSPAddress address` - Check the address to an LSP server.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-dockerfile.txt b/doc/ale-dockerfile.txt
index 805cc478..284c6a10 100644
--- a/doc/ale-dockerfile.txt
+++ b/doc/ale-dockerfile.txt
@@ -3,6 +3,29 @@ ALE Dockerfile Integration *ale-dockerfile-options*
===============================================================================
+dockerfile_lint *ale-dockerfile-dockerfile_lint*
+
+g:ale_dockerfile_dockerfile_lint_executable
+ *g:ale_dockerfile_dockerfile_lint_executable*
+ *b:ale_dockerfile_dockerfile_lint_executable*
+ Type: |String|
+ Default: `'dockerfile_lint'`
+
+ This variable can be changed to specify the executable used to run
+ dockerfile_lint.
+
+
+g:ale_dockerfile_dockerfile_lint_options
+ *g:ale_dockerfile_dockerfile_lint_options*
+ *b:ale_dockerfile_dockerfile_lint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to add additional command-line arguments to
+ the dockerfile lint invocation - like custom rule file definitions.
+
+
+===============================================================================
hadolint *ale-dockerfile-hadolint*
hadolint can be found at: https://github.com/hadolint/hadolint
diff --git a/doc/ale-elixir.txt b/doc/ale-elixir.txt
index ac0ec605..45c6de1d 100644
--- a/doc/ale-elixir.txt
+++ b/doc/ale-elixir.txt
@@ -5,6 +5,11 @@ ALE Elixir Integration *ale-elixir-options*
===============================================================================
mix *ale-elixir-mix*
+
+The `mix` linter is disabled by default, as it can bee too expensive to run.
+See `:help g:ale_linters`
+
+
g:ale_elixir_mix_options *g:ale_elixir_mix_options*
*b:ale_elixir_mix_options*
Type: |String|
@@ -41,4 +46,32 @@ See https://github.com/jeremyjh/dialyxir#with-explaining-stuff for more
information.
===============================================================================
+elixir-ls *ale-elixir-elixir-ls*
+
+Elixir Language Server (https://github.com/JakeBecker/elixir-ls)
+
+g:ale_elixir_elixir_ls_release *g:ale_elixir_elixir_ls_release*
+ *b:ale_elixir_elixir_ls_release*
+ Type: |String|
+ Default: `'elixir-ls'`
+
+ Location of the elixir-ls release directory. This directory must contain
+ the language server scripts (language_server.sh and language_server.bat).
+
+g:ale_elixir_elixir_ls_config *g:ale_elixir_elixir_ls_config*
+ *b:ale_elixir_elixir_ls_config*
+ Type: |Dictionary|
+ Default: `{}`
+
+ Dictionary containing configuration settings that will be passed to the
+ language server. For example, to disable Dialyzer: >
+ {
+ \ 'elixirLS': {
+ \ 'dialyzerEnabled': v:false,
+ \ },
+ \ }
+<
+ Consult the ElixirLS documentation for more information about settings.
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-eruby.txt b/doc/ale-eruby.txt
index a0f6f4f8..d75d3868 100644
--- a/doc/ale-eruby.txt
+++ b/doc/ale-eruby.txt
@@ -1,15 +1,37 @@
===============================================================================
ALE Eruby Integration *ale-eruby-options*
-There are three linters for `eruby` files:
+There are four linters for `eruby` files:
- `erb`
- `erubis`
- `erubi`
+- `ruumba`
`erb` is in the Ruby standard library and is mostly universal. `erubis` is the
default parser in Rails between 3.0 and 5.1. `erubi` is the default in Rails
-5.1 and later. To selectively enable a subset, see |g:ale_linters|.
+5.1 and later. `ruumba` can extract Ruby from eruby files and run rubocop on
+the result. To selectively enable a subset, see |g:ale_linters|.
+
+===============================================================================
+ruumba *ale-eruby-ruumba*
+
+g:ale_eruby_ruumba_executable *g:ale_eruby_ruumba_executable*
+ *b:ale_eruby_ruumba_executable*
+ Type: String
+ Default: `'ruumba`
+
+ Override the invoked ruumba binary. This is useful for running ruumba
+ from binstubs or a bundle.
+
+
+g:ale_eruby_ruumba_options *g:ale_ruby_ruumba_options*
+ *b:ale_ruby_ruumba_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be change to modify flags given to ruumba.
+
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-go.txt b/doc/ale-go.txt
index 60d6cb84..43289bd5 100644
--- a/doc/ale-go.txt
+++ b/doc/ale-go.txt
@@ -7,7 +7,7 @@ Integration Information
The `gometalinter` linter is disabled by default. ALE enables `gofmt`,
`golint` and `go vet` by default. It also supports `staticcheck`, `go
-build` and `gosimple`.
+build`, `gosimple`, and `golangserver`.
To enable `gometalinter`, update |g:ale_linters| as appropriate:
>
@@ -20,6 +20,15 @@ the benefit of running a number of linters, more than ALE would by default,
while ensuring it doesn't run any linters known to be slow or resource
intensive.
+g:ale_go_go_executable *g:ale_go_go_options*
+ *b:ale_go_go_options*
+
+ Type: |String|
+ Default: `'go'`
+
+ The executable that will be run for the `gobuild` and `govet` linters, and
+ the `gomod` fixer.
+
===============================================================================
gobuild *ale-go-gobuild*
@@ -45,6 +54,36 @@ g:ale_go_gofmt_options *g:ale_go_gofmt_options*
===============================================================================
+golint *ale-go-golint*
+
+g:ale_go_golint_executable *g:ale_go_golint_executable*
+ *b:ale_go_golint_executable*
+ Type: |String|
+ Default: `'golint'`
+
+ This variable can be set to change the golint executable path.
+
+
+g:ale_go_golint_options *g:ale_go_golint_options*
+ *b:ale_go_golint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the golint linter.
+
+
+===============================================================================
+govet *ale-go-govet*
+
+g:ale_go_govet_options *g:ale_go_govet_options*
+ *b:ale_go_govet_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the go vet linter.
+
+
+===============================================================================
gometalinter *ale-go-gometalinter*
`gometalinter` is a `lint_file` linter, which only lints files that are
@@ -104,4 +143,57 @@ g:ale_go_staticcheck_lint_package *g:ale_go_staticcheck_lint_package*
===============================================================================
+golangserver *ale-go-golangserver*
+
+g:ale_go_langserver_executable *g:ale_go_langserver_executable*
+ *b:ale_go_langserver_executable*
+ Type: |String|
+ Default: `'go-langserver'`
+
+ Location of the go-langserver binary file.
+
+g:ale_go_langserver_options *g:ale_go_langserver_options*
+ *b:ale_go_langserver_options*
+ Type: |String|
+ Default: `''`
+
+ Additional options passed to the go-langserver command. Note that the
+ `-gocodecompletion` option is ignored because it is handled automatically
+ by the |g:ale_completion_enabled| variable.
+
+
+===============================================================================
+golangci-lint *ale-go-golangci-lint*
+
+`golangci-lint` is a `lint_file` linter, which only lints files that are
+written to disk. This differs from the default behavior of linting the buffer.
+See: |ale-lint-file|
+
+g:ale_go_golangci_lint_executable *g:ale_go_golangci_lint_executable*
+ *b:ale_go_golangci_lint_executable*
+ Type: |String|
+ Default: `'golangci-lint'`
+
+ The executable that will be run for golangci-lint.
+
+
+g:ale_go_golangci_lint_options *g:ale_go_golangci_lint_options*
+ *b:ale_go_golangci_lint_options*
+ Type: |String|
+ Default: `'--enable-all'`
+
+ This variable can be changed to alter the command-line arguments to the
+ golangci-lint invocation.
+
+
+g:ale_go_golangci_lint_package *g:ale_go_golangci_lint_package*
+ *b:ale_go_golangci_lint_package*
+ Type: |Number|
+ Default: `0`
+
+ When set to `1`, the whole Go package will be checked instead of only the
+ current file.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-hack.txt b/doc/ale-hack.txt
new file mode 100644
index 00000000..4776b8cf
--- /dev/null
+++ b/doc/ale-hack.txt
@@ -0,0 +1,51 @@
+===============================================================================
+ALE Hack Integration *ale-hack-options*
+ *ale-integration-hack*
+
+ HHAST is disabled by default, as it executes code in the project root.
+
+ Currently linters must be enabled globally. HHAST can be enabled with:
+
+>
+ let g:ale_linters = {'hack': ['hack', 'hhast']}
+<
+
+===============================================================================
+hack *ale-hack-hack*
+
+g:ale_hack_hack_executable *g:ale_hack_hack_executable*
+ *b:ale_hack_hack_executable*
+
+ Type: |String|
+ Default: `'hh_client'`
+
+ This variable can be set to use a specific executable to interact with the
+ Hack typechecker.
+
+
+===============================================================================
+hackfmt *ale-hack-hackfmt*
+
+g:ale_hack_hackfmt_options *g:ale_hack_hackfmt_options*
+ *b:ale_hack_hackfmt_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the hackfmt fixer.
+
+
+===============================================================================
+hhast *ale-hack-hhast*
+
+g:ale_hack_hhast_executable *g:ale_hack_hhast_executable*
+ *b:ale_hack_hhast_executable*
+
+ Type: |String|
+ Default: `'vendor/bin/hhast-lint'`
+
+ This variable can be set to use a specific executable to interact with the
+ Hack typechecker.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-haskell.txt b/doc/ale-haskell.txt
index 15d3ce48..a4db683b 100644
--- a/doc/ale-haskell.txt
+++ b/doc/ale-haskell.txt
@@ -23,6 +23,16 @@ g:ale_haskell_ghc_options *g:ale_haskell_ghc_options*
This variable can be changed to modify flags given to ghc.
===============================================================================
+ghc-mod *ale-haskell-ghc-mod*
+
+g:ale_haskell_ghc_mod_executable *g:ale_haskell_ghc_mod_executable*
+ *b:ale_haskell_ghc_mod_executable*
+ Type: |String|
+ Default: `'ghc-mod'`
+
+ This variable can be changed to use a different executable for ghc-mod.
+
+===============================================================================
cabal-ghc *ale-haskell-cabal-ghc*
g:ale_haskell_cabal_ghc_options *g:ale_haskell_cabal_ghc_options*
@@ -68,6 +78,25 @@ g:ale_haskell_hfmt_executable *g:ale_haskell_hfmt_executable*
This variable can be changed to use a different executable for hfmt.
===============================================================================
+hlint *ale-haskell-hlint*
+
+g:ale_haskell_hlint_executable *g:ale_haskell_hlint_executable*
+ *b:ale_haskell_hlint_executable*
+ Type: |String|
+ Default: `'hlint'`
+
+ This variable can be changed to use a different executable for hlint.
+
+
+g:ale_haskell_hlint_options g:ale_haskell_hlint_options
+ b:ale_haskell_hlint_options
+ Type: String
+ Default: ''
+
+ This variable can be used to pass extra options to the underlying hlint
+ executable.
+
+===============================================================================
stack-build *ale-haskell-stack-build*
g:ale_haskell_stack_build_options *g:ale_haskell_stack_build_options*
@@ -78,6 +107,27 @@ g:ale_haskell_stack_build_options *g:ale_haskell_stack_build_options*
We default to using `'--fast'`. Since Stack generates binaries, your
programs will be slower unless you separately rebuild them outside of ALE.
+===============================================================================
+stylish-haskell *ale-haskell-stylish-haskell*
+
+g:ale_haskell_stylish_haskell_executable
+ *g:ale_haskell_stylish_haskell_executable*
+ *b:ale_haskell_stylish_haskell_executable*
+ Type: |String|
+ Default: `'stylish-haskell'`
+
+ This variable can be changed to use a different executable for stylish-haskell.
+
+===============================================================================
+hie *ale-haskell-hie*
+
+g:ale_haskell_hie_executable *g:ale_haskell_hie_executable*
+ *b:ale_haskell_hie_executable*
+ Type: |String|
+ Default: `'hie'`
+
+ This variable can be changed to use a different executable for the haskell
+ ide engine. i.e. `'hie-wrapper'`
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-hcl.txt b/doc/ale-hcl.txt
new file mode 100644
index 00000000..8060ac44
--- /dev/null
+++ b/doc/ale-hcl.txt
@@ -0,0 +1,11 @@
+===============================================================================
+ALE HCL Integration *ale-hcl-options*
+
+
+===============================================================================
+terraform-fmt *ale-hcl-terraform-fmt*
+
+See |ale-terraform-fmt| for information about the available options.
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-html.txt b/doc/ale-html.txt
index 98fddc58..1d30929f 100644
--- a/doc/ale-html.txt
+++ b/doc/ale-html.txt
@@ -80,6 +80,39 @@ g:ale_html_tidy_use_global *g:html_tidy_use_global*
===============================================================================
+prettier *ale-html-prettier*
+
+See |ale-javascript-prettier| for information about the available options.
+
+
+===============================================================================
+stylelint *ale-html-stylelint*
+
+g:ale_html_stylelint_executable *g:ale_html_stylelint_executable*
+ *b:ale_html_stylelint_executable*
+ Type: |String|
+ Default: `'stylelint'`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_html_stylelint_options *g:ale_html_stylelint_options*
+ *b:ale_html_stylelint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to stylelint.
+
+
+g:ale_html_stylelint_use_global *g:ale_html_stylelint_use_global*
+ *b:ale_html_stylelint_use_global*
+ Type: |String|
+ Default: `0`
+
+ See |ale-integrations-local-executables|
+
+
+===============================================================================
write-good *ale-html-write-good*
See |ale-write-good-options|
diff --git a/doc/ale-ispc.txt b/doc/ale-ispc.txt
new file mode 100644
index 00000000..bf30e8e3
--- /dev/null
+++ b/doc/ale-ispc.txt
@@ -0,0 +1,24 @@
+===============================================================================
+ALE ISPC Integration *ale-ispc-options*
+
+
+===============================================================================
+ispc *ale-ispc-ispc*
+
+g:ale_ispc_ispc_executable *g:ale_ispc_ispc_executable*
+ *b:ale_ispc_ispc_executable*
+ Type: |String|
+ Default: `'ispc'`
+
+ This variable can be changed to use a different executable for ispc.
+
+
+g:ale_ispc_ispc_options *g:ale_ispc_ispc_options*
+ *b:ale_ispc_ispc_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to modify flags given to ispc.
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-java.txt b/doc/ale-java.txt
index 4481e823..7bba12a3 100644
--- a/doc/ale-java.txt
+++ b/doc/ale-java.txt
@@ -76,4 +76,33 @@ g:ale_java_pmd_options *g:ale_java_pmd_options*
===============================================================================
+javalsp *ale-java-javalsp*
+
+To enable Java LSP linter you need to download and build the vscode-javac
+language server from https://github.com/georgewfraser/vscode-javac. Simply
+download the source code and then build the plugin using maven:
+
+ mvn package
+
+This generates a out/fat-jar.jar file that contains the language server. To
+let ALE use this language server you need to set the g:ale_java_javalsp_jar
+variable to the absolute path of this jar file.
+
+g:ale_java_javalsp_jar *g:ale_java_javalsp_jar*
+ *b:ale_java_javalsp_jar*
+
+ Type: String
+ Default: 'fat-jar.jar
+
+ Path to the location of the vscode-javac language server plugin.
+ and -d. They are added automatically.
+
+
+===============================================================================
+uncrustify *ale-java-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-json.txt b/doc/ale-json.txt
index 0ec7932d..6a0a9fae 100644
--- a/doc/ale-json.txt
+++ b/doc/ale-json.txt
@@ -73,6 +73,13 @@ g:ale_json_jq_options *g:ale_json_jq_options*
This option can be changed to pass extra options to `jq`.
+g:ale_json_jq_filters *g:ale_json_jq_filters*
+ *b:ale_json_jq_filters*
+ Type: |String|
+ Default: `'.'`
+
+ This option can be changed to pass custom filters to `jq`.
+
===============================================================================
prettier *ale-json-prettier*
diff --git a/doc/ale-julia.txt b/doc/ale-julia.txt
new file mode 100644
index 00000000..51532419
--- /dev/null
+++ b/doc/ale-julia.txt
@@ -0,0 +1,20 @@
+===============================================================================
+ALE Julia Integration *ale-julia-options*
+
+===============================================================================
+languageserver *ale-julia-languageserver*
+
+To enable Julia LSP linter you need to install the LanguageServer.jl package
+within julia.
+
+g:ale_julia_executable *g:ale_julia_executable*
+ *b:ale_julia_executable*
+
+ Type: |String|
+ Default: 'julia'
+
+ Path to the julia exetuable.
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
+
diff --git a/doc/ale-objc.txt b/doc/ale-objc.txt
index 35b9a795..0163175a 100644
--- a/doc/ale-objc.txt
+++ b/doc/ale-objc.txt
@@ -14,4 +14,60 @@ g:ale_objc_clang_options *g:ale_objc_clang_options*
===============================================================================
+clangd *ale-objc-clangd*
+
+g:ale_objc_clangd_executable *g:ale_objc_clangd_executable*
+ *b:ale_objc_clangd_executable*
+ Type: |String|
+ Default: `'clangd'`
+
+ This variable can be changed to use a different executable for clangd.
+
+
+g:ale_objc_clangd_options *g:ale_objc_clangd_options*
+ *b:ale_objc_clangd_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to modify flags given to clangd.
+
+
+===============================================================================
+uncrustify *ale-objc-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
+ccls *ale-objc-ccls*
+
+g:ale_objc_ccls_executable *g:ale_objc_ccls_executable*
+ *b:ale_objc_ccls_executable*
+ Type: |String|
+ Default: `'ccls'`
+
+ This variable can be changed to use a different executable for ccls.
+
+
+g:ale_objc_ccls_init_options *g:ale_objc_ccls_init_options*
+ *b:ale_objc_ccls_init_options*
+ Type: |Dictionary|
+ Default: `{}`
+
+ This variable can be changed to customize ccls initialization options.
+ Example: >
+ {
+ \ 'cacheDirectory': '/tmp/ccls',
+ \ 'cacheFormat': 'binary',
+ \ 'diagnostics': {
+ \ 'onOpen': 0,
+ \ 'opChange': 1000,
+ \ },
+ \ }
+<
+ Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
+ available options and explanations.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-objcpp.txt b/doc/ale-objcpp.txt
index 73d68a2e..cd65ab73 100644
--- a/doc/ale-objcpp.txt
+++ b/doc/ale-objcpp.txt
@@ -14,4 +14,29 @@ g:ale_objcpp_clang_options *g:ale_objcpp_clang_options*
===============================================================================
+clangd *ale-objcpp-clangd*
+
+g:ale_objcpp_clangd_executable *g:ale_objcpp_clangd_executable*
+ *b:ale_objcpp_clangd_executable*
+ Type: |String|
+ Default: `'clangd'`
+
+ This variable can be changed to use a different executable for clangd.
+
+
+g:ale_objcpp_clangd_options *g:ale_objcpp_clangd_options*
+ *b:ale_objcpp_clangd_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to modify flags given to clangd.
+
+
+===============================================================================
+uncrustify *ale-objcpp-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-ocaml.txt b/doc/ale-ocaml.txt
index a7ef8d29..adf17716 100644
--- a/doc/ale-ocaml.txt
+++ b/doc/ale-ocaml.txt
@@ -34,4 +34,21 @@ g:ale_ocaml_ols_use_global *g:ale_ocaml_ols_use_global*
executable. See also |ale-integrations-local-executables|.
===============================================================================
+ocamlformat *ale-ocaml-ocamlformat*
+
+g:ale_ocaml_ocamlformat_executable *g:ale_ocaml_ocamlformat_executable*
+ *b:ale_ocaml_ocamlformat_executable*
+ Type: |String|
+ Default: `'ocamlformat'`
+
+ This variable can be set to pass the path of the ocamlformat fixer.
+
+g:ale_ocaml_ocamlformat_options *g:ale_ocaml_ocamlformat_options*
+ *b:ale_ocaml_ocamlformat_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the ocamlformat fixer.
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-pawn.txt b/doc/ale-pawn.txt
new file mode 100644
index 00000000..f836df97
--- /dev/null
+++ b/doc/ale-pawn.txt
@@ -0,0 +1,12 @@
+===============================================================================
+ALE Pawn Integration *ale-pawn-options*
+
+
+===============================================================================
+uncrustify *ale-pawn-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
+vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-perl6.txt b/doc/ale-perl6.txt
new file mode 100644
index 00000000..94953db5
--- /dev/null
+++ b/doc/ale-perl6.txt
@@ -0,0 +1,43 @@
+===============================================================================
+ALE Perl6 Integration *ale-perl6-options*
+
+Checking code with `perl6` is disabled by default, as `perl6` code cannot be
+checked without executing it. Specifically, we use the `-c` flag to see if
+`perl6` code compiles. This does not execute all of the code in a file, but it
+does run `BEGIN` and `CHECK` blocks. See `perl6 --help`
+
+Full support requires a perl6 implementation that supports the
+PERL6_EXCEPTIONS_HANDLER environment variable and JSON error output,
+which was specified in 6.d. Rakudo version 2018.08 is the first rakudo release
+that supports this. See `perl6 --version` and
+https://docs.perl6.org/programs/03-environment-variables.
+
+Without this variable, errors and warnings will appear at line 1, and can be
+viewed with ALEDetail. This also serves as a fallback for errors and warnings
+that do not trigger JSON output.
+
+See |g:ale_linters|.
+
+
+===============================================================================
+perl6 *ale-perl6-perl6*
+
+g:ale_perl6_perl6_executable *g:ale_perl6_perl6_executable*
+ *b:ale_perl6_perl6_executable*
+ Type: |String|
+ Default: `'perl6'`
+
+ This variable can be changed to modify the executable used for linting
+ perl6.
+
+
+g:ale_perl6_perl6_options *g:ale_perl6_perl6_options*
+ *b:ale_perl6_perl6_options*
+ Type: |String|
+ Default: `'-c -Ilib'`
+
+ This variable can be changed to alter the command-line arguments to the
+ perl6 invocation.
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-php.txt b/doc/ale-php.txt
index 33796f7c..83bc0fd5 100644
--- a/doc/ale-php.txt
+++ b/doc/ale-php.txt
@@ -1,24 +1,6 @@
===============================================================================
ALE PHP Integration *ale-php-options*
-
-===============================================================================
-hack *ale-php-hack*
-
-There are no options for this linter.
-
-
-===============================================================================
-hackfmt *ale-php-hackfmt*
-
-g:ale_php_hackfmt_options *g:ale_php_hackfmt_options*
- *b:ale_php_hackfmt_options*
- Type: |String|
- Default: `''`
-
- This variable can be set to pass additional options to the hackfmt fixer.
-
-
===============================================================================
langserver *ale-php-langserver*
@@ -132,6 +114,13 @@ g:ale_php_phpcs_use_global *g:ale_php_phpcs_use_global*
See |ale-integrations-local-executables|
+g:ale_php_phpcs_options *g:ale_php_phpcs_options*
+ *b:ale_php_phpcs_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to php-cs
+
===============================================================================
phpmd *ale-php-phpmd*
@@ -181,6 +170,16 @@ g:ale_php_phpstan_configuration *g:ale_php_phpstan_configuration*
===============================================================================
+psalm *ale-php-psalm*
+
+g:ale_php_psalm_executable *g:ale_php_psalm_executable*
+ *b:ale_php_psalm_executable*
+ Type: |String|
+ Default: `'psalm'`
+
+ This variable sets the executable used for psalm.
+
+===============================================================================
php-cs-fixer *ale-php-php-cs-fixer*
g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable*
@@ -205,4 +204,14 @@ g:ale_php_cs_fixer_options *g:ale_php_cs_fixer_options*
This variable can be set to pass additional options to php-cs-fixer.
===============================================================================
+php *ale-php-php*
+
+g:ale_php_php_executable *g:ale_php_php_executable*
+ *b:ale_php_php_executable*
+ Type: |String|
+ Default: `'php'`
+
+ This variable sets the executable used for php.
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-prolog.txt b/doc/ale-prolog.txt
new file mode 100644
index 00000000..14062a5a
--- /dev/null
+++ b/doc/ale-prolog.txt
@@ -0,0 +1,56 @@
+===============================================================================
+ALE Prolog Integration *ale-prolog-options*
+
+
+===============================================================================
+swipl *ale-prolog-swipl*
+
+g:ale_prolog_swipl_executable *g:ale_prolog_swipl_executable*
+ *b:ale_prolog_swipl_executable*
+ Type: |String|
+ Default: `'swipl'`
+
+ The executable that will be run for the `swipl` linter.
+
+g:ale_prolog_swipl_load *g:ale_prolog_swipl_load*
+ *b:ale_prolog_swipl_load*
+ Type: |String|
+ Default: `'current_prolog_flag(argv, [File]), load_files(File, [sandboxed(true)]), halt.'`
+
+ The prolog goals that will be passed to |g:ale_prolog_swipl_executable| with `-g` option.
+
+ It does:
+ 1. Takes the first command argument (current file path)
+ 2. Checks (syntactic / semantic) problems and output to stderr
+
+ NOTE: `sandboxed(true)` prohibits executing some directives such as 'initialization main'.
+
+g:ale_prolog_swipl_timeout *g:ale_prolog_swipl_timeout*
+ *b:ale_prolog_swipl_timeout*
+ Type: |Number|
+ Default: `3`
+
+ Timeout seconds to detect long-running linter.
+ It is done by setting SIGALRM.
+ See |g:ale_prolog_swipl_alarm| and |g:ale_prolog_swipl_alarm_handler|.
+
+g:ale_prolog_swipl_alarm *g:ale_prolog_swipl_alarm*
+ *b:ale_prolog_swipl_alarm*
+ Type: |String|
+ Default: `'alarm(%t, (%h), _, [])'`
+
+ The prolog goals to be expected to set SIGALRM.
+ `%t` is replaced by |g:ale_prolog_swipl_timeout|.
+ `%h` is replaced by |g:ale_prolog_swipl_alarm_handler|.
+
+g:ale_prolog_swipl_alarm_handler *g:ale_prolog_swipl_alarm_handler*
+ *b:ale_prolog_swipl_alarm_handler*
+ Type: |String|
+ Default: `'writeln(user_error, "ERROR: Exceeded %t seconds, Please change g:prolog_swipl_timeout to modify the limit."), halt(1)'`
+
+ The prolog goals to be expected that will be run on SIGALRM.
+ `%t` is replaced by |g:ale_prolog_swipl_timeout|.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-puppet.txt b/doc/ale-puppet.txt
index 7c67484e..daa8c10f 100644
--- a/doc/ale-puppet.txt
+++ b/doc/ale-puppet.txt
@@ -3,6 +3,26 @@ ALE Puppet Integration *ale-puppet-options*
===============================================================================
+puppet *ale-puppet-puppet*
+
+g:ale_puppet_puppet_executable *g:ale_puppet_puppet_executable*
+ *b:ale_puppet_puppet_executable*
+ Type: |String|
+ Default: `'puppet'`
+
+ This variable can be changed to specify the executable used for puppet.
+
+
+g:ale_puppet_puppet_options *g:ale_puppet_puppet_options*
+ *b:ale_puppet_puppet_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be changed to add command-line arguments to the
+ puppet parser validate invocation.
+
+
+===============================================================================
puppetlint *ale-puppet-puppetlint*
g:ale_puppet_puppetlint_executable *g:ale_puppet_puppetlint_executable*
diff --git a/doc/ale-python.txt b/doc/ale-python.txt
index e24ef1aa..0b8e1746 100644
--- a/doc/ale-python.txt
+++ b/doc/ale-python.txt
@@ -2,6 +2,14 @@
ALE Python Integration *ale-python-options*
+g:ale_python_auto_pipenv *g:ale_python_auto_pipenv*
+ *b:ale_python_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
===============================================================================
ALE Python Project Root Behavior *ale-python-root*
@@ -22,6 +30,7 @@ ALE will look for configuration files with the following filenames. >
mypy.ini
pycodestyle.cfg
flake8.cfg
+ .flake8rc
Pipfile
Pipfile.lock
<
@@ -136,6 +145,15 @@ g:ale_python_flake8_use_global *g:ale_python_flake8_use_global*
Both variables can be set with `b:` buffer variables instead.
+g:ale_python_flake8_auto_pipenv *g:ale_python_flake8_auto_pipenv*
+ *b:ale_python_flake8_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
isort *ale-python-isort*
@@ -210,6 +228,15 @@ g:ale_python_mypy_use_global *g:ale_python_mypy_use_global*
See |ale-integrations-local-executables|
+g:ale_python_mypy_auto_pipenv *g:ale_python_mypy_auto_pipenv*
+ *b:ale_python_mypy_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
prospector *ale-python-prospector*
@@ -252,6 +279,15 @@ g:ale_python_prospector_use_global *g:ale_python_prospector_use_global*
See |ale-integrations-local-executables|
+g:ale_python_prospector_auto_pipenv *g:ale_python_prospector_auto_pipenv*
+ *b:ale_python_prospector_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pycodestyle *ale-python-pycodestyle*
@@ -283,6 +319,15 @@ g:ale_python_pycodestyle_use_global *g:ale_python_pycodestyle_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pycodestyle_auto_pipenv *g:ale_python_pycodestyle_auto_pipenv*
+ *b:ale_python_pycodestyle_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pyflakes *ale-python-pyflakes*
@@ -297,6 +342,15 @@ g:ale_python_pyflakes_executable *g:ale_python_pyflakes_executable*
Set this to `'pipenv'` to invoke `'pipenv` `run` `pyflakes'`.
+g:ale_python_pyflakes_auto_pipenv *g:ale_python_pyflakes_auto_pipenv*
+ *b:ale_python_pyflakes_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pylint *ale-python-pylint*
@@ -349,6 +403,15 @@ g:ale_python_pylint_use_global *g:ale_python_pylint_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pylint_auto_pipenv *g:ale_python_pylint_auto_pipenv*
+ *b:ale_python_pylint_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pyls *ale-python-pyls*
@@ -373,6 +436,15 @@ g:ale_python_pyls_use_global *g:ale_python_pyls_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pyls_auto_pipenv *g:ale_python_pyls_auto_pipenv*
+ *b:ale_python_pyls_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
===============================================================================
pyre *ale-python-pyre*
@@ -397,6 +469,45 @@ g:ale_python_pyre_use_global *g:ale_python_pyre_use_global*
See |ale-integrations-local-executables|
+g:ale_python_pyre_auto_pipenv *g:ale_python_pyre_auto_pipenv*
+ *b:ale_python_pyre_auto_pipenv*
+ Type: |Number|
+ Default: `0`
+
+ Detect whether the file is inside a pipenv, and set the executable to `pipenv`
+ if true. This is overridden by a manually-set executable.
+
+
+===============================================================================
+vulture *ale-python-vulture*
+
+g:ale_python_vulture_change_directory *g:ale_python_vulture_change_directory*
+ *b:ale_python_vulture_change_directory*
+ Type: |Number|
+ Default: `1`
+
+ If set to `1`, ALE will switch to the directory the Python file being
+ checked with `vulture` is in before checking it and check the whole project
+ directory instead of checking only the file opened in the current buffer.
+ This helps `vulture` to know the context and avoid false-negative results.
+
+
+g:ale_python_vulture_executable *g:ale_python_vulture_executable*
+ *b:ale_python_vulture_executable*
+ Type: |String|
+ Default: `'vulture'`
+
+ See |ale-integrations-local-executables|
+
+
+g:ale_python_vulture_use_global *g:ale_python_vulture_use_global*
+ *b:ale_python_vulture_use_global*
+ Type: |Number|
+ Default: `get(g:, 'ale_use_global_executables', 0)`
+
+ See |ale-integrations-local-executables|
+
+
===============================================================================
yapf *ale-python-yapf*
diff --git a/doc/ale-ruby.txt b/doc/ale-ruby.txt
index 85a3e137..f8a41999 100644
--- a/doc/ale-ruby.txt
+++ b/doc/ale-ruby.txt
@@ -5,6 +5,15 @@ ALE Ruby Integration *ale-ruby-options*
===============================================================================
brakeman *ale-ruby-brakeman*
+g:ale_ruby_brakeman_executable *g:ale_ruby_brakeman_executable*
+ *b:ale_ruby_brakeman_executable*
+ Type: String
+ Default: `'brakeman'`
+
+ Override the invoked brakeman binary. Set this to `'bundle'` to invoke
+ `'bundle` `exec` brakeman'.
+
+
g:ale_ruby_brakeman_options *g:ale_ruby_brakeman_options*
*b:ale_ruby_brakeman_options*
Type: |String|
@@ -20,10 +29,11 @@ g:ale_ruby_rails_best_practices_executable
*g:ale_ruby_rails_best_practices_executable*
*b:ale_ruby_rails_best_practices_executable*
Type: String
- Default: 'rails_best_practices'
+ Default: `'rails_best_practices'`
Override the invoked rails_best_practices binary. Set this to `'bundle'` to
- invoke `'bundle` `exec` `rails_best_practices'`.
+ invoke `'bundle` `exec` rails_best_practices'.
+
g:ale_ruby_rails_best_practices_options
*g:ale_ruby_rails_best_practices_options*
@@ -37,6 +47,15 @@ g:ale_ruby_rails_best_practices_options
===============================================================================
reek *ale-ruby-reek*
+g:ale_ruby_reek_executable *g:ale_ruby_reek_executable*
+ *b:ale_ruby_reek_executable*
+ Type: String
+ Default: `'reek'`
+
+ Override the invoked reek binary. Set this to `'bundle'` to invoke
+ `'bundle` `exec` reek'.
+
+
g:ale_ruby_reek_show_context *g:ale_ruby_reek_show_context*
*b:ale_ruby_reek_show_context*
Type: |Number|
@@ -63,8 +82,8 @@ g:ale_ruby_rubocop_executable *g:ale_ruby_rubocop_executable*
Type: String
Default: `'rubocop'`
- Override the invoked rubocop binary. This is useful for running rubocop
- from binstubs or a bundle.
+ Override the invoked rubocop binary. Set this to `'bundle'` to invoke
+ `'bundle` `exec` rubocop'.
g:ale_ruby_rubocop_options *g:ale_ruby_rubocop_options*
@@ -99,4 +118,16 @@ g:ale_ruby_rufo_executable *g:ale_ruby_rufo_executable*
===============================================================================
+solargraph *ale-ruby-solargraph*
+
+g:ale_ruby_solargraph_executable *g:ale_ruby_solargraph_executable*
+ *b:ale_ruby_solargraph_executable*
+ Type: String
+ Default: `'solargraph'`
+
+ Override the invoked solargraph binary. This is useful for running solargraph
+ from binstubs or a bundle.
+
+
+===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-rust.txt b/doc/ale-rust.txt
index d61e5b55..7510dfbd 100644
--- a/doc/ale-rust.txt
+++ b/doc/ale-rust.txt
@@ -5,8 +5,9 @@ ALE Rust Integration *ale-rust-options*
===============================================================================
Integration Information
- Since Vim does not detect the rust file type out-of-the-box, you need the
- runtime files for rust from here: https://github.com/rust-lang/rust.vim
+ If Vim does not detect the Rust file type out-of-the-box, you need the runtime
+ files for Rust distributed in Vim >=8.0.0501 or upstream:
+ https://github.com/rust-lang/rust.vim
Note that there are three possible linters for Rust files:
@@ -108,14 +109,45 @@ g:ale_rust_cargo_include_features *g:ale_rust_cargo_include_features*
When defined, ALE will set the `--features` option when invoking `cargo` to
perform the lint check. See |g:ale_rust_cargo_default_feature_behavior|.
+
g:ale_rust_cargo_avoid_whole_workspace *g:ale_rust_cargo_avoid_whole_workspace*
*b:ale_rust_cargo_avoid_whole_workspace*
Type: |Number|
Default: `1`
When set to 1, and ALE is used to edit a crate that is part of a Cargo
- workspace, avoid building the entire entire workspace by invoking
- `cargo` directly in the crate's directory. Otherwise, behave as usual.
+ workspace, avoid building the entire workspace by invoking `cargo` directly
+ in the crate's directory. Otherwise, behave as usual.
+
+
+g:ale_rust_cargo_use_clippy
+ *g:ale_rust_cargo_use_clippy*
+ *b:ale_rust_cargo_use_clippy*
+ Type: |Number|
+ Default: `0`
+
+ When set to 1, `cargo clippy` will be used instead of `cargo check` or
+ `cargo build` as linter.
+ For details of `cargo clippy`, please visit the following link:
+
+ https://github.com/rust-lang-nursery/rust-clippy
+
+ Since `cargo clippy` is optional toolchain, it's safer to check whether
+ `cargo-clippy` is executable as follows:
+>
+ let g:ale_rust_cargo_use_clippy = executable('cargo-clippy')
+<
+
+g:ale_rust_cargo_clippy_options
+ *g:ale_rust_cargo_clippy_options*
+ *b:ale_rust_cargo_clippy_options*
+
+ Type: |String|
+ Default: `''`
+
+ When `cargo clippy` is used, this value will be added to a command line to run
+ it. This variable is useful when you want to add some extra options which
+ only `cargo clippy` supports (e.g. `--deny`).
===============================================================================
@@ -147,11 +179,11 @@ rustc *ale-rust-rustc*
g:ale_rust_rustc_options *g:ale_rust_rustc_options*
*b:ale_rust_rustc_options*
Type: |String|
- Default: `'-Z no-trans'`
+ Default: `'-Z no-codegen'`
The variable can be used to change the options passed to `rustc`.
- `-Z no-trans` should only work with nightly builds of Rust. Be careful when
+ `-Z no-codegen` should only work with nightly builds of Rust. Be careful when
setting the options, as running `rustc` could execute code or generate
binary files.
@@ -166,6 +198,22 @@ g:ale_rust_ignore_error_codes *g:ale_rust_ignore_error_codes*
>
let g:ale_rust_ignore_error_codes = ['E0432', 'E0433']
+g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans*
+ *b:ale_rust_ignore_secondary_spans*
+ Type: Number
+ Default: 0
+
+ When set to 1, instructs the Rust error repporting to ignore secondary
+ spans. The problem with secondary spans is that they sometimes appear in
+ error messages before the main cause of the error, for example: >
+
+ 1 src/main.rs|98 col 5 error| this function takes 4 parameters but 5
+ parameters were supplied: defined here
+ 2 src/main.rs|430 col 32 error| this function takes 4 parameters but 5
+ parameters were supplied: expected 4 parameters
+<
+ This is due to the sorting by line numbers. With this option set to 1,
+ the 'defined here' span will not be presented.
===============================================================================
rustfmt *ale-rust-rustfmt*
diff --git a/doc/ale-scala.txt b/doc/ale-scala.txt
index b992d428..ff43cd6c 100644
--- a/doc/ale-scala.txt
+++ b/doc/ale-scala.txt
@@ -3,6 +3,39 @@ ALE Scala Integration *ale-scala-options*
===============================================================================
+sbtserver *ale-scala-sbtserver*
+
+`sbtserver` requires a running ^1.1.x sbt shell to connect to. It will attempt
+to connect via TCP to the address defined in `g:ale_scala_sbtserver_address`.
+As `sbt` defaults to listening via unix sockets, place these settings into
+your `~/.sbt/1.0/global.sbt` to ensure that ale will always attempt to connect
+to the right socket:
+
+`serverConnectionType := ConnectionType.Tcp` and `serverPort := 4273`
+
+
+g:ale_scala_sbtserver_address *g:ale_scala_sbtserver_address*
+ *b:ale_scala_sbtserver_address*
+ Type: |String|
+ Default: `'127.0.0.1:4273'`
+
+ By default the address is found by parsing `active.json`, however, reading a
+ file is a blocking operation which should be avoided in ale. The easy way
+ around this is to configure sbt to always connect to the same port, which
+ the instructions above describe.
+
+
+g:ale_scala_sbtserver_project_root *g:ale_scala_sbtserver_project_root*
+ *b:ale_scala_sbtserver_project_root*
+ Type: |String|
+ Default: `''`
+
+ By default the project root is found by searching upwards for `build.sbt`.
+ If the project root is elsewhere, you can override the project root
+ directory.
+
+
+===============================================================================
scalafmt *ale-scala-scalafmt*
If Nailgun is used, override `g:ale_scala_scalafmt_executable` like so: >
diff --git a/doc/ale-scss.txt b/doc/ale-scss.txt
index 14e6feb7..3ad84fc1 100644
--- a/doc/ale-scss.txt
+++ b/doc/ale-scss.txt
@@ -18,6 +18,12 @@ g:ale_scss_stylelint_executable *g:ale_scss_stylelint_executable*
See |ale-integrations-local-executables|
+g:ale_scss_stylelint_options *g:ale_scss_stylelint_options*
+ *b:ale_scss_stylelint_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to stylelint.
g:ale_scss_stylelint_use_global *g:ale_scss_stylelint_use_global*
*b:ale_scss_stylelint_use_global*
diff --git a/doc/ale-sql.txt b/doc/ale-sql.txt
new file mode 100644
index 00000000..75d4b0cf
--- /dev/null
+++ b/doc/ale-sql.txt
@@ -0,0 +1,25 @@
+===============================================================================
+ALE SQL Integration *ale-sql-options*
+
+
+===============================================================================
+sqlfmt *ale-sql-sqlfmt*
+
+g:ale_sql_sqlfmt_executable *g:ale_sql_sqlfmt_executable*
+ *b:ale_sql_sqlfmt_executable*
+ Type: |String|
+ Default: `'sqlfmt'`
+
+ This variable sets executable used for sqlfmt.
+
+g:ale_sql_sqlfmt_options *g:ale_sql_sqlfmt_options*
+ *b:ale_sql_sqlfmt_options*
+ Type: |String|
+ Default: `''`
+
+ This variable can be set to pass additional options to the sqlfmt fixer.
+ At this time only the -u flag is available to format with upper-case.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-terraform.txt b/doc/ale-terraform.txt
index ec86e9a0..49a55028 100644
--- a/doc/ale-terraform.txt
+++ b/doc/ale-terraform.txt
@@ -3,6 +3,24 @@ ALE Terraform Integration *ale-terraform-options*
===============================================================================
+fmt *ale-terraform-fmt*
+
+g:ale_terraform_fmt_executable *g:ale_terraform_fmt_executable*
+ *b:ale_terraform_fmt_executable*
+
+ Type: |String|
+ Default: `'terraform'`
+
+ This variable can be changed to use a different executable for terraform.
+
+
+g:ale_terraform_fmt_options *g:ale_terraform_fmt_options*
+ *b:ale_terraform_fmt_options*
+ Type: |String|
+ Default: `''`
+
+
+===============================================================================
tflint *ale-terraform-tflint*
g:ale_terraform_tflint_executable *g:ale_terraform_tflint_executable*
diff --git a/doc/ale-thrift.txt b/doc/ale-thrift.txt
index ed858db8..bb2ec058 100644
--- a/doc/ale-thrift.txt
+++ b/doc/ale-thrift.txt
@@ -28,7 +28,7 @@ g:ale_thrift_thrift_generators *g:ale_thrift_thrift_generators*
g:ale_thrift_thrift_includes *g:ale_thrift_thrift_includes*
*b:ale_thrift_thrift_includes*
Type: |List| of |String|s
- Default: `[]`
+ Default: `['.']`
This list contains paths that will be searched for thrift `include`
directives.
diff --git a/doc/ale-typescript.txt b/doc/ale-typescript.txt
index 1bccf5a3..7dc59820 100644
--- a/doc/ale-typescript.txt
+++ b/doc/ale-typescript.txt
@@ -19,6 +19,18 @@ See |ale-javascript-prettier| for information about the available options.
===============================================================================
tslint *ale-typescript-tslint*
+This linter isn't recommended, because TSLint can't be used for checking for
+problems while you type. You should probably use the tsserver plugin instead.
+tsserver plugins are described here:
+https://github.com/Microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin
+
+Follow the instructions on the plugin website for installing it:
+https://github.com/Microsoft/typescript-tslint-plugin
+
+Then disable TSLint in vimrc or any other Vim configuration file. >
+ let g:ale_linters_ignore = {'typescript': ['tslint']}
+<
+
g:ale_typescript_tslint_executable *g:ale_typescript_tslint_executable*
*b:ale_typescript_tslint_executable*
Type: |String|
diff --git a/doc/ale-vala.txt b/doc/ale-vala.txt
new file mode 100644
index 00000000..ca24bcf4
--- /dev/null
+++ b/doc/ale-vala.txt
@@ -0,0 +1,12 @@
+===============================================================================
+ALE VALA Integration *ale-vala-options*
+
+
+===============================================================================
+uncrustify *ale-vala-uncrustify*
+
+See |ale-c-uncrustify| for information about the available options.
+
+
+===============================================================================
+vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-xml.txt b/doc/ale-xml.txt
index 6c8af6c7..e43fdefd 100644
--- a/doc/ale-xml.txt
+++ b/doc/ale-xml.txt
@@ -21,6 +21,14 @@ g:ale_xml_xmllint_options *g:ale_xml_xmllint_options*
This variable can be set to pass additional options to xmllint.
+g:ale_xml_xmllint_indentsize *g:ale_xml_xmllint_indentsize*
+ *b:ale_xml_xmllint_indentsize*
+ Type: |Number|
+ Default: 2
+
+ This variable can be sent to specify the amount of spaces used for
+ indentation.
+
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale-yaml.txt b/doc/ale-yaml.txt
index 044d0b3d..c9a12ea1 100644
--- a/doc/ale-yaml.txt
+++ b/doc/ale-yaml.txt
@@ -1,7 +1,21 @@
===============================================================================
ALE YAML Integration *ale-yaml-options*
+===============================================================================
+prettier *ale-yaml-prettier*
+
+Website: https://github.com/prettier/prettier
+
+
+Installation
+-------------------------------------------------------------------------------
+Install prettier either globally or locally: >
+
+ npm install prettier -g # global
+ npm install prettier # local
+<
+
===============================================================================
swaglint *ale-yaml-swaglint*
diff --git a/doc/ale-yang.txt b/doc/ale-yang.txt
new file mode 100644
index 00000000..ad619733
--- /dev/null
+++ b/doc/ale-yang.txt
@@ -0,0 +1,17 @@
+===============================================================================
+ALE YANG Integration *ale-yang-options*
+
+
+===============================================================================
+yang-lsp *ale-yang-lsp*
+
+g:ale_yang_lsp_executable *g:ale_yang_lsp_executable*
+ *b:ale_yang_lsp_executable*
+ Type: |String|
+ Default: `'yang-language-server'`
+
+ This variable can be changed to use a different executable for yang-lsp.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale.txt b/doc/ale.txt
index 8182c27a..1a37f73f 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -9,15 +9,22 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint|
+ 3.1 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp|
5.1 Completion........................|ale-completion|
5.2 Go To Definition..................|ale-go-to-definition|
5.3 Find References...................|ale-find-references|
+ 5.4 Hovering..........................|ale-hover|
+ 5.5 Symbol Search.....................|ale-symbol-search|
6. Global Options.......................|ale-options|
6.1 Highlights........................|ale-highlights|
6.2 Options for write-good Linter.....|ale-write-good-options|
7. Integration Documentation............|ale-integrations|
+ ada...................................|ale-ada-options|
+ gcc.................................|ale-ada-gcc|
+ ansible...............................|ale-ansible-options|
+ ansible-lint........................|ale-ansible-ansible-lint|
asciidoc..............................|ale-asciidoc-options|
write-good..........................|ale-asciidoc-write-good|
asm...................................|ale-asm-options|
@@ -30,8 +37,11 @@ CONTENTS *ale-contents*
clang-format........................|ale-c-clangformat|
clangtidy...........................|ale-c-clangtidy|
cppcheck............................|ale-c-cppcheck|
+ cquery..............................|ale-c-cquery|
flawfinder..........................|ale-c-flawfinder|
gcc.................................|ale-c-gcc|
+ uncrustify..........................|ale-c-uncrustify|
+ ccls................................|ale-c-ccls|
chef..................................|ale-chef-options|
foodcritic..........................|ale-chef-foodcritic|
clojure...............................|ale-clojure-options|
@@ -42,31 +52,41 @@ CONTENTS *ale-contents*
cmakelint...........................|ale-cmake-cmakelint|
cpp...................................|ale-cpp-options|
clang...............................|ale-cpp-clang|
+ clangd..............................|ale-cpp-clangd|
clangcheck..........................|ale-cpp-clangcheck|
clang-format........................|ale-cpp-clangformat|
clangtidy...........................|ale-cpp-clangtidy|
+ clazy...............................|ale-cpp-clazy|
cppcheck............................|ale-cpp-cppcheck|
cpplint.............................|ale-cpp-cpplint|
cquery..............................|ale-cpp-cquery|
flawfinder..........................|ale-cpp-flawfinder|
gcc.................................|ale-cpp-gcc|
+ uncrustify..........................|ale-cpp-uncrustify|
+ ccls................................|ale-cpp-ccls|
c#....................................|ale-cs-options|
mcs.................................|ale-cs-mcs|
mcsc................................|ale-cs-mcsc|
+ uncrustify..........................|ale-cs-uncrustify|
css...................................|ale-css-options|
prettier............................|ale-css-prettier|
stylelint...........................|ale-css-stylelint|
cuda..................................|ale-cuda-options|
nvcc................................|ale-cuda-nvcc|
+ d.....................................|ale-d-options|
+ dls.................................|ale-d-dls|
+ uncrustify..........................|ale-d-uncrustify|
dart..................................|ale-dart-options|
dartanalyzer........................|ale-dart-dartanalyzer|
dartfmt.............................|ale-dart-dartfmt|
dockerfile............................|ale-dockerfile-options|
+ dockerfile_lint.....................|ale-dockerfile-dockerfile_lint|
hadolint............................|ale-dockerfile-hadolint|
elixir................................|ale-elixir-options|
mix.................................|ale-elixir-mix|
mix_format..........................|ale-elixir-mix-format|
dialyxir............................|ale-elixir-dialyxir|
+ elixir-ls...........................|ale-elixir-elixir-ls|
elm...................................|ale-elm-options|
elm-format..........................|ale-elm-elm-format|
elm-make............................|ale-elm-elm-make|
@@ -74,6 +94,7 @@ CONTENTS *ale-contents*
erlc................................|ale-erlang-erlc|
syntaxerl...........................|ale-erlang-syntaxerl|
eruby.................................|ale-eruby-options|
+ ruumba..............................|ale-eruby-ruumba|
fish..................................|ale-fish-options|
fortran...............................|ale-fortran-options|
gcc.................................|ale-fortran-gcc|
@@ -89,32 +110,52 @@ CONTENTS *ale-contents*
go....................................|ale-go-options|
gobuild.............................|ale-go-gobuild|
gofmt...............................|ale-go-gofmt|
+ golint..............................|ale-go-golint|
+ govet...............................|ale-go-govet|
gometalinter........................|ale-go-gometalinter|
staticcheck.........................|ale-go-staticcheck|
+ golangserver........................|ale-go-golangserver|
+ golangci-lint.......................|ale-go-golangci-lint|
graphql...............................|ale-graphql-options|
eslint..............................|ale-graphql-eslint|
gqlint..............................|ale-graphql-gqlint|
prettier............................|ale-graphql-prettier|
+ hack..................................|ale-hack-options|
+ hack................................|ale-hack-hack|
+ hackfmt.............................|ale-hack-hackfmt|
+ hhast...............................|ale-hack-hhast|
handlebars............................|ale-handlebars-options|
ember-template-lint.................|ale-handlebars-embertemplatelint|
haskell...............................|ale-haskell-options|
brittany............................|ale-haskell-brittany|
ghc.................................|ale-haskell-ghc|
+ ghc-mod.............................|ale-haskell-ghc-mod|
cabal-ghc...........................|ale-haskell-cabal-ghc|
hdevtools...........................|ale-haskell-hdevtools|
hfmt................................|ale-haskell-hfmt|
+ hlint...............................|ale-haskell-hlint|
stack-build.........................|ale-haskell-stack-build|
+ stylish-haskell.....................|ale-haskell-stylish-haskell|
+ hie.................................|ale-haskell-hie|
+ hcl...................................|ale-hcl-options|
+ terraform-fmt.......................|ale-hcl-terraform-fmt|
html..................................|ale-html-options|
htmlhint............................|ale-html-htmlhint|
tidy................................|ale-html-tidy|
+ prettier............................|ale-html-prettier|
+ stylelint...........................|ale-html-stylelint|
write-good..........................|ale-html-write-good|
idris.................................|ale-idris-options|
idris...............................|ale-idris-idris|
+ ispc..................................|ale-ispc-options|
+ ispc................................|ale-ispc-ispc|
java..................................|ale-java-options|
checkstyle..........................|ale-java-checkstyle|
javac...............................|ale-java-javac|
google-java-format..................|ale-java-google-java-format|
pmd.................................|ale-java-pmd|
+ javalsp.............................|ale-java-javalsp|
+ uncrustify..........................|ale-java-uncrustify|
javascript............................|ale-javascript-options|
eslint..............................|ale-javascript-eslint|
flow................................|ale-javascript-flow|
@@ -131,6 +172,8 @@ CONTENTS *ale-contents*
jsonlint............................|ale-json-jsonlint|
jq..................................|ale-json-jq|
prettier............................|ale-json-prettier|
+ julia.................................|ale-julia-options|
+ languageserver......................|ale-julia-languageserver|
kotlin................................|ale-kotlin-options|
kotlinc.............................|ale-kotlin-kotlinc|
ktlint..............................|ale-kotlin-ktlint|
@@ -160,36 +203,49 @@ CONTENTS *ale-contents*
write-good..........................|ale-nroff-write-good|
objc..................................|ale-objc-options|
clang...............................|ale-objc-clang|
+ clangd..............................|ale-objc-clangd|
+ uncrustify..........................|ale-objc-uncrustify|
+ ccls................................|ale-objc-ccls|
objcpp................................|ale-objcpp-options|
clang...............................|ale-objcpp-clang|
+ clangd..............................|ale-objcpp-clangd|
+ uncrustify..........................|ale-objcpp-uncrustify|
ocaml.................................|ale-ocaml-options|
merlin..............................|ale-ocaml-merlin|
ols.................................|ale-ocaml-ols|
+ ocamlformat.........................|ale-ocaml-ocamlformat|
+ pawn..................................|ale-pawn-options|
+ uncrustify..........................|ale-pawn-uncrustify|
perl..................................|ale-perl-options|
perl................................|ale-perl-perl|
perlcritic..........................|ale-perl-perlcritic|
perltidy............................|ale-perl-perltidy|
+ perl6.................................|ale-perl6-options|
+ perl6...............................|ale-perl6-perl6|
php...................................|ale-php-options|
- hack................................|ale-php-hack|
- hackfmt.............................|ale-php-hackfmt|
langserver..........................|ale-php-langserver|
phan................................|ale-php-phan|
phpcbf..............................|ale-php-phpcbf|
phpcs...............................|ale-php-phpcs|
phpmd...............................|ale-php-phpmd|
phpstan.............................|ale-php-phpstan|
+ psalm...............................|ale-php-psalm|
php-cs-fixer........................|ale-php-php-cs-fixer|
+ php.................................|ale-php-php|
po....................................|ale-po-options|
write-good..........................|ale-po-write-good|
pod...................................|ale-pod-options|
write-good..........................|ale-pod-write-good|
pony..................................|ale-pony-options|
ponyc...............................|ale-pony-ponyc|
+ prolog................................|ale-prolog-options|
+ swipl...............................|ale-prolog-swipl|
proto.................................|ale-proto-options|
protoc-gen-lint.....................|ale-proto-protoc-gen-lint|
pug...................................|ale-pug-options|
puglint.............................|ale-pug-puglint|
puppet................................|ale-puppet-options|
+ puppet..............................|ale-puppet-puppet|
puppetlint..........................|ale-puppet-puppetlint|
puppet-languageserver...............|ale-puppet-languageserver|
pyrex (cython)........................|ale-pyrex-options|
@@ -206,6 +262,7 @@ CONTENTS *ale-contents*
pylint..............................|ale-python-pylint|
pyls................................|ale-python-pyls|
pyre................................|ale-python-pyre|
+ vulture.............................|ale-python-vulture|
yapf................................|ale-python-yapf|
qml...................................|ale-qml-options|
qmlfmt..............................|ale-qml-qmlfmt|
@@ -224,6 +281,7 @@ CONTENTS *ale-contents*
rubocop.............................|ale-ruby-rubocop|
ruby................................|ale-ruby-ruby|
rufo................................|ale-ruby-rufo|
+ solargraph..........................|ale-ruby-solargraph|
rust..................................|ale-rust-options|
cargo...............................|ale-rust-cargo|
rls.................................|ale-rust-rls|
@@ -232,6 +290,7 @@ CONTENTS *ale-contents*
sass..................................|ale-sass-options|
stylelint...........................|ale-sass-stylelint|
scala.................................|ale-scala-options|
+ sbtserver...........................|ale-scala-sbtserver|
scalafmt............................|ale-scala-scalafmt|
scalastyle..........................|ale-scala-scalastyle|
scss..................................|ale-scss-options|
@@ -249,11 +308,14 @@ CONTENTS *ale-contents*
solium..............................|ale-solidity-solium|
spec..................................|ale-spec-options|
rpmlint.............................|ale-spec-rpmlint|
+ sql...................................|ale-sql-options|
+ sqlfmt..............................|ale-sql-sqlfmt|
stylus................................|ale-stylus-options|
stylelint...........................|ale-stylus-stylelint|
tcl...................................|ale-tcl-options|
nagelfar............................|ale-tcl-nagelfar|
terraform.............................|ale-terraform-options|
+ fmt.................................|ale-terraform-fmt|
tflint..............................|ale-terraform-tflint|
tex...................................|ale-tex-options|
chktex..............................|ale-tex-chktex|
@@ -270,6 +332,8 @@ CONTENTS *ale-contents*
prettier............................|ale-typescript-prettier|
tslint..............................|ale-typescript-tslint|
tsserver............................|ale-typescript-tsserver|
+ vala..................................|ale-vala-options|
+ uncrustify..........................|ale-vala-uncrustify|
verilog/systemverilog.................|ale-verilog-options|
iverilog............................|ale-verilog-iverilog|
verilator...........................|ale-verilog-verilator|
@@ -285,8 +349,11 @@ CONTENTS *ale-contents*
xml...................................|ale-xml-options|
xmllint.............................|ale-xml-xmllint|
yaml..................................|ale-yaml-options|
+ prettier............................|ale-yaml-prettier|
swaglint............................|ale-yaml-swaglint|
yamllint............................|ale-yaml-yamllint|
+ yang..................................|ale-yang-options|
+ yang-lsp............................|ale-yang-lsp|
8. Commands/Keybinds....................|ale-commands|
9. API..................................|ale-api|
10. Special Thanks......................|ale-special-thanks|
@@ -329,17 +396,18 @@ Notes:
`^` No linters for text or Vim help filetypes are enabled by default.
`!!` These linters check only files on disk. See |ale-lint-file-linters|
+* Ada: `gcc`
* ASM: `gcc`
* Ansible: `ansible-lint`
* API Blueprint: `drafter`
-* AsciiDoc: `alex`!!, `proselint`, `redpen`, `write-good`
+* AsciiDoc: `alex`!!, `proselint`, `redpen`, `write-good`, `vale`
* Awk: `gawk`
* Bash: `language-server`, `shell` (-n flag), `shellcheck`, `shfmt`
* Bourne Shell: `shell` (-n flag), `shellcheck`, `shfmt`
-* C: `cppcheck`, `cpplint`!!, `clang`, `clangd`, `clangtidy`!!, `clang-format`, `flawfinder`, `gcc`
-* C++ (filetype cpp): `clang`, `clangcheck`!!, `clangtidy`!!, `clang-format`, `cppcheck`, `cpplint`!!, `cquery`, `flawfinder`, `gcc`
+* C: `cppcheck`, `cpplint`!!, `clang`, `clangd`, `clangtidy`!!, `clang-format`, `cquery`, `flawfinder`, `gcc`, `uncrustify`, `ccls`
+* C++ (filetype cpp): `clang`, `clangd`, `clangcheck`!!, `clangtidy`!!, `clang-format`, `clazy`!!, `cppcheck`, `cpplint`!!, `cquery`, `flawfinder`, `gcc`, `uncrustify`, `ccls`
* CUDA: `nvcc`!!
-* C#: `mcs`, `mcsc`!!
+* C#: `mcs`, `mcsc`!!, `uncrustify`
* Chef: `foodcritic`
* Clojure: `joker`
* CloudFormation: `cfn-python-lint`
@@ -349,13 +417,13 @@ Notes:
* CSS: `csslint`, `prettier`, `stylelint`
* Cucumber: `cucumber`
* Cython (pyrex filetype): `cython`
-* D: `dmd`
+* D: `dls`, `dmd`, `uncrustify`
* Dafny: `dafny`!!
* Dart: `dartanalyzer`!!, `language_server`, dartfmt!!
-* Dockerfile: `hadolint`
-* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!
+* Dockerfile: `dockerfile_lint`, `hadolint`
+* Elixir: `credo`, `dialyxir`, `dogma`, `mix`!!, `elixir-ls`
* Elm: `elm-format, elm-make`
-* Erb: `erb`, `erubi`, `erubis`
+* Erb: `erb`, `erubi`, `erubis`, `ruumba`
* Erlang: `erlc`, `SyntaxErl`
* Fish: `fish` (-n flag)
* Fortran: `gcc`, `language_server`
@@ -363,16 +431,20 @@ Notes:
* FusionScript: `fusion-lint`
* Git Commit Messages: `gitlint`
* GLSL: glslang, `glslls`
-* Go: `gofmt`, `goimports`, `go vet`!!, `golint`, `gotype`!!, `gometalinter`!!, `go build`!!, `gosimple`!!, `staticcheck`!!
+* Go: `gofmt`, `goimports`, `go mod`!!, `go vet`!!, `golint`, `gotype`!!, `gometalinter`!!, `go build`!!, `gosimple`!!, `staticcheck`!!, `golangserver`, `golangci-lint`!!
* GraphQL: `eslint`, `gqlint`, `prettier`
+* Hack: `hack`, `hackfmt`, `hhast`
* Haml: `haml-lint`
* Handlebars: `ember-template-lint`
-* Haskell: `brittany`, `ghc`, `cabal-ghc`, `stack-ghc`, `stack-build`!!, `ghc-mod`, `stack-ghc-mod`, `hlint`, `hdevtools`, `hfmt`
-* HTML: `alex`!!, `HTMLHint`, `proselint`, `tidy`, `write-good`
+* Haskell: `brittany`, `ghc`, `cabal-ghc`, `stylish-haskell`, `stack-ghc`, `stack-build`!!, `ghc-mod`, `hlint`, `hdevtools`, `hfmt`, `hie`
+* HCL: `terraform-fmt`
+* HTML: `alex`!!, `HTMLHint`, `proselint`, `tidy`, `prettier`, `write-good`
* Idris: `idris`
-* Java: `checkstyle`, `javac`, `google-java-format`, `PMD`
+* ISPC: `ispc`!!
+* Java: `checkstyle`, `javac`, `google-java-format`, `PMD`, `javalsp`, `uncrustify`
* JavaScript: `eslint`, `flow`, `jscs`, `jshint`, `prettier`, `prettier-eslint`, `prettier-standard`, `standard`, `xo`
* JSON: `fixjson`, `jsonlint`, `jq`, `prettier`
+* Julia: `languageserver`
* Kotlin: `kotlinc`!!, `ktlint`!!, `languageserver`
* LaTeX (tex): `alex`!!, `chktex`, `lacheck`, `proselint`, `redpen`, `vale`, `write-good`
* Less: `lessc`, `prettier`, `stylelint`
@@ -387,48 +459,53 @@ Notes:
* Nim: `nim check`!!
* nix: `nix-instantiate`
* nroff: `alex`!!, `proselint`, `write-good`
-* Objective-C: `clang`
-* Objective-C++: `clang`
-* OCaml: `merlin` (see |ale-ocaml-merlin|), `ols`
+* Objective-C: `clang`, `clangd`, `uncrustify`, `ccls`
+* Objective-C++: `clang`, `clangd`, `uncrustify`
+* OCaml: `merlin` (see |ale-ocaml-merlin|), `ols`, `ocamlformat`
+* Pawn: `uncrustify`
* Perl: `perl -c`, `perl-critic`, `perltidy`
-* PHP: `hack`, `hackfmt`, `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`
+* Perl6: `perl6 -c`
+* PHP: `langserver`, `phan`, `php -l`, `phpcs`, `phpmd`, `phpstan`, `phpcbf`, `php-cs-fixer`, `psalm`!!
* PO: `alex`!!, `msgfmt`, `proselint`, `write-good`
* Pod: `alex`!!, `proselint`, `write-good`
* Pony: `ponyc`
+* Prolog: `swipl`
* proto: `protoc-gen-lint`
* Pug: `pug-lint`
* Puppet: `languageserver`, `puppet`, `puppet-lint`
-* Python: `autopep8`, `black`, `flake8`, `isort`, `mypy`, `prospector`, `pycodestyle`, `pyls`, `pyre`, `pylint`!!, `yapf`
+* Python: `autopep8`, `black`, `flake8`, `isort`, `mypy`, `prospector`, `pycodestyle`, `pyls`, `pyre`, `pylint`!!, `vulture`!!, `yapf`
* QML: `qmlfmt`, `qmllint`
* R: `lintr`
* ReasonML: `merlin`, `ols`, `refmt`
* reStructuredText: `alex`!!, `proselint`, `redpen`, `rstcheck`, `vale`, `write-good`
* Re:VIEW: `redpen`
* RPM spec: `rpmlint`
-* Ruby: `brakeman`, `rails_best_practices`!!, `reek`, `rubocop`, `ruby`, `rufo`
+* Ruby: `brakeman`, `rails_best_practices`!!, `reek`, `rubocop`, `ruby`, `rufo`, `solargraph`
* Rust: `cargo`!!, `rls`, `rustc` (see |ale-integration-rust|), `rustfmt`
* SASS: `sass-lint`, `stylelint`
* SCSS: `prettier`, `sass-lint`, `scss-lint`, `stylelint`
-* Scala: `fsc`, `scalac`, `scalafmt`, `scalastyle`
+* Scala: `fsc`, `sbtserver`, `scalac`, `scalafmt`, `scalastyle`
* Slim: `slim-lint`
* SML: `smlnj`
* Solidity: `solhint`, `solium`
* Stylus: `stylelint`
-* SQL: `sqlint`
+* SQL: `sqlint`, `sqlfmt`
* Swift: `swiftlint`, `swiftformat`
* Tcl: `nagelfar`!!
-* Terraform: `tflint`
+* Terraform: `fmt`, `tflint`
* Texinfo: `alex`!!, `proselint`, `write-good`
* Text^: `alex`!!, `proselint`, `redpen`, `textlint`, `vale`, `write-good`
* Thrift: `thrift`
* TypeScript: `eslint`, `prettier`, `tslint`, `tsserver`, `typecheck`
+* VALA: `uncrustify`
* Verilog: `iverilog`, `verilator`
* Vim: `vint`
* Vim help^: `alex`!!, `proselint`, `write-good`
* Vue: `prettier`, `vls`
* XHTML: `alex`!!, `proselint`, `write-good`
* XML: `xmllint`
-* YAML: `swaglint`, `yamllint`
+* YAML: `prettier`, `swaglint`, `yamllint`
+* YANG: `yang-lsp`
===============================================================================
3. Linting *ale-lint*
@@ -483,12 +560,14 @@ circumstances.
ALE will report problems with your code in the following ways, listed with
their relevant options.
-* By updating loclist. (On by default) - |g:ale_set_loclist|
-* By updating quickfix. (Off by default) - |g:ale_set_quickfix|
-* By setting error highlights. - |g:ale_set_highlights|
-* By creating signs in the sign column. - |g:ale_set_signs|
-* By echoing messages based on your cursor. - |g:ale_echo_cursor|
-* By showing balloons for your mouse cursor - |g:ale_set_balloons|
+* By updating loclist. (On by default) - |g:ale_set_loclist|
+* By updating quickfix. (Off by default) - |g:ale_set_quickfix|
+* By setting error highlights. - |g:ale_set_highlights|
+* By creating signs in the sign column. - |g:ale_set_signs|
+* By echoing messages based on your cursor. - |g:ale_echo_cursor|
+* By inline text based on your cursor. - |g:ale_virtualtext_cursor|
+* By displaying the preview based on your cursor. - |g:ale_cursor_detail|
+* By showing balloons for your mouse cursor - |g:ale_set_balloons|
Please consult the documentation for each option, which can reveal some other
ways of tweaking the behaviour of each way of displaying problems. You can
@@ -509,6 +588,68 @@ ALE offers several options for controlling which linters are run.
* Only running linters you asked for. - |g:ale_linters_explicit|
+-------------------------------------------------------------------------------
+3.1 Other Sources *ale-lint-other-sources*
+
+Problems for a buffer can be taken from other sources and rendered by ALE.
+This allows ALE to be used in combination with other plugins which also want
+to display any problems they might find with a buffer. ALE's API includes the
+following components for making this possible.
+
+* |ale#other_source#StartChecking()| - Tell ALE that a buffer is being checked.
+* |ale#other_source#ShowResults()| - Show results from another source.
+* |ALEWantResults| - A signal for when ALE wants results.
+
+Other resources can provide results for ALE to display at any time, following
+ALE's loclist format. (See |ale-loclist-format|) For example: >
+
+ " Tell ALE to show some results.
+ " This function can be called at any time.
+ call ale#other_source#ShowResults(bufnr(''), 'some-linter-name', [
+ \ {'text': 'Something went wrong', 'lnum': 13},
+ \])
+<
+
+Other sources should use a unique name for identifying themselves. A single
+linter name can be used for all problems from another source, or a series of
+unique linter names can be used. Results can be cleared for that source by
+providing an empty List.
+
+|ale#other_source#StartChecking()| should be called whenever another source
+starts checking a buffer, so other tools can know that a buffer is being
+checked by some plugin. The |ALEWantResults| autocmd event can be used to
+start checking a buffer for problems every time that ALE does. When
+|ALEWantResults| is signaled, |g:ale_want_results_buffer| will be set to the
+number of the buffer that ALE wants to check.
+|ale#other_source#StartChecking()| should be called synchronously, and other
+sources should perform their checks on a buffer in the background
+asynchronously, so they don't interrupt editing.
+
+A plugin might integrate its own checks with ALE like so: >
+
+ augroup SomeGroupName
+ autocmd!
+ autocmd User ALEWantResults call Hook(g:ale_want_results_buffer)
+ augroup END
+
+ function! DoBackgroundWork(buffer) abort
+ " Start some work in the background here.
+ " ...
+ " Then call WorkDone(a:buffer, results)
+ endfunction
+
+ function! Hook(buffer) abort
+ " Tell ALE we're going to check this buffer.
+ call ale#other_source#StartChecking(a:buffer, 'some-name')
+ call DoBackgroundWork(a:buffer)
+ endfunction
+
+ function! WorkDone(buffer, results) abort
+ " Send results to ALE after they have been collected.
+ call ale#other_source#ShowResults(buffer, 'some-name', a:results)
+ endfunction
+<
+
===============================================================================
4. Fixing Problems *ale-fix*
@@ -644,10 +785,10 @@ servers. LSP linters can be used in combination with any other linter, and
will automatically connect to LSP servers when needed. ALE also supports
`tsserver` for TypeScript, which uses a different but very similar protocol.
-ALE supports the following LSP/tsserver features.
+ALE supports the following LSP/tsserver features:
1. Diagnostics/linting - Enabled via selecting linters as usual.
-2. Completion (Only for tsserver)
+2. Completion
3. Go to definition
@@ -655,18 +796,29 @@ ALE supports the following LSP/tsserver features.
5.1 Completion *ale-completion*
ALE offers limited support for automatic completion of code while you type.
-Completion is only supported while a least one LSP linter is enabled. ALE
+Completion is only supported while at least one LSP linter is enabled. ALE
will only suggest symbols provided by the LSP servers.
Suggestions will be made while you type after completion is enabled.
-Completion can be enabled by setting |g:ale_completion_enabled| to `1`. The
-delay for completion can be configured with |g:ale_completion_delay|. ALE will
-only suggest so many possible matches for completion. The maximum number of
-items can be controlled with |g:ale_completion_max_suggestions|.
+Completion can be enabled by setting |g:ale_completion_enabled| to `1`. This
+setting must be set to `1` before ALE is loaded. The delay for completion can
+be configured with |g:ale_completion_delay|. ALE will only suggest so many
+possible matches for completion. The maximum number of items can be controlled
+with |g:ale_completion_max_suggestions|.
If you don't like some of the suggestions you see, you can filter them out
with |g:ale_completion_excluded_words| or |b:ale_completion_excluded_words|.
+ *ale-completion-completopt-bug*
+
+ALE implements completion as you type by temporarily adjusting |completeopt|
+before opening the omnicomplete menu with <C-x><C-o>. In some versions of Vim,
+the value set for the option will not be respected. If you experience issues
+with Vim automatically inserting text while you type, set the following option
+in vimrc, and your issues should go away. >
+
+ set completeopt=menu,menuone,preview,noselect,noinsert
+<
-------------------------------------------------------------------------------
5.2 Go To Definition *ale-go-to-definition*
@@ -698,12 +850,34 @@ at the cursor taken from LSP linters. The following commands are supported:
|ALEHover| - Print information about the symbol at the cursor.
-If |b:ale_set_balloons| is set to `1` and your version of Vim supports the
+If |g:ale_set_balloons| is set to `1` and your version of Vim supports the
|balloon_show()| function, then "hover" information also show up when you move
the mouse over a symbol in a buffer. Diagnostic information will take priority
over hover information for balloons. If a line contains a problem, that
problem will be displayed in a balloon instead of hover information.
+For Vim 8.1+ terminals, mouse hovering is disabled by default. Enabling
+|balloonexpr| commands in terminals can cause scrolling issues in terminals,
+so ALE will not attempt to show balloons unless |g:ale_set_balloons| is set to
+`1` before ALE is loaded.
+
+For enabling mouse support in terminals, you may have to change your mouse
+settings. For example: >
+
+ " Example mouse settings.
+ " You will need to try different settings, depending on your terminal.
+ set mouse=a
+ set ttymouse=xterm
+<
+
+-------------------------------------------------------------------------------
+5.5 Symbol Search *ale-symbol-search*
+
+ALE supports searching for workspace symbols via LSP linters. The following
+commands are supported:
+
+|ALESymbolSearch| - Search for symbols in the workspace.
+
===============================================================================
6. Global Options *ale-options*
@@ -751,6 +925,20 @@ g:ale_change_sign_column_color *g:ale_change_sign_column_color*
windows.
+g:ale_close_preview_on_insert *g:ale_close_preview_on_insert*
+
+ Type: |Number|
+ Default: `0`
+
+ When this option is set to `1`, ALE's |preview-window| will be automatically
+ closed upon entering Insert Mode. This option can be used in combination
+ with |g:ale_cursor_detail| for automatically displaying the preview window
+ on problem lines, and automatically closing it again when editing text.
+
+ This setting must be set to `1` before ALE is loaded for this behavior
+ to be enabled. See |ale-lint-settings-on-startup|.
+
+
g:ale_command_wrapper *g:ale_command_wrapper*
*b:ale_command_wrapper*
Type: |String|
@@ -802,6 +990,9 @@ g:ale_completion_enabled *g:ale_completion_enabled*
When this option is set to `1`, completion support will be enabled.
+ This setting must be set to `1` before ALE is loaded for this behavior
+ to be enabled.
+
See |ale-completion|
@@ -839,6 +1030,27 @@ g:ale_completion_max_suggestions *g:ale_completion_max_suggestions*
Adjust this option as needed, depending on the complexity of your codebase
and your available processing power.
+g:ale_cursor_detail *g:ale_cursor_detail*
+
+ Type: |Number|
+ Default: `0`
+
+ When this option is set to `1`, ALE's |preview-window| will be automatically
+ opened when the cursor moves onto lines with problems. ALE will search for
+ problems using the same logic that |g:ale_echo_cursor| uses. The preview
+ window will be closed automatically when you move away from the line.
+
+ Messages are only displayed after a short delay. See |g:ale_echo_delay|.
+
+ The preview window is opened without stealing focus, which means your cursor
+ will stay in the same buffer as it currently is.
+
+ The preview window can be closed automatically upon entering Insert mode
+ by setting |g:ale_close_preview_on_insert| to `1`.
+
+ Either this setting or |g:ale_echo_cursor| must be set to `1` before ALE is
+ loaded for messages to be displayed. See |ale-lint-settings-on-startup|.
+
g:ale_echo_cursor *g:ale_echo_cursor*
@@ -849,11 +1061,14 @@ g:ale_echo_cursor *g:ale_echo_cursor*
cursor is near a warning or error. ALE will attempt to find the warning or
error at a column nearest to the cursor when the cursor is resting on a line
which contains a warning or error. This option can be set to `0` to disable
- this behaviour.
- The format of the message can be customizable in |g:ale_echo_msg_format|.
+ this behavior.
- You should set this setting once before ALE is loaded, and restart Vim if
- you want to change your preferences. See |ale-lint-settings-on-startup|.
+ Messages are only displayed after a short delay. See |g:ale_echo_delay|.
+
+ The format of the message can be customized with |g:ale_echo_msg_format|.
+
+ Either this setting or |g:ale_cursor_detail| must be set to `1` before ALE
+ is loaded for messages to be displayed. See |ale-lint-settings-on-startup|.
g:ale_echo_delay *g:ale_echo_delay*
@@ -862,7 +1077,7 @@ g:ale_echo_delay *g:ale_echo_delay*
Default: `10`
Given any integer, this option controls the number of milliseconds before
- ALE will echo a message for a problem near the cursor.
+ ALE will echo or preview a message for a problem near the cursor.
The value can be increased to decrease the amount of processing ALE will do
for files displaying a large number of problems.
@@ -980,6 +1195,9 @@ b:ale_fix_on_save *b:ale_fix_on_save*
after files are fixed, only when the buffer is open, or re-opened. Changes
to the file will be saved to the file on disk.
+ Files will not be fixed on `:wq`, so you should check your code before
+ closing a buffer.
+
Fixing files can be disabled or enabled for individual buffers by setting
`b:ale_fix_on_save` to `0` or `1`.
@@ -1109,6 +1327,12 @@ g:ale_lint_on_text_changed *g:ale_lint_on_text_changed*
ALE will check buffers after a short delay, with a timer which resets on
each change. The delay can be configured by adjusting the |g:ale_lint_delay|
variable.
+ *ale-linting-interrupts-mapping*
+
+ Due to a bug in Vim, ALE can interrupt mappings with pending key presses,
+ per |timeoutlen|. If this happens, follow the advice for enabling
+ |g:ale_lint_on_insert_leave| below, and set this option to `'normal'`, or
+ disable it entirely.
You should set this setting once before ALE is loaded, and restart Vim if
you want to change your preferences. See |ale-lint-settings-on-startup|.
@@ -1124,7 +1348,7 @@ g:ale_lint_on_insert_leave *g:ale_lint_on_insert_leave*
ALE will not lint files when you escape insert mode with |CTRL-C| by
default. You can make ALE lint files with this option when you use |CTRL-C|
- with the following keybind. >
+ with the following mapping. >
" Make using Ctrl+C do the same as Escape, to trigger autocmd commands
inoremap <C-c> <Esc>
@@ -1152,6 +1376,7 @@ g:ale_linter_aliases *g:ale_linter_aliases*
\ 'systemverilog': 'verilog',
\ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'],
\ 'vimwiki': 'markdown',
+ \ 'vue': ['vue', 'javascript'],
\ 'zsh': 'sh',
\}
<
@@ -1178,10 +1403,12 @@ g:ale_linter_aliases *g:ale_linter_aliases*
ALE will first look for aliases for filetypes in the `b:ale_linter_aliases`
variable, then `g:ale_linter_aliases`, and then a default Dictionary.
- `b:ale_linter_aliases` can be set to a |List|, to tell ALE to load the
- linters for specific filetypes for a given buffer. >
+ `b:ale_linter_aliases` can be set to a |List| or a |String|, to tell ALE to
+ load the linters for specific filetypes for a given buffer. >
let b:ale_linter_aliases = ['html', 'javascript', 'css']
+ " OR, Alias a filetype to only a single filetype with a String.
+ let b:ale_linter_aliases = 'javascript'
<
No linters will be loaded when the buffer's filetype is empty.
@@ -1198,13 +1425,17 @@ g:ale_linters *g:ale_linters*
{
\ 'csh': ['shell'],
+ \ 'elixir': ['credo', 'dialyxir', 'dogma', 'elixir-ls'],
\ 'go': ['gofmt', 'golint', 'go vet'],
+ \ 'hack': ['hack'],
\ 'help': [],
\ 'perl': ['perlcritic'],
+ \ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint'],
\ 'rust': ['cargo'],
\ 'spec': [],
\ 'text': [],
+ \ 'vue': ['eslint', 'vls'],
\ 'zsh': ['shell'],
\}
<
@@ -1652,6 +1883,49 @@ g:ale_use_global_executables *g:ale_use_global_executables*
options.
+g:ale_virtualtext_cursor *g:ale_virtualtext_cursor*
+
+ Type: |Number|
+ Default: `0`
+
+ When this option is set to `1`, a message will be shown when a cursor is
+ near a warning or error. ALE will attempt to find the warning or error at a
+ column nearest to the cursor when the cursor is resting on a line which
+ contains a warning or error. This option can be set to `0` to disable this
+ behavior.
+
+ Messages are only displayed after a short delay. See |g:ale_virtualtext_delay|.
+
+ Messages can be prefixed prefixed with a string. See |g:ale_virtualtext_prefix|.
+
+ ALE will use the following highlight groups for problems:
+
+ |ALEVirtualTextError| - Items with `'type': 'E'`
+ |ALEVirtualTextWarning| - Items with `'type': 'W'`
+ |ALEVirtualTextInfo| - Items with `'type': 'I'`
+ |ALEVirtualTextStyleError| - Items with `'type': 'E'` and `'sub_type': 'style'`
+ |ALEVirtualTextStyleWarning| - Items with `'type': 'W'` and `'sub_type': 'style'`
+
+
+g:ale_virtualtext_delay *g:ale_virtualtext_delay*
+b:ale_virtualtext_delay *b:ale_virtualtext_delay*
+ Type: |Number|
+ Default: `10`
+
+ Given any integer, this option controls the number of milliseconds before
+ ALE will show a message for a problem near the cursor.
+
+ The value can be increased to decrease the amount of processing ALE will do
+ for files displaying a large number of problems.
+
+
+g:ale_virtualtext_prefix *g:ale_virtualtext_prefix*
+
+ Type: |String|
+ Default: `'> '`
+
+ Prefix to be used with |g:ale_virtualtext_cursor|.
+
g:ale_virtualenv_dir_names *g:ale_virtualenv_dir_names*
b:ale_virtualenv_dir_names *b:ale_virtualenv_dir_names*
@@ -1718,7 +1992,7 @@ ALEError *ALEError*
Default: `highlight link ALEError SpellBad`
- The highlight used for highlighted errors. See |g:ale_set_highlights|.
+ The highlight for highlighted errors. See |g:ale_set_highlights|.
ALEErrorLine *ALEErrorLine*
@@ -1735,21 +2009,21 @@ ALEErrorSign *ALEErrorSign*
Default: `highlight link ALEErrorSign error`
- The highlight used for error signs. See |g:ale_set_signs|.
+ The highlight for error signs. See |g:ale_set_signs|.
ALEInfo *ALEInfo.*
*ALEInfo-highlight*
Default: `highlight link ALEInfo ALEWarning`
- The highlight used for highlighted info messages. See |g:ale_set_highlights|.
+ The highlight for highlighted info messages. See |g:ale_set_highlights|.
ALEInfoSign *ALEInfoSign*
Default: `highlight link ALEInfoSign ALEWarningSign`
- The highlight used for info message signs. See |g:ale_set_signs|.
+ The highlight for info message signs. See |g:ale_set_signs|.
ALEInfoLine *ALEInfoLine*
@@ -1766,35 +2040,70 @@ ALEStyleError *ALEStyleError*
Default: `highlight link ALEStyleError ALEError`
- The highlight used for highlighted style errors. See |g:ale_set_highlights|.
+ The highlight for highlighted style errors. See |g:ale_set_highlights|.
ALEStyleErrorSign *ALEStyleErrorSign*
Default: `highlight link ALEStyleErrorSign ALEErrorSign`
- The highlight used for style error signs. See |g:ale_set_signs|.
+ The highlight for style error signs. See |g:ale_set_signs|.
ALEStyleWarning *ALEStyleWarning*
Default: `highlight link ALEStyleWarning ALEError`
- The highlight used for highlighted style warnings. See |g:ale_set_highlights|.
+ The highlight for highlighted style warnings. See |g:ale_set_highlights|.
ALEStyleWarningSign *ALEStyleWarningSign*
Default: `highlight link ALEStyleWarningSign ALEWarningSign`
- The highlight used for style warning signs. See |g:ale_set_signs|.
+ The highlight for style warning signs. See |g:ale_set_signs|.
+
+
+ALEVirtualTextError *ALEVirtualTextError*
+
+ Default: `highlight link ALEVirtualTextError ALEError`
+
+ The highlight for virtualtext errors. See |g:ale_virtualtext_cursor|.
+
+
+ALEVirtualTextInfo *ALEVirtualTextInfo*
+
+ Default: `highlight link ALEVirtualTextInfo ALEVirtualTextWarning`
+
+ The highlight for virtualtext info. See |g:ale_virtualtext_cursor|.
+
+
+ALEVirtualTextStyleError *ALEVirtualTextStyleError*
+
+ Default: `highlight link ALEVirtualTextStyleError ALEVirtualTextError`
+
+ The highlight for virtualtext style errors. See |g:ale_virtualtext_cursor|.
+
+
+ALEVirtualTextStyleWarning *ALEVirtualTextStyleWarning*
+
+ Default: `highlight link ALEVirtualTextStyleWarning ALEVirtualTextWarning`
+
+ The highlight for virtualtext style warnings. See |g:ale_virtualtext_cursor|.
+
+
+ALEVirtualTextWarning *ALEVirtualTextWarning*
+
+ Default: `highlight link ALEVirtualTextWarning ALEWarning`
+
+ The highlight for virtualtext errors. See |g:ale_virtualtext_cursor|.
ALEWarning *ALEWarning*
Default: `highlight link ALEWarning SpellCap`
- The highlight used for highlighted warnings. See |g:ale_set_highlights|.
+ The highlight for highlighted warnings. See |g:ale_set_highlights|.
ALEWarningLine *ALEWarningLine*
@@ -1811,7 +2120,7 @@ ALEWarningSign *ALEWarningSign*
Default: `highlight link ALEWarningSign todo`
- The highlight used for warning signs. See |g:ale_set_signs|.
+ The highlight for warning signs. See |g:ale_set_signs|.
-------------------------------------------------------------------------------
@@ -1944,6 +2253,14 @@ ALEHover *ALEHover*
A plug mapping `<Plug>(ale_hover)` is defined for this command.
+
+ALESymbolSearch `<query>` *ALESymbolSearch*
+
+ Search for symbols in the workspace, taken from any available LSP linters.
+
+ The arguments provided to this command will be used as a search query for
+ finding symbols in the workspace, such as functions, types, etc.
+
*:ALELint*
ALELint *ALELint*
@@ -2316,6 +2633,13 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
`type` - Defaults to `'E'`.
`nr` - Defaults to `-1`.
+ Numeric error code. If `nr` is not `-1`, `code`
+ likely should contain the string representation of
+ the same value.
+ `code` - No default; may be unset.
+
+ Human-readable |String| error code.
+
`executable` A |String| naming the executable itself which
will be run. This value will be used to check if the
program requested is installed or not.
@@ -2456,6 +2780,9 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
`initialization_options_callback` may be defined to
pass initialization options to the LSP.
+ An optional `lsp_config` or `lsp_config_callback` may
+ be defined to pass configuration settings to the LSP.
+
`address_callback` A |String| or |Funcref| for a callback function
accepting a buffer number. A |String| should be
returned with an address to connect to.
@@ -2516,6 +2843,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
This can be used in place of `initialization_options`
when more complicated processing is needed.
+ `lsp_config` A |Dictionary| of configuration settings for LSPs.
+ This will be fed (as JSON) to the LSP in the
+ workspace/didChangeConfiguration command.
+
+ `lsp_config_callback` A |String| or |Funcref| for a callback function
+ accepting a buffer number. A |Dictionary| should be
+ returned for configuration settings to pass the LSP.
+ This can be used in place of `lsp_config` when more
+ complicated processing is needed.
+
Only one of `command`, `command_callback`, or `command_chain` should be
specified. `command_callback` is generally recommended when a command string
needs to be generated dynamically, or any global options are used.
@@ -2616,6 +2953,25 @@ ale#linter#PreventLoading(filetype) *ale#linter#PreventLoading()*
|runtimepath| for that filetype. This function can be called from vimrc or
similar to prevent ALE from loading linters.
+ale#other_source#ShowResults(buffer, linter_name, loclist)
+ *ale#other_source#ShowResults()*
+
+ Show results from another source of information.
+
+ `buffer` must be a valid buffer number, and `linter_name` must be a unique
+ name for identifying another source of information. The `loclist` given
+ where the problems in a buffer are, and should be provided in the format ALE
+ uses for regular linter results. See |ale-loclist-format|.
+
+
+ale#other_source#StartChecking(buffer, linter_name)
+ *ale#other_source#StartChecking()*
+
+ Tell ALE that another source of information has started checking a buffer.
+
+ `buffer` must be a valid buffer number, and `linter_name` must be a unique
+ name for identifying another source of information.
+
ale#statusline#Count(buffer) *ale#statusline#Count()*
@@ -2644,10 +3000,21 @@ b:ale_linted *b:ale_linted*
echo getbufvar(bufnr(''), 'ale_linted', 0) > 0 ? 'checked' : 'not checked'
<
+g:ale_want_results_buffer *g:ale_want_results_buffer*
+
+ `g:ale_want_results_buffer` is set to the number of the buffer being checked
+ when the |ALEWantResults| event is signaled. This variable should be read to
+ figure out which buffer other sources should lint.
+
+
ALELintPre *ALELintPre-autocmd*
+ *ALELintPre*
ALELintPost *ALELintPost-autocmd*
+ *ALELintPost*
ALEFixPre *ALEFixPre-autocmd*
+ *ALEFixPre*
ALEFixPost *ALEFixPost-autocmd*
+ *ALEFixPost*
These |User| autocommands are triggered before and after every lint or fix
cycle. They can be used to update statuslines, send notifications, etc.
@@ -2660,8 +3027,8 @@ ALEFixPost *ALEFixPost-autocmd*
augroup ALEProgress
autocmd!
autocmd User ALELintPre hi Statusline ctermfg=darkgrey
- autocmd User ALELintPOST hi Statusline ctermfg=NONE
- augroup end
+ autocmd User ALELintPost hi Statusline ctermfg=NONE
+ augroup END
<
Or to display the progress in the statusline:
>
@@ -2671,10 +3038,11 @@ ALEFixPost *ALEFixPost-autocmd*
autocmd!
autocmd User ALELintPre let s:ale_running = 1 | redrawstatus
autocmd User ALELintPost let s:ale_running = 0 | redrawstatus
- augroup end
+ augroup END
<
ALEJobStarted *ALEJobStarted-autocmd*
+ *ALEJobStarted*
This |User| autocommand is triggered immediately after a job is successfully
run. This provides better accuracy for checking linter status with
@@ -2682,6 +3050,22 @@ ALEJobStarted *ALEJobStarted-autocmd*
triggered before any linters are executed.
+ALEWantResults *ALEWantResults-autocmd*
+ *ALEWantResults*
+
+ This |User| autocommand is triggered before ALE begins a lint cycle. Another
+ source can respond by calling |ale#other_source#StartChecking()|, and
+ |ALELintPre| will be signaled thereafter, to allow other plugins to know
+ that another source is checking the buffer.
+
+ |g:ale_want_results_buffer| will be set to the number for a buffer being
+ checked when the event is signaled, and deleted after the event is done.
+ This variable should be read to know which buffer to check.
+
+ Other plugins can use this event to start checking buffers when ALE events
+ for checking buffers are triggered.
+
+
===============================================================================
10. Special Thanks *ale-special-thanks*
diff --git a/plugin/ale.vim b/plugin/ale.vim
index f0f90b6b..7231d1bd 100644
--- a/plugin/ale.vim
+++ b/plugin/ale.vim
@@ -14,7 +14,7 @@ let g:loaded_ale_dont_use_this_in_other_plugins_please = 1
" A flag for detecting if the required features are set.
if has('nvim')
- let s:has_features = has('timers')
+ let s:has_features = has('timers') && has('nvim-0.2.0')
else
" Check if Job and Channel functions are available, instead of the
" features. This works better on old MacVim versions.
@@ -24,7 +24,7 @@ endif
if !s:has_features
" Only output a warning if editing some special files.
if index(['', 'gitcommit'], &filetype) == -1
- execute 'echoerr ''ALE requires NeoVim >= 0.1.5 or Vim 8 with +timers +job +channel'''
+ execute 'echoerr ''ALE requires NeoVim >= 0.2.0 or Vim 8 with +timers +job +channel'''
execute 'echoerr ''Please update your editor appropriately.'''
endif
@@ -109,6 +109,16 @@ let g:ale_set_highlights = get(g:, 'ale_set_highlights', has('syntax'))
" This flag can be set to 0 to disable echoing when the cursor moves.
let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1)
+" This flag can be set to 1 to automatically show errors in the preview window.
+let g:ale_cursor_detail = get(g:, 'ale_cursor_detail', 0)
+
+" This flag can be set to 1 to enable virtual text when the cursor moves.
+let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', 0)
+
+" This flag can be set to 1 to automatically close the preview window upon
+" entering Insert Mode.
+let g:ale_close_preview_on_insert = get(g:, 'ale_close_preview_on_insert', 0)
+
" This flag can be set to 0 to disable balloon support.
let g:ale_set_balloons = get(g:, 'ale_set_balloons', has('balloon_eval') && has('gui_running'))
@@ -126,6 +136,9 @@ let g:ale_history_log_output = get(g:, 'ale_history_log_output', 1)
" Enable automatic completion with LSP servers and tsserver
let g:ale_completion_enabled = get(g:, 'ale_completion_enabled', 0)
+" Enable automatic detection of pipenv for Python linters.
+let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', 0)
+
if g:ale_set_balloons
call ale#balloon#Enable()
endif
@@ -184,6 +197,9 @@ command! -bar ALEFindReferences :call ale#references#Find()
command! -bar ALEHover :call ale#hover#Show(bufnr(''), getcurpos()[1],
\ getcurpos()[2], {})
+" Search for appearances of a symbol, such as a type name or function name.
+command! -nargs=1 ALESymbolSearch :call ale#symbol#Search(<q-args>)
+
" <Plug> mappings for commands
nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return>
nnoremap <silent> <Plug>(ale_previous_wrap) :ALEPreviousWrap<Return>
@@ -217,4 +233,8 @@ augroup ALECleanupGroup
" Clean up buffers automatically when they are unloaded.
autocmd BufDelete * if exists('*ale#engine#Cleanup') | call ale#engine#Cleanup(str2nr(expand('<abuf>'))) | endif
autocmd QuitPre * call ale#events#QuitEvent(str2nr(expand('<abuf>')))
+
+ if exists('##VimSuspend')
+ autocmd VimSuspend * if exists('*ale#engine#CleanupEveryBuffer') | call ale#engine#CleanupEveryBuffer() | endif
+ endif
augroup END
diff --git a/run-tests.bat b/run-tests.bat
index a3b47056..9ba6b554 100644
--- a/run-tests.bat
+++ b/run-tests.bat
@@ -13,7 +13,7 @@ set VADER_OUTPUT_FILE=%~dp0\vader_output
REM Automatically re-run Windows tests, which can fail some times.
set tries=0
-RUN_TESTS:
+:RUN_TESTS
set /a tries=%tries%+1
type nul > "%VADER_OUTPUT_FILE%"
C:\vim\vim\vim80\vim.exe -u test/vimrc "+Vader! %tests%"
@@ -23,7 +23,7 @@ IF %code% EQU 0 GOTO :SHOW_RESULTS
IF %tries% GEQ 2 GOTO :SHOW_RESULTS
GOTO :RUN_TESTS
-SHOW_RESULTS:
+:SHOW_RESULTS
type "%VADER_OUTPUT_FILE%"
del "%VADER_OUTPUT_FILE%"
diff --git a/test/hack_files/testfile.php b/test/command_callback/ccls_paths/with_ccls-root/.ccls-root
index e69de29b..e69de29b 100644
--- a/test/hack_files/testfile.php
+++ b/test/command_callback/ccls_paths/with_ccls-root/.ccls-root
diff --git a/test/command_callback/ccls_paths/with_ccls/.ccls b/test/command_callback/ccls_paths/with_ccls/.ccls
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/ccls_paths/with_ccls/.ccls
diff --git a/test/command_callback/ccls_paths/with_compile_commands_json/compile_commands.json b/test/command_callback/ccls_paths/with_compile_commands_json/compile_commands.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/ccls_paths/with_compile_commands_json/compile_commands.json
diff --git a/test/command_callback/cquery_paths/with_compile_commands_json/compile_commands.json b/test/command_callback/cquery_paths/with_compile_commands_json/compile_commands.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/cquery_paths/with_compile_commands_json/compile_commands.json
diff --git a/test/command_callback/cquery_paths/with_cquery/.cquery b/test/command_callback/cquery_paths/with_cquery/.cquery
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/cquery_paths/with_cquery/.cquery
diff --git a/test/command_callback/elixir_paths/mix_project/lib/app.ex b/test/command_callback/elixir_paths/mix_project/lib/app.ex
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/elixir_paths/mix_project/lib/app.ex
diff --git a/test/command_callback/elixir_paths/mix_project/mix.exs b/test/command_callback/elixir_paths/mix_project/mix.exs
new file mode 100644
index 00000000..419685ae
--- /dev/null
+++ b/test/command_callback/elixir_paths/mix_project/mix.exs
@@ -0,0 +1,3 @@
+defmodule Test.MixProject do
+ # fake mix project file
+end
diff --git a/test/command_callback/elixir_paths/umbrella_project/apps/app1/lib/app.ex b/test/command_callback/elixir_paths/umbrella_project/apps/app1/lib/app.ex
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/elixir_paths/umbrella_project/apps/app1/lib/app.ex
diff --git a/test/command_callback/elixir_paths/umbrella_project/apps/app1/mix.exs b/test/command_callback/elixir_paths/umbrella_project/apps/app1/mix.exs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/elixir_paths/umbrella_project/apps/app1/mix.exs
diff --git a/test/command_callback/elixir_paths/umbrella_project/apps/app2/lib/app.ex b/test/command_callback/elixir_paths/umbrella_project/apps/app2/lib/app.ex
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/elixir_paths/umbrella_project/apps/app2/lib/app.ex
diff --git a/test/command_callback/elixir_paths/umbrella_project/apps/app2/mix.exs b/test/command_callback/elixir_paths/umbrella_project/apps/app2/mix.exs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/elixir_paths/umbrella_project/apps/app2/mix.exs
diff --git a/test/command_callback/elixir_paths/umbrella_project/mix.exs b/test/command_callback/elixir_paths/umbrella_project/mix.exs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/elixir_paths/umbrella_project/mix.exs
diff --git a/test/command_callback/go_paths/go1/prj1/file.go b/test/command_callback/go_paths/go1/prj1/file.go
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/go_paths/go1/prj1/file.go
diff --git a/test/command_callback/go_paths/go2/prj2/file.go b/test/command_callback/go_paths/go2/prj2/file.go
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/go_paths/go2/prj2/file.go
diff --git a/test/command_callback/julia-languageserver-project/REQUIRE b/test/command_callback/julia-languageserver-project/REQUIRE
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/julia-languageserver-project/REQUIRE
diff --git a/test/command_callback/julia-languageserver-project/test.jl b/test/command_callback/julia-languageserver-project/test.jl
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/julia-languageserver-project/test.jl
diff --git a/test/command_callback/mix_paths/wrapped_project/mix.exs b/test/command_callback/mix_paths/wrapped_project/mix.exs
deleted file mode 100644
index d2d855e6..00000000
--- a/test/command_callback/mix_paths/wrapped_project/mix.exs
+++ /dev/null
@@ -1 +0,0 @@
-use Mix.Config
diff --git a/test/command_callback/psalm-project/vendor/bin/psalm-language-server b/test/command_callback/psalm-project/vendor/bin/psalm-language-server
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/psalm-project/vendor/bin/psalm-language-server
diff --git a/test/command_callback/stack_build_paths/stack.yaml b/test/command_callback/stack_build_paths/stack.yaml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/stack_build_paths/stack.yaml
diff --git a/test/command_callback/stack_ghc_paths/stack.yaml b/test/command_callback/stack_ghc_paths/stack.yaml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/stack_ghc_paths/stack.yaml
diff --git a/test/command_callback/test_ada_gcc_command_callbacks.vader b/test/command_callback/test_ada_gcc_command_callbacks.vader
new file mode 100644
index 00000000..de6e355e
--- /dev/null
+++ b/test/command_callback/test_ada_gcc_command_callbacks.vader
@@ -0,0 +1,44 @@
+Before:
+ call ale#assert#SetUpLinterTest('ada', 'gcc')
+ call ale#test#SetFilename('dummy.adb')
+
+ function! GetOutputDir(command) abort
+ let l:split_command = split(a:command)
+ let l:index = index(l:split_command, '-o')
+ return l:split_command[l:index + 1]
+ endfunction
+
+ let b:out_file = GetOutputDir(ale_linters#ada#gcc#GetCommand(bufnr('')))
+
+After:
+ delfunction GetOutputDir
+
+ unlet! b:out_file
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(The executable should be configurable):
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc') . ' -x ada -c -gnatc'
+ \ . ' -o ' . b:out_file
+ \ . ' -I ' . ale#Escape(getcwd())
+ \ . ' -gnatwa -gnatq %t'
+
+ let b:ale_ada_gcc_executable = 'foo'
+
+ AssertLinter 'foo',
+ \ ale#Escape('foo') . ' -x ada -c -gnatc'
+ \ . ' -o ' . b:out_file
+ \ . ' -I ' . ale#Escape(getcwd())
+ \ . ' -gnatwa -gnatq %t'
+
+Execute(The options should be configurable):
+
+ let g:ale_ada_gcc_options = '--foo --bar'
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc') . ' -x ada -c -gnatc'
+ \ . ' -o ' . b:out_file
+ \ . ' -I ' . ale#Escape(getcwd())
+ \ . ' --foo --bar %t'
diff --git a/test/command_callback/test_ansible_lint_command_callback.vader b/test/command_callback/test_ansible_lint_command_callback.vader
new file mode 100644
index 00000000..ddc6c6c8
--- /dev/null
+++ b/test/command_callback/test_ansible_lint_command_callback.vader
@@ -0,0 +1,17 @@
+Before:
+ call ale#assert#SetUpLinterTest('ansible', 'ansible_lint')
+ let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
+
+After:
+ unlet! b:bin_dir
+ unlet! b:executable
+ call ale#assert#TearDownLinterTest()
+
+Execute(The ansible_lint command callback should return default string):
+ AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' -p %t'
+
+Execute(The ansible_lint executable should be configurable):
+ let g:ale_ansible_ansible_lint_executable = '~/.local/bin/ansible-lint'
+
+ AssertLinter '~/.local/bin/ansible-lint',
+ \ ale#Escape('~/.local/bin/ansible-lint') . ' -p %t'
diff --git a/test/command_callback/test_brakeman_command_callback.vader b/test/command_callback/test_brakeman_command_callback.vader
index 61be4caf..15dbbe1c 100644
--- a/test/command_callback/test_brakeman_command_callback.vader
+++ b/test/command_callback/test_brakeman_command_callback.vader
@@ -12,7 +12,8 @@ Execute(The brakeman command callback should detect absence of a valid Rails app
Execute(The brakeman command callback should find a valid Rails app root):
call ale#test#SetFilename('../ruby_fixtures/valid_rails_app/db/test.rb')
- AssertLinter 'brakeman', 'brakeman -f json -q -p '
+ AssertLinter 'brakeman', ale#Escape('brakeman')
+ \ . ' -f json -q -p '
\ . ale#Escape(ale#path#Simplify(g:dir . '/../ruby_fixtures/valid_rails_app'))
Execute(The brakeman command callback should include configured options):
@@ -20,5 +21,17 @@ Execute(The brakeman command callback should include configured options):
let g:ale_ruby_brakeman_options = '--combobulate'
- AssertLinter 'brakeman', 'brakeman -f json -q --combobulate -p '
+ AssertLinter 'brakeman', ale#Escape('brakeman')
+ \ . ' -f json -q --combobulate -p '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../ruby_fixtures/valid_rails_app'))
+
+Execute(Setting bundle appends 'exec brakeman'):
+ call ale#test#SetFilename('../ruby_fixtures/valid_rails_app/db/test.rb')
+
+ let g:ale_ruby_brakeman_executable = 'bundle'
+ let g:ale_ruby_brakeman_options = '--combobulate'
+
+ AssertLinter 'bundle', ale#Escape('bundle')
+ \ . ' exec brakeman'
+ \ . ' -f json -q --combobulate -p '
\ . ale#Escape(ale#path#Simplify(g:dir . '/../ruby_fixtures/valid_rails_app'))
diff --git a/test/command_callback/test_c_ccls_command_callbacks.vader b/test/command_callback/test_c_ccls_command_callbacks.vader
new file mode 100644
index 00000000..b8f3ab5b
--- /dev/null
+++ b/test/command_callback/test_c_ccls_command_callbacks.vader
@@ -0,0 +1,43 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>
+" Description: A language server for C
+
+Before:
+ call ale#assert#SetUpLinterTest('c', 'ccls')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The project root should be detected correctly using compile_commands.json file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_compile_commands_json/dummy.c')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_compile_commands_json')
+
+Execute(The project root should be detected correctly using .ccls file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_ccls/dummy.c')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_ccls')
+
+Execute(The project root should be detected correctly using .ccls-root file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_ccls-root/dummy.c')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_ccls-root')
+
+Execute(The executable should be configurable):
+ AssertLinter 'ccls', ale#Escape('ccls')
+
+ let b:ale_c_ccls_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar')
+
+Execute(The initialization options should be configurable):
+ AssertLSPOptions {}
+
+ let b:ale_c_ccls_init_options = { 'cacheDirectory': '/tmp/ccls' }
+
+ AssertLSPOptions { 'cacheDirectory': '/tmp/ccls' }
diff --git a/test/command_callback/test_c_clang_command_callbacks.vader b/test/command_callback/test_c_clang_command_callbacks.vader
index 87f7fd06..7d2ff0bf 100644
--- a/test/command_callback/test_c_clang_command_callbacks.vader
+++ b/test/command_callback/test_c_clang_command_callbacks.vader
@@ -1,4 +1,7 @@
Before:
+ Save g:ale_c_parse_makefile
+ let g:ale_c_parse_makefile = 0
+
call ale#assert#SetUpLinterTest('c', 'clang')
let b:command_tail = ' -S -x c -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())
diff --git a/test/command_callback/test_c_clang_tidy_command_callback.vader b/test/command_callback/test_c_clang_tidy_command_callback.vader
index 582d4798..f78d0ea7 100644
--- a/test/command_callback/test_c_clang_tidy_command_callback.vader
+++ b/test/command_callback/test_c_clang_tidy_command_callback.vader
@@ -7,7 +7,7 @@ After:
Execute(The clangtidy command default should be correct):
AssertLinter 'clang-tidy',
- \ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s'
+ \ ale#Escape('clang-tidy') . ' %s'
Execute(You should be able to remove the -checks option for clang-tidy):
let b:ale_c_clangtidy_checks = []
@@ -23,12 +23,14 @@ Execute(You should be able to set other checks for clang-tidy):
\ . ' -checks=' . ale#Escape('-*,clang-analyzer-*') . ' %s'
Execute(You should be able to manually set compiler flags for clang-tidy):
+ let b:ale_c_clangtidy_checks = ['*']
let b:ale_c_clangtidy_options = '-Wall'
AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
Execute(The build directory should be configurable):
+ let b:ale_c_clangtidy_checks = ['*']
let b:ale_c_build_dir = '/foo/bar'
AssertLinter 'clang-tidy',
@@ -37,6 +39,7 @@ Execute(The build directory should be configurable):
\ . ' -p ' . ale#Escape('/foo/bar')
Execute(The build directory setting should override the options):
+ let b:ale_c_clangtidy_checks = ['*']
let b:ale_c_build_dir = '/foo/bar'
let b:ale_c_clangtidy_options = '-Wall'
@@ -48,6 +51,7 @@ Execute(The build directory setting should override the options):
Execute(The build directory should be ignored for header files):
call ale#test#SetFilename('test.h')
+ let b:ale_c_clangtidy_checks = ['*']
let b:ale_c_build_dir = '/foo/bar'
let b:ale_c_clangtidy_options = '-Wall'
@@ -61,6 +65,7 @@ Execute(The build directory should be ignored for header files):
\ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
Execute(The executable should be configurable):
+ let b:ale_c_clangtidy_checks = ['*']
let b:ale_c_clangtidy_executable = 'foobar'
AssertLinter 'foobar',
diff --git a/test/command_callback/test_c_cppcheck_command_callbacks.vader b/test/command_callback/test_c_cppcheck_command_callbacks.vader
index 3fc87a79..3ae4bdbe 100644
--- a/test/command_callback/test_c_cppcheck_command_callbacks.vader
+++ b/test/command_callback/test_c_cppcheck_command_callbacks.vader
@@ -19,6 +19,6 @@ Execute(cppcheck for C++ should detect compile_commands.json files):
call ale#test#SetFilename('cppcheck_paths/one/foo.cpp')
AssertLinter 'cppcheck',
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/cppcheck_paths/one')) . ' && '
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/one'))
\ . ale#Escape('cppcheck')
\ . ' -q --language=c --project=compile_commands.json --enable=style %t'
diff --git a/test/command_callback/test_c_cquery_command_callbacks.vader b/test/command_callback/test_c_cquery_command_callbacks.vader
new file mode 100644
index 00000000..13b7a567
--- /dev/null
+++ b/test/command_callback/test_c_cquery_command_callbacks.vader
@@ -0,0 +1,33 @@
+Before:
+ call ale#assert#SetUpLinterTest('c', 'cquery')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The project root should be detected correctly using compile_commands.json file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('cquery_paths/with_compile_commands_json/dummy.c')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/cquery_paths/with_compile_commands_json')
+
+Execute(The project root should be detected correctly using .cquery file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('cquery_paths/with_cquery/dummy.c')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/cquery_paths/with_cquery')
+
+Execute(The executable should be configurable):
+ AssertLinter 'cquery', ale#Escape('cquery')
+
+ let b:ale_c_cquery_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar')
+
+Execute(The cache directory should be configurable):
+ AssertLSPOptions {'cacheDirectory': expand('$HOME/.cache/cquery')}
+
+ let b:ale_c_cquery_cache_directory = '/foo/bar'
+
+ AssertLSPOptions {'cacheDirectory': '/foo/bar'}
diff --git a/test/command_callback/test_c_flawfinder_command_callbacks.vader b/test/command_callback/test_c_flawfinder_command_callbacks.vader
index 44573ff5..38385e2b 100644
--- a/test/command_callback/test_c_flawfinder_command_callbacks.vader
+++ b/test/command_callback/test_c_flawfinder_command_callbacks.vader
@@ -13,7 +13,7 @@ Execute(The minlevel of flawfinder should be configurable):
AssertLinter 'flawfinder', ale#Escape('flawfinder') . ' -CDQS --minlevel=8 %t'
Execute(Additional flawfinder options should be configurable):
- let b:ale_c_flawfinder_options = ' --foobar'
+ let b:ale_c_flawfinder_options = '--foobar'
AssertLinter 'flawfinder',
\ ale#Escape('flawfinder') . ' -CDQS --foobar --minlevel=1 %t'
diff --git a/test/command_callback/test_c_gcc_command_callbacks.vader b/test/command_callback/test_c_gcc_command_callbacks.vader
index 45514051..1f51c3bc 100644
--- a/test/command_callback/test_c_gcc_command_callbacks.vader
+++ b/test/command_callback/test_c_gcc_command_callbacks.vader
@@ -1,4 +1,7 @@
Before:
+ Save g:ale_c_parse_makefile
+ let g:ale_c_parse_makefile = 0
+
call ale#assert#SetUpLinterTest('c', 'gcc')
let b:command_tail = ' -S -x c -fsyntax-only -iquote'
diff --git a/test/command_callback/test_c_import_paths.vader b/test/command_callback/test_c_import_paths.vader
new file mode 100644
index 00000000..0b5fac40
--- /dev/null
+++ b/test/command_callback/test_c_import_paths.vader
@@ -0,0 +1,223 @@
+Before:
+ " Make sure the c.vim file is loaded first.
+ call ale#c#FindProjectRoot(bufnr(''))
+
+ Save g:ale_c_parse_makefile
+ Save g:__ale_c_project_filenames
+
+ let g:original_project_filenames = g:__ale_c_project_filenames
+
+ " Remove the .git/HEAD dir for C import paths for these tests.
+ " The tests run inside of a git repo.
+ let g:__ale_c_project_filenames = filter(
+ \ copy(g:__ale_c_project_filenames),
+ \ 'v:val isnot# ''.git/HEAD'''
+ \)
+
+ let g:ale_c_parse_makefile = 0
+
+After:
+ unlet! g:original_project_filenames
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(The C GCC handler should include 'include' directories for projects with a Makefile):
+ call ale#assert#SetUpLinterTest('c', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.c')
+ let g:ale_c_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c -fsyntax-only'
+ \ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
+ \ . ' -'
+
+Execute(The C GCC handler should include 'include' directories for projects with a configure file):
+ call ale#assert#SetUpLinterTest('c', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.c')
+ let g:ale_c_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
+ \ . ' -'
+
+Execute(The C GCC handler should include root directories for projects with .h files in them):
+ call ale#assert#SetUpLinterTest('c', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c')
+ let g:ale_c_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
+ \ . ' -'
+
+Execute(The C GCC handler should include root directories for projects with .hpp files in them):
+ call ale#assert#SetUpLinterTest('c', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.c')
+ let g:ale_c_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
+ \ . ' -'
+
+Execute(The C Clang handler should include 'include' directories for projects with a Makefile):
+ call ale#assert#SetUpLinterTest('c', 'clang')
+ call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.c')
+ let g:ale_c_clang_options = ''
+
+ AssertLinter 'clang',
+ \ ale#Escape('clang')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
+ \ . ' -'
+
+Execute(The C Clang handler should include 'include' directories for projects with a configure file):
+ call ale#assert#SetUpLinterTest('c', 'clang')
+ call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c')
+ let g:ale_c_clang_options = ''
+
+ AssertLinter 'clang',
+ \ ale#Escape('clang')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
+ \ . ' -'
+
+Execute(The C Clang handler should include root directories for projects with .h files in them):
+ call ale#assert#SetUpLinterTest('c', 'clang')
+ call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c')
+ let g:ale_c_clang_options = ''
+
+ AssertLinter 'clang',
+ \ ale#Escape('clang')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
+ \ . ' -'
+
+Execute(The C Clang handler should include root directories for projects with .hpp files in them):
+ call ale#assert#SetUpLinterTest('c', 'clang')
+ call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.c')
+ let g:ale_c_clang_options = ''
+
+ AssertLinter 'clang',
+ \ ale#Escape('clang')
+ \ . ' -S -x c -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
+ \ . ' -'
+
+Execute(The C++ GCC handler should include 'include' directories for projects with a Makefile):
+ call ale#assert#SetUpLinterTest('cpp', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.cpp')
+ let g:ale_cpp_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
+ \ . ' -'
+
+Execute(The C++ GCC handler should include 'include' directories for projects with a configure file):
+ call ale#assert#SetUpLinterTest('cpp', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.cpp')
+ let g:ale_cpp_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
+ \ . ' -'
+
+Execute(The C++ GCC handler should include root directories for projects with .h files in them):
+ call ale#assert#SetUpLinterTest('cpp', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.cpp')
+ let g:ale_cpp_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
+ \ . ' -'
+
+Execute(The C++ GCC handler should include root directories for projects with .hpp files in them):
+ call ale#assert#SetUpLinterTest('cpp', 'gcc')
+ call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.cpp')
+ let g:ale_cpp_gcc_options = ''
+
+ AssertLinter 'gcc',
+ \ ale#Escape('gcc')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
+ \ . ' -'
+
+Execute(The C++ Clang handler should include 'include' directories for projects with a Makefile):
+ call ale#assert#SetUpLinterTest('cpp', 'clang')
+ call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.cpp')
+ let g:ale_cpp_clang_options = ''
+
+ AssertLinter 'clang++',
+ \ ale#Escape('clang++')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
+ \ . ' -'
+
+Execute(The C++ Clang handler should include 'include' directories for projects with a configure file):
+ call ale#assert#SetUpLinterTest('cpp', 'clang')
+ call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.cpp')
+ let g:ale_cpp_clang_options = ''
+
+ AssertLinter 'clang++',
+ \ ale#Escape('clang++')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
+ \ . ' -'
+
+Execute(The C++ Clang handler should include root directories for projects with .h files in them):
+ call ale#assert#SetUpLinterTest('cpp', 'clang')
+ call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.cpp')
+ let g:ale_cpp_clang_options = ''
+
+ AssertLinter 'clang++',
+ \ ale#Escape('clang++')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
+ \ . ' -'
+
+Execute(The C++ Clang handler should include root directories for projects with .hpp files in them):
+ call ale#assert#SetUpLinterTest('cpp', 'clang')
+ call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.cpp')
+ let g:ale_cpp_clang_options = ''
+
+ AssertLinter 'clang++',
+ \ ale#Escape('clang++')
+ \ . ' -S -x c++ -fsyntax-only '
+ \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir'))
+ \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
+ \ . ' -'
+
+Execute(The C++ ClangTidy handler should include json folders for projects with suitable build directory in them):
+ call ale#assert#SetUpLinterTest('cpp', 'clangtidy')
+ call ale#test#SetFilename('../test_c_projects/json_project/subdir/file.cpp')
+
+ AssertLinter 'clang-tidy',
+ \ ale#Escape('clang-tidy')
+ \ . ' %s '
+ \ . '-p ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/json_project/build'))
diff --git a/test/command_callback/test_cargo_command_callbacks.vader b/test/command_callback/test_cargo_command_callbacks.vader
index ac8846b0..f0afbc91 100644
--- a/test/command_callback/test_cargo_command_callbacks.vader
+++ b/test/command_callback/test_cargo_command_callbacks.vader
@@ -128,3 +128,27 @@ Execute(When a crate belongs to a workspace we chdir into the crate, unless we d
\ 'cargo --version',
\ 'cargo check --frozen --message-format=json -q',
\]
+
+Execute(When ale_rust_cargo_use_clippy is set, cargo-clippy is used as linter):
+ let b:ale_rust_cargo_use_clippy = 1
+ AssertLinter '', [
+ \ 'cargo --version',
+ \ 'cargo clippy --frozen --message-format=json -q ',
+ \]
+
+Execute(When ale_rust_cargo_clippy_options is set, cargo-clippy appends it to commandline):
+ let b:ale_rust_cargo_use_clippy = 1
+ let b:ale_rust_cargo_clippy_options = '-- -D warnings'
+ AssertLinter '', [
+ \ 'cargo --version',
+ \ 'cargo clippy --frozen --message-format=json -q -- -D warnings',
+ \]
+
+Execute(cargo-check does not refer ale_rust_cargo_clippy_options):
+ let b:ale_rust_cargo_use_clippy = 0
+ let b:ale_rust_cargo_use_check = 1
+ let b:ale_rust_cargo_clippy_options = '-- -D warnings'
+ AssertLinter '', [
+ \ 'cargo --version',
+ \ 'cargo check --frozen --message-format=json -q',
+ \]
diff --git a/test/command_callback/test_clang_tidy_command_callback.vader b/test/command_callback/test_clang_tidy_command_callback.vader
index f28609ee..3297a4cb 100644
--- a/test/command_callback/test_clang_tidy_command_callback.vader
+++ b/test/command_callback/test_clang_tidy_command_callback.vader
@@ -7,12 +7,13 @@ After:
Execute(The clangtidy command default should be correct):
AssertLinter 'clang-tidy',
- \ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s'
+ \ ale#Escape('clang-tidy') . ' %s'
Execute(You should be able to remove the -checks option for clang-tidy):
let b:ale_cpp_clangtidy_checks = []
- AssertLinter 'clang-tidy', ale#Escape('clang-tidy') . ' %s'
+ AssertLinter 'clang-tidy',
+ \ ale#Escape('clang-tidy') . ' %s'
Execute(You should be able to set other checks for clang-tidy):
let b:ale_cpp_clangtidy_checks = ['-*', 'clang-analyzer-*']
@@ -22,34 +23,41 @@ Execute(You should be able to set other checks for clang-tidy):
\ . ' -checks=' . ale#Escape('-*,clang-analyzer-*') . ' %s'
Execute(You should be able to manually set compiler flags for clang-tidy):
+ let b:ale_cpp_clangtidy_checks = ['*']
let b:ale_cpp_clangtidy_options = '-Wall'
AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
- \
+
Execute(The build directory should be configurable):
+ let b:ale_cpp_clangtidy_checks = ['*']
let b:ale_c_build_dir = '/foo/bar'
AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy')
- \ . ' -checks=' . ale#Escape('*') . ' %s -p ' . ale#Escape('/foo/bar')
+ \ . ' -checks=' . ale#Escape('*') . ' %s'
+ \ . ' -p ' . ale#Escape('/foo/bar')
Execute(The build directory setting should override the options):
+ let b:ale_cpp_clangtidy_checks = ['*']
let b:ale_c_build_dir = '/foo/bar'
let b:ale_cpp_clangtidy_options = '-Wall'
AssertLinter 'clang-tidy',
\ ale#Escape('clang-tidy')
- \ . ' -checks=' . ale#Escape('*') . ' %s -p ' . ale#Escape('/foo/bar')
+ \ . ' -checks=' . ale#Escape('*') . ' %s'
+ \ . ' -p ' . ale#Escape('/foo/bar')
Execute(The build directory should be ignored for header files):
call ale#test#SetFilename('test.h')
+ let b:ale_cpp_clangtidy_checks = ['*']
let b:ale_c_build_dir = '/foo/bar'
let b:ale_cpp_clangtidy_options = '-Wall'
AssertLinter 'clang-tidy',
- \ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
+ \ ale#Escape('clang-tidy')
+ \ . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
call ale#test#SetFilename('test.hpp')
@@ -57,6 +65,7 @@ Execute(The build directory should be ignored for header files):
\ ale#Escape('clang-tidy') . ' -checks=' . ale#Escape('*') . ' %s -- -Wall'
Execute(The executable should be configurable):
+ let b:ale_cpp_clangtidy_checks = ['*']
let b:ale_cpp_clangtidy_executable = 'foobar'
AssertLinter 'foobar',
diff --git a/test/command_callback/test_cpp_ccls_command_callbacks.vader b/test/command_callback/test_cpp_ccls_command_callbacks.vader
new file mode 100644
index 00000000..38947acf
--- /dev/null
+++ b/test/command_callback/test_cpp_ccls_command_callbacks.vader
@@ -0,0 +1,43 @@
+" Author: Ye Jingchen <ye.jingchen@gmail.com>, Ben Falconer <ben@falconers.me.uk>
+" Description: A language server for C++
+
+Before:
+ call ale#assert#SetUpLinterTest('cpp', 'ccls')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The project root should be detected correctly using compile_commands.json file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_compile_commands_json/dummy.cpp')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_compile_commands_json')
+
+Execute(The project root should be detected correctly using .ccls file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_ccls/dummy.cpp')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_ccls')
+
+Execute(The project root should be detected correctly using .ccls-root file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_ccls-root/dummy.cpp')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_ccls-root')
+
+Execute(The executable should be configurable):
+ AssertLinter 'ccls', ale#Escape('ccls')
+
+ let b:ale_cpp_ccls_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar')
+
+Execute(The initialization options should be configurable):
+ AssertLSPOptions {}
+
+ let b:ale_cpp_ccls_init_options = { 'cacheDirectory': '/tmp/ccls' }
+
+ AssertLSPOptions { 'cacheDirectory': '/tmp/ccls' }
diff --git a/test/command_callback/test_cpp_clang_command_callbacks.vader b/test/command_callback/test_cpp_clang_command_callbacks.vader
index 3a5ea945..e96fd8e7 100644
--- a/test/command_callback/test_cpp_clang_command_callbacks.vader
+++ b/test/command_callback/test_cpp_clang_command_callbacks.vader
@@ -1,4 +1,7 @@
Before:
+ Save g:ale_c_parse_makefile
+ let g:ale_c_parse_makefile = 0
+
call ale#assert#SetUpLinterTest('cpp', 'clang')
let b:command_tail = ' -S -x c++ -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())
diff --git a/test/command_callback/test_cpp_clazy_command_callback.vader b/test/command_callback/test_cpp_clazy_command_callback.vader
new file mode 100644
index 00000000..1be43b96
--- /dev/null
+++ b/test/command_callback/test_cpp_clazy_command_callback.vader
@@ -0,0 +1,54 @@
+Before:
+ call ale#assert#SetUpLinterTest('cpp', 'clazy')
+ call ale#test#SetFilename('test.cpp')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The clazy command default should be correct):
+ AssertLinter 'clazy-standalone',
+ \ ale#Escape('clazy-standalone') . ' -checks=' . ale#Escape('level1') . ' %s'
+
+Execute(You should be able to remove the -checks option for clazy-standalone):
+ let b:ale_cpp_clazy_checks = []
+
+ AssertLinter 'clazy-standalone', ale#Escape('clazy-standalone') . ' %s'
+
+Execute(You should be able to set other checks for clazy-standalone):
+ let b:ale_cpp_clazy_checks = ['level2', 'level3']
+
+ AssertLinter 'clazy-standalone',
+ \ ale#Escape('clazy-standalone')
+ \ . ' -checks=' . ale#Escape('level2,level3') . ' %s'
+
+Execute(You should be able to manually set compiler flags for clazy-standalone):
+ let b:ale_cpp_clazy_options = '-qt4-compat'
+
+ AssertLinter 'clazy-standalone',
+ \ ale#Escape('clazy-standalone') . ' -checks=' . ale#Escape('level1') . ' -qt4-compat' . ' %s'
+ \
+Execute(The build directory should be configurable):
+ let b:ale_c_build_dir = '/foo/bar'
+
+ AssertLinter 'clazy-standalone',
+ \ ale#Escape('clazy-standalone')
+ \ . ' -checks=' . ale#Escape('level1') . ' -p ' . ale#Escape('/foo/bar') . ' %s'
+
+Execute(The build directory should be ignored for header files):
+ call ale#test#SetFilename('test.h')
+
+ let b:ale_c_build_dir = '/foo/bar'
+
+ AssertLinter 'clazy-standalone',
+ \ ale#Escape('clazy-standalone') . ' -checks=' . ale#Escape('level1') . ' %s'
+
+ call ale#test#SetFilename('test.hpp')
+
+ AssertLinter 'clazy-standalone',
+ \ ale#Escape('clazy-standalone') . ' -checks=' . ale#Escape('level1') . ' %s'
+
+Execute(The executable should be configurable):
+ let b:ale_cpp_clazy_executable = 'foobar'
+
+ AssertLinter 'foobar',
+ \ ale#Escape('foobar') . ' -checks=' . ale#Escape('level1') . ' %s'
diff --git a/test/command_callback/test_cpp_cppcheck_command_callbacks.vader b/test/command_callback/test_cpp_cppcheck_command_callbacks.vader
index 3a7ada2c..352c88d5 100644
--- a/test/command_callback/test_cpp_cppcheck_command_callbacks.vader
+++ b/test/command_callback/test_cpp_cppcheck_command_callbacks.vader
@@ -17,6 +17,6 @@ Execute(cppcheck for C++ should detect compile_commands.json files):
call ale#test#SetFilename('cppcheck_paths/one/foo.cpp')
AssertLinter 'cppcheck',
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/cppcheck_paths/one')) . ' && '
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/one'))
\ . ale#Escape('cppcheck')
\ . ' -q --language=c++ --project=compile_commands.json --enable=style %t'
diff --git a/test/command_callback/test_cpp_cquery_command_callbacks.vader b/test/command_callback/test_cpp_cquery_command_callbacks.vader
index b355d052..682c90d5 100644
--- a/test/command_callback/test_cpp_cquery_command_callbacks.vader
+++ b/test/command_callback/test_cpp_cquery_command_callbacks.vader
@@ -7,6 +7,20 @@ Before:
After:
call ale#assert#TearDownLinterTest()
+Execute(The project root should be detected correctly using compile_commands.json file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('cquery_paths/with_compile_commands_json/dummy.cpp')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/cquery_paths/with_compile_commands_json')
+
+Execute(The project root should be detected correctly using .cquery file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('cquery_paths/with_cquery/dummy.cpp')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/cquery_paths/with_cquery')
+
Execute(The executable should be configurable):
AssertLinter 'cquery', ale#Escape('cquery')
diff --git a/test/command_callback/test_cpp_gcc_command_callbacks.vader b/test/command_callback/test_cpp_gcc_command_callbacks.vader
index f9fad8c8..0a86df4f 100644
--- a/test/command_callback/test_cpp_gcc_command_callbacks.vader
+++ b/test/command_callback/test_cpp_gcc_command_callbacks.vader
@@ -1,4 +1,7 @@
Before:
+ Save g:ale_c_parse_makefile
+ let g:ale_c_parse_makefile = 0
+
call ale#assert#SetUpLinterTest('cpp', 'gcc')
let b:command_tail = ' -S -x c++ -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())
diff --git a/test/command_callback/test_cs_mcsc_command_callbacks.vader b/test/command_callback/test_cs_mcsc_command_callbacks.vader
index 20ddb28b..d15898e0 100644
--- a/test/command_callback/test_cs_mcsc_command_callbacks.vader
+++ b/test/command_callback/test_cs_mcsc_command_callbacks.vader
@@ -5,43 +5,43 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The mcsc linter should return the correct default command):
- AssertLinter 'mcs', 'cd ' . ale#Escape(g:dir) . ' && '
+ AssertLinter 'mcs', ale#path#CdString(g:dir)
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The options should be be used in the command):
let g:ale_cs_mcsc_options = '-pkg:dotnet'
- AssertLinter 'mcs', 'cd ' . ale#Escape(g:dir) . ' && '
+ AssertLinter 'mcs', ale#path#CdString(g:dir)
\ . 'mcs -unsafe -pkg:dotnet -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The souce path should be be used in the command):
let g:ale_cs_mcsc_source = '../foo/bar'
- AssertLinter 'mcs', 'cd ' . ale#Escape('../foo/bar') . ' && '
+ AssertLinter 'mcs', ale#path#CdString('../foo/bar')
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The list of search pathes for assemblies should be be used in the command if not empty):
let g:ale_cs_mcsc_assembly_path = ['/usr/lib/mono', '../foo/bar']
- AssertLinter 'mcs', 'cd ' . ale#Escape(g:dir) . ' && '
+ AssertLinter 'mcs', ale#path#CdString(g:dir)
\ . 'mcs -unsafe'
\ . ' -lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar')
\ . ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
let g:ale_cs_mcsc_assembly_path = []
- AssertLinter 'mcs', 'cd ' . ale#Escape(g:dir) . ' && '
+ AssertLinter 'mcs', ale#path#CdString(g:dir)
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The list of assemblies should be be used in the command if not empty):
let g:ale_cs_mcsc_assemblies = ['foo.dll', 'bar.dll']
- AssertLinter 'mcs', 'cd ' . ale#Escape(g:dir) . ' && '
+ AssertLinter 'mcs', ale#path#CdString(g:dir)
\ . 'mcs -unsafe'
\ . ' -r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll')
\ . ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
let g:ale_cs_mcsc_assemblies = []
- AssertLinter 'mcs', 'cd ' . ale#Escape(g:dir) . ' && '
+ AssertLinter 'mcs', ale#path#CdString(g:dir)
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
diff --git a/test/command_callback/test_cuda_nvcc_command_callbacks.vader b/test/command_callback/test_cuda_nvcc_command_callbacks.vader
index 9e2b5ac6..4578d052 100644
--- a/test/command_callback/test_cuda_nvcc_command_callbacks.vader
+++ b/test/command_callback/test_cuda_nvcc_command_callbacks.vader
@@ -12,3 +12,9 @@ Execute(The executable should be configurable):
AssertLinter 'foobar',
\ ale#Escape('foobar') . ' -cuda -std=c++11 %s -o ' . g:ale#util#nul_file
+
+Execute(The options should be configurable):
+ let g:ale_cuda_nvcc_options = '--foobar'
+
+ AssertLinter 'nvcc',
+ \ ale#Escape('nvcc') . ' -cuda --foobar %s -o ' . g:ale#util#nul_file
diff --git a/test/command_callback/test_d_dls_callbacks.vader b/test/command_callback/test_d_dls_callbacks.vader
new file mode 100644
index 00000000..156ebf66
--- /dev/null
+++ b/test/command_callback/test_d_dls_callbacks.vader
@@ -0,0 +1,19 @@
+Before:
+ call ale#assert#SetUpLinterTest('d', 'dls')
+
+ Save &filetype
+ let &filetype = 'd'
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The language string should be correct):
+ AssertLSPLanguage 'd'
+
+Execute(The default executable should be correct):
+ AssertLinter 'dls', 'dls'
+
+Execute(The executable should be configurable):
+ let g:ale_d_dls_executable = 'foobar'
+
+ AssertLinter 'foobar', 'foobar'
diff --git a/test/command_callback/test_dart_language_server_command_callback.vader b/test/command_callback/test_dart_language_server_command_callback.vader
new file mode 100644
index 00000000..5567f271
--- /dev/null
+++ b/test/command_callback/test_dart_language_server_command_callback.vader
@@ -0,0 +1,8 @@
+Before:
+ call ale#assert#SetUpLinterTest('dart', 'language_server')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'dart_language_server', ale#Escape('dart_language_server')
diff --git a/test/command_callback/test_dockerfile_lint_command_callback.vader b/test/command_callback/test_dockerfile_lint_command_callback.vader
new file mode 100644
index 00000000..abc32e0d
--- /dev/null
+++ b/test/command_callback/test_dockerfile_lint_command_callback.vader
@@ -0,0 +1,19 @@
+Before:
+ call ale#assert#SetUpLinterTest('dockerfile', 'dockerfile_lint')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'dockerfile_lint', ale#Escape('dockerfile_lint') . ' -p -j -f %t'
+
+Execute(The executable should be configurable):
+ let b:ale_dockerfile_dockerfile_lint_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar') . ' -p -j -f %t'
+
+Execute(The options should be configurable):
+ let b:ale_dockerfile_dockerfile_lint_options = '-r additional.yaml'
+
+ AssertLinter 'dockerfile_lint', ale#Escape('dockerfile_lint') . ' -r additional.yaml -p -j -f %t'
+
diff --git a/test/command_callback/test_elixir_ls_command_callbacks.vader b/test/command_callback/test_elixir_ls_command_callbacks.vader
new file mode 100644
index 00000000..ca785054
--- /dev/null
+++ b/test/command_callback/test_elixir_ls_command_callbacks.vader
@@ -0,0 +1,35 @@
+Before:
+ call ale#assert#SetUpLinterTest('elixir', 'elixir_ls')
+
+ let g:ale_has_override['win32'] = 0
+
+After:
+ let g:ale_has_override = {}
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(should set correct defaults (unix)):
+ AssertLinter 'elixir-ls/language_server.sh', 'elixir-ls/language_server.sh'
+
+Execute(should set correct defaults (win32)):
+ let g:ale_has_override['win32'] = 1
+
+ AssertLinter 'elixir-ls\language_server.bat', 'elixir-ls\language_server.bat'
+
+Execute(should configure elixir-ls release location):
+ let b:ale_elixir_elixir_ls_release = 'boo'
+
+ AssertLinter 'boo/language_server.sh', 'boo/language_server.sh'
+
+Execute(should set correct LSP values):
+ call ale#test#SetFilename('elixir_paths/umbrella_project/apps/app1/lib/app.ex')
+
+ AssertLSPLanguage 'elixir'
+ AssertLSPOptions {}
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . '/elixir_paths/umbrella_project')
+
+Execute(should accept configuration settings):
+ AssertLSPConfig {}
+ let b:ale_elixir_elixir_ls_config = {'elixirLS': {'dialyzerEnabled': v:false}}
+ AssertLSPConfig {'elixirLS': {'dialyzerEnabled': v:false}}
diff --git a/test/command_callback/test_elixir_mix_command_callbacks.vader b/test/command_callback/test_elixir_mix_command_callbacks.vader
index 18fb13ed..b0d0af98 100644
--- a/test/command_callback/test_elixir_mix_command_callbacks.vader
+++ b/test/command_callback/test_elixir_mix_command_callbacks.vader
@@ -11,9 +11,23 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default mix command should be correct):
- call ale#test#SetFilename('mix_paths/wrapped_project/lib/app.ex')
+ call ale#test#SetFilename('elixir_paths/mix_project/lib/app.ex')
AssertLinter 'mix',
- \ ale#path#CdString(ale#path#Simplify(g:dir . '/mix_paths/wrapped_project'))
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/elixir_paths/mix_project'))
\ . g:env_prefix
\ . 'mix compile %s'
+
+Execute(FindMixProjectRoot should detect the project root directory via mix.exs):
+ silent execute 'file ' . fnameescape(g:dir . '/elixir_paths/mix_project/lib/app.ex')
+
+ AssertEqual
+ \ ale#path#Simplify(g:dir . '/elixir_paths/mix_project'),
+ \ ale#handlers#elixir#FindMixProjectRoot(bufnr(''))
+
+Execute(FindMixUmbrellaRoot should detect the umbrella root directory via mix.exs):
+ silent execute 'file ' . fnameescape(g:dir . '/elixir_paths/umbrella_project/apps/app1/lib/app.ex')
+
+ AssertEqual
+ \ ale#path#Simplify(g:dir . '/elixir_paths/umbrella_project'),
+ \ ale#handlers#elixir#FindMixUmbrellaRoot(bufnr(''))
diff --git a/test/command_callback/test_elm_make_command_callback.vader b/test/command_callback/test_elm_make_command_callback.vader
new file mode 100644
index 00000000..6d95676f
--- /dev/null
+++ b/test/command_callback/test_elm_make_command_callback.vader
@@ -0,0 +1,32 @@
+Before:
+ call ale#assert#SetUpLinterTest('elm', 'make')
+
+After:
+ unlet! g:executable
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(should get valid executable with default params):
+ call ale#test#SetFilename('../elm-test-files/app/testfile.elm')
+
+ let g:executable = ale#path#Simplify(g:dir . '/../elm-test-files/app/node_modules/.bin/elm')
+
+ AssertLinter g:executable,
+ \ ale#Escape(g:executable) . ' make --report=json --output=/dev/null %t'
+
+Execute(should get valid executable with 'use_global' params):
+ let g:ale_elm_make_use_global = 1
+
+ call ale#test#SetFilename('../elm-test-files/app/testfile.elm')
+
+ AssertLinter 'elm',
+ \ ale#Escape('elm') . ' make --report=json --output=/dev/null %t'
+
+Execute(should get valid executable with 'use_global' and 'executable' params):
+ let g:ale_elm_make_executable = 'other-elm'
+ let g:ale_elm_make_use_global = 1
+
+ call ale#test#SetFilename('../elm-test-files/app/testfile.elm')
+
+ AssertLinter 'other-elm',
+ \ ale#Escape('other-elm') . ' make --report=json --output=/dev/null %t'
diff --git a/test/command_callback/test_flake8_command_callback.vader b/test/command_callback/test_flake8_command_callback.vader
index f12b6747..ede511e0 100644
--- a/test/command_callback/test_flake8_command_callback.vader
+++ b/test/command_callback/test_flake8_command_callback.vader
@@ -1,5 +1,6 @@
Before:
call ale#assert#SetUpLinterTest('python', 'flake8')
+
let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
WithChainResults ['3.0.0']
@@ -152,8 +153,16 @@ Execute(Using `python -m flake8` should be supported for running flake8):
Execute(Setting executable to 'pipenv' should append 'run flake8'):
let g:ale_python_flake8_executable = 'path/to/pipenv'
- " FIXME: pipenv should check the vresion with flake8.
+ " FIXME: pipenv should check the version with flake8.
WithChainResults []
AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run flake8 --format=default -'
+
+Execute(Pipenv is detected when python_flake8_auto_pipenv is set):
+ let g:ale_python_flake8_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -'
diff --git a/test/command_callback/test_fsc_command_callback.vader b/test/command_callback/test_fsc_command_callback.vader
index 5fb5e7fa..278e7c16 100644
--- a/test/command_callback/test_fsc_command_callback.vader
+++ b/test/command_callback/test_fsc_command_callback.vader
@@ -10,4 +10,4 @@ Execute(The default executable and command should be correct):
Given scala.sbt(An empty SBT file):
Execute(fsc should not be run for sbt files):
- AssertLinter '', ''
+ AssertLinterNotExecuted
diff --git a/test/command_callback/test_gawk_command_callback.vader b/test/command_callback/test_gawk_command_callback.vader
index 6bc0a438..ba9f59ab 100644
--- a/test/command_callback/test_gawk_command_callback.vader
+++ b/test/command_callback/test_gawk_command_callback.vader
@@ -6,14 +6,14 @@ After:
Execute(The default command should be correct):
AssertLinter 'gawk',
- \ ale#Escape('gawk') . ' --source ''BEGIN { exit } END { exit 1 }'''
+ \ ale#Escape('gawk') . ' --source ' . ale#Escape('BEGIN { exit } END { exit 1 }')
\ . ' -f %t --lint /dev/null'
Execute(The executable should be configurable):
let b:ale_awk_gawk_executable = '/other/gawk'
AssertLinter '/other/gawk',
- \ ale#Escape('/other/gawk') . ' --source ''BEGIN { exit } END { exit 1 }'''
+ \ ale#Escape('/other/gawk') . ' --source ' . ale#Escape('BEGIN { exit } END { exit 1 }')
\ . ' -f %t --lint /dev/null'
Execute(The options should be configurable):
@@ -21,5 +21,5 @@ Execute(The options should be configurable):
let b:ale_awk_gawk_options = '--something'
AssertLinter 'gawk',
- \ ale#Escape('gawk') . ' --source ''BEGIN { exit } END { exit 1 }'''
+ \ ale#Escape('gawk') . ' --source ' . ale#Escape('BEGIN { exit } END { exit 1 }')
\ . ' --something -f %t --lint /dev/null'
diff --git a/test/command_callback/test_gfortran_command_callback.vader b/test/command_callback/test_gfortran_command_callback.vader
index a6ab50cd..3e6ef951 100644
--- a/test/command_callback/test_gfortran_command_callback.vader
+++ b/test/command_callback/test_gfortran_command_callback.vader
@@ -5,20 +5,20 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The fortran gcc command callback should return the correct default string):
- AssertLinter 'gcc', 'gcc -S -x f95 -fsyntax-only -ffree-form -Wall -'
+ AssertLinter 'gcc', ale#Escape('gcc') . ' -S -x f95 -fsyntax-only -ffree-form -Wall -'
Execute(The fortran gcc command callback should let you set options):
let g:ale_fortran_gcc_options = '-Wotherthings'
- AssertLinter 'gcc', 'gcc -S -x f95 -fsyntax-only -ffree-form -Wotherthings -'
+ AssertLinter 'gcc', ale#Escape('gcc') . ' -S -x f95 -fsyntax-only -ffree-form -Wotherthings -'
Execute(The fortran gcc command callback should let you use -ffixed-form):
let g:ale_fortran_gcc_use_free_form = 0
- AssertLinter 'gcc', 'gcc -S -x f95 -fsyntax-only -ffixed-form -Wall -'
+ AssertLinter 'gcc', ale#Escape('gcc') . ' -S -x f95 -fsyntax-only -ffixed-form -Wall -'
Execute(The fortran executable should be configurable):
let g:ale_fortran_gcc_executable = 'gfortran'
AssertLinter 'gfortran',
- \ 'gfortran -S -x f95 -fsyntax-only -ffree-form -Wall -'
+ \ ale#Escape('gfortran') . ' -S -x f95 -fsyntax-only -ffree-form -Wall -'
diff --git a/test/command_callback/test_gobuild_command_callback.vader b/test/command_callback/test_gobuild_command_callback.vader
index 86113728..c6e324f2 100644
--- a/test/command_callback/test_gobuild_command_callback.vader
+++ b/test/command_callback/test_gobuild_command_callback.vader
@@ -1,36 +1,31 @@
Before:
- call ale#assert#SetUpLinterTest('go', 'gobuild')
+ Save g:ale_go_go_executable
- let g:env_prefix = has('win32')
- \ ? 'set GOPATH=' . ale#Escape('/foo/bar') . ' && '
- \ : 'GOPATH=' . ale#Escape('/foo/bar') . ' '
- call ale_linters#go#gobuild#ResetEnv()
+ call ale#assert#SetUpLinterTest('go', 'gobuild')
WithChainResults ['/foo/bar', '/foo/baz']
After:
- unlet! g:env_prefix
+ Restore
call ale#assert#TearDownLinterTest()
Execute(The default commands should be correct):
- AssertLinter 'go', [
- \ 'go env GOPATH GOROOT',
- \ g:env_prefix . 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
- \ . 'go test -c -o /dev/null ./'
- \]
-
- " We shouldn't run `go env` many times after we've got it.
- AssertLinter 'go', [
- \ '',
- \ g:env_prefix . 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ AssertLinter 'go',
+ \ ale#path#CdString(expand('%:p:h'))
\ . 'go test -c -o /dev/null ./'
- \]
Execute(Extra options should be supported):
let g:ale_go_gobuild_options = '--foo-bar'
- AssertLinter 'go', [
- \ 'go env GOPATH GOROOT',
- \ g:env_prefix . 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ AssertLinter 'go',
+ \ ale#path#CdString(expand('%:p:h'))
\ . 'go test --foo-bar -c -o /dev/null ./'
- \]
+
+ let g:ale_go_gobuild_options = ''
+
+Execute(The executable should be configurable):
+ let g:ale_go_go_executable = 'foobar'
+
+ AssertLinter 'foobar',
+ \ ale#path#CdString(expand('%:p:h'))
+ \ . 'foobar test -c -o /dev/null ./'
diff --git a/test/command_callback/test_golangci_lint_command_callback.vader b/test/command_callback/test_golangci_lint_command_callback.vader
new file mode 100644
index 00000000..345f58b1
--- /dev/null
+++ b/test/command_callback/test_golangci_lint_command_callback.vader
@@ -0,0 +1,38 @@
+Before:
+ call ale#assert#SetUpLinterTest('go', 'golangci_lint')
+ call ale#test#SetFilename('test.go')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The golangci-lint defaults should be correct):
+ AssertLinter 'golangci-lint',
+ \ ale#path#CdString(expand('%:p:h'))
+ \ . ale#Escape('golangci-lint')
+ \ . ' run ' . ale#Escape(expand('%' . ':t'))
+ \ . ' --enable-all'
+
+Execute(The golangci-lint callback should use a configured executable):
+ let b:ale_go_golangci_lint_executable = 'something else'
+
+ AssertLinter 'something else',
+ \ ale#path#CdString(expand('%:p:h'))
+ \ . ale#Escape('something else')
+ \ . ' run ' . ale#Escape(expand('%' . ':t'))
+ \ . ' --enable-all'
+
+Execute(The golangci-lint callback should use configured options):
+ let b:ale_go_golangci_lint_options = '--foobar'
+
+ AssertLinter 'golangci-lint',
+ \ ale#path#CdString(expand('%:p:h'))
+ \ . ale#Escape('golangci-lint')
+ \ . ' run ' . ale#Escape(expand('%' . ':t'))
+ \ . ' --foobar'
+
+Execute(The golangci-lint `lint_package` option should use the correct command):
+ let b:ale_go_golangci_lint_package = 1
+
+ AssertLinter 'golangci-lint',
+ \ ale#path#CdString(expand('%:p:h'))
+ \ . ale#Escape('golangci-lint') . ' run --enable-all'
diff --git a/test/command_callback/test_golangserver_command_callback.vader b/test/command_callback/test_golangserver_command_callback.vader
new file mode 100644
index 00000000..90fdc26f
--- /dev/null
+++ b/test/command_callback/test_golangserver_command_callback.vader
@@ -0,0 +1,68 @@
+Before:
+ Save $GOPATH
+ Save g:ale_completion_enabled
+
+ let g:ale_completion_enabled = 0
+ let g:sep = has('win32') ? ';' : ':'
+
+ call ale#assert#SetUpLinterTest('go', 'langserver')
+ let $GOPATH = ale#path#Simplify(g:dir . '/go_paths/go1')
+ \ . g:sep
+ \ . ale#path#Simplify(g:dir . '/go_paths/go2')
+
+After:
+ Restore
+
+ unlet! b:ale_completion_enabled
+ unlet! g:sep
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(should set correct defaults):
+ AssertLinter 'go-langserver', ale#Escape('go-langserver')
+
+Execute(should configure go-langserver callback executable):
+ let b:ale_go_langserver_executable = 'boo'
+
+ AssertLinter 'boo', ale#Escape('boo')
+
+Execute(should set go-langserver options):
+ call ale#test#SetFilename('go_paths/go1/prj1/file.go')
+ let b:ale_completion_enabled = 1
+ let b:ale_go_langserver_options = ''
+
+ AssertLinter 'go-langserver',
+ \ ale#Escape('go-langserver') . ' -gocodecompletion'
+
+ let b:ale_go_langserver_options = '-trace'
+
+ AssertLinter 'go-langserver',
+ \ ale#Escape('go-langserver') . ' -gocodecompletion -trace'
+
+Execute(should ignore go-langserver -gocodecompletion option):
+ call ale#test#SetFilename('go_paths/go1/prj1/file.go')
+
+ let b:ale_go_langserver_options = '-trace -gocodecompletion'
+ let b:ale_completion_enabled = 1
+
+ AssertLinter 'go-langserver',
+ \ ale#Escape('go-langserver') . ' -gocodecompletion -trace'
+
+ let b:ale_completion_enabled = 0
+
+ AssertLinter 'go-langserver', ale#Escape('go-langserver') . ' -trace'
+
+Execute(should set go-langserver for go app1):
+ call ale#test#SetFilename('go_paths/go1/prj1/file.go')
+
+ AssertLSPLanguage 'go'
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go1')
+
+Execute(should set go-langserver for go app2):
+ call ale#test#SetFilename('go_paths/go2/prj1/file.go')
+
+ AssertLSPLanguage 'go'
+ AssertLSPOptions {}
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . '/go_paths/go2')
diff --git a/test/command_callback/test_golint_command_callbacks.vader b/test/command_callback/test_golint_command_callbacks.vader
new file mode 100644
index 00000000..7c300309
--- /dev/null
+++ b/test/command_callback/test_golint_command_callbacks.vader
@@ -0,0 +1,18 @@
+Before:
+ call ale#assert#SetUpLinterTest('go', 'golint')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default golint command should be correct):
+ AssertLinter 'golint', ale#Escape('golint') . ' %t'
+
+Execute(The golint executable should be configurable):
+ let b:ale_go_golint_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar') . ' %t'
+
+Execute(The golint options should be configurable):
+ let b:ale_go_golint_options = '--foo'
+
+ AssertLinter 'golint', ale#Escape('golint') . ' --foo %t'
diff --git a/test/command_callback/test_gometalinter_command_callback.vader b/test/command_callback/test_gometalinter_command_callback.vader
index d788c5bd..88e86801 100644
--- a/test/command_callback/test_gometalinter_command_callback.vader
+++ b/test/command_callback/test_gometalinter_command_callback.vader
@@ -7,7 +7,7 @@ After:
Execute(The gometalinter defaults should be correct):
AssertLinter 'gometalinter',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .'
@@ -16,7 +16,7 @@ Execute(The gometalinter callback should use a configured executable):
let b:ale_go_gometalinter_executable = 'something else'
AssertLinter 'something else',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('something else')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .'
@@ -25,7 +25,7 @@ Execute(The gometalinter callback should use configured options):
let b:ale_go_gometalinter_options = '--foobar'
AssertLinter 'gometalinter',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' --foobar' . ' .'
@@ -34,5 +34,5 @@ Execute(The gometalinter `lint_package` option should use the correct command):
let b:ale_go_gometalinter_lint_package = 1
AssertLinter 'gometalinter',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('gometalinter') . ' .'
diff --git a/test/command_callback/test_gosimple_command_callback.vader b/test/command_callback/test_gosimple_command_callback.vader
index 7b8c66ae..59013df0 100644
--- a/test/command_callback/test_gosimple_command_callback.vader
+++ b/test/command_callback/test_gosimple_command_callback.vader
@@ -7,4 +7,4 @@ After:
Execute(The default gosimple command should be correct):
AssertLinter 'gosimple',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && gosimple .'
+ \ ale#path#CdString(expand('%:p:h')) . ' gosimple .'
diff --git a/test/command_callback/test_gotype_command_callback.vader b/test/command_callback/test_gotype_command_callback.vader
index da9ceaf3..1898a0cb 100644
--- a/test/command_callback/test_gotype_command_callback.vader
+++ b/test/command_callback/test_gotype_command_callback.vader
@@ -7,7 +7,7 @@ After:
Execute(The default gotype command should be correct):
AssertLinter 'gotype',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && gotype .'
+ \ ale#path#CdString(expand('%:p:h')) . ' gotype .'
Execute(The gotype callback should ignore test files):
call ale#test#SetFilename('bla_test.go')
diff --git a/test/command_callback/test_govet_command_callback.vader b/test/command_callback/test_govet_command_callback.vader
index a73118ae..a55c0812 100644
--- a/test/command_callback/test_govet_command_callback.vader
+++ b/test/command_callback/test_govet_command_callback.vader
@@ -1,8 +1,19 @@
Before:
+ Save g:ale_go_go_executable
+ Save g:ale_go_govet_options
call ale#assert#SetUpLinterTest('go', 'govet')
After:
+ Restore
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'go', 'cd ' . ale#Escape(expand('%:p:h')) . ' && go vet .'
+ AssertLinter 'go', ale#path#CdString(expand('%:p:h')) . ' go vet .'
+
+Execute(Extra options should be supported):
+ let g:ale_go_govet_options = '--foo-bar'
+ AssertLinter 'go', ale#path#CdString(expand('%:p:h')) . ' go vet --foo-bar .'
+
+Execute(The executable should be configurable):
+ let g:ale_go_go_executable = 'foobar'
+ AssertLinter 'foobar', ale#path#CdString(expand('%:p:h')) . ' foobar vet .'
diff --git a/test/command_callback/test_haml_hamllint_command_callback.vader b/test/command_callback/test_haml_hamllint_command_callback.vader
index a59446ca..694b21d3 100644
--- a/test/command_callback/test_haml_hamllint_command_callback.vader
+++ b/test/command_callback/test_haml_hamllint_command_callback.vader
@@ -35,3 +35,7 @@ Execute(The command should include a .rubocop.yml and a .haml-lint if both are f
AssertLinter 'haml-lint',
\ ale#Env('HAML_LINT_RUBOCOP_CONF', b:conf_rubocop)
\ . 'haml-lint --config ' . ale#Escape(b:conf_hamllint) . ' %t'
+
+Execute(The executable can be overridden):
+ let b:ale_haml_hamllint_executable = 'bin/haml-lint'
+ AssertLinter 'bin/haml-lint', 'bin/haml-lint %t'
diff --git a/test/command_callback/test_haskell_ghc_mod_command_callbacks.vader b/test/command_callback/test_haskell_ghc_mod_command_callbacks.vader
new file mode 100644
index 00000000..c1cc8597
--- /dev/null
+++ b/test/command_callback/test_haskell_ghc_mod_command_callbacks.vader
@@ -0,0 +1,10 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'ghc_mod')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Default should use ghc-mod):
+ AssertLinter
+ \ 'ghc-mod',
+ \ ale#Escape('ghc-mod') . ' --map-file %s=%t check %s'
diff --git a/test/command_callback/test_haskell_hie_callbacks.vader b/test/command_callback/test_haskell_hie_callbacks.vader
new file mode 100644
index 00000000..5bd2794c
--- /dev/null
+++ b/test/command_callback/test_haskell_hie_callbacks.vader
@@ -0,0 +1,27 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'hie')
+
+ Save &filetype
+ let &filetype = 'haskell'
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The language string should be correct):
+ AssertLSPLanguage 'haskell'
+
+Execute(The default executable should be correct):
+ AssertLinter 'hie',
+ \ ale#Escape('hie') . ' --lsp'
+
+Execute(The project root should be detected correctly):
+ AssertLSPProject g:dir
+
+ call ale#test#SetFilename('hie_paths/file.hs')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/hie_paths')
+
+Execute(The executable should be configurable):
+ let g:ale_haskell_hie_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar') . ' --lsp'
diff --git a/test/command_callback/test_haskell_hlint_command_callbacks.vader b/test/command_callback/test_haskell_hlint_command_callbacks.vader
new file mode 100644
index 00000000..6d227c9d
--- /dev/null
+++ b/test/command_callback/test_haskell_hlint_command_callbacks.vader
@@ -0,0 +1,17 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'hlint')
+
+ let b:base_opts = '--color=never --json -'
+
+After:
+ unlet! b:base_opts
+ call ale#assert#TearDownLinterTest()
+
+Execute(executable should be configurable):
+ AssertLinter 'hlint', ale#Escape('hlint') . ' ' . b:base_opts
+ let b:ale_haskell_hlint_executable = 'myHlint'
+ AssertLinter 'myHlint', ale#Escape('myHlint') . ' ' . b:base_opts
+
+Execute(should accept options):
+ let b:ale_haskell_hlint_options= '-h myhlintfile.yaml'
+ AssertLinter 'hlint', ale#Escape('hlint') . ' -h myhlintfile.yaml ' . b:base_opts
diff --git a/test/command_callback/test_haskell_stack_build_command_callback.vader b/test/command_callback/test_haskell_stack_build_command_callback.vader
new file mode 100644
index 00000000..f1e6f755
--- /dev/null
+++ b/test/command_callback/test_haskell_stack_build_command_callback.vader
@@ -0,0 +1,13 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'stack_build')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The linter should not be executed when there's no stack.yaml file):
+ AssertLinterNotExecuted
+
+Execute(The linter should be executed when there is a stack.yaml file):
+ call ale#test#SetFilename('stack_build_paths/test.hs')
+
+ AssertLinter 'stack', 'stack build --fast'
diff --git a/test/command_callback/test_haskell_stack_ghc_command_callback.vader b/test/command_callback/test_haskell_stack_ghc_command_callback.vader
new file mode 100644
index 00000000..4adab583
--- /dev/null
+++ b/test/command_callback/test_haskell_stack_ghc_command_callback.vader
@@ -0,0 +1,14 @@
+Before:
+ call ale#assert#SetUpLinterTest('haskell', 'stack_ghc')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The linter should not be executed when there's no stack.yaml file):
+ AssertLinterNotExecuted
+
+Execute(The linter should be executed when there is a stack.yaml file):
+ call ale#test#SetFilename('stack_ghc_paths/test.hs')
+
+ AssertLinter 'stack', 'stack ghc -- -fno-code -v0 %t'
+
diff --git a/test/command_callback/test_html_stylelint_command_callback.vader b/test/command_callback/test_html_stylelint_command_callback.vader
new file mode 100644
index 00000000..49d7d143
--- /dev/null
+++ b/test/command_callback/test_html_stylelint_command_callback.vader
@@ -0,0 +1,60 @@
+Before:
+ Save g:ale_html_stylelint_executable
+ Save g:ale_html_stylelint_use_global
+ Save g:ale_html_stylelint_options
+
+ unlet! b:executable
+
+ unlet! g:ale_html_stylelint_executable
+ unlet! g:ale_html_stylelint_use_global
+ unlet! g:ale_html_stylelint_options
+
+ call ale#test#SetDirectory('/testplugin/test/command_callback')
+ call ale#test#SetFilename('testfile.html')
+
+ runtime ale_linters/html/stylelint.vim
+
+After:
+ Restore
+
+ unlet! b:executable
+ unlet! b:ale_html_stylelint_executable
+ unlet! b:ale_html_stylelint_use_global
+ unlet! b:ale_html_stylelint_options
+
+ call ale#test#SetFilename('test.txt')
+
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+Execute(node_modules directories should be discovered):
+ call ale#test#SetFilename('stylelint_paths/nested/testfile.html')
+
+ let b:executable = ale#path#Simplify(
+ \ g:dir
+ \ . '/stylelint_paths/node_modules/.bin/stylelint'
+ \)
+
+ AssertEqual b:executable, ale_linters#html#stylelint#GetExecutable(bufnr(''))
+ AssertEqual
+ \ ale#Escape(b:executable) . ' --stdin-filename %s',
+ \ ale_linters#html#stylelint#GetCommand(bufnr(''))
+
+Execute(The global override should work):
+ let b:ale_html_stylelint_executable = 'foobar'
+ let b:ale_html_stylelint_use_global = 1
+
+ call ale#test#SetFilename('stylelint_paths/nested/testfile.html')
+
+ AssertEqual 'foobar', ale_linters#html#stylelint#GetExecutable(bufnr(''))
+ AssertEqual
+ \ ale#Escape('foobar') . ' --stdin-filename %s',
+ \ ale_linters#html#stylelint#GetCommand(bufnr(''))
+
+Execute(Extra options should be configurable):
+ let b:ale_html_stylelint_options = '--whatever'
+
+ AssertEqual 'stylelint', ale_linters#html#stylelint#GetExecutable(bufnr(''))
+ AssertEqual
+ \ ale#Escape('stylelint') . ' --whatever --stdin-filename %s',
+ \ ale_linters#html#stylelint#GetCommand(bufnr(''))
diff --git a/test/command_callback/test_ispc_ispc_command_callbacks.vader b/test/command_callback/test_ispc_ispc_command_callbacks.vader
new file mode 100644
index 00000000..f1aeb2f8
--- /dev/null
+++ b/test/command_callback/test_ispc_ispc_command_callbacks.vader
@@ -0,0 +1,20 @@
+Before:
+ call ale#assert#SetUpLinterTest('ispc', 'ispc')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The executable should be configurable):
+ AssertLinter 'ispc',
+ \ ale#Escape('ispc') . ' --nowrap %s'
+
+ let b:ale_ispc_ispc_executable = 'foo'
+
+ AssertLinter 'foo',
+ \ ale#Escape('foo') . ' --nowrap %s'
+
+Execute(The options should be configurable):
+ let g:ale_ispc_ispc_options = '--foo'
+
+ AssertLinter 'ispc',
+ \ ale#Escape('ispc') . ' --nowrap --foo' . ' %s'
diff --git a/test/command_callback/test_javac_command_callback.vader b/test/command_callback/test_javac_command_callback.vader
index 07a0794a..2dcb6a1b 100644
--- a/test/command_callback/test_javac_command_callback.vader
+++ b/test/command_callback/test_javac_command_callback.vader
@@ -3,7 +3,7 @@ Before:
call ale#test#SetFilename('dummy.java')
let g:cp_sep = has('unix') ? ':' : ';'
- let g:prefix = 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ let g:prefix = ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('javac') . ' -Xlint'
function! GetCommand(previous_output) abort
@@ -43,7 +43,7 @@ Execute(The executable should be configurable):
let g:ale_java_javac_executable = 'foobar'
AssertLinter 'foobar',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('foobar') . ' -Xlint'
\ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t'
@@ -106,7 +106,7 @@ Execute(The javac callback should detect source directories):
call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint'
+ \ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/')
\ )
@@ -124,7 +124,7 @@ Execute(The javac callback should combine detected source directories and classp
\ '/xyz/abc.jar',
\]
AssertLinter 'javac',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint'
+ \ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint'
\ . ' -cp ' . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep))
\ . ' -sourcepath ' . ale#Escape(
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/')
@@ -147,7 +147,7 @@ Execute(The javac callback should include src/test/java for test paths):
call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint'
+ \ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths/src/test/java/'),
@@ -160,7 +160,7 @@ Execute(The javac callback should include src/main/jaxb when available):
call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint'
+ \ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/jaxb/'),
diff --git a/test/command_callback/test_javalsp_command_callback.vader b/test/command_callback/test_javalsp_command_callback.vader
new file mode 100644
index 00000000..1fbfddfb
--- /dev/null
+++ b/test/command_callback/test_javalsp_command_callback.vader
@@ -0,0 +1,10 @@
+
+Before:
+ call ale#assert#SetUpLinterTest('java', 'javalsp')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The javalsp callback should return the correct default value):
+ AssertLinter 'java', ale#Escape('java -cp javacs.jar -Xverify:none org.javacs.Main')
+
diff --git a/test/command_callback/test_javascript_tsserver_command_callback.vader b/test/command_callback/test_javascript_tsserver_command_callback.vader
new file mode 100644
index 00000000..638dd873
--- /dev/null
+++ b/test/command_callback/test_javascript_tsserver_command_callback.vader
@@ -0,0 +1,8 @@
+Before:
+ call ale#assert#SetUpLinterTest('javascript', 'tsserver')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'tsserver', ale#Escape('tsserver')
diff --git a/test/command_callback/test_jshint_command_callback.vader b/test/command_callback/test_jshint_command_callback.vader
new file mode 100644
index 00000000..517c957c
--- /dev/null
+++ b/test/command_callback/test_jshint_command_callback.vader
@@ -0,0 +1,17 @@
+Before:
+ Save g:ale_jshint_config_loc
+
+ unlet! g:ale_jshint_config_loc
+
+ call ale#assert#SetUpLinterTest('javascript', 'jshint')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'jshint', ale#Escape('jshint') . ' --reporter unix --extract auto --filename %s -'
+
+Execute(Setting a config location should add the config parameter):
+ let g:ale_jshint_config_loc = '/some/file'
+
+ AssertLinter 'jshint', ale#Escape('jshint') . ' --reporter unix --extract auto --config ' . ale#Escape('/some/file') . ' --filename %s -'
diff --git a/test/command_callback/test_julia_languageserver_callbacks.vader b/test/command_callback/test_julia_languageserver_callbacks.vader
new file mode 100644
index 00000000..3bc46e3d
--- /dev/null
+++ b/test/command_callback/test_julia_languageserver_callbacks.vader
@@ -0,0 +1,30 @@
+Before:
+ Save g:ale_julia_executable
+
+ call ale#assert#SetUpLinterTest('julia', 'languageserver')
+
+After:
+ Restore
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default executable path should be correct):
+ AssertLinter 'julia',
+ \ ale#Escape('julia') .
+ \' --startup-file=no --history-file=no -e ' .
+ \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);')
+
+Execute(The executable should be configurable):
+ let g:ale_julia_executable = 'julia-new'
+
+ AssertLinter 'julia-new',
+ \ ale#Escape('julia-new') .
+ \' --startup-file=no --history-file=no -e ' .
+ \ ale#Escape('using LanguageServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, false); server.runlinter = true; run(server);')
+
+Execute(The project root should be detected correctly):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('julia-languageserver-project/test.jl')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/julia-languageserver-project')
diff --git a/test/command_callback/test_kotlin_languageserver_command_callback.vader b/test/command_callback/test_kotlin_languageserver_command_callback.vader
new file mode 100644
index 00000000..e83a4f37
--- /dev/null
+++ b/test/command_callback/test_kotlin_languageserver_command_callback.vader
@@ -0,0 +1,8 @@
+Before:
+ call ale#assert#SetUpLinterTest('kotlin', 'languageserver')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'kotlin-language-server', ale#Escape('kotlin-language-server')
diff --git a/test/command_callback/test_lintr_command_callback.vader b/test/command_callback/test_lintr_command_callback.vader
index 8a0e6c1c..187d3875 100644
--- a/test/command_callback/test_lintr_command_callback.vader
+++ b/test/command_callback/test_lintr_command_callback.vader
@@ -6,7 +6,7 @@ After:
Execute(The default lintr command should be correct):
AssertLinter 'Rscript',
- \ 'cd ' . ale#Escape(getcwd()) . ' && '
+ \ ale#path#CdString(getcwd())
\ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint(cache = FALSE, commandArgs(TRUE), '
@@ -17,7 +17,7 @@ Execute(The lintr options should be configurable):
let b:ale_r_lintr_options = 'with_defaults(object_usage_linter = NULL)'
AssertLinter 'Rscript',
- \ 'cd ' . ale#Escape(getcwd()) . ' && '
+ \ ale#path#CdString(getcwd())
\ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint(cache = FALSE, commandArgs(TRUE), '
@@ -28,7 +28,7 @@ Execute(If the lint_package flag is set, lintr::lint_package should be called):
let b:ale_r_lintr_lint_package = 1
AssertLinter 'Rscript',
- \ 'cd ' . ale#Escape(getcwd()) . ' && '
+ \ ale#path#CdString(getcwd())
\ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint_package(cache = FALSE, '
diff --git a/test/command_callback/test_luac_command_callback.vader b/test/command_callback/test_luac_command_callback.vader
index 8a2345ec..55f39cba 100644
--- a/test/command_callback/test_luac_command_callback.vader
+++ b/test/command_callback/test_luac_command_callback.vader
@@ -5,9 +5,9 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'luac', ale#Escape('luac') . ' -p - '
+ AssertLinter 'luac', ale#Escape('luac') . ' -p -'
Execute(The luac executable should be configurable):
let g:ale_lua_luac_executable = 'luac.sh'
- AssertLinter 'luac.sh', ale#Escape('luac.sh') . ' -p - '
+ AssertLinter 'luac.sh', ale#Escape('luac.sh') . ' -p -'
diff --git a/test/command_callback/test_luacheck_command_callback.vader b/test/command_callback/test_luacheck_command_callback.vader
index 58d0cdc0..f0ef221c 100644
--- a/test/command_callback/test_luacheck_command_callback.vader
+++ b/test/command_callback/test_luacheck_command_callback.vader
@@ -6,7 +6,7 @@ After:
Execute(The lua luacheck command callback should return the correct default string):
AssertLinter 'luacheck',
- \ ale#Escape('luacheck') . ' --formatter plain --codes --filename %s -'
+ \ ale#Escape('luacheck') . ' --formatter plain --codes --filename %s -'
Execute(The lua luacheck command callback should let you set options):
let g:ale_lua_luacheck_options = '--config filename'
@@ -20,4 +20,4 @@ Execute(The luacheck executable should be configurable):
let g:ale_lua_luacheck_executable = 'luacheck.sh'
AssertLinter 'luacheck.sh',
- \ ale#Escape('luacheck.sh') . ' --formatter plain --codes --filename %s -'
+ \ ale#Escape('luacheck.sh') . ' --formatter plain --codes --filename %s -'
diff --git a/test/command_callback/test_mercury_mmc_command_callback.vader b/test/command_callback/test_mercury_mmc_command_callback.vader
index 2948e799..ab61fddf 100644
--- a/test/command_callback/test_mercury_mmc_command_callback.vader
+++ b/test/command_callback/test_mercury_mmc_command_callback.vader
@@ -8,18 +8,18 @@ After:
Execute(The default command should be correct):
AssertLinter 'mmc',
\ ale#path#BufferCdString(bufnr(''))
- \ . 'mmc --errorcheck-only --make --output-compile-error-lines 100 dummy'
+ \ . ale#Escape('mmc') . ' --errorcheck-only --make --output-compile-error-lines 100 dummy'
Execute(The executable should be configurable):
let b:ale_mercury_mmc_executable = 'foo'
AssertLinter 'foo',
\ ale#path#BufferCdString(bufnr(''))
- \ . 'foo --errorcheck-only --make --output-compile-error-lines 100 dummy'
+ \ . ale#Escape('foo') . ' --errorcheck-only --make --output-compile-error-lines 100 dummy'
Execute(The options should be configurable):
let b:ale_mercury_mmc_options = '--bar'
AssertLinter 'mmc',
\ ale#path#BufferCdString(bufnr(''))
- \ . 'mmc --errorcheck-only --bar dummy'
+ \ . ale#Escape('mmc') . ' --errorcheck-only --bar dummy'
diff --git a/test/command_callback/test_mypy_command_callback.vader b/test/command_callback/test_mypy_command_callback.vader
index 988dfb1b..8ca35207 100644
--- a/test/command_callback/test_mypy_command_callback.vader
+++ b/test/command_callback/test_mypy_command_callback.vader
@@ -12,7 +12,7 @@ After:
Execute(The mypy callbacks should return the correct default values):
AssertLinter 'mypy',
- \ 'cd ' . ale#Escape(g:dir) . ' && ' . ale#Escape('mypy')
+ \ ale#path#CdString(g:dir) . ale#Escape('mypy')
\ . ' --show-column-numbers '
\ . '--shadow-file %s %t %s'
@@ -20,7 +20,7 @@ Execute(The mypy executable should be configurable, and escaped properly):
let g:ale_python_mypy_executable = 'executable with spaces'
AssertLinter 'executable with spaces',
- \ 'cd ' . ale#Escape(g:dir) . ' && ' . ale#Escape('executable with spaces')
+ \ ale#path#CdString(g:dir) . ale#Escape('executable with spaces')
\ . ' --show-column-numbers '
\ . '--shadow-file %s %t %s'
@@ -28,7 +28,7 @@ Execute(The mypy command callback should let you set options):
let g:ale_python_mypy_options = '--some-option'
AssertLinter 'mypy',
- \ 'cd ' . ale#Escape(g:dir) . ' && ' . ale#Escape('mypy')
+ \ ale#path#CdString(g:dir) . ale#Escape('mypy')
\ . ' --show-column-numbers --some-option '
\ . '--shadow-file %s %t %s'
@@ -36,8 +36,8 @@ Execute(The mypy command should switch directories to the detected project root)
silent execute 'file ' . fnameescape(g:dir . '/python_paths/no_virtualenv/subdir/foo/bar.py')
AssertLinter 'mypy',
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/no_virtualenv/subdir'))
- \ . ' && ' . ale#Escape('mypy')
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/no_virtualenv/subdir'))
+ \ . ale#Escape('mypy')
\ . ' --show-column-numbers '
\ . '--shadow-file %s %t %s'
@@ -47,8 +47,8 @@ Execute(The mypy callbacks should detect virtualenv directories and switch to th
let b:executable = ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/mypy')
AssertLinter b:executable,
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
- \ . ' && ' . ale#Escape(b:executable)
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
+ \ . ale#Escape(b:executable)
\ . ' --show-column-numbers '
\ . '--shadow-file %s %t %s'
@@ -57,8 +57,8 @@ Execute(You should able able to use the global mypy instead):
let g:ale_python_mypy_use_global = 1
AssertLinter 'mypy',
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
- \ . ' && ' . ale#Escape('mypy')
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir'))
+ \ . ale#Escape('mypy')
\ . ' --show-column-numbers '
\ . '--shadow-file %s %t %s'
@@ -69,3 +69,11 @@ Execute(Setting executable to 'pipenv' appends 'run mypy'):
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run mypy'
\ . ' --show-column-numbers --shadow-file %s %t %s'
+
+Execute(Pipenv is detected when python_mypy_auto_pipenv is set):
+ let g:ale_python_mypy_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape('pipenv') . ' run mypy --show-column-numbers --shadow-file %s %t %s'
diff --git a/test/command_callback/test_nasm_nasm_command_callbacks.vader b/test/command_callback/test_nasm_nasm_command_callbacks.vader
index 4e0cf608..8e077306 100644
--- a/test/command_callback/test_nasm_nasm_command_callbacks.vader
+++ b/test/command_callback/test_nasm_nasm_command_callbacks.vader
@@ -2,9 +2,9 @@ Before:
call ale#assert#SetUpLinterTest('nasm', 'nasm')
let b:command_tail =
- \ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' %s'
+ \ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' %s -o ' . (has('win32') ? 'NUL' : '/dev/null')
let b:command_tail_opt =
- \ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w+orphan-labels %s'
+ \ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w+orphan-labels %s -o ' . (has('win32') ? 'NUL' : '/dev/null')
After:
unlet! b:command_tail
@@ -23,7 +23,7 @@ Execute(The options should be configurable):
let b:ale_nasm_nasm_options = '-w-macro-params'
AssertLinter 'nasm', ale#Escape('nasm')
- \ . ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w-macro-params %s'
+ \ . ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w-macro-params %s -o ' . (has('win32') ? 'NUL' : '/dev/null')
Execute(The options should be used in command):
let b:ale_nasm_nasm_options = '-w+orphan-labels'
diff --git a/test/command_callback/test_objc_ccls_command_callbacks.vader b/test/command_callback/test_objc_ccls_command_callbacks.vader
new file mode 100644
index 00000000..9d0c7690
--- /dev/null
+++ b/test/command_callback/test_objc_ccls_command_callbacks.vader
@@ -0,0 +1,40 @@
+Before:
+ call ale#assert#SetUpLinterTest('objc', 'ccls')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The project root should be detected correctly using compile_commands.json file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_compile_commands_json/dummy.m')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_compile_commands_json')
+
+Execute(The project root should be detected correctly using .ccls file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_ccls/dummy.m')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_ccls')
+
+Execute(The project root should be detected correctly using .ccls-root file):
+ AssertLSPProject ''
+
+ call ale#test#SetFilename('ccls_paths/with_ccls-root/dummy.m')
+
+ AssertLSPProject ale#path#Simplify(g:dir . '/ccls_paths/with_ccls-root')
+
+Execute(The executable should be configurable):
+ AssertLinter 'ccls', ale#Escape('ccls')
+
+ let b:ale_objc_ccls_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar')
+
+Execute(The initialization options should be configurable):
+ AssertLSPOptions {}
+
+ let b:ale_objc_ccls_init_options = { 'cacheDirectory': '/tmp/ccls' }
+
+ AssertLSPOptions { 'cacheDirectory': '/tmp/ccls' }
diff --git a/test/command_callback/test_perl6_command_callback.vader b/test/command_callback/test_perl6_command_callback.vader
new file mode 100644
index 00000000..d3ec6e17
--- /dev/null
+++ b/test/command_callback/test_perl6_command_callback.vader
@@ -0,0 +1,14 @@
+Before:
+ call ale#assert#SetUpLinterTest('perl6', 'perl6')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default Perl6 command callback should be correct):
+ AssertLinter 'perl6', 'perl6' . ' -c -Ilib %t'
+
+Execute(Overriding the executable and command should work):
+ let b:ale_perl6_perl6_executable = 'foobar'
+ let b:ale_perl6_perl6_options = '-w'
+
+ AssertLinter 'foobar', 'foobar' . ' -w %t'
diff --git a/test/command_callback/test_php_command_callback.vader b/test/command_callback/test_php_command_callback.vader
new file mode 100644
index 00000000..670d7196
--- /dev/null
+++ b/test/command_callback/test_php_command_callback.vader
@@ -0,0 +1,15 @@
+Before:
+ call ale#assert#SetUpLinterTest('php', 'php')
+ let b:command_tail = ' -l -d error_reporting=E_ALL -d display_errors=1'
+ \ . ' -d log_errors=0 --'
+
+After:
+ unlet! b:command_tail
+ call ale#assert#TearDownLinterTest()
+
+Execute(The executable should be configurable):
+ AssertLinter 'php', ale#Escape('php') . b:command_tail
+
+ let b:ale_php_php_executable = '/path/to/php'
+
+ AssertLinter '/path/to/php', ale#Escape('/path/to/php') . b:command_tail
diff --git a/test/command_callback/test_phpcs_command_callback.vader b/test/command_callback/test_phpcs_command_callback.vader
new file mode 100644
index 00000000..e5d2f449
--- /dev/null
+++ b/test/command_callback/test_phpcs_command_callback.vader
@@ -0,0 +1,35 @@
+Before:
+ call ale#assert#SetUpLinterTest('php', 'phpcs')
+
+After:
+ unlet! g:executable
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(The local phpcs executable should be used):
+ call ale#test#SetFilename('../phpcs-test-files/project-with-phpcs/foo/test.php')
+
+ let g:executable = ale#path#Simplify(g:dir . '/../phpcs-test-files/project-with-phpcs/vendor/bin/phpcs')
+
+ AssertLinter g:executable,
+ \ ale#Escape(g:executable) . ' -s --report=emacs --stdin-path=%s'
+
+Execute(use_global should override local executable detection):
+ let g:ale_php_phpcs_use_global = 1
+
+ call ale#test#SetFilename('../phpcs-test-files/project-with-phpcs/foo/test.php')
+
+ AssertLinter 'phpcs',
+ \ ale#Escape('phpcs') . ' -s --report=emacs --stdin-path=%s'
+
+Execute(Projects without local executables should use the global one):
+ call ale#test#SetFilename('../phpcs-test-files/project-without-phpcs/foo/test.php')
+
+ AssertLinter 'phpcs',
+ \ ale#Escape('phpcs') . ' -s --report=emacs --stdin-path=%s'
+
+Execute(User provided options are used):
+ let g:ale_php_phpcs_options = '--my-user-provided-option my-value'
+
+ AssertLinter 'phpcs',
+ \ ale#Escape('phpcs') . ' -s --report=emacs --stdin-path=%s --my-user-provided-option my-value'
diff --git a/test/command_callback/test_phpstan_command_callbacks.vader b/test/command_callback/test_phpstan_command_callbacks.vader
index c7db587a..665661a3 100644
--- a/test/command_callback/test_phpstan_command_callbacks.vader
+++ b/test/command_callback/test_phpstan_command_callbacks.vader
@@ -1,6 +1,8 @@
Before:
call ale#assert#SetUpLinterTest('php', 'phpstan')
+ WithChainResults ['0.10.2']
+
After:
call ale#assert#TearDownLinterTest()
@@ -22,3 +24,11 @@ Execute(Custom phpstan configuration file):
AssertLinter 'phpstan',
\ ale#Escape('phpstan') . ' analyze -l4 --errorFormat raw -c phpstan_config %s'
+
+Execute(Choose the right format for error format param):
+ WithChainResults ['0.10.3']
+
+ AssertLinter 'phpstan', [
+ \ ale#Escape('phpstan') . ' --version',
+ \ ale#Escape('phpstan') . ' analyze -l4 --error-format raw %s'
+ \ ]
diff --git a/test/command_callback/test_prospector_command_callback.vader b/test/command_callback/test_prospector_command_callback.vader
index 316b9883..0d692bde 100644
--- a/test/command_callback/test_prospector_command_callback.vader
+++ b/test/command_callback/test_prospector_command_callback.vader
@@ -10,3 +10,11 @@ Execute(Setting executable to 'pipenv' appends 'run prospector'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run prospector'
\ . ' --messages-only --absolute-paths --zero-exit --output-format json %s'
+
+Execute(Pipenv is detected when python_prospector_auto_pipenv is set):
+ let g:ale_python_prospector_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run prospector'
+ \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s'
diff --git a/test/command_callback/test_psalm_command_callbacks.vader b/test/command_callback/test_psalm_command_callbacks.vader
new file mode 100644
index 00000000..d731054f
--- /dev/null
+++ b/test/command_callback/test_psalm_command_callbacks.vader
@@ -0,0 +1,29 @@
+Before:
+ call ale#assert#SetUpLinterTest('php', 'psalm')
+
+After:
+ if isdirectory(g:dir . '/.git')
+ call delete(g:dir . '/.git', 'd')
+ endif
+
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default executable path should be correct):
+ AssertLinter 'psalm-language-server',
+ \ ale#Escape('psalm-language-server')
+
+Execute(Vendor executables should be detected):
+ call ale#test#SetFilename('psalm-project/test.php')
+
+ AssertLinter
+ \ ale#path#Simplify(g:dir . '/psalm-project/vendor/bin/psalm-language-server'),
+ \ ale#Escape(ale#path#Simplify(
+ \ g:dir
+ \ . '/psalm-project/vendor/bin/psalm-language-server'
+ \ ))
+
+Execute(The project path should be correct for .git directories):
+ call ale#test#SetFilename('psalm-project/test.php')
+ call mkdir(g:dir . '/.git')
+
+ AssertLSPProject g:dir \ No newline at end of file
diff --git a/test/command_callback/test_pycodestyle_command_callback.vader b/test/command_callback/test_pycodestyle_command_callback.vader
index 851eede9..a3a338a9 100644
--- a/test/command_callback/test_pycodestyle_command_callback.vader
+++ b/test/command_callback/test_pycodestyle_command_callback.vader
@@ -24,3 +24,10 @@ Execute(Setting executable to 'pipenv' appends 'run pycodestyle'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run pycodestyle -'
+
+Execute(Pipenv is detected when python_pycodestyle_auto_pipenv is set):
+ let g:ale_python_pycodestyle_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pycodestyle -'
diff --git a/test/command_callback/test_pyflakes_command_callback.vader b/test/command_callback/test_pyflakes_command_callback.vader
index efc925fe..92f83820 100644
--- a/test/command_callback/test_pyflakes_command_callback.vader
+++ b/test/command_callback/test_pyflakes_command_callback.vader
@@ -37,3 +37,10 @@ Execute(Setting executable to 'pipenv' appends 'run pyflakes'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run pyflakes %t',
+
+Execute(Pipenv is detected when python_pyflakes_auto_pipenv is set):
+ let g:ale_python_pyflakes_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pyflakes %t'
diff --git a/test/command_callback/test_pylint_command_callback.vader b/test/command_callback/test_pylint_command_callback.vader
index be2908f9..6b21b127 100644
--- a/test/command_callback/test_pylint_command_callback.vader
+++ b/test/command_callback/test_pylint_command_callback.vader
@@ -68,3 +68,12 @@ Execute(Setting executable to 'pipenv' appends 'run pylint'):
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run pylint'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
+
+Execute(Pipenv is detected when python_pylint_auto_pipenv is set):
+ let g:ale_python_pylint_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#path#BufferCdString(bufnr(''))
+ \ . ale#Escape('pipenv') . ' run pylint'
+ \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
diff --git a/test/command_callback/test_pyls_command_callback.vader b/test/command_callback/test_pyls_command_callback.vader
index 53bf3000..531b5b3b 100644
--- a/test/command_callback/test_pyls_command_callback.vader
+++ b/test/command_callback/test_pyls_command_callback.vader
@@ -38,3 +38,10 @@ Execute(Setting executable to 'pipenv' appends 'run pyls'):
let g:ale_python_pyls_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run pyls'
+
+Execute(Pipenv is detected when python_pyls_auto_pipenv is set):
+ let g:ale_python_pyls_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pyls'
diff --git a/test/command_callback/test_pyre_command_callback.vader b/test/command_callback/test_pyre_command_callback.vader
index 6ad19b56..ba57c117 100644
--- a/test/command_callback/test_pyre_command_callback.vader
+++ b/test/command_callback/test_pyre_command_callback.vader
@@ -37,3 +37,10 @@ Execute(Setting executable to 'pipenv' appends 'run pyre'):
AssertLinter 'path/to/pipenv',
\ ale#Escape('path/to/pipenv') . ' run pyre persistent'
+
+Execute(Pipenv is detected when python_pyre_auto_pipenv is set):
+ let g:ale_python_pyre_auto_pipenv = 1
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertLinter 'pipenv',
+ \ ale#Escape('pipenv') . ' run pyre persistent'
diff --git a/test/command_callback/test_reek_command_callback.vader b/test/command_callback/test_reek_command_callback.vader
index 059e5e36..a7cb7fb9 100644
--- a/test/command_callback/test_reek_command_callback.vader
+++ b/test/command_callback/test_reek_command_callback.vader
@@ -7,8 +7,8 @@ After:
Execute(The reek callbacks should return the correct default values):
WithChainResults ['reek 5.0.0']
AssertLinter 'reek', [
- \ 'reek --version',
- \ 'reek -f json --no-progress --no-color --stdin-filename %s',
+ \ ale#Escape('reek') . ' --version',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s',
\]
" Try with older versions.
@@ -16,19 +16,35 @@ Execute(The reek callbacks should return the correct default values):
WithChainResults ['reek 4.8.2']
AssertLinter 'reek', [
- \ 'reek --version',
- \ 'reek -f json --no-progress --no-color',
+ \ ale#Escape('reek') . ' --version',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion',
\]
+Execute(Setting bundle appends 'exec reek'):
+ let g:ale_ruby_reek_executable = 'bundle'
+
+ WithChainResults ['reek 5.0.0']
+ AssertLinter 'bundle', ale#Escape('bundle')
+ \ . ' exec reek'
+ \ . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s',
+
+ " Try with older versions.
+ call ale#semver#ResetVersionCache()
+
+ WithChainResults ['reek 4.8.2']
+ AssertLinter 'bundle', ale#Escape('bundle')
+ \ . ' exec reek'
+ \ . ' -f json --no-progress --no-color --force-exclusion'
+
Execute(The reek version check should be cached):
WithChainResults ['reek 5.0.0']
AssertLinter 'reek', [
- \ 'reek --version',
- \ 'reek -f json --no-progress --no-color --stdin-filename %s',
+ \ ale#Escape('reek') . ' --version',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s',
\]
WithChainResults []
AssertLinter 'reek', [
\ '',
- \ 'reek -f json --no-progress --no-color --stdin-filename %s',
+ \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s',
\]
diff --git a/test/command_callback/test_ruby_solargraph.vader b/test/command_callback/test_ruby_solargraph.vader
new file mode 100644
index 00000000..c6aee271
--- /dev/null
+++ b/test/command_callback/test_ruby_solargraph.vader
@@ -0,0 +1,44 @@
+" Author: Horacio Sanson <https://github.com/hsanson>
+" Description: Tests for solargraph lsp linter.
+
+Before:
+ call ale#assert#SetUpLinterTest('ruby', 'solargraph')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(command callback should return default string):
+ AssertLinter 'solargraph', ale#Escape('solargraph') . ' stdio'
+
+Execute(command callback executable can be overridden):
+ let g:ale_ruby_solargraph_executable = 'foobar'
+ AssertLinter 'foobar', ale#Escape('foobar') . ' stdio'
+
+Execute(should set solargraph for rails app):
+ call ale#test#SetFilename('../ruby_fixtures/valid_rails_app/app/models/thing.rb')
+ AssertLSPLanguage 'ruby'
+ AssertLSPOptions {}
+ AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_rails_app')
+
+Execute(should set solargraph for ruby app1):
+ call ale#test#SetFilename('../ruby_fixtures/valid_ruby_app1/lib/file.rb')
+ AssertLSPLanguage 'ruby'
+ AssertLSPOptions {}
+ AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_ruby_app1')
+
+Execute(should set solargraph for ruby app2):
+ call ale#test#SetFilename('../ruby_fixtures/valid_ruby_app2/lib/file.rb')
+ AssertLSPLanguage 'ruby'
+ AssertLSPOptions {}
+ AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_ruby_app2')
+
+Execute(should set solargraph for ruby app3):
+ call ale#test#SetFilename('../ruby_fixtures/valid_ruby_app3/lib/file.rb')
+ AssertLSPLanguage 'ruby'
+ AssertLSPOptions {}
+ AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../ruby_fixtures/valid_ruby_app3')
+
+Execute(should accept initialization options):
+ AssertLSPOptions {}
+ let b:ale_ruby_solargraph_options = { 'diagnostics': 'true' }
+ AssertLSPOptions { 'diagnostics': 'true' }
diff --git a/test/command_callback/test_rustc_command_callback.vader b/test/command_callback/test_rustc_command_callback.vader
index 7ca02760..f765e725 100644
--- a/test/command_callback/test_rustc_command_callback.vader
+++ b/test/command_callback/test_rustc_command_callback.vader
@@ -5,7 +5,7 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'rustc', 'rustc --error-format=json -Z no-trans -'
+ AssertLinter 'rustc', 'rustc --error-format=json -Z no-codegen -'
Execute(The options should be configurable):
let b:ale_rust_rustc_options = '--foo'
@@ -15,7 +15,7 @@ Execute(The options should be configurable):
Execute(Some default paths should be included when the project is a Cargo project):
call ale#test#SetFilename('cargo_paths/test.rs')
- AssertLinter 'rustc', 'rustc --error-format=json -Z no-trans'
+ AssertLinter 'rustc', 'rustc --error-format=json -Z no-codegen'
\ . ' -L ' . ale#Escape(ale#path#GetAbsPath(g:dir, 'cargo_paths/target/debug/deps'))
\ . ' -L ' . ale#Escape(ale#path#GetAbsPath(g:dir, 'cargo_paths/target/release/deps'))
\ . ' -'
diff --git a/test/command_callback/test_ruumba_command_callback.vader b/test/command_callback/test_ruumba_command_callback.vader
new file mode 100644
index 00000000..244b264a
--- /dev/null
+++ b/test/command_callback/test_ruumba_command_callback.vader
@@ -0,0 +1,29 @@
+Before:
+ call ale#assert#SetUpLinterTest('eruby', 'ruumba')
+ call ale#test#SetFilename('dummy.html.erb')
+
+ let g:ale_eruby_ruumba_executable = 'ruumba'
+ let g:ale_eruby_ruumba_options = ''
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Executable should default to ruumba):
+ AssertLinter 'ruumba', ale#Escape('ruumba')
+ \ . ' --format json --force-exclusion --stdin '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.html.erb'))
+
+Execute(Should be able to set a custom executable):
+ let g:ale_eruby_ruumba_executable = 'bin/ruumba'
+
+ AssertLinter 'bin/ruumba' , ale#Escape('bin/ruumba')
+ \ . ' --format json --force-exclusion --stdin '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.html.erb'))
+
+Execute(Setting bundle appends 'exec ruumba'):
+ let g:ale_eruby_ruumba_executable = 'path to/bundle'
+
+ AssertLinter 'path to/bundle', ale#Escape('path to/bundle')
+ \ . ' exec ruumba'
+ \ . ' --format json --force-exclusion --stdin '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.html.erb'))
diff --git a/test/command_callback/test_sasslint_command_callback.vader b/test/command_callback/test_sasslint_command_callback.vader
index 4d7cc4c7..9142c441 100644
--- a/test/command_callback/test_sasslint_command_callback.vader
+++ b/test/command_callback/test_sasslint_command_callback.vader
@@ -7,5 +7,5 @@ After:
Execute(The default sasslint command should be correct):
AssertLinter 'sass-lint',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('sass-lint') . ' -v -q -f compact %t'
diff --git a/test/command_callback/test_scala_sbtserver.vader b/test/command_callback/test_scala_sbtserver.vader
new file mode 100644
index 00000000..1c7d8472
--- /dev/null
+++ b/test/command_callback/test_scala_sbtserver.vader
@@ -0,0 +1,21 @@
+" Author: ophirr33 <coghlan.ty@gmail.com>
+" Description: Tests for the sbt Server lsp linter
+
+Before:
+ call ale#assert#SetUpLinterTest('scala', 'sbtserver')
+After:
+ call ale#assert#TearDownLinterTest()
+Execute(should set sbtserver for sbt project with build.sbt):
+ call ale#test#SetFilename('../scala_fixtures/valid_sbt_project/Main.scala')
+ AssertLSPLanguage 'scala'
+ AssertLSPOptions {}
+ AssertLSPConfig {}
+ AssertLSPProject ale#path#Simplify(g:dir . 'command_callback/../scala_fixtures/valid_sbt_project')
+ AssertLSPAddress '127.0.0.1:4273'
+Execute(should not set sbtserver for sbt project without build.sbt):
+ call ale#test#SetFilename('../scala_fixtures/invalid_sbt_project/Main.scala')
+ AssertLSPLanguage 'scala'
+ AssertLSPOptions {}
+ AssertLSPConfig {}
+ AssertLSPProject ''
+ AssertLSPAddress '127.0.0.1:4273'
diff --git a/test/command_callback/test_scalac_command_callback.vader b/test/command_callback/test_scalac_command_callback.vader
index 115731b3..5184aa0b 100644
--- a/test/command_callback/test_scalac_command_callback.vader
+++ b/test/command_callback/test_scalac_command_callback.vader
@@ -6,8 +6,8 @@ After:
Given scala(An empty Scala file):
Execute(The default executable and command should be correct):
- AssertLinter 'scalac', ale#Escape('scalac') . ' -Ystop-after:parser %t'
+ AssertLinter 'scalac', ale#Escape('scalac') . ' -Ystop-before:jvm %t'
Given scala.sbt(An empty SBT file):
Execute(scalac should not be run for sbt files):
- AssertLinter '', ''
+ AssertLinterNotExecuted
diff --git a/test/command_callback/test_scss_stylelint_command_callback.vader b/test/command_callback/test_scss_stylelint_command_callback.vader
new file mode 100644
index 00000000..9c3a02d8
--- /dev/null
+++ b/test/command_callback/test_scss_stylelint_command_callback.vader
@@ -0,0 +1,31 @@
+Before:
+ call ale#assert#SetUpLinterTest('scss', 'stylelint')
+ unlet! b:executable
+
+After:
+ unlet! b:executable
+ call ale#assert#TearDownLinterTest()
+
+Execute(node_modules directories should be discovered):
+ call ale#test#SetFilename('stylelint_paths/nested/testfile.scss')
+
+ let b:executable = ale#path#Simplify(
+ \ g:dir
+ \ . '/stylelint_paths/node_modules/.bin/stylelint'
+ \)
+
+ AssertLinter b:executable, ale#Escape(b:executable) . ' --stdin-filename %s'
+
+Execute(The global override should work):
+ let b:ale_scss_stylelint_executable = 'foobar'
+ let b:ale_scss_stylelint_use_global = 1
+
+ call ale#test#SetFilename('stylelint_paths/nested/testfile.scss')
+
+ AssertLinter 'foobar', ale#Escape('foobar') . ' --stdin-filename %s'
+
+Execute(Extra options should be configurable):
+ let b:ale_scss_stylelint_options = '--configFile ''/absolute/path/to/file'''
+
+ AssertLinter 'stylelint',
+ \ ale#Escape('stylelint') . ' --configFile ''/absolute/path/to/file'' --stdin-filename %s'
diff --git a/test/command_callback/test_shellcheck_command_callback.vader b/test/command_callback/test_shellcheck_command_callback.vader
index 23684026..22a9ccb5 100644
--- a/test/command_callback/test_shellcheck_command_callback.vader
+++ b/test/command_callback/test_shellcheck_command_callback.vader
@@ -2,7 +2,7 @@ Before:
call ale#assert#SetUpLinterTest('sh', 'shellcheck')
call ale#test#SetFilename('test.sh')
- let b:prefix = 'cd ' . ale#Escape(ale#path#Simplify(g:dir)) . ' && '
+ let b:prefix = ale#path#CdString(ale#path#Simplify(g:dir))
let b:suffix = ' -f gcc -'
After:
diff --git a/test/command_callback/test_staticcheck_command_callback.vader b/test/command_callback/test_staticcheck_command_callback.vader
index 918c12a0..7f17b146 100644
--- a/test/command_callback/test_staticcheck_command_callback.vader
+++ b/test/command_callback/test_staticcheck_command_callback.vader
@@ -7,7 +7,7 @@ After:
Execute(The staticcheck callback should return the right defaults):
AssertLinter 'staticcheck',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . 'staticcheck '
\ . ale#Escape(expand('%' . ':t'))
@@ -15,7 +15,7 @@ Execute(The staticcheck callback should use configured options):
let b:ale_go_staticcheck_options = '-test'
AssertLinter 'staticcheck',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . 'staticcheck '
\ . '-test ' . ale#Escape(expand('%' . ':t'))
@@ -23,4 +23,4 @@ Execute(The staticcheck `lint_package` option should use the correct command):
let b:ale_go_staticcheck_lint_package = 1
AssertLinter 'staticcheck',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && staticcheck .',
+ \ ale#path#CdString(expand('%:p:h')) . 'staticcheck .',
diff --git a/test/command_callback/test_swaglint_command_callback.vader b/test/command_callback/test_swaglint_command_callback.vader
index fe8fb722..68fb1406 100644
--- a/test/command_callback/test_swaglint_command_callback.vader
+++ b/test/command_callback/test_swaglint_command_callback.vader
@@ -5,25 +5,25 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The yaml swaglint command callback should return the correct default string):
- AssertLinter 'swaglint', 'swaglint -r compact --stdin'
+ AssertLinter 'swaglint', ale#Escape('swaglint') . ' -r compact --stdin'
Execute(The yaml swaglint command callback should be configurable):
let g:ale_yaml_swaglint_executable = '~/.local/bin/swaglint'
AssertLinter '~/.local/bin/swaglint',
- \ '~/.local/bin/swaglint -r compact --stdin'
+ \ ale#Escape('~/.local/bin/swaglint') . ' -r compact --stdin'
Execute(The yaml swaglint command callback should allow a global installation to be used):
let g:ale_yaml_swaglint_executable = '/usr/local/bin/swaglint'
let g:ale_yaml_swaglint_use_global = 1
AssertLinter '/usr/local/bin/swaglint',
- \ '/usr/local/bin/swaglint -r compact --stdin'
+ \ ale#Escape('/usr/local/bin/swaglint') . ' -r compact --stdin'
Execute(The yaml swaglint command callback should allow a local installation to be used):
call ale#test#SetFilename('swaglint_paths/docs/swagger.yaml')
AssertLinter
\ ale#path#Simplify(g:dir . '/swaglint_paths/node_modules/.bin/swaglint'),
- \ ale#path#Simplify(g:dir . '/swaglint_paths/node_modules/.bin/swaglint')
+ \ ale#Escape(ale#path#Simplify(g:dir . '/swaglint_paths/node_modules/.bin/swaglint'))
\ . ' -r compact --stdin'
diff --git a/test/command_callback/test_terraform_tflint_command_callback.vader b/test/command_callback/test_terraform_tflint_command_callback.vader
index c32d9bcf..0cef0176 100644
--- a/test/command_callback/test_terraform_tflint_command_callback.vader
+++ b/test/command_callback/test_terraform_tflint_command_callback.vader
@@ -17,3 +17,12 @@ Execute(Overriding options should work):
let g:ale_terraform_tflint_options = '--whatever'
AssertLinter 'fnord', ale#Escape('fnord') . ' --whatever -f json %t'
+
+Execute(Configuration files should be found):
+ call ale#test#SetFilename('../tflint-test-files/foo/bar.tf')
+
+ AssertLinter 'tflint',
+ \ ale#Escape('tflint')
+ \ . ' --config '
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/../tflint-test-files/foo/.tflint.hcl'))
+ \ . ' -f json %t'
diff --git a/test/command_callback/test_thrift_command_callback.vader b/test/command_callback/test_thrift_command_callback.vader
index ea217259..cbada818 100644
--- a/test/command_callback/test_thrift_command_callback.vader
+++ b/test/command_callback/test_thrift_command_callback.vader
@@ -23,22 +23,22 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -strict' . b:suffix
+ AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -I . -strict' . b:suffix
Execute(The executable should be configurable):
let b:ale_thrift_thrift_executable = 'foobar'
- AssertLinter 'foobar', ale#Escape('foobar') . ' --gen cpp -strict' . b:suffix
+ AssertLinter 'foobar', ale#Escape('foobar') . ' --gen cpp -I . -strict' . b:suffix
Execute(The list of generators should be configurable):
let b:ale_thrift_thrift_generators = ['java', 'py:dynamic']
AssertLinter 'thrift', ale#Escape('thrift')
- \ . ' --gen java --gen py:dynamic -strict' . b:suffix
+ \ . ' --gen java --gen py:dynamic -I . -strict' . b:suffix
let b:ale_thrift_thrift_generators = []
- AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -strict' . b:suffix
+ AssertLinter 'thrift', ale#Escape('thrift') . ' --gen cpp -I . -strict' . b:suffix
Execute(The list of include paths should be configurable):
let b:ale_thrift_thrift_includes = ['included/path']
@@ -50,4 +50,4 @@ Execute(The string of compiler options should be configurable):
let b:ale_thrift_thrift_options = '-strict --allow-64bit-consts'
AssertLinter 'thrift', ale#Escape('thrift')
- \ . ' --gen cpp -strict --allow-64bit-consts' . b:suffix
+ \ . ' --gen cpp -I . -strict --allow-64bit-consts' . b:suffix
diff --git a/test/command_callback/test_tslint_command_callback.vader b/test/command_callback/test_tslint_command_callback.vader
index bd8a12ec..229ccc96 100644
--- a/test/command_callback/test_tslint_command_callback.vader
+++ b/test/command_callback/test_tslint_command_callback.vader
@@ -7,14 +7,14 @@ After:
Execute(The default tslint command should be correct):
AssertLinter 'tslint',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('tslint') . ' --format json %t'
Execute(The rules directory option should be included if set):
let b:ale_typescript_tslint_rules_dir = '/foo/bar'
AssertLinter 'tslint',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('tslint') . ' --format json'
\ . ' -r ' . ale#Escape('/foo/bar')
\ . ' %t'
@@ -23,5 +23,5 @@ Execute(The executable should be configurable and escaped):
let b:ale_typescript_tslint_executable = 'foo bar'
AssertLinter 'foo bar',
- \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('foo bar') . ' --format json %t'
diff --git a/test/command_callback/test_typescript_tsserver_command_callback.vader b/test/command_callback/test_typescript_tsserver_command_callback.vader
new file mode 100644
index 00000000..719ac184
--- /dev/null
+++ b/test/command_callback/test_typescript_tsserver_command_callback.vader
@@ -0,0 +1,8 @@
+Before:
+ call ale#assert#SetUpLinterTest('typescript', 'tsserver')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'tsserver', ale#Escape('tsserver')
diff --git a/test/command_callback/test_yang_lsp_command_callbacks.vader b/test/command_callback/test_yang_lsp_command_callbacks.vader
new file mode 100644
index 00000000..5be7501f
--- /dev/null
+++ b/test/command_callback/test_yang_lsp_command_callbacks.vader
@@ -0,0 +1,12 @@
+Before:
+ call ale#assert#SetUpLinterTest('yang', 'yang_lsp')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The executable should be configurable):
+ AssertLinter 'yang-language-server', ale#Escape('yang-language-server')
+
+ let b:ale_yang_lsp_executable = 'foobar'
+
+ AssertLinter 'foobar', ale#Escape('foobar')
diff --git a/test/completion/test_completion_events.vader b/test/completion/test_completion_events.vader
index f3e05950..3f0bfa70 100644
--- a/test/completion/test_completion_events.vader
+++ b/test/completion/test_completion_events.vader
@@ -129,6 +129,10 @@ Execute(ale#completion#Show() should remember the omnifunc setting and replace i
AssertEqual 'FooBar', b:ale_old_omnifunc
AssertEqual 'ale#completion#OmniFunc', &l:omnifunc
+ AssertEqual [], g:feedkeys_calls
+ sleep 1ms
+ AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
+
Execute(ale#completion#Show() should remember the completeopt setting and replace it):
let &l:completeopt = 'menu'
@@ -137,6 +141,10 @@ Execute(ale#completion#Show() should remember the completeopt setting and replac
AssertEqual 'menu', b:ale_old_completopt
AssertEqual 'menu,menuone,noselect,noinsert', &l:completeopt
+ AssertEqual [], g:feedkeys_calls
+ sleep 1ms
+ AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
+
Execute(ale#completion#Show() should set the preview option if it's set):
let &l:completeopt = 'menu,preview'
@@ -145,6 +153,10 @@ Execute(ale#completion#Show() should set the preview option if it's set):
AssertEqual 'menu,preview', b:ale_old_completopt
AssertEqual 'menu,menuone,preview,noselect,noinsert', &l:completeopt
+ AssertEqual [], g:feedkeys_calls
+ sleep 1ms
+ AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
+
Execute(ale#completion#OmniFunc() should also remember the completeopt setting and replace it):
let &l:completeopt = 'menu'
@@ -164,6 +176,8 @@ Execute(ale#completion#OmniFunc() should set the preview option if it's set):
Execute(ale#completion#Show() should make the correct feedkeys() call):
call ale#completion#Show('Response', 'Parser')
+ AssertEqual [], g:feedkeys_calls
+ sleep 1ms
AssertEqual [["\<Plug>(ale_show_completion_menu)"]], g:feedkeys_calls
Execute(ale#completion#Show() shouldn't do anything if you switch back to normal mode):
diff --git a/test/completion/test_completion_filtering.vader b/test/completion/test_completion_filtering.vader
index ae91a952..ffb313ef 100644
--- a/test/completion/test_completion_filtering.vader
+++ b/test/completion/test_completion_filtering.vader
@@ -12,16 +12,17 @@ After:
Execute(Prefix filtering should work for Lists of strings):
AssertEqual
\ ['FooBar', 'foo'],
- \ ale#completion#Filter(bufnr(''), ['FooBar', 'FongBar', 'baz', 'foo'], 'foo')
+ \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], 'foo')
AssertEqual
\ ['FooBar', 'FongBar', 'baz', 'foo'],
- \ ale#completion#Filter(bufnr(''), ['FooBar', 'FongBar', 'baz', 'foo'], '.')
+ \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '.')
Execute(Prefix filtering should work for completion items):
AssertEqual
\ [{'word': 'FooBar'}, {'word': 'foo'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'FooBar'},
\ {'word': 'FongBar'},
@@ -40,6 +41,7 @@ Execute(Prefix filtering should work for completion items):
\ ],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'FooBar'},
\ {'word': 'FongBar'},
@@ -56,6 +58,7 @@ Execute(Excluding words from completion results should work):
\ [{'word': 'Italian'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'Italian'},
\ {'word': 'it'},
@@ -67,6 +70,7 @@ Execute(Excluding words from completion results should work):
\ [{'word': 'Deutsch'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'describe'},
\ {'word': 'Deutsch'},
@@ -78,6 +82,7 @@ Execute(Excluding words from completion results should work):
\ [{'word': 'Deutsch'}],
\ ale#completion#Filter(
\ bufnr(''),
+ \ '',
\ [
\ {'word': 'describe'},
\ {'word': 'Deutsch'},
@@ -90,19 +95,26 @@ Execute(Excluding words from completion results should work with lists of String
AssertEqual
\ ['Italian'],
- \ ale#completion#Filter(bufnr(''), ['Italian', 'it'], 'it')
+ \ ale#completion#Filter(bufnr(''), '', ['Italian', 'it'], 'it')
AssertEqual
\ ['Deutsch'],
- \ ale#completion#Filter(bufnr(''), ['describe', 'Deutsch'], 'de')
+ \ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], 'de')
AssertEqual
\ ['Deutsch'],
- \ ale#completion#Filter(bufnr(''), ['describe', 'Deutsch'], '.')
+ \ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], '.')
Execute(Filtering shouldn't modify the original list):
let b:ale_completion_excluded_words = ['it', 'describe']
let b:suggestions = [{'word': 'describe'}]
- AssertEqual [], ale#completion#Filter(bufnr(''), b:suggestions, '.')
+ AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, '.')
AssertEqual b:suggestions, [{'word': 'describe'}]
- AssertEqual [], ale#completion#Filter(bufnr(''), b:suggestions, 'de')
+ AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, 'de')
AssertEqual b:suggestions, [{'word': 'describe'}]
+
+Execute(Filtering should respect filetype triggers):
+ let b:suggestions = [{'word': 'describe'}]
+
+ AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), '', b:suggestions, '.')
+ AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '.')
+ AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '::')
diff --git a/test/completion/test_completion_prefixes.vader b/test/completion/test_completion_prefixes.vader
index 0b2cfeaf..3f2cab15 100644
--- a/test/completion/test_completion_prefixes.vader
+++ b/test/completion/test_completion_prefixes.vader
@@ -43,3 +43,23 @@ Execute(Completion should be done after words in parens in Rust):
Execute(Completion should not be done after parens in Rust):
AssertEqual '', ale#completion#GetPrefix(&filetype, 3, 15)
+
+Given lisp():
+ (minus-name
+ (full-name)
+
+Execute(Completion should be done for function names with minuses in Lisp):
+ AssertEqual 'minus-name', ale#completion#GetPrefix(&filetype, 1, 12)
+
+Execute(Completion should not be done after parens in Lisp):
+ AssertEqual '', ale#completion#GetPrefix(&filetype, 2, 12)
+
+Given clojure():
+ (minus-name
+ (full-name)
+
+Execute(Completion should be done for function names with minuses in Clojure):
+ AssertEqual 'minus-name', ale#completion#GetPrefix(&filetype, 1, 12)
+
+Execute(Completion should not be done after parens in Clojure):
+ AssertEqual '', ale#completion#GetPrefix(&filetype, 2, 12)
diff --git a/test/completion/test_lsp_completion_messages.vader b/test/completion/test_lsp_completion_messages.vader
index ed0f358b..130f31b9 100644
--- a/test/completion/test_lsp_completion_messages.vader
+++ b/test/completion/test_lsp_completion_messages.vader
@@ -14,17 +14,17 @@ Before:
let g:message_list = []
let g:capability_checked = ''
+ let g:conn_id = v:null
let g:Callback = ''
let g:wait_callback_list = []
function! ale#lsp_linter#StartLSP(buffer, linter) abort
- let l:conn = ale#lsp#NewConnection({})
- let l:conn.id = 347
- let l:conn.open_documents = {a:buffer : -1}
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
return {
\ 'buffer': a:buffer,
- \ 'connection_id': 347,
+ \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar',
\ 'language_id': 'python',
\}
@@ -35,7 +35,7 @@ Before:
return 'i'
endfunction
- function! ale#lsp#WaitForCapability(conn_id, project_root, capability, callback) abort
+ function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort
let g:capability_checked = a:capability
call add(g:wait_callback_list, a:callback)
endfunction
@@ -45,7 +45,7 @@ Before:
endfunction
" Replace the Send function for LSP, so we can monitor calls to it.
- function! ale#lsp#Send(conn_id, message, ...) abort
+ function! ale#lsp#Send(conn_id, message) abort
call add(g:message_list, a:message)
return 1
@@ -54,9 +54,14 @@ Before:
After:
Restore
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
unlet! g:message_list
unlet! g:capability_checked
unlet! g:wait_callback_list
+ unlet! g:conn_id
unlet! g:Callback
unlet! b:ale_old_omnifunc
unlet! b:ale_old_completopt
@@ -72,7 +77,6 @@ After:
return call('mode', a:000)
endfunction
- call ale#lsp#RemoveConnectionWithID(347)
call ale#test#RestoreDirectory()
call ale#linter#Reset()
@@ -102,7 +106,7 @@ Execute(The right message should be sent for the initial tsserver request):
AssertEqual 1, len(g:wait_callback_list)
AssertEqual 'completion', g:capability_checked
- call map(g:wait_callback_list, 'v:val([347, ''/foo/bar''])')
+ call map(g:wait_callback_list, 'v:val([g:conn_id, ''/foo/bar''])')
" We should send the right callback.
AssertEqual
@@ -116,7 +120,7 @@ Execute(The right message should be sent for the initial tsserver request):
AssertEqual
\ {
\ 'line_length': 3,
- \ 'conn_id': 347,
+ \ 'conn_id': g:conn_id,
\ 'column': 3,
\ 'request_id': 1,
\ 'line': 1,
@@ -189,7 +193,7 @@ Execute(The right message should be sent for the initial LSP request):
AssertEqual 1, len(g:wait_callback_list)
AssertEqual 'completion', g:capability_checked
- call map(g:wait_callback_list, 'v:val([347, ''/foo/bar''])')
+ call map(g:wait_callback_list, 'v:val([g:conn_id, ''/foo/bar''])')
" We should send the right callback.
AssertEqual
@@ -219,7 +223,7 @@ Execute(The right message should be sent for the initial LSP request):
AssertEqual
\ {
\ 'line_length': 3,
- \ 'conn_id': 347,
+ \ 'conn_id': g:conn_id,
\ 'column': 3,
\ 'request_id': 1,
\ 'line': 1,
diff --git a/test/completion/test_lsp_completion_parsing.vader b/test/completion/test_lsp_completion_parsing.vader
index d5a45b54..71e53ab6 100644
--- a/test/completion/test_lsp_completion_parsing.vader
+++ b/test/completion/test_lsp_completion_parsing.vader
@@ -447,3 +447,27 @@ Execute(Should handle missing keys):
\ ]
\ }
\ })
+
+Execute(Should handle documentation in the markdown format):
+ AssertEqual
+ \ [
+ \ {'word': 'migrations', 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1},
+ \ ],
+ \ ale#completion#ParseLSPCompletions({
+ \ 'jsonrpc': '2.0',
+ \ 'id': 6,
+ \ 'result': {
+ \ 'isIncomplete': v:false,
+ \ 'items': [
+ \ {
+ \ 'label': 'migrations',
+ \ 'kind': 3,
+ \ 'detail': 'xxx',
+ \ 'documentation': {
+ \ 'kind': 'markdown',
+ \ 'value': 'Markdown documentation',
+ \ },
+ \ },
+ \ ],
+ \ },
+ \ })
diff --git a/test/completion/test_tsserver_completion_parsing.vader b/test/completion/test_tsserver_completion_parsing.vader
index c8e2c993..dbc4f9e2 100644
--- a/test/completion/test_tsserver_completion_parsing.vader
+++ b/test/completion/test_tsserver_completion_parsing.vader
@@ -32,6 +32,13 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'kind': 'f',
\ 'icase': 1,
\ },
+ \ {
+ \ 'word': 'ghi',
+ \ 'menu': '(class) Foo',
+ \ 'info': '',
+ \ 'kind': 'f',
+ \ 'icase': 1,
+ \ },
\ ],
\ ale#completion#ParseTSServerCompletionEntryDetails({
\ 'body': [
@@ -74,6 +81,17 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ {'text': 'baz'},
\ ],
\ },
+ \ {
+ \ 'name': 'ghi',
+ \ 'kind': 'className',
+ \ 'displayParts': [
+ \ {'text': '('},
+ \ {'text': 'class'},
+ \ {'text': ')'},
+ \ {'text': ' '},
+ \ {'text': 'Foo'},
+ \ ],
+ \ },
\ ],
\})
diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader
index 67b8b212..90407681 100644
--- a/test/fix/test_ale_fix.vader
+++ b/test/fix/test_ale_fix.vader
@@ -23,7 +23,7 @@ Before:
autocmd!
autocmd User ALEFixPre let g:pre_success = 1
autocmd User ALEFixPost let g:post_success = 1
- augroup end
+ augroup END
if !has('win32')
let &shell = '/bin/bash'
@@ -180,7 +180,7 @@ After:
unlet! g:ale_emulate_job_failure
unlet! b:ale_fixers
unlet! b:ale_fix_on_save
- augroup! VaderTest
+ unlet! b:ale_quitting
delfunction AddCarets
delfunction AddDollars
delfunction DoNothing
@@ -204,6 +204,12 @@ After:
delfunction FixWithJSONPostProcessing
delfunction JSONPostProcessor
+ augroup VaderTest
+ autocmd!
+ augroup END
+
+ augroup! VaderTest
+
call ale#test#RestoreDirectory()
call ale#fix#registry#ResetToDefaults()
@@ -426,7 +432,7 @@ Given testft (A file with three lines):
b
c
-Execute(ALEFix should save files on the save event):
+Execute(ALEFix should fix files on the save event):
let g:ale_fix_on_save = 1
let g:ale_lint_on_save = 1
let g:ale_enabled = 1
@@ -466,6 +472,36 @@ Expect(The buffer should be modified):
$b
$c
+Execute(ALEFix should not fix files on :wq):
+ let g:ale_fix_on_save = 1
+ let g:ale_lint_on_save = 1
+ let g:ale_enabled = 1
+
+ noautocmd silent file fix_test_file
+ call writefile(getline(1, '$'), 'fix_test_file')
+
+ let g:ale_fixers.testft = ['AddDollars']
+
+ " We have to set the buftype to empty so the file will be written.
+ setlocal buftype=
+
+ call ale#events#QuitEvent(bufnr(''))
+
+ call SetUpLinters()
+ call ale#events#SaveEvent(bufnr(''))
+
+ " We should save the file.
+ AssertEqual ['a', 'b', 'c'], readfile('fix_test_file')
+ Assert &modified, 'The was not marked as ''modified'''
+
+ " We should not run the linter.
+ AssertEqual [], ale#test#GetLoclistWithoutModule()
+
+Expect(The buffer should not be modified):
+ a
+ b
+ c
+
Given testft (A file with three lines):
a
b
diff --git a/test/fixers/test_eslint_fixer_callback.vader b/test/fixers/test_eslint_fixer_callback.vader
index be33825c..774595e3 100644
--- a/test/fixers/test_eslint_fixer_callback.vader
+++ b/test/fixers/test_eslint_fixer_callback.vader
@@ -170,3 +170,10 @@ Execute(The eslint_d post-processor should handle error messages correctly):
\ ale#fixers#eslint#ProcessEslintDOutput(bufnr(''), [
\ 'Error: No ESLint configuration found.',
\ ])
+
+Execute(The eslint_d post-processor should handle failing to connect properly):
+ AssertEqual
+ \ [],
+ \ ale#fixers#eslint#ProcessEslintDOutput(bufnr(''), [
+ \ 'Could not connect',
+ \ ])
diff --git a/test/fixers/test_gomod_fixer_callback.vader b/test/fixers/test_gomod_fixer_callback.vader
new file mode 100644
index 00000000..a378e961
--- /dev/null
+++ b/test/fixers/test_gomod_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_go_go_executable
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_go_go_executable = 'xxxinvalid'
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The gomod callback should return the correct default values):
+ call ale#test#SetFilename('../go_files/go.mod')
+ setl ft=gomod
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' mod edit -fmt'
+ \ . ' %t',
+ \ },
+ \ ale#fixers#gomod#Fix(bufnr(''))
diff --git a/test/fixers/test_goofle_java_format_fixer_callback.vader b/test/fixers/test_goofle_java_format_fixer_callback.vader
index d64e2788..4c28b330 100644
--- a/test/fixers/test_goofle_java_format_fixer_callback.vader
+++ b/test/fixers/test_goofle_java_format_fixer_callback.vader
@@ -1,8 +1,8 @@
Before:
- Save g:ale_google_java_format_executable
+ Save g:ale_java_google_java_format_executable
" Use an invalid global executable, so we don't match it.
- let g:ale_google_java_format_executable = 'xxxinvalid'
+ let g:ale_java_google_java_format_executable = 'xxxinvalid'
call ale#test#SetDirectory('/testplugin/test/fixers')
@@ -17,11 +17,11 @@ Execute(The google-java-format callback should return 0 when the executable isn'
\ ale#fixers#google_java_format#Fix(bufnr(''))
Execute(The google-java-format callback should run the command when the executable test passes):
- let g:ale_google_java_format_executable = has('win32') ? 'cmd' : 'echo'
+ let g:ale_java_google_java_format_executable = has('win32') ? 'cmd' : 'echo'
AssertEqual
\ {
\ 'read_temporary_file': 1,
- \ 'command': ale#Escape(ale_google_java_format_executable) . ' --replace %t'
+ \ 'command': ale#Escape(ale_java_google_java_format_executable) . ' --replace %t'
\ },
\ ale#fixers#google_java_format#Fix(bufnr(''))
diff --git a/test/fixers/test_hackfmt_fixer_callback.vader b/test/fixers/test_hackfmt_fixer_callback.vader
index ed78fc85..d294c15e 100644
--- a/test/fixers/test_hackfmt_fixer_callback.vader
+++ b/test/fixers/test_hackfmt_fixer_callback.vader
@@ -1,10 +1,10 @@
Before:
- Save g:ale_php_hackfmt_executable
- Save g:ale_php_hackfmt_options
+ Save g:ale_hack_hackfmt_executable
+ Save g:ale_hack_hackfmt_options
" Use an invalid global executable, so we don't match it.
- let g:ale_php_hackfmt_executable = 'xxxinvalid'
- let g:ale_php_hackfmt_options = ''
+ let g:ale_hack_hackfmt_executable = 'xxxinvalid'
+ let g:ale_hack_hackfmt_options = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
@@ -14,7 +14,7 @@ After:
call ale#test#RestoreDirectory()
Execute(The hackfmt callback should return the correct default values):
- call ale#test#SetFilename('../hack_files/testfile.php')
+ call ale#test#SetFilename('../hack_files/testfile.hack')
AssertEqual
\ {
@@ -25,8 +25,8 @@ Execute(The hackfmt callback should return the correct default values):
\ ale#fixers#hackfmt#Fix(bufnr(''))
Execute(The hackfmt callback should include custom hackfmt options):
- let g:ale_php_hackfmt_options = "--some-option"
- call ale#test#SetFilename('../hack_files/testfile.php')
+ let g:ale_hack_hackfmt_options = "--some-option"
+ call ale#test#SetFilename('../hack_files/testfile.hack')
AssertEqual
\ {
diff --git a/test/fixers/test_hlint_fixer_callback.vader b/test/fixers/test_hlint_fixer_callback.vader
new file mode 100644
index 00000000..08f08fae
--- /dev/null
+++ b/test/fixers/test_hlint_fixer_callback.vader
@@ -0,0 +1,20 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The hlint callback should return the correct default values):
+ call ale#test#SetFilename('../haskell_files/testfile.hs')
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('hlint')
+ \ . ' --refactor'
+ \ . ' --refactor-options="--inplace"'
+ \ . ' %t',
+ \ },
+ \ ale#fixers#hlint#Fix(bufnr(''))
diff --git a/test/fixers/test_importjs_fixer_callback.vader b/test/fixers/test_importjs_fixer_callback.vader
index c3e57f8b..53b87c2e 100644
--- a/test/fixers/test_importjs_fixer_callback.vader
+++ b/test/fixers/test_importjs_fixer_callback.vader
@@ -1,8 +1,8 @@
Before:
- Save g:ale_js_importjs_executable
+ Save g:ale_javascript_importjs_executable
" Use an invalid global executable, so we don't match it.
- let g:ale_js_importjs_executable = 'xxxinvalid'
+ let g:ale_javascript_importjs_executable = 'xxxinvalid'
call ale#test#SetDirectory('/testplugin/test/fixers')
call ale#test#SetFilename('../javascript_files/test.js')
@@ -18,12 +18,12 @@ Execute(The importjs callback should return 0 when the executable isn't executab
\ ale#fixers#importjs#Fix(bufnr(''))
Execute(The importjs callback should run the command when the executable test passes):
- let g:ale_js_importjs_executable = has('win32') ? 'cmd' : 'echo'
+ let g:ale_javascript_importjs_executable = has('win32') ? 'cmd' : 'echo'
AssertEqual
\ {
\ 'process_with': 'ale#fixers#importjs#ProcessOutput',
- \ 'command': ale#Escape(g:ale_js_importjs_executable) . ' fix %s'
+ \ 'command': ale#Escape(g:ale_javascript_importjs_executable) . ' fix %s'
\ },
\ ale#fixers#importjs#Fix(bufnr(''))
diff --git a/test/fixers/test_isort_fixer_callback.vader b/test/fixers/test_isort_fixer_callback.vader
index 56c08d26..50818621 100644
--- a/test/fixers/test_isort_fixer_callback.vader
+++ b/test/fixers/test_isort_fixer_callback.vader
@@ -27,7 +27,7 @@ Execute(The isort callback should return the correct default values):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo')) . ' && '
+ \ 'command': ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo'))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort')) . ' -',
\ },
\ ale#fixers#isort#Fix(bufnr(''))
@@ -42,7 +42,7 @@ Execute(The isort callback should respect custom options):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo')) . ' && '
+ \ 'command': ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo'))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort'))
\ . ' --multi-line=3 --trailing-comma -',
\ },
diff --git a/test/fixers/test_jq_fixer_callback.vader b/test/fixers/test_jq_fixer_callback.vader
index 2e32bf8e..74580d3b 100644
--- a/test/fixers/test_jq_fixer_callback.vader
+++ b/test/fixers/test_jq_fixer_callback.vader
@@ -1,6 +1,7 @@
Before:
Save g:ale_json_jq_executable
Save g:ale_json_jq_options
+ Save g:ale_json_jq_filters
After:
Restore
@@ -8,7 +9,18 @@ After:
Execute(The jq fixer should use the options you set):
let g:ale_json_jq_executable = 'foo'
let g:ale_json_jq_options = '--bar'
+ let g:ale_json_jq_filters = '.baz'
AssertEqual
- \ {'command': ale#Escape('foo') . ' . --bar'},
+ \ {'command': ale#Escape('foo') . ' .baz --bar'},
+ \ ale#fixers#jq#Fix(bufnr(''))
+
+Execute(The jq fixer should return 0 when there are no filters):
+ let g:ale_json_jq_executable = 'jq'
+ let g:ale_json_jq_options = ''
+
+ let g:ale_json_jq_filters = ''
+
+ AssertEqual
+ \ 0,
\ ale#fixers#jq#Fix(bufnr(''))
diff --git a/test/fixers/test_ocamlformat_fixer_callback.vader b/test/fixers/test_ocamlformat_fixer_callback.vader
new file mode 100644
index 00000000..f0c36ed7
--- /dev/null
+++ b/test/fixers/test_ocamlformat_fixer_callback.vader
@@ -0,0 +1,38 @@
+Before:
+ Save g:ale_ocaml_ocamlformat_executable
+ Save g:ale_ocaml_ocamlformat_options
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_ocaml_ocamlformat_executable = 'xxxinvalid'
+ let g:ale_ocaml_ocamlformat_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The ocamlformat callback should return the correct default values):
+ call ale#test#SetFilename('../ocaml-test-files/testfile.re')
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' --name=' . ale#Escape(bufname(bufnr('')))
+ \ . ' -',
+ \ },
+ \ ale#fixers#ocamlformat#Fix(bufnr(''))
+
+Execute(The ocamlformat callback should include custom ocamlformat options):
+ let g:ale_ocaml_ocamlformat_options = "-m 78"
+ call ale#test#SetFilename('../ocaml-test-files/testfile.re')
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' ' . g:ale_ocaml_ocamlformat_options
+ \ . ' --name=' . ale#Escape(bufname(bufnr('')))
+ \ . ' -',
+ \ },
+ \ ale#fixers#ocamlformat#Fix(bufnr(''))
diff --git a/test/fixers/test_prettier_eslint_fixer.callback.vader b/test/fixers/test_prettier_eslint_fixer.callback.vader
index ef0b35df..5c899d86 100644
--- a/test/fixers/test_prettier_eslint_fixer.callback.vader
+++ b/test/fixers/test_prettier_eslint_fixer.callback.vader
@@ -85,7 +85,7 @@ Execute(The new --stdin-filepath option should be used when the version is new e
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('prettier-eslint')
\ . ' --eslint-config-path ' . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/.eslintrc.js'))
\ . ' --stdin-filepath %s --stdin',
@@ -106,7 +106,7 @@ Execute(The version number should be cached):
" The newer command should be used.
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape('prettier-eslint')
\ . ' --stdin-filepath %s --stdin',
\ },
diff --git a/test/fixers/test_prettier_fixer_callback.vader b/test/fixers/test_prettier_fixer_callback.vader
index 2018c3a6..7f25471b 100644
--- a/test/fixers/test_prettier_fixer_callback.vader
+++ b/test/fixers/test_prettier_fixer_callback.vader
@@ -74,7 +74,7 @@ Execute(--stdin-filepath should be used when prettier is new enough):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --no-semi'
\ . ' --stdin-filepath %s --stdin',
@@ -90,7 +90,7 @@ Execute(The version number should be cached):
" Call it again without the version output. We should use the newer command.
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --stdin-filepath %s --stdin',
\ },
@@ -103,7 +103,7 @@ Execute(Should set --parser based on filetype, TypeScript):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser typescript'
\ . ' --stdin-filepath %s --stdin',
@@ -117,7 +117,7 @@ Execute(Should set --parser based on filetype, CSS):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser css'
\ . ' --stdin-filepath %s --stdin',
@@ -131,7 +131,7 @@ Execute(Should set --parser based on filetype, LESS):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser less'
\ . ' --stdin-filepath %s --stdin',
@@ -145,7 +145,7 @@ Execute(Should set --parser based on filetype, SCSS):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser scss'
\ . ' --stdin-filepath %s --stdin',
@@ -159,7 +159,7 @@ Execute(Should set --parser based on filetype, JSON):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser json'
\ . ' --stdin-filepath %s --stdin',
@@ -173,7 +173,7 @@ Execute(Should set --parser based on filetype, JSON5):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser json5'
\ . ' --stdin-filepath %s --stdin',
@@ -187,7 +187,7 @@ Execute(Should set --parser based on filetype, GraphQL):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser graphql'
\ . ' --stdin-filepath %s --stdin',
@@ -201,7 +201,7 @@ Execute(Should set --parser based on filetype, Markdown):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser markdown'
\ . ' --stdin-filepath %s --stdin',
@@ -215,13 +215,41 @@ Execute(Should set --parser based on filetype, Vue):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser vue'
\ . ' --stdin-filepath %s --stdin',
\ },
\ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0'])
+Execute(Should set --parser based on filetype, YAML):
+ call ale#test#SetFilename('../prettier-test-files/testfile')
+
+ set filetype=yaml
+
+ AssertEqual
+ \ {
+ \ 'command': ale#path#CdString(expand('%:p:h'))
+ \ . ale#Escape(g:ale_javascript_prettier_executable)
+ \ . ' --parser yaml'
+ \ . ' --stdin-filepath %s --stdin',
+ \ },
+ \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0'])
+
+Execute(Should set --parser based on filetype, HTML):
+ call ale#test#SetFilename('../prettier-test-files/testfile')
+
+ set filetype=html
+
+ AssertEqual
+ \ {
+ \ 'command': ale#path#CdString(expand('%:p:h'))
+ \ . ale#Escape(g:ale_javascript_prettier_executable)
+ \ . ' --parser html'
+ \ . ' --stdin-filepath %s --stdin',
+ \ },
+ \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0'])
+
Execute(Should set --parser based on first filetype of multiple filetypes):
call ale#test#SetFilename('../prettier-test-files/testfile')
@@ -229,9 +257,27 @@ Execute(Should set --parser based on first filetype of multiple filetypes):
AssertEqual
\ {
- \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && '
+ \ 'command': ale#path#CdString(expand('%:p:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --parser css'
\ . ' --stdin-filepath %s --stdin',
\ },
\ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0'])
+
+Execute(The prettier_d post-processor should permit regular JavaScript content):
+ AssertEqual
+ \ [
+ \ 'const x = ''Error: foo''',
+ \ 'const y = 3',
+ \ ],
+ \ ale#fixers#prettier#ProcessPrettierDOutput(bufnr(''), [
+ \ 'const x = ''Error: foo''',
+ \ 'const y = 3',
+ \ ])
+
+Execute(The prettier_d post-processor should handle error messages correctly):
+ AssertEqual
+ \ [],
+ \ ale#fixers#prettier#ProcessPrettierDOutput(bufnr(''), [
+ \ 'SyntaxError: Unexpected token, expected "," (36:28)',
+ \ ])
diff --git a/test/fixers/test_python_add_blank_lines_fixer.vader b/test/fixers/test_python_add_blank_lines_fixer.vader
index 4a91aa10..7d042c8a 100644
--- a/test/fixers/test_python_add_blank_lines_fixer.vader
+++ b/test/fixers/test_python_add_blank_lines_fixer.vader
@@ -6,15 +6,22 @@ After:
Given python(Some Python without blank lines):
def foo():
+ """ This is a simple test docstring """
return 1
def bar():
+ '''This is another simple test docstring'''
return 1
return 4
def bar():
+ """
+ This is a multi-line
+ docstring
+ """
+
if x:
pass
for l in x:
@@ -44,16 +51,25 @@ Execute(Blank lines should be added appropriately):
Expect python(Newlines should be added):
def foo():
+ """ This is a simple test docstring """
+
return 1
def bar():
+ '''This is another simple test docstring'''
+
return 1
return 4
def bar():
+ """
+ This is a multi-line
+ docstring
+ """
+
if x:
pass
@@ -109,3 +125,43 @@ Expect python(extra newlines shouldn't be added to the main block):
if __name__ == '__main__':
main()
+
+
+Given python(A file with variables/docstring that start with a control statement):
+ def some():
+ """
+ This is a docstring that contains an
+ break control statement and also contains a
+ return something funny.
+ """
+
+ continue_some_var = True
+ forward_something = False
+
+ if (
+ continue_some_var and
+ forwarded_something
+ ):
+ return True
+
+
+Execute(Fix the file):
+ let g:ale_fixers = {'python': ['add_blank_lines_for_python_control_statements']}
+ ALEFix
+
+Expect python(Extra new lines are not added to the file):
+ def some():
+ """
+ This is a docstring that contains an
+ break control statement and also contains a
+ return something funny.
+ """
+
+ continue_some_var = True
+ forward_something = False
+
+ if (
+ continue_some_var and
+ forwarded_something
+ ):
+ return True
diff --git a/test/fixers/test_rubocop_fixer_callback.vader b/test/fixers/test_rubocop_fixer_callback.vader
index 045256f8..866326bf 100644
--- a/test/fixers/test_rubocop_fixer_callback.vader
+++ b/test/fixers/test_rubocop_fixer_callback.vader
@@ -23,7 +23,7 @@ Execute(The rubocop callback should return the correct default values):
\ {
\ 'read_temporary_file': 1,
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
- \ . ' --auto-correct %t',
+ \ . ' --auto-correct --force-exclusion %t',
\ },
\ ale#fixers#rubocop#Fix(bufnr(''))
@@ -35,7 +35,7 @@ Execute(The rubocop callback should include configuration files):
\ 'read_temporary_file': 1,
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
- \ . ' --auto-correct %t',
+ \ . ' --auto-correct --force-exclusion %t',
\ },
\ ale#fixers#rubocop#Fix(bufnr(''))
@@ -49,6 +49,6 @@ Execute(The rubocop callback should include custom rubocop options):
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --except Lint/Debugger'
- \ . ' --auto-correct %t',
+ \ . ' --auto-correct --force-exclusion %t',
\ },
\ ale#fixers#rubocop#Fix(bufnr(''))
diff --git a/test/fixers/test_shfmt_fixer_callback.vader b/test/fixers/test_shfmt_fixer_callback.vader
index 5dc6e863..99cb0987 100644
--- a/test/fixers/test_shfmt_fixer_callback.vader
+++ b/test/fixers/test_shfmt_fixer_callback.vader
@@ -1,17 +1,52 @@
Before:
Save g:ale_sh_shfmt_executable
Save g:ale_sh_shfmt_options
+ Save &l:expandtab
+ Save &l:shiftwidth
+ Save &l:tabstop
After:
Restore
-Execute(The shfmt callback should return the correct default values):
+Execute(The shfmt callback should return 'shfmt' as default command):
+ setlocal noexpandtab
+ Assert
+ \ ale#fixers#shfmt#Fix(bufnr('')).command =~# '^' . ale#Escape('shfmt'),
+ \ "Default command name is expected to be 'shfmt'"
+
+Execute(The shfmt callback should return the command with no option as default when noexpandtab is set):
+ let g:ale_sh_shfmt_executable = 'shfmt'
+ let g:ale_sh_shfmt_options = ''
+ setlocal noexpandtab
AssertEqual
\ {
\ 'command': ale#Escape('shfmt'),
\ },
\ ale#fixers#shfmt#Fix(bufnr(''))
+Execute(The shfmt callback should return the command specifying indent width by looking shiftwidth as default):
+ let g:ale_sh_shfmt_executable = 'shfmt'
+ let g:ale_sh_shfmt_options = ''
+ setlocal expandtab
+ setlocal shiftwidth=4
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('shfmt') . ' -i 4',
+ \ },
+ \ ale#fixers#shfmt#Fix(bufnr(''))
+
+Execute(The shfmt callback should return the command specifying indent width by looking tabstop when shiftwidth is 0 as default):
+ let g:ale_sh_shfmt_executable = 'shfmt'
+ let g:ale_sh_shfmt_options = ''
+ setlocal expandtab
+ setlocal shiftwidth=0
+ setlocal tabstop=8
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('shfmt') . ' -i 8',
+ \ },
+ \ ale#fixers#shfmt#Fix(bufnr(''))
+
Execute(The shfmt executable and options should be configurable):
let g:ale_sh_shfmt_executable = 'foobar'
let g:ale_sh_shfmt_options = '--some-option'
diff --git a/test/fixers/test_sqlfmt_fixer_callback.vader b/test/fixers/test_sqlfmt_fixer_callback.vader
new file mode 100644
index 00000000..3046edb3
--- /dev/null
+++ b/test/fixers/test_sqlfmt_fixer_callback.vader
@@ -0,0 +1,26 @@
+Before:
+ Save g:ale_sql_sqlfmt_executable
+ Save g:ale_sql_sqlfmt_options
+
+After:
+ Restore
+
+Execute(The sqlfmt callback should return the correct default values):
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('sqlfmt')
+ \ . ' -w',
+ \ },
+ \ ale#fixers#sqlfmt#Fix(bufnr(''))
+
+Execute(The sqlfmt executable and options should be configurable):
+ let g:ale_sql_sqlfmt_executable = '/path/to/sqlfmt'
+ let g:ale_sql_sqlfmt_options = '-u'
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('/path/to/sqlfmt')
+ \ . ' -w'
+ \ . ' -u',
+ \ },
+ \ ale#fixers#sqlfmt#Fix(bufnr(''))
diff --git a/test/fixers/test_stylish_haskell_fixer_callback.vader b/test/fixers/test_stylish_haskell_fixer_callback.vader
new file mode 100644
index 00000000..755d3430
--- /dev/null
+++ b/test/fixers/test_stylish_haskell_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_haskell_stylish_haskell_executable
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_haskell_stylish_haskell_executable = 'xxxinvalid'
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The stylish-haskell callback should return the correct default values):
+ call ale#test#SetFilename('../haskell_files/testfile.hs')
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' --inplace'
+ \ . ' %t',
+ \ },
+ \ ale#fixers#stylish_haskell#Fix(bufnr(''))
diff --git a/test/fixers/test_terraform_fmt_fixer_callback.vader b/test/fixers/test_terraform_fmt_fixer_callback.vader
new file mode 100644
index 00000000..15377a7e
--- /dev/null
+++ b/test/fixers/test_terraform_fmt_fixer_callback.vader
@@ -0,0 +1,34 @@
+Before:
+ Save g:ale_terraform_fmt_executable
+ Save g:ale_terraform_fmt_options
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_terraform_fmt_executable = 'xxxinvalid'
+ let g:ale_terraform_fmt_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The terraform fmt callback should return the correct default values):
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('xxxinvalid') . ' fmt -',
+ \ },
+ \ ale#fixers#terraform#Fix(bufnr(''))
+
+Execute(The terraform fmt callback should include custom options):
+ let g:ale_terraform_fmt_options = "-list=true"
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' fmt'
+ \ . ' ' . g:ale_terraform_fmt_options
+ \ . ' -',
+ \ },
+ \ ale#fixers#terraform#Fix(bufnr(''))
diff --git a/test/fixers/test_uncrustify_fixer_callback.vader b/test/fixers/test_uncrustify_fixer_callback.vader
new file mode 100644
index 00000000..8ef4e79b
--- /dev/null
+++ b/test/fixers/test_uncrustify_fixer_callback.vader
@@ -0,0 +1,36 @@
+Before:
+ Save g:ale_c_uncrustify_executable
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_c_uncrustify_executable = 'xxxinvalid'
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+ silent cd ..
+ silent cd command_callback
+ let g:dir = getcwd()
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The clang-format callback should return the correct default values):
+ call ale#test#SetFilename('c_paths/dummy.c')
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape(g:ale_c_uncrustify_executable)
+ \ . ' --no-backup'
+ \ },
+ \ ale#fixers#uncrustify#Fix(bufnr(''))
+
+Execute(The uncrustify callback should include any additional options):
+ call ale#test#SetFilename('c_paths/dummy.c')
+ let b:ale_c_uncrustify_options = '--some-option'
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape(g:ale_c_uncrustify_executable)
+ \ . ' --no-backup --some-option',
+ \ },
+ \ ale#fixers#uncrustify#Fix(bufnr(''))
diff --git a/test/fixers/test_xmllint_fixer_callback.vader b/test/fixers/test_xmllint_fixer_callback.vader
new file mode 100644
index 00000000..54fe05bd
--- /dev/null
+++ b/test/fixers/test_xmllint_fixer_callback.vader
@@ -0,0 +1,46 @@
+Before:
+ Save g:ale_xml_xmllint_executable
+ Save g:ale_xml_xmllint_indentsize
+ Save g:ale_xml_xmllint_options
+
+ let g:ale_xml_xmllint_executable = '/path/to/xmllint'
+ let g:ale_xml_xmllint_indentsize = ''
+ let g:ale_xml_xmllint_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+Execute(The xmllint callback should return the correct default command):
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('/path/to/xmllint')
+ \ . ' --format '
+ \ . ale#Escape(bufname(bufnr('')))
+ \ },
+ \ ale#fixers#xmllint#Fix(bufnr(''))
+
+Execute(The xmllint callback should include the XMLLINT_INDENT variable):
+ let g:ale_xml_xmllint_indentsize = 2
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Env('XMLLINT_INDENT', ' ')
+ \ . ale#Escape('/path/to/xmllint')
+ \ . ' --format '
+ \ . ale#Escape(bufname(bufnr('')))
+ \ },
+ \ ale#fixers#xmllint#Fix(bufnr(''))
+
+Execute(The xmllint callback should include additional options):
+ let g:ale_xml_xmllint_options = '--nonet'
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('/path/to/xmllint')
+ \ . ' --format '
+ \ . ale#Escape(bufname(bufnr('')))
+ \ . ' --nonet'
+ \ },
+ \ ale#fixers#xmllint#Fix(bufnr(''))
diff --git a/test/go_files/go.mod b/test/go_files/go.mod
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/go_files/go.mod
@@ -0,0 +1 @@
+
diff --git a/test/handler/test_ada_gcc_handler.vader b/test/handler/test_ada_gcc_handler.vader
new file mode 100644
index 00000000..06ddfe1f
--- /dev/null
+++ b/test/handler/test_ada_gcc_handler.vader
@@ -0,0 +1,36 @@
+Before:
+ runtime ale_linters/ada/gcc.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The gcc handler for Ada should parse input correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 8,
+ \ 'col': 5,
+ \ 'type': 'W',
+ \ 'text': 'variable "X" is assigned but never read',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 6,
+ \ 'col': 22,
+ \ 'type': 'E',
+ \ 'text': 'type definition expected',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 8,
+ \ 'col': 9,
+ \ 'type': 'E',
+ \ 'text': 'aspect specifications not allowed here',
+ \ },
+ \ ],
+ \ ale_linters#ada#gcc#Handle(0, [
+ \ 'foobar.adb:8:05: warning: variable "X" is assigned but never read',
+ \ 'foobar.ads:6:22: type definition expected',
+ \ 'foobar.ads:8:09: aspect specifications not allowed here',
+ \ ])
diff --git a/test/handler/test_checkstyle_handler.vader b/test/handler/test_checkstyle_handler.vader
index 2f1f0f8d..218fe344 100644
--- a/test/handler/test_checkstyle_handler.vader
+++ b/test/handler/test_checkstyle_handler.vader
@@ -26,3 +26,16 @@ Execute(The checkstyle handler should parse lines correctly):
\ '[WARN] whatever:101: ''method def rcurly'' has incorrect indentation level 4, expected level should be 2. [Indentation]',
\ '[WARN] whatever:63:3: Missing a Javadoc comment. [JavadocMethod]',
\ ])
+
+Execute(The checkstyle handler should parse lines from older checkstyle versions correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 289,
+ \ 'text': '''method def modifier'' have incorrect indentation level 4, expected level should be 2.',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#java#checkstyle#Handle(666, [
+ \ '/home/languitar/src/rsb-java/rsb-java/src/main/java/rsb/Listener.java:289: warning: ''method def modifier'' have incorrect indentation level 4, expected level should be 2.',
+ \ ])
diff --git a/test/handler/test_clang_handler.vader b/test/handler/test_clang_handler.vader
index 278737a8..cc8eabd0 100644
--- a/test/handler/test_clang_handler.vader
+++ b/test/handler/test_clang_handler.vader
@@ -8,9 +8,20 @@ Execute(clang errors from included files should be parsed correctly):
\ 'type': 'E',
\ 'text': 'expected identifier or ''(''',
\ },
+ \ {
+ \ 'lnum': 3,
+ \ 'text': 'Error found in header. See :ALEDetail',
+ \ 'detail': join([
+ \ 'In file included from <stdin>:3:',
+ \ 'In file included from ./a.h:1:',
+ \ './b.h:1:1: error: expected identifier or ''(''',
+ \ '{{{',
+ \ '^',
+ \ ], "\n"),
+ \ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
- \ 'In file included from test.c:3:',
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
+ \ 'In file included from <stdin>:3:',
\ 'In file included from ./a.h:1:',
\ './b.h:1:1: error: expected identifier or ''(''',
\ '{{{',
diff --git a/test/handler/test_credo_handler.vader b/test/handler/test_credo_handler.vader
index 5eb0e967..1fd54bb5 100644
--- a/test/handler/test_credo_handler.vader
+++ b/test/handler/test_credo_handler.vader
@@ -10,20 +10,44 @@ Execute(The credo handler should parse lines correctly):
\ {
\ 'bufnr': 347,
\ 'lnum': 1,
+ \ 'col': 24,
+ \ 'text': 'This code can be refactored',
+ \ 'type': 'W',
+ \ },
+ \ {
+ \ 'bufnr': 347,
+ \ 'lnum': 1,
\ 'col': 4,
\ 'text': 'There is no whitespace around parentheses/brackets most of the time, but here there is.',
- \ 'type': 'E',
+ \ 'type': 'W',
+ \ },
+ \ {
+ \ 'bufnr': 347,
+ \ 'lnum': 5,
+ \ 'col': 21,
+ \ 'text': 'TODO comment',
+ \ 'type': 'I',
\ },
\ {
\ 'bufnr': 347,
\ 'lnum': 26,
\ 'col': 0,
\ 'text': 'If/else blocks should not have a negated condition in `if`.',
+ \ 'type': 'I',
+ \ },
+ \ {
+ \ 'bufnr': 347,
+ \ 'lnum': 15,
+ \ 'col': 1,
+ \ 'text': 'Warning in the code',
\ 'type': 'W',
\ },
\ ],
\ ale_linters#elixir#credo#Handle(347, [
\ 'This line should be ignored completely',
+ \ 'lib/my_code/test.ex:1:24: F: This code can be refactored',
\ 'lib/filename.ex:1:4: C: There is no whitespace around parentheses/brackets most of the time, but here there is.',
+ \ 'lib/my_code/test.ex:5:21: D: TODO comment',
\ 'lib/phoenix/channel.ex:26: R: If/else blocks should not have a negated condition in `if`.',
+ \ 'lib/my_code/test.ex:15:1: W: Warning in the code',
\ ])
diff --git a/test/handler/test_dockerfile_lint_handler.vader b/test/handler/test_dockerfile_lint_handler.vader
new file mode 100644
index 00000000..619b7bde
--- /dev/null
+++ b/test/handler/test_dockerfile_lint_handler.vader
@@ -0,0 +1,108 @@
+Before:
+ runtime ale_linters/dockerfile/dockerfile_lint.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The dockerfile_lint handler should handle broken JSON):
+ AssertEqual
+ \ [],
+ \ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), ["{asdf"])
+
+Execute(The dockerfile_lint handler should handle an empty string response):
+ AssertEqual
+ \ [],
+ \ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), [])
+
+Execute(The dockerfile_lint handler should handle an empty result, even if it shouldn't happen):
+ AssertEqual
+ \ [],
+ \ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), ["{}"])
+
+Execute(The dockerfile_lint handler should handle a normal example):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': -1,
+ \ 'type': 'E',
+ \ 'text': "Required LABEL name/key 'Name' is not defined",
+ \ },
+ \ {
+ \ 'lnum': -1,
+ \ 'type': 'E',
+ \ 'text': "Required LABEL name/key 'Version' is not defined",
+ \ },
+ \ {
+ \ 'lnum': 3,
+ \ 'type': 'I',
+ \ 'text': "the MAINTAINER command is deprecated. MAINTAINER is deprecated in favor of using LABEL since Docker v1.13.0",
+ \ },
+ \ {
+ \ 'lnum': -1,
+ \ 'type': 'I',
+ \ 'text': "There is no 'CMD' instruction",
+ \ },
+ \ ],
+ \ ale_linters#dockerfile#dockerfile_lint#Handle(bufnr(''), [
+ \ '{',
+ \ ' "error": {',
+ \ ' "count": 2,',
+ \ ' "data": [',
+ \ ' {',
+ \ " \"message\": \"Required LABEL name/key 'Name' is not defined\",",
+ \ ' "line": -1,',
+ \ ' "level": "error",',
+ \ ' "lineContent": "",',
+ \ ' "reference_url": [',
+ \ ' "http://docs.projectatomic.io/container-best-practices/#",',
+ \ ' "_recommended_labels_for_your_project"',
+ \ ' ]',
+ \ ' },',
+ \ ' {',
+ \ " \"message\": \"Required LABEL name/key 'Version' is not defined\",",
+ \ ' "line": -1,',
+ \ ' "level": "error",',
+ \ ' "lineContent": "",',
+ \ ' "reference_url": [',
+ \ ' "http://docs.projectatomic.io/container-best-practices/#",',
+ \ ' "_recommended_labels_for_your_project"',
+ \ ' ]',
+ \ ' }',
+ \ ' ]',
+ \ ' },',
+ \ ' "warn": {',
+ \ ' "count": 0,',
+ \ ' "data": []',
+ \ ' },',
+ \ ' "info": {',
+ \ ' "count": 2,',
+ \ ' "data": [',
+ \ ' {',
+ \ ' "label": "maintainer_deprecated",',
+ \ ' "regex": {},',
+ \ ' "level": "info",',
+ \ ' "message": "the MAINTAINER command is deprecated",',
+ \ ' "description": "MAINTAINER is deprecated in favor of using LABEL since Docker v1.13.0",',
+ \ ' "reference_url": [',
+ \ ' "https://github.com/docker/cli/blob/master/docs/deprecated.md",',
+ \ ' "#maintainer-in-dockerfile"',
+ \ ' ],',
+ \ ' "lineContent": "MAINTAINER Alexander Olofsson <ace@haxalot.com>",',
+ \ ' "line": 3',
+ \ ' },',
+ \ ' {',
+ \ ' "instruction": "CMD",',
+ \ ' "count": 1,',
+ \ ' "level": "info",',
+ \ " \"message\": \"There is no 'CMD' instruction\",",
+ \ ' "description": "None",',
+ \ ' "reference_url": [',
+ \ ' "https://docs.docker.com/engine/reference/builder/",',
+ \ ' "#cmd"',
+ \ ' ]',
+ \ ' }',
+ \ ' ]',
+ \ ' },',
+ \ ' "summary": []',
+ \ '}',
+ \ ])
diff --git a/test/handler/test_eslint_handler.vader b/test/handler/test_eslint_handler.vader
index 2e8bfd2a..4a57927b 100644
--- a/test/handler/test_eslint_handler.vader
+++ b/test/handler/test_eslint_handler.vader
@@ -365,3 +365,15 @@ Execute(eslint should handle react errors correctly):
\ ale#handlers#eslint#Handle(bufnr(''), [
\ '/path/editor-help.jsx:59:9: Property should be placed on the same line as the component declaration [Error/react/jsx-first-prop-new-line]',
\ ])
+
+Execute(Failing to connect to eslint_d should be handled correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.',
+ \ },
+ \ ],
+ \ ale#handlers#eslint#Handle(bufnr(''), [
+ \ 'Could not connect',
+ \ ])
diff --git a/test/handler/test_flake8_handler.vader b/test/handler/test_flake8_handler.vader
index efacdfb2..cdf20bc0 100644
--- a/test/handler/test_flake8_handler.vader
+++ b/test/handler/test_flake8_handler.vader
@@ -21,6 +21,7 @@ Execute(The flake8 handler should handle basic warnings and syntax errors):
\ {
\ 'lnum': 6,
\ 'col': 6,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'text': 'indentation is not a multiple of four',
\ 'code': 'E111',
@@ -29,6 +30,7 @@ Execute(The flake8 handler should handle basic warnings and syntax errors):
\ {
\ 'lnum': 7,
\ 'col': 6,
+ \ 'vcol': 1,
\ 'type': 'W',
\ 'text': 'some warning',
\ 'code': 'W123',
@@ -37,6 +39,7 @@ Execute(The flake8 handler should handle basic warnings and syntax errors):
\ {
\ 'lnum': 8,
\ 'col': 3,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'text': 'SyntaxError: invalid syntax',
\ 'code': 'E999',
@@ -54,6 +57,7 @@ Execute(The flake8 handler should set end column indexes for certain errors):
\ {
\ 'lnum': 25,
\ 'col': 1,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'end_col': 3,
\ 'text': 'undefined name ''foo''',
@@ -62,6 +66,7 @@ Execute(The flake8 handler should set end column indexes for certain errors):
\ {
\ 'lnum': 28,
\ 'col': 5,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'end_col': 9,
\ 'text': 'hello may be undefined, or defined from star imports: x',
@@ -70,6 +75,7 @@ Execute(The flake8 handler should set end column indexes for certain errors):
\ {
\ 'lnum': 104,
\ 'col': 5,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'end_col': 12,
\ 'text': '''continue'' not properly in loop',
@@ -78,6 +84,7 @@ Execute(The flake8 handler should set end column indexes for certain errors):
\ {
\ 'lnum': 106,
\ 'col': 5,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'end_col': 9,
\ 'text': '''break'' outside loop',
@@ -86,6 +93,7 @@ Execute(The flake8 handler should set end column indexes for certain errors):
\ {
\ 'lnum': 109,
\ 'col': 5,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'end_col': 8,
\ 'text': 'local variable ''test'' is assigned to but never used',
@@ -143,6 +151,7 @@ Execute(The flake8 handler should handle names with spaces):
\ {
\ 'lnum': 6,
\ 'col': 6,
+ \ 'vcol': 1,
\ 'type': 'E',
\ 'text': 'indentation is not a multiple of four',
\ 'code': 'E111',
@@ -159,6 +168,7 @@ Execute(Warnings about trailing whitespace should be reported by default):
\ {
\ 'lnum': 6,
\ 'col': 1,
+ \ 'vcol': 1,
\ 'code': 'W291',
\ 'type': 'W',
\ 'sub_type': 'style',
@@ -167,6 +177,7 @@ Execute(Warnings about trailing whitespace should be reported by default):
\ {
\ 'lnum': 6,
\ 'col': 1,
+ \ 'vcol': 1,
\ 'code': 'W293',
\ 'type': 'W',
\ 'sub_type': 'style',
@@ -195,6 +206,7 @@ Execute(Warnings about trailing blank lines should be reported by default):
\ {
\ 'lnum': 6,
\ 'col': 1,
+ \ 'vcol': 1,
\ 'code': 'W391',
\ 'type': 'W',
\ 'sub_type': 'style',
@@ -221,6 +233,7 @@ Execute(F401 should be a warning):
\ {
\ 'lnum': 6,
\ 'col': 1,
+ \ 'vcol': 1,
\ 'code': 'F401',
\ 'type': 'W',
\ 'text': 'module imported but unused',
@@ -236,6 +249,7 @@ Execute(E112 should be a syntax error):
\ {
\ 'lnum': 6,
\ 'col': 1,
+ \ 'vcol': 1,
\ 'code': 'E112',
\ 'type': 'E',
\ 'text': 'expected an indented block',
diff --git a/test/handler/test_gcc_handler.vader b/test/handler/test_gcc_handler.vader
index 678d3f42..3daa9e60 100644
--- a/test/handler/test_gcc_handler.vader
+++ b/test/handler/test_gcc_handler.vader
@@ -1,7 +1,7 @@
Execute(The GCC handler should ignore other lines of output):
AssertEqual
\ [],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ 'foo',
\ 'bar',
\ 'baz',
@@ -17,12 +17,24 @@ Execute(GCC errors from included files should be parsed correctly):
\ 'type': 'E',
\ 'text': 'expected identifier or ''('' before ''{'' token',
\ },
+ \ {
+ \ 'lnum': 3,
+ \ 'col': 2,
+ \ 'text': 'Error found in header. See :ALEDetail',
+ \ 'detail': join([
+ \ 'In file included from <stdin>:3:2:',
+ \ 'broken.h:1:1: error: expected identifier or ''('' before ''{'' token',
+ \ ' {{{',
+ \ ' ^',
+ \ ], "\n"),
+ \ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
- \ 'In file included from <stdin>:3:0:',
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
+ \ 'In file included from <stdin>:3:2:',
\ 'broken.h:1:1: error: expected identifier or ''('' before ''{'' token',
\ ' {{{',
\ ' ^',
+ \ 'compilation terminated.',
\ ])
AssertEqual
@@ -34,13 +46,25 @@ Execute(GCC errors from included files should be parsed correctly):
\ 'type': 'E',
\ 'text': 'expected identifier or ''('' before ''{'' token',
\ },
+ \ {
+ \ 'lnum': 5,
+ \ 'text': 'Error found in header. See :ALEDetail',
+ \ 'detail': join([
+ \ 'In file included from a.h:1:0,',
+ \ ' from <stdin>:5:',
+ \ 'b.h:1:1: error: expected identifier or ''('' before ''{'' token',
+ \ ' {{{',
+ \ ' ^',
+ \ ], "\n"),
+ \ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ 'In file included from a.h:1:0,',
- \ ' from test.c:3:',
+ \ ' from <stdin>:5:',
\ 'b.h:1:1: error: expected identifier or ''('' before ''{'' token',
\ ' {{{',
\ ' ^',
+ \ 'compilation terminated.',
\ ])
AssertEqual
@@ -59,16 +83,31 @@ Execute(GCC errors from included files should be parsed correctly):
\ 'type': 'E',
\ 'text': 'unknown type name ''other_bad_type''',
\ },
+ \ {
+ \ 'lnum': 3,
+ \ 'text': 'Error found in header. See :ALEDetail',
+ \ 'detail': join([
+ \ 'In file included from a.h:1:0,',
+ \ ' from <stdin>:3:',
+ \ 'b.h:1:1: error: unknown type name ‘bad_type’',
+ \ ' bad_type x;',
+ \ ' ^',
+ \ 'b.h:2:1: error: unknown type name ‘other_bad_type’',
+ \ ' other_bad_type y;',
+ \ ' ^',
+ \ ], "\n"),
+ \ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ 'In file included from a.h:1:0,',
- \ ' from test.c:3:',
+ \ ' from <stdin>:3:',
\ 'b.h:1:1: error: unknown type name ‘bad_type’',
\ ' bad_type x;',
\ ' ^',
\ 'b.h:2:1: error: unknown type name ‘other_bad_type’',
\ ' other_bad_type y;',
\ ' ^',
+ \ 'compilation terminated.',
\ ])
Execute(The GCC handler shouldn't complain about #pragma once for headers):
@@ -76,7 +115,7 @@ Execute(The GCC handler shouldn't complain about #pragma once for headers):
AssertEqual
\ [],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ '<stdin>:1:1: warning: #pragma once in main file [enabled by default]',
\ ])
@@ -84,7 +123,7 @@ Execute(The GCC handler shouldn't complain about #pragma once for headers):
AssertEqual
\ [],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ '<stdin>:1:1: warning: #pragma once in main file [enabled by default]',
\ ])
@@ -119,7 +158,7 @@ Execute(The GCC handler should handle syntax errors):
\ 'text': 'expected '';'' before ''o'''
\ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ '<stdin>:6:12: error: invalid suffix "p" on integer constant',
\ '<stdin>:17:5: error: invalid suffix "n" on integer constant',
\ '<stdin>:4: error: variable or field ''foo'' declared void',
@@ -130,11 +169,27 @@ Execute(The GCC handler should handle syntax errors):
Execute(The GCC handler should handle notes with no previous message):
AssertEqual
\ [],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ '<stdin>:1:1: note: x',
\ '<stdin>:1:1: note: x',
\ ])
+Execute(The GCC handler should attach notes to previous messages):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 6,
+ \ 'col': 12,
+ \ 'type': 'E',
+ \ 'text': 'Some error',
+ \ 'detail': "Some error\n<stdin>:1:1: note: x",
+ \ },
+ \ ],
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
+ \ '-:6:12: error: Some error',
+ \ '<stdin>:1:1: note: x',
+ \ ])
+
Execute(The GCC handler should interpret - as being the current file):
AssertEqual
\ [
@@ -145,7 +200,7 @@ Execute(The GCC handler should interpret - as being the current file):
\ 'text': 'Some error',
\ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ '-:6:12: error: Some error',
\ ])
@@ -159,6 +214,6 @@ Execute(The GCC handler should handle fatal error messages due to missing files)
\ 'text': 'foo.h: No such file or directory'
\ },
\ ],
- \ ale#handlers#gcc#HandleGCCFormat(347, [
+ \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [
\ '<stdin>:3:12: fatal error: foo.h: No such file or directory',
\ ])
diff --git a/test/handler/test_gitlint_handler.vader b/test/handler/test_gitlint_handler.vader
index 60d632a0..5c531664 100644
--- a/test/handler/test_gitlint_handler.vader
+++ b/test/handler/test_gitlint_handler.vader
@@ -61,6 +61,19 @@ Execute(Disabling trailing whitespace warnings should work):
\ '8: T2 Trailing whitespace',
\])
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 8,
+ \ 'type': 'E',
+ \ 'text': 'Trailing whitespace',
+ \ 'code': 'B2',
+ \ },
+ \ ],
+ \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [
+ \ '8: B2 Trailing whitespace',
+ \])
+
let b:ale_warn_about_trailing_whitespace = 0
AssertEqual
@@ -68,3 +81,9 @@ Execute(Disabling trailing whitespace warnings should work):
\ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [
\ '8: T2 Trailing whitespace',
\ ])
+
+ AssertEqual
+ \ [],
+ \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [
+ \ '8: B2 Trailing whitespace',
+ \ ])
diff --git a/test/handler/test_golangci_lint_handler.vader b/test/handler/test_golangci_lint_handler.vader
new file mode 100644
index 00000000..fb6841f4
--- /dev/null
+++ b/test/handler/test_golangci_lint_handler.vader
@@ -0,0 +1,55 @@
+Before:
+ runtime ale_linters/go/golangci_lint.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute (The golangci-lint handler should handle names with spaces):
+ " We can't test Windows paths with the path resovling on Linux, but we can
+ " test the regex.
+ AssertEqual
+ \ [
+ \ [
+ \ 'C:\something\file with spaces.go',
+ \ '12',
+ \ '3',
+ \ 'expected ''package'', found ''IDENT'' gibberish (staticcheck)',
+ \ ],
+ \ [
+ \ 'C:\something\file with spaces.go',
+ \ '37',
+ \ '5',
+ \ 'expected ''package'', found ''IDENT'' gibberish (golint)',
+ \ ],
+ \ ],
+ \ map(ale_linters#go#golangci_lint#GetMatches([
+ \ 'C:\something\file with spaces.go:12:3: expected ''package'', found ''IDENT'' gibberish (staticcheck)',
+ \ 'C:\something\file with spaces.go:37:5: expected ''package'', found ''IDENT'' gibberish (golint)',
+ \ ]), 'v:val[1:4]')
+
+Execute (The golangci-lint handler should handle paths correctly):
+ call ale#test#SetFilename('app/test.go')
+
+ let file = ale#path#GetAbsPath(expand('%:p:h'), 'test.go')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 12,
+ \ 'col': 3,
+ \ 'text': 'expected ''package'', found ''IDENT'' gibberish (staticcheck)',
+ \ 'type': 'E',
+ \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'),
+ \ },
+ \ {
+ \ 'lnum': 37,
+ \ 'col': 5,
+ \ 'text': 'expected ''package'', found ''IDENT'' gibberish (golint)',
+ \ 'type': 'E',
+ \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'),
+ \ },
+ \ ],
+ \ ale_linters#go#golangci_lint#Handler(bufnr(''), [
+ \ file . ':12:3: expected ''package'', found ''IDENT'' gibberish (staticcheck)',
+ \ file . ':37:5: expected ''package'', found ''IDENT'' gibberish (golint)',
+ \ ])
diff --git a/test/handler/test_haskell_stack_handler.vader b/test/handler/test_haskell_stack_handler.vader
new file mode 100644
index 00000000..07e7e69c
--- /dev/null
+++ b/test/handler/test_haskell_stack_handler.vader
@@ -0,0 +1,7 @@
+Before:
+ runtime ale/handlers/haskell_stack.vim
+
+Execute(Escape stack should correctly identify a stack exec command):
+ AssertEqual
+ \ ale#Escape('stack') . ' exec ' . ale#Escape('hlint') . ' --',
+ \ ale#handlers#haskell_stack#EscapeExecutable('stack', 'hlint')
diff --git a/test/handler/test_ispc_ispc_handler.vader b/test/handler/test_ispc_ispc_handler.vader
new file mode 100644
index 00000000..619773fe
--- /dev/null
+++ b/test/handler/test_ispc_ispc_handler.vader
@@ -0,0 +1,90 @@
+Before:
+ runtime ale_linters/ispc/ispc.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The ispc handler should parse input correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 33,
+ \ 'col': 14,
+ \ 'type': 'E',
+ \ 'text': 'syntax error, unexpected ''int'', expecting '','' or '';''.',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 36,
+ \ 'col': 5,
+ \ 'type': 'E',
+ \ 'text': 'syntax error, unexpected ''for''.',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 51,
+ \ 'col': 9,
+ \ 'type': 'E',
+ \ 'text': '''foobar.h'' file not found',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 79,
+ \ 'col': 52,
+ \ 'type': 'W',
+ \ 'text': 'Modulus operator with varying types is very inefficient.',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 85,
+ \ 'col': 13,
+ \ 'type': 'W',
+ \ 'text': 'Undefined behavior: all program instances are writing to the same location!',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 93,
+ \ 'col': 19,
+ \ 'type': 'W',
+ \ 'text': 'Gather required to load value.',
+ \ },
+ \ {
+ \ 'bufnr': 0,
+ \ 'lnum': 93,
+ \ 'col': 9,
+ \ 'type': 'W',
+ \ 'text': 'Scatter required to store value.',
+ \ },
+ \ ],
+ \ ale_linters#ispc#ispc#Handle(0, [
+ \ 'Warning: No output file or header file name specified. Program will be compiled and warnings/errors will be issued, but no output will be generated. ',
+ \ 'Warning: No --target specified on command-line. Using default system target "avx2-i32x8".',
+ \ 'mandelbrot.ispc:33:14: Error: syntax error, unexpected ''int'', expecting '','' or '';''.',
+ \ 'static iline int mandel(float c_re, float c_im, int count) {',
+ \ ' ^^^',
+ \ '',
+ \ 'mandelbrot.ispc:36:5: Error: syntax error, unexpected ''for''.',
+ \ ' for (i = 0; i < count; ++i) {',
+ \ ' ^^^',
+ \ '',
+ \ 'mandelbrot.ispc:51:9: fatal error: ''foobar.h'' file not found',
+ \ '#include<foobar.h>',
+ \ ' ^~~~~~~~~~',
+ \ 'mandelbrot.ispc:79:52: Performance Warning: Modulus operator with varying types is very inefficient.',
+ \ ' double x = x0 + i * (dx + epsilon*(k%2)*delta);',
+ \ ' ^^^',
+ \ '',
+ \ 'mandelbrot.ispc:85:13: Warning: Undefined behavior: all program instances are writing to the same location!',
+ \ ' output[index] = (NNN) / sample_size;',
+ \ ' ^^^^^^^^^^^^^',
+ \ '',
+ \ 'mandelbrot.ispc:93:19: Performance Warning: Gather required to load value.',
+ \ ' A[i*8] *= A[i*8];',
+ \ ' ^^^^^^',
+ \ '',
+ \ 'mandelbrot.ispc:93:9: Performance Warning: Scatter required to store value.',
+ \ ' A[i*8] *= A[i*8];',
+ \ ' ^^^^^^',
+ \ '',
+ \ ])
diff --git a/test/handler/test_perl6_handler.vader b/test/handler/test_perl6_handler.vader
new file mode 100644
index 00000000..452a9174
--- /dev/null
+++ b/test/handler/test_perl6_handler.vader
@@ -0,0 +1,277 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test/handler')
+
+ runtime ale_linters/perl6/perl6.vim
+
+After:
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+Execute(The Perl6 linter should handle empty output):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual [], ale_linters#perl6#perl6#Handle(bufnr(''), [])
+
+Execute(The Perl6 linter should complain about undeclared variables):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '6',
+ \ 'text': 'Variable ''$tes'' is not declared. Did you mean any of these? $res $test ',
+ \ 'type': 'E',
+ \ 'col': '',
+ \ 'end_lnum': '',
+ \ 'code': 'X::Undeclared',
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{
+ \ "X::Undeclared" : {
+ \ "highexpect" : [ ],
+ \ "is-compile-time" : 1,
+ \ "modules" : [ ],
+ \ "column" : null,
+ \ "pos" : 18,
+ \ "symbol" : "$tes",
+ \ "filename" : "bar.pl6",
+ \ "what" : "Variable",
+ \ "pre" : "my $test = 0; say ",
+ \ "post" : "$tes",
+ \ "suggestions" : [
+ \ "$res",
+ \ "$test"
+ \ ],
+ \ "line" : 6,
+ \ "message" : "Variable ''$tes'' is not declared. Did you mean any of these?\n $res\n $test\n"
+ \ }
+ \ }'
+ \ ])
+
+Execute(The Perl6 linter should complain about Comp::AdHoc errors):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '3',
+ \ 'type': 'E',
+ \ 'text': 'is repr(...) trait needs a parameter',
+ \ 'col': '',
+ \ 'end_lnum': '',
+ \ 'code': 'X::Comp::AdHoc',
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{
+ \ "X::Comp::AdHoc" : {
+ \ "pre" : "class test is repr",
+ \ "message" : "is repr(...) trait needs a parameter",
+ \ "line" : 3,
+ \ "post" : " {}",
+ \ "is-compile-time" : true,
+ \ "pos" : 19,
+ \ "highexpect" : [ ],
+ \ "payload" : "is repr(...) trait needs a parameter",
+ \ "filename" : "bar.pl6",
+ \ "column" : null,
+ \ "modules" : [ ]
+ \ }
+ \ }'
+ \])
+
+Execute(The Perl6 linter should be able to extract a line number from an error message):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '3',
+ \ 'text': 'Could not find Module::Does::not::exist at line 3 in: /usr/share/perl6/site /usr/share/perl6/vendor /usr/share/perl6 CompUnit::Repository::AbsolutePath<94023691448416> CompUnit::Repository::NQP<94023670532736> CompUnit::Repository::Perl5<94023670532776>',
+ \ 'col': '',
+ \ 'type': 'E',
+ \ 'end_lnum': '',
+ \ 'code': 'X::CompUnit::UnsatisfiedDependency',
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{
+ \ "X::CompUnit::UnsatisfiedDependency" : {
+ \ "message" : "Could not find Module::Does::not::exist at line 3 in:\n /usr/share/perl6/site\n /usr/share/perl6/vendor\n /usr/share/perl6\n CompUnit::Repository::AbsolutePath<94023691448416>\n CompUnit::Repository::NQP<94023670532736>\n CompUnit::Repository::Perl5<94023670532776>",
+ \ "specification" : "Module::Does::not::exist"
+ \ }
+ \ }'
+ \ ])
+
+Execute(The Perl6 linter should be able to differentiate between warnings and errors):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '1',
+ \ 'col': '',
+ \ 'code': 'X::Syntax::Regex::Unterminated',
+ \ 'end_lnum': '',
+ \ 'type': 'E',
+ \ 'text': 'Regex not terminated.',
+ \ },
+ \ {
+ \ 'lnum': '1',
+ \ 'col': '',
+ \ 'code': 'X::Comp::AdHoc',
+ \ 'end_lnum': '',
+ \ 'type': 'W',
+ \ 'text': 'Space is not significant here; please use quotes or :s (:sigspace) modifier (or, to suppress this warning, omit the space, or otherwise change the spacing)',
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{
+ \ "X::Comp::Group" : {
+ \ "message" : "Regex not terminated.\nUnable to parse regex; couldn''t find final ''/''\nSpace is not significant here; please use quotes or :s (:sigspace) modifier (or, to suppress this warning, omit the space, or otherwise change the spacing)",
+ \ "panic" : "Unable to parse regex; couldn''t find final ''/''",
+ \ "sorrows" : [
+ \ {
+ \ "X::Syntax::Regex::Unterminated" : {
+ \ "highexpect" : [
+ \ "infix stopper"
+ \ ],
+ \ "pos" : 6,
+ \ "is-compile-time" : 1,
+ \ "modules" : [ ],
+ \ "post" : "<EOL>",
+ \ "message" : "Regex not terminated.",
+ \ "line" : 1,
+ \ "filename" : "bar.pl6",
+ \ "column" : null,
+ \ "pre" : "/win 3"
+ \ }
+ \ }
+ \ ],
+ \ "worries" : [
+ \ {
+ \ "X::Comp::AdHoc" : {
+ \ "filename" : "bar.pl6",
+ \ "line" : 1,
+ \ "column" : null,
+ \ "pre" : "/win",
+ \ "highexpect" : [ ],
+ \ "payload" : "Space is not significant here; please use quotes or :s (:sigspace) modifier (or, to suppress this warning, omit the space, or otherwise change the spacing)",
+ \ "post" : " 3",
+ \ "message" : "Space is not significant here; please use quotes or :s (:sigspace) modifier (or, to suppress this warning, omit the space, or otherwise change the spacing)",
+ \ "modules" : [ ],
+ \ "is-compile-time" : true,
+ \ "pos" : 4
+ \ }
+ \ }
+ \ ]
+ \ }
+ \ }'
+ \])
+
+Execute(The Perl6 linter should gracefully handle non-JSON messages):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '1',
+ \ 'text': 'Received output in the default Perl6 error format. See :ALEDetail for details',
+ \ 'type': 'W',
+ \ 'detail': join([
+ \ 'Potential difficulties:',
+ \ ' Redeclaration of symbol ''$_''',
+ \ ' at /home/travis/perl6-error-fail/insanity-test.pl6:1',
+ \ ' ------> sub foo($_) {.say}; my $_<HERE> = 1; .&foo;',
+ \ ' Space is not significant here; please use quotes or :s (:sigspace) modifier (or, to suppress this warning, omit the space, or otherwise change the spacing)',
+ \ ' at /home/travis/perl6-error-fail/insanity-test.pl6:4',
+ \ ' ------> /win<HERE> 3/',
+ \ 'Syntax OK',], "\n")
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ 'Potential difficulties:',
+ \ ' Redeclaration of symbol ''$_''',
+ \ ' at /home/travis/perl6-error-fail/insanity-test.pl6:1',
+ \ ' ------> sub foo($_) {.say}; my $_<HERE> = 1; .&foo;',
+ \ ' Space is not significant here; please use quotes or :s (:sigspace) modifier (or, to suppress this warning, omit the space, or otherwise change the spacing)',
+ \ ' at /home/travis/perl6-error-fail/insanity-test.pl6:4',
+ \ ' ------> /win<HERE> 3/',
+ \ 'Syntax OK'
+ \ ])
+
+Execute(The Perl6 linter should gracefully handle messages without a line number):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '1',
+ \ 'end_lnum': '',
+ \ 'text': 'Cannot find method ''has_compile_time_value'' on object of type NQPMu',
+ \ 'type': 'E',
+ \ 'col' : '',
+ \ 'code': 'X::AdHoc',
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{',
+ \ '"X::AdHoc" : {',
+ \ '"message" : "Cannot find method ''has_compile_time_value'' on object of type NQPMu",',
+ \ '"payload" : "Cannot find method ''has_compile_time_value'' on object of type NQPMu"',
+ \ '}',
+ \ '}',
+ \ ])
+
+Execute(The Perl6 linter should not include errors from a known separate file):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{
+ \ "X::Undeclared" : {
+ \ "highexpect" : [ ],
+ \ "is-compile-time" : 1,
+ \ "modules" : [ ],
+ \ "column" : null,
+ \ "pos" : 18,
+ \ "symbol" : "$tes",
+ \ "filename" : "foo.pl6",
+ \ "what" : "Variable",
+ \ "pre" : "my $test = 0; say ",
+ \ "post" : "$tes",
+ \ "suggestions" : [
+ \ "$res",
+ \ "$test"
+ \ ],
+ \ "line" : 6,
+ \ "message" : "Variable ''$tes'' is not declared. Did you mean any of these?\n $res\n $test\n"
+ \ }
+ \ }'
+ \ ])
+
+Execute(The Perl6 linter should not ignore errors without a filename):
+ call ale#test#SetFilename('bar.pl6')
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': '3',
+ \ 'end_lnum': '',
+ \ 'text': 'Cannot find method ''has_compile_time_value'' on object of type NQPMu',
+ \ 'type': 'E',
+ \ 'col' : '',
+ \ 'code': 'X::AdHoc',
+ \ }
+ \ ],
+ \ ale_linters#perl6#perl6#Handle(bufnr(''), [
+ \ '{',
+ \ '"X::AdHoc" : {',
+ \ '"line" : 3,',
+ \ '"message" : "Cannot find method ''has_compile_time_value'' on object of type NQPMu",',
+ \ '"payload" : "Cannot find method ''has_compile_time_value'' on object of type NQPMu"',
+ \ '}',
+ \ '}',
+ \ ])
diff --git a/test/handler/test_perl_handler.vader b/test/handler/test_perl_handler.vader
index c5791d76..e769550c 100644
--- a/test/handler/test_perl_handler.vader
+++ b/test/handler/test_perl_handler.vader
@@ -7,6 +7,11 @@ After:
call ale#test#RestoreDirectory()
call ale#linter#Reset()
+Execute(The Perl linter should handle empty output):
+ call ale#test#SetFilename('bar.pl')
+
+ AssertEqual [], ale_linters#perl#perl#Handle(bufnr(''), [])
+
Execute(The Perl linter should ignore errors from other files):
call ale#test#SetFilename('bar.pl')
diff --git a/test/handler/test_pmd_handler.vader b/test/handler/test_pmd_handler.vader
index 0c95fb2a..4f64c9ca 100644
--- a/test/handler/test_pmd_handler.vader
+++ b/test/handler/test_pmd_handler.vader
@@ -25,3 +25,18 @@ Execute(The pmd handler should parse lines correctly):
\ '"1","rsb.performance.test.ros","/home/languitar/src/rsb-performance-test-api-ros/src/main/java/rsb/performance/test/ros/NodeHolder.java","3","18","Each class should declare at least one constructor","Code Style","AtLeastOneConstructor"',
\ '"2","rsb.performance.test.ros","/home/languitar/src/rsb-performance-test-api-ros/src/main/java/rsb/performance/test/ros/NodeHolder.java","1","36","Local variable ''node'' could be declared final","Code Style","LocalVariableCouldBeFinal"'
\ ])
+
+Execute(The pmd handler should parse lines correctly for java files that use unnamed packages):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 8,
+ \ 'text': 'Avoid unused local variables such as ''stest''.',
+ \ 'code': 'Best Practices - UnusedLocalVariable',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#java#pmd#Handle(666, [
+ \ '"Problem","Package","File","Priority","Line","Description","Rule set","Rule"',
+ \ '"1","","/Users/diego/Projects/github.com/dlresende/kata-fizz-buzz/src/main/java/App.java","3","8","Avoid unused local variables such as ''stest''.","Best Practices","UnusedLocalVariable"'
+ \ ])
diff --git a/test/handler/test_rust_handler.vader b/test/handler/test_rust_handler.vader
index e3ab3e86..4764e713 100644
--- a/test/handler/test_rust_handler.vader
+++ b/test/handler/test_rust_handler.vader
@@ -285,3 +285,148 @@ Execute(The Rust handler should find correct files):
\ },
\ }),
\ ])
+
+Execute(The Rust handler should remove secondary spans if set):
+ call ale#test#SetFilename('src/noerrors/mod.rs')
+
+ let g:ale_rust_ignore_secondary_spans = 0
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'end_lnum': 1,
+ \ 'type': 'E',
+ \ 'end_col': 21,
+ \ 'col': 1,
+ \ 'text': 'this function takes 1 parameter but 0 were supplied: defined here',
+ \ },
+ \ {
+ \ 'lnum': 1,
+ \ 'end_lnum': 1,
+ \ 'type': 'E',
+ \ 'end_col': 46,
+ \ 'col': 40,
+ \ 'text': 'this function takes 1 parameter but 0 were supplied: expected 1 parameter',
+ \ },
+ \ ],
+ \ ale#handlers#rust#HandleRustErrors(bufnr(''), [
+ \ '',
+ \ 'fn test(x: u8) -> u8 { x } fn main() { x(); }',
+ \ json_encode({
+ \ 'message': {
+ \ 'code': {
+ \ 'code': 'E0061',
+ \ 'explanation': 'Dummy explanation; not used'
+ \ },
+ \ 'level': 'error',
+ \ 'message': 'this function takes 1 parameter but 0 were supplied',
+ \ 'spans': [
+ \ {
+ \ 'byte_end': 20,
+ \ 'byte_start': 0,
+ \ 'column_end': 21,
+ \ 'column_start': 1,
+ \ 'file_name': 'src/noerrors/mod.rs',
+ \ 'is_primary': v:false,
+ \ 'label': 'defined here',
+ \ 'line_end': 1,
+ \ 'line_start': 1,
+ \ },
+ \ {
+ \ 'byte_end': 45,
+ \ 'byte_start': 39,
+ \ 'column_end': 46,
+ \ 'column_start': 40,
+ \ 'file_name': '<anon>',
+ \ 'is_primary': v:true,
+ \ 'label': 'expected 1 parameter',
+ \ 'line_end': 1,
+ \ 'line_start': 1,
+ \ },
+ \ ]
+ \ },
+ \ }),
+ \ json_encode({
+ \ 'message': {
+ \ 'code': v:null,
+ \ 'level': 'error',
+ \ 'message': 'aborting due to previous error',
+ \ 'spans': []
+ \ },
+ \ }),
+ \ json_encode({
+ \ 'message': {
+ \ 'code': v:null,
+ \ 'level': 'error',
+ \ 'message': 'For more information about this error, try `rustc --explain E0061`.',
+ \ 'spans': []
+ \ },
+ \ }),
+ \ ])
+
+ let g:ale_rust_ignore_secondary_spans = 1
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'end_lnum': 1,
+ \ 'type': 'E',
+ \ 'end_col': 46,
+ \ 'col': 40,
+ \ 'text': 'this function takes 1 parameter but 0 were supplied: expected 1 parameter',
+ \ },
+ \ ],
+ \ ale#handlers#rust#HandleRustErrors(bufnr(''), [
+ \ '',
+ \ 'fn test(x: u8) -> u8 { x } fn main() { x(); }',
+ \ json_encode({
+ \ 'message': {
+ \ 'code': {
+ \ 'code': 'E0061',
+ \ 'explanation': 'Dummy explanation; not used'
+ \ },
+ \ 'level': 'error',
+ \ 'message': 'this function takes 1 parameter but 0 were supplied',
+ \ 'spans': [
+ \ {
+ \ 'byte_end': 20,
+ \ 'byte_start': 0,
+ \ 'column_end': 21,
+ \ 'column_start': 1,
+ \ 'file_name': 'src/noerrors/mod.rs',
+ \ 'is_primary': v:false,
+ \ 'label': 'defined here',
+ \ 'line_end': 1,
+ \ 'line_start': 1,
+ \ },
+ \ {
+ \ 'byte_end': 45,
+ \ 'byte_start': 39,
+ \ 'column_end': 46,
+ \ 'column_start': 40,
+ \ 'file_name': '<anon>',
+ \ 'is_primary': v:true,
+ \ 'label': 'expected 1 parameter',
+ \ 'line_end': 1,
+ \ 'line_start': 1,
+ \ },
+ \ ]
+ \ },
+ \ }),
+ \ json_encode({
+ \ 'message': {
+ \ 'code': v:null,
+ \ 'level': 'error',
+ \ 'message': 'aborting due to previous error',
+ \ 'spans': []
+ \ },
+ \ }),
+ \ json_encode({
+ \ 'message': {
+ \ 'code': v:null,
+ \ 'level': 'error',
+ \ 'message': 'For more information about this error, try `rustc --explain E0061`.',
+ \ 'spans': []
+ \ },
+ \ }),
+ \ ])
diff --git a/test/handler/test_swipl_handler.vader b/test/handler/test_swipl_handler.vader
new file mode 100644
index 00000000..9e425cf6
--- /dev/null
+++ b/test/handler/test_swipl_handler.vader
@@ -0,0 +1,95 @@
+Before:
+ runtime ale_linters/prolog/swipl.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute (The swipl handler should handle oneline warning / error):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 5,
+ \ 'col': 1,
+ \ 'text': 'Syntax error: Operator expected',
+ \ 'type': 'E',
+ \ },
+ \ ],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'ERROR: /path/to/test.pl:5:1: Syntax error: Operator expected',
+ \ ])
+
+Execute (The swipl handler should handle a warning / error of two lines):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 9,
+ \ 'col': 0,
+ \ 'text': 'Singleton variables: [M]',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'Warning: /path/to/test.pl:9:',
+ \ ' Singleton variables: [M]',
+ \ ])
+
+Execute (The swipl handler should join three or more lines with '. '):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 10,
+ \ 'col': 0,
+ \ 'text': 'Clauses of fib/2 are not together in the source-file. Earlier definition at /path/to/test.pl:7. Current predicate: f/0. Use :- discontiguous fib/2. to suppress this message',
+ \ 'type': 'W',
+ \ },
+ \ ],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'Warning: /path/to/test.pl:10:',
+ \ ' Clauses of fib/2 are not together in the source-file',
+ \ ' Earlier definition at /path/to/test.pl:7',
+ \ ' Current predicate: f/0',
+ \ ' Use :- discontiguous fib/2. to suppress this message',
+ \ ])
+
+Execute (The swipl handler should ignore warnings / errors 'No permission to call sandboxed ...'):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'ERROR: /path/to/test.pl:11:',
+ \ ' No permission to call sandboxed `''$set_predicate_attribute''(_G3416:_G3417,_G3413,_G3414)''',
+ \ ' Reachable from:',
+ \ ' system:''$set_pattr''(A,B,C,D)',
+ \ ' system:''$set_pattr''(vimscript:A,B,C)',
+ \ ' vimscript: (multifile A)',
+ \ 'ERROR: /path/to/test.pl:12:',
+ \ ' No permission to call sandboxed `''$set_predicate_attribute''(_G205:_G206,_G202,_G203)''',
+ \ ' Reachable from:',
+ \ ' system:''$set_pattr''(A,B,C,D)',
+ \ ' system:''$set_pattr''(vimscript:A,B,C)',
+ \ ' vimscript: (multifile A)',
+ \ 'ERROR: /path/to/test.pl:13:',
+ \ ' No permission to call sandboxed `''$set_predicate_attribute''(_G1808:_G1809,_G1805,_G1806)''',
+ \ ' Reachable from:',
+ \ ' system:''$set_pattr''(A,B,C,D)',
+ \ ' system:''$set_pattr''(vimscript:A,B,C)',
+ \ ' vimscript: (multifile A)',
+ \ ])
+
+Execute (The swipl handler should handle a warning / error with no line number):
+ call ale#test#SetFilename('test.pl')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'col': 0,
+ \ 'text': 'Exported procedure module_name:pred/0 is not defined',
+ \ 'type': 'E',
+ \ },
+ \ ],
+ \ ale_linters#prolog#swipl#Handle(bufnr(''), [
+ \ 'ERROR: Exported procedure module_name:pred/0 is not defined',
+ \ ])
diff --git a/test/handler/test_vulture_handler.vader b/test/handler/test_vulture_handler.vader
new file mode 100644
index 00000000..c6bd7643
--- /dev/null
+++ b/test/handler/test_vulture_handler.vader
@@ -0,0 +1,92 @@
+Before:
+ runtime ale_linters/python/vulture.vim
+
+ call ale#test#SetDirectory('/testplugin/test/handler')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+ silent file something_else.py
+
+Execute(Basic vulture check with relative path in result should be handled):
+ call ale#test#SetFilename('something_else.py')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 34,
+ \ 'text': 'unused variable ''foo'' (60% confidence)',
+ \ 'type': 'W',
+ \ 'filename': ale#path#Simplify(g:dir . '/something_else.py'),
+ \ },
+ \ ],
+ \ ale_linters#python#vulture#Handle(bufnr(''), [
+ \ './something_else.py:34: unused variable ''foo'' (60% confidence)',
+ \ ])
+
+Execute(Basic vulture check with absolute path in result should be handled):
+ call ale#test#SetFilename('something_else.py')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 34,
+ \ 'text': 'unused variable ''foo'' (60% confidence)',
+ \ 'type': 'W',
+ \ 'filename': ale#path#Simplify(g:dir . '/something_else.py'),
+ \ },
+ \ ],
+ \ ale_linters#python#vulture#Handle(bufnr(''), [
+ \ ale#path#Simplify(g:dir . '/something_else.py') . ':34: unused variable ''foo'' (60% confidence)',
+ \ ])
+
+Execute(Vulture check for two files should be handled):
+ call ale#test#SetFilename('something_else.py')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 34,
+ \ 'text': 'unused variable ''foo'' (60% confidence)',
+ \ 'type': 'W',
+ \ 'filename': ale#path#Simplify(g:dir . '/something_else.py'),
+ \ },
+ \ {
+ \ 'lnum': 12,
+ \ 'text': 'unused variable ''bar'' (60% confidence)',
+ \ 'type': 'W',
+ \ 'filename': ale#path#Simplify(g:dir . '/second_one.py'),
+ \ },
+ \ ],
+ \ ale_linters#python#vulture#Handle(bufnr(''), [
+ \ './something_else.py:34: unused variable ''foo'' (60% confidence)',
+ \ './second_one.py:12: unused variable ''bar'' (60% confidence)',
+ \ ])
+
+
+Execute(Vulture exception should be handled):
+ call ale#test#SetFilename('something_else.py')
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'text': 'An exception was thrown. See :ALEDetail',
+ \ 'detail': join([
+ \ 'Traceback (most recent call last):',
+ \ ' File "/usr/lib/python3.6/site-packages/vulture/__init__.py", line 13, in <module>',
+ \ ' from .core import stuff',
+ \ 'BaddestException: Everything gone wrong',
+ \ ], "\n"),
+ \ }
+ \ ],
+ \ ale_linters#python#vulture#Handle(bufnr(''), [
+ \ 'Traceback (most recent call last):',
+ \ ' File "/usr/lib/python3.6/site-packages/vulture/__init__.py", line 13, in <module>',
+ \ ' from .core import stuff',
+ \ 'BaddestException: Everything gone wrong',
+ \ ])
+
+Execute(The vulture handler should handle empty output):
+ AssertEqual
+ \ [],
+ \ ale_linters#python#vulture#Handle(bufnr(''), [])
diff --git a/test/lsp/test_did_save_event.vader b/test/lsp/test_did_save_event.vader
index 428135fb..f8ff8f70 100644
--- a/test/lsp/test_did_save_event.vader
+++ b/test/lsp/test_did_save_event.vader
@@ -13,6 +13,7 @@ Before:
let b:ale_enabled = 1
let g:ale_lsp_next_message_id = 1
let g:ale_run_synchronously = 1
+ let g:conn_id = v:null
let g:message_list = []
function! LanguageCallback() abort
@@ -34,26 +35,29 @@ Before:
let g:ale_linters = {'foobar': ['dummy_linter']}
function! ale#lsp_linter#StartLSP(buffer, linter) abort
- let l:conn = ale#lsp#NewConnection({})
- let l:conn.id = 347
- let l:conn.open_documents = {a:buffer : -1}
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
return {
\ 'buffer': a:buffer,
- \ 'connection_id': 347,
+ \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar',
\ 'language_id': 'foobar',
\}
endfunction
" Replace the Send function for LSP, so we can monitor calls to it.
- function! ale#lsp#Send(conn_id, message, ...) abort
+ function! ale#lsp#Send(conn_id, message) abort
call add(g:message_list, a:message)
endfunction
After:
Restore
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
unlet! b:ale_enabled
unlet! b:ale_linters
unlet! g:message_list
@@ -61,7 +65,6 @@ After:
delfunction LanguageCallback
delfunction ProjectRootCallback
- call ale#lsp#RemoveConnectionWithID(347)
call ale#test#RestoreDirectory()
call ale#linter#Reset()
diff --git a/test/lsp/test_lsp_client_messages.vader b/test/lsp/test_lsp_client_messages.vader
index dc28c2e9..71768ce5 100644
--- a/test/lsp/test_lsp_client_messages.vader
+++ b/test/lsp/test_lsp_client_messages.vader
@@ -161,6 +161,17 @@ Execute(ale#lsp#message#References() should return correct messages):
\ ],
\ ale#lsp#message#References(bufnr(''), 12, 34)
+Execute(ale#lsp#message#Symbol() should return correct messages):
+ AssertEqual
+ \ [
+ \ 0,
+ \ 'workspace/symbol',
+ \ {
+ \ 'query': 'foobar',
+ \ }
+ \ ],
+ \ ale#lsp#message#Symbol('foobar')
+
Execute(ale#lsp#message#Hover() should return correct messages):
AssertEqual
\ [
@@ -175,6 +186,22 @@ Execute(ale#lsp#message#Hover() should return correct messages):
\ ],
\ ale#lsp#message#Hover(bufnr(''), 12, 34)
+Execute(ale#lsp#message#DidChangeConfiguration() should return correct messages):
+ let g:ale_lsp_configuration = {
+ \ 'foo': 'bar'
+ \ }
+ AssertEqual
+ \ [
+ \ 0,
+ \ 'workspace/didChangeConfiguration',
+ \ {
+ \ 'settings': {
+ \ 'foo': 'bar',
+ \ }
+ \ }
+ \ ],
+ \ ale#lsp#message#DidChangeConfiguration(bufnr(''), g:ale_lsp_configuration)
+
Execute(ale#lsp#tsserver_message#Open() should return correct messages):
AssertEqual
\ [
diff --git a/test/lsp/test_lsp_command_formatting.vader b/test/lsp/test_lsp_command_formatting.vader
index 9d2c84ee..9721f37f 100644
--- a/test/lsp/test_lsp_command_formatting.vader
+++ b/test/lsp/test_lsp_command_formatting.vader
@@ -5,7 +5,7 @@ Before:
" Mock the StartProgram function so we can just capture the arguments.
function! ale#lsp#StartProgram(...) abort
- let g:args = a:000
+ let g:args = a:000[1:]
endfunction
After:
@@ -27,10 +27,10 @@ Execute(Command formatting should be applied correctly for LSP linters):
if has('win32')
AssertEqual
- \ ['cmd', 'cmd /s/c "cmd --foo"', {}],
+ \ ['cmd', 'cmd /s/c "cmd --foo"'],
\ g:args
else
AssertEqual
- \ ['true', [&shell, '-c', '''true'' --foo'], {}],
+ \ ['true', [&shell, '-c', '''true'' --foo']],
\ g:args
endif
diff --git a/test/lsp/test_lsp_connections.vader b/test/lsp/test_lsp_connections.vader
index ae64eadb..1c2fceab 100644
--- a/test/lsp/test_lsp_connections.vader
+++ b/test/lsp/test_lsp_connections.vader
@@ -225,57 +225,3 @@ Execute(ale#lsp#ReadMessageData() should handle a message with part of a second
\ . '{"id":2,"jsonrpc":"2.0","result":{"foo":"barÜ"}}'
\ . b:data
\ )
-
-Execute(Projects with regular project roots should be registered correctly):
- let b:conn = ale#lsp#NewConnection({})
- call ale#lsp#RegisterProject(b:conn.id, '/foo/bar')
-
- AssertEqual
- \ {
- \ '/foo/bar': {
- \ 'root': '/foo/bar',
- \ 'initialized': 0,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ 'init_request_id': 0,
- \ },
- \ },
- \ b:conn.projects
-
-Execute(Projects with regular project roots should be fetched correctly):
- let b:conn = {
- \ 'projects': {
- \ '/foo/bar': {'initialized': 0, 'message_queue': [], 'init_request_id': 0},
- \ },
- \}
-
- AssertEqual
- \ {'initialized': 0, 'message_queue': [], 'init_request_id': 0},
- \ ale#lsp#GetProject(b:conn, '/foo/bar')
-
-Execute(Projects with empty project roots should be registered correctly):
- let b:conn = ale#lsp#NewConnection({})
- call ale#lsp#RegisterProject(b:conn.id, '')
-
- AssertEqual
- \ {
- \ '<<EMPTY>>': {
- \ 'root': '',
- \ 'initialized': 1,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ 'init_request_id': 0,
- \ },
- \ },
- \ b:conn.projects
-
-Execute(Projects with empty project roots should be fetched correctly):
- let b:conn = {
- \ 'projects': {
- \ '<<EMPTY>>': {'initialized': 1, 'message_queue': [], 'init_request_id': 0},
- \ },
- \}
-
- AssertEqual
- \ {'initialized': 1, 'message_queue': [], 'init_request_id': 0},
- \ ale#lsp#GetProject(b:conn, '')
diff --git a/test/lsp/test_other_initialize_message_handling.vader b/test/lsp/test_other_initialize_message_handling.vader
index 45457979..2f59535d 100644
--- a/test/lsp/test_other_initialize_message_handling.vader
+++ b/test/lsp/test_other_initialize_message_handling.vader
@@ -1,83 +1,47 @@
Before:
- let b:project = {
+ let b:conn = {
+ \ 'is_tsserver': 0,
+ \ 'data': '',
+ \ 'root': '/foo/bar',
+ \ 'open_documents': {},
\ 'initialized': 0,
- \ 'init_request_id': 3,
+ \ 'init_request_id': 0,
+ \ 'init_options': {},
+ \ 'config': {},
+ \ 'callback_list': [],
\ 'message_queue': [],
\ 'capabilities_queue': [],
- \}
-
- let b:conn = {
- \ 'projects': {
- \ '/foo/bar': b:project,
- \ },
\ 'capabilities': {
\ 'hover': 0,
\ 'references': 0,
\ 'completion': 0,
\ 'completion_trigger_characters': [],
\ 'definition': 0,
+ \ 'symbol_search': 0,
\ },
\}
After:
- unlet! b:project
unlet! b:conn
-Execute(publishDiagnostics messages with files inside project directories should initialize projects):
- " This is for some other file, ignore this one.
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {
- \ 'method': 'textDocument/publishDiagnostics',
- \ 'params': {'uri': 'file:///xyz/bar/baz.txt'},
- \})
-
- AssertEqual
- \ {
- \ 'initialized': 0,
- \ 'init_request_id': 3,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ },
- \ b:project
-
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {
- \ 'method': 'textDocument/publishDiagnostics',
- \ 'params': {'uri': 'file:///foo/bar/baz.txt'},
- \})
-
- AssertEqual
- \ {
- \ 'initialized': 1,
- \ 'init_request_id': 3,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ },
- \ b:project
-
Execute(Messages with no method and capabilities should initialize projects):
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {
+ call ale#lsp#HandleInitResponse(b:conn, {
\ 'result': {'capabilities': {}},
\})
- AssertEqual
- \ {
- \ 'initialized': 1,
- \ 'init_request_id': 3,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ },
- \ b:project
+ AssertEqual 1, b:conn.initialized
Execute(Other messages should not initialize projects):
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {'method': 'lolwat'})
+ call ale#lsp#HandleInitResponse(b:conn, {'method': 'lolwat'})
- AssertEqual 0, b:project.initialized
+ AssertEqual 0, b:conn.initialized
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {'result': {'x': {}}})
+ call ale#lsp#HandleInitResponse(b:conn, {'result': {'x': {}}})
- AssertEqual 0, b:project.initialized
+ AssertEqual 0, b:conn.initialized
Execute(Capabilities should bet set up correctly):
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {
+ call ale#lsp#HandleInitResponse(b:conn, {
\ 'jsonrpc': '2.0',
\ 'id': 1,
\ 'result': {
@@ -105,34 +69,26 @@ Execute(Capabilities should bet set up correctly):
\ },
\ 'definitionProvider': v:true,
\ 'experimental': {},
- \ 'documentHighlightProvider': v:true
+ \ 'documentHighlightProvider': v:true,
+ \ 'workspaceSymbolProvider': v:true
\ },
\ },
\})
+ AssertEqual 1, b:conn.initialized
AssertEqual
\ {
- \ 'capabilities': {
- \ 'completion_trigger_characters': ['.'],
- \ 'completion': 1,
- \ 'references': 1,
- \ 'hover': 1,
- \ 'definition': 1,
- \ },
- \ 'message_queue': [],
- \ 'projects': {
- \ '/foo/bar': {
- \ 'initialized': 1,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ 'init_request_id': 3,
- \ },
- \ },
+ \ 'completion_trigger_characters': ['.'],
+ \ 'completion': 1,
+ \ 'references': 1,
+ \ 'hover': 1,
+ \ 'definition': 1,
+ \ 'symbol_search': 1,
\ },
- \ b:conn
+ \ b:conn.capabilities
Execute(Disabled capabilities should be recognised correctly):
- call ale#lsp#HandleOtherInitializeResponses(b:conn, {
+ call ale#lsp#HandleInitResponse(b:conn, {
\ 'jsonrpc': '2.0',
\ 'id': 1,
\ 'result': {
@@ -161,23 +117,21 @@ Execute(Disabled capabilities should be recognised correctly):
\ },
\})
+ AssertEqual 1, b:conn.initialized
AssertEqual
\ {
- \ 'capabilities': {
- \ 'completion_trigger_characters': [],
- \ 'completion': 0,
- \ 'references': 0,
- \ 'hover': 0,
- \ 'definition': 0,
- \ },
- \ 'message_queue': [],
- \ 'projects': {
- \ '/foo/bar': {
- \ 'initialized': 1,
- \ 'message_queue': [],
- \ 'capabilities_queue': [],
- \ 'init_request_id': 3,
- \ },
- \ },
+ \ 'completion_trigger_characters': [],
+ \ 'completion': 0,
+ \ 'references': 0,
+ \ 'hover': 0,
+ \ 'definition': 0,
+ \ 'symbol_search': 0,
\ },
- \ b:conn
+ \ b:conn.capabilities
+
+Execute(Results that are not dictionaries should be handled correctly):
+ call ale#lsp#HandleInitResponse(b:conn, {
+ \ 'jsonrpc': '2.0',
+ \ 'id': 1,
+ \ 'result': v:null,
+ \})
diff --git a/test/lsp/test_read_lsp_diagnostics.vader b/test/lsp/test_read_lsp_diagnostics.vader
index 6ca4f962..a5c5ded3 100644
--- a/test/lsp/test_read_lsp_diagnostics.vader
+++ b/test/lsp/test_read_lsp_diagnostics.vader
@@ -18,7 +18,7 @@ Execute(ale#lsp#response#ReadDiagnostics() should handle errors):
\ 'col': 11,
\ 'end_lnum': 5,
\ 'end_col': 16,
- \ 'nr': 'some-error',
+ \ 'code': 'some-error',
\ }
\ ],
\ ale#lsp#response#ReadDiagnostics({'params': {'uri': 'filename.ts', 'diagnostics': [
@@ -39,7 +39,7 @@ Execute(ale#lsp#response#ReadDiagnostics() should handle warnings):
\ 'col': 4,
\ 'end_lnum': 2,
\ 'end_col': 4,
- \ 'nr': 'some-warning',
+ \ 'code': 'some-warning',
\ }
\ ],
\ ale#lsp#response#ReadDiagnostics({'params': {'uri': 'filename.ts', 'diagnostics': [
@@ -60,7 +60,7 @@ Execute(ale#lsp#response#ReadDiagnostics() should treat messages with missing se
\ 'col': 11,
\ 'end_lnum': 5,
\ 'end_col': 16,
- \ 'nr': 'some-error',
+ \ 'code': 'some-error',
\ }
\ ],
\ ale#lsp#response#ReadDiagnostics({'params': {'uri': 'filename.ts', 'diagnostics': [
@@ -109,6 +109,25 @@ Execute(ale#lsp#response#ReadDiagnostics() should include sources in detail):
\ }
\ ]}})
+Execute(ale#lsp#response#ReadDiagnostics() should consider -1 to be a meaningless code):
+ AssertEqual [
+ \ {
+ \ 'type': 'E',
+ \ 'text': 'Something went wrong!',
+ \ 'lnum': 3,
+ \ 'col': 11,
+ \ 'end_lnum': 5,
+ \ 'end_col': 16,
+ \ }
+ \ ],
+ \ ale#lsp#response#ReadDiagnostics({'params': {'uri': 'filename.ts', 'diagnostics': [
+ \ {
+ \ 'range': Range(2, 10, 4, 15),
+ \ 'message': 'Something went wrong!',
+ \ 'code': -1,
+ \ },
+ \ ]}})
+
Execute(ale#lsp#response#ReadDiagnostics() should handle multiple messages):
AssertEqual [
\ {
@@ -140,12 +159,42 @@ Execute(ale#lsp#response#ReadDiagnostics() should handle multiple messages):
\ },
\ ]}})
+Execute(ale#lsp#response#ReadDiagnostics() should use relatedInformation for detail):
+ AssertEqual [
+ \ {
+ \ 'type': 'E',
+ \ 'text': 'Something went wrong!',
+ \ 'lnum': 1,
+ \ 'col': 3,
+ \ 'end_lnum': 1,
+ \ 'end_col': 3,
+ \ 'detail': "Something went wrong!\n/tmp/someotherfile.txt:43:80:\n\tmight be this"
+ \ }
+ \ ],
+ \ ale#lsp#response#ReadDiagnostics({'params': {'uri': 'filename.ts', 'diagnostics': [
+ \ {
+ \ 'range': Range(0, 2, 0, 2),
+ \ 'message': 'Something went wrong!',
+ \ 'relatedInformation': [{
+ \ 'message': 'might be this',
+ \ 'location': {
+ \ 'uri': 'file:///tmp/someotherfile.txt',
+ \ 'range': {
+ \ 'start': { 'line': 42, 'character': 79 },
+ \ 'end': { 'line': 142, 'character': 179},
+ \ }
+ \ }
+ \ }]
+ \ }
+ \ ]}})
+
Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle tsserver responses):
AssertEqual
\ [
\ {
\ 'type': 'E',
\ 'nr': 2365,
+ \ 'code': '2365',
\ 'text': 'Operator ''''+'''' cannot be applied to types ''''3'''' and ''''{}''''.',
\ 'lnum': 1,
\ 'col': 11,
@@ -162,6 +211,7 @@ Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle warnings from t
\ 'lnum': 27,
\ 'col': 3,
\ 'nr': 2515,
+ \ 'code': '2515',
\ 'end_lnum': 27,
\ 'type': 'W',
\ 'end_col': 14,
@@ -177,6 +227,7 @@ Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle suggestions fro
\ 'lnum': 27,
\ 'col': 3,
\ 'nr': 2515,
+ \ 'code': '2515',
\ 'end_lnum': 27,
\ 'type': 'I',
\ 'end_col': 14,
diff --git a/test/lsp/test_update_config.vader b/test/lsp/test_update_config.vader
new file mode 100644
index 00000000..07068bc8
--- /dev/null
+++ b/test/lsp/test_update_config.vader
@@ -0,0 +1,17 @@
+Before:
+ runtime autoload/ale/lsp.vim
+
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+
+After:
+ Restore
+
+ unlet! g:conn_id
+
+ runtime autoload/ale/lsp.vim
+
+Execute(Only send updates when the configuration dictionary changes):
+ AssertEqual 0, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {})
+ AssertEqual 1, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'a': 1})
+ AssertEqual 0, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'a': 1})
+ AssertEqual 1, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {})
diff --git a/test/ocaml-test-files/testfile.ml b/test/ocaml-test-files/testfile.ml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ocaml-test-files/testfile.ml
diff --git a/test/python_fixtures/pipenv/Pipfile.lock b/test/python_fixtures/pipenv/Pipfile.lock
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/python_fixtures/pipenv/Pipfile.lock
diff --git a/test/ruby_fixtures/valid_ruby_app1/Rakefile b/test/ruby_fixtures/valid_ruby_app1/Rakefile
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ruby_fixtures/valid_ruby_app1/Rakefile
diff --git a/test/ruby_fixtures/valid_ruby_app1/lib/file.rb b/test/ruby_fixtures/valid_ruby_app1/lib/file.rb
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ruby_fixtures/valid_ruby_app1/lib/file.rb
diff --git a/test/ruby_fixtures/valid_ruby_app2/Gemfile b/test/ruby_fixtures/valid_ruby_app2/Gemfile
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ruby_fixtures/valid_ruby_app2/Gemfile
diff --git a/test/ruby_fixtures/valid_ruby_app2/lib/file.rb b/test/ruby_fixtures/valid_ruby_app2/lib/file.rb
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ruby_fixtures/valid_ruby_app2/lib/file.rb
diff --git a/test/ruby_fixtures/valid_ruby_app3/.solargraph.yml b/test/ruby_fixtures/valid_ruby_app3/.solargraph.yml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ruby_fixtures/valid_ruby_app3/.solargraph.yml
diff --git a/test/ruby_fixtures/valid_ruby_app3/lib/file.rb b/test/ruby_fixtures/valid_ruby_app3/lib/file.rb
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ruby_fixtures/valid_ruby_app3/lib/file.rb
diff --git a/test/scala_fixtures/invalid_sbt_project/Main.scala b/test/scala_fixtures/invalid_sbt_project/Main.scala
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/scala_fixtures/invalid_sbt_project/Main.scala
diff --git a/test/scala_fixtures/valid_sbt_project/Main.scala b/test/scala_fixtures/valid_sbt_project/Main.scala
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/scala_fixtures/valid_sbt_project/Main.scala
diff --git a/test/scala_fixtures/valid_sbt_project/build.sbt b/test/scala_fixtures/valid_sbt_project/build.sbt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/scala_fixtures/valid_sbt_project/build.sbt
diff --git a/test/script/block-padding-checker b/test/script/block-padding-checker
new file mode 100755
index 00000000..b13c9b92
--- /dev/null
+++ b/test/script/block-padding-checker
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+"""
+This script checks for missing or forbidden blank lines before or after
+particular Vim commands. This script ensures that VimL scripts are padded
+correctly, so they are easier to read.
+"""
+
+import sys
+import re
+
+INDENTATION_RE = re.compile(r'^ *')
+COMMENT_LINE_RE = re.compile(r'^ *"')
+COMMAND_RE = re.compile(r'^ *([a-zA-Z]+)')
+
+START_BLOCKS = set(['if', 'for', 'while', 'try', 'function'])
+END_BLOCKS = set(['endif', 'endfor', 'endwhile', 'endtry', 'endfunction'])
+MIDDLE_BLOCKS = set(['else', 'elseif', 'catch', 'finally'])
+TERMINATORS = set(['return', 'throw'])
+
+WHITESPACE_BEFORE_SET = START_BLOCKS | TERMINATORS
+WHITESPACE_FORBIDDEN_BEFORE_SET = END_BLOCKS | MIDDLE_BLOCKS
+WHITESPACE_AFTER_SET = END_BLOCKS
+WHITESPACE_FORBIDDEN_AFTER_SET = START_BLOCKS | MIDDLE_BLOCKS
+
+
+def remove_comment_lines(line_iter):
+ for line_number, line in enumerate(line_iter, 1):
+ if not COMMENT_LINE_RE.match(line):
+ yield (line_number, line)
+
+
+def check_lines(line_iter):
+ previous_indentation_level = None
+ previous_command = None
+ previous_line_blank = False
+
+ for line_number, line in remove_comment_lines(line_iter):
+ if len(line) == 0:
+ # Check for commands where we shouldn't have blank lines after
+ # them, like `else` or the start of blocks like `function`.
+ if (
+ previous_command is not None
+ and previous_command in WHITESPACE_FORBIDDEN_AFTER_SET
+ ):
+ yield (
+ line_number,
+ 'Blank line forbidden after `%s`' % (command,)
+ )
+
+ previous_line_blank = True
+ previous_command = None
+ else:
+ indentation_level = INDENTATION_RE.match(line).end()
+ command_match = COMMAND_RE.match(line)
+
+ if command_match:
+ command = command_match.group(1)
+
+ # Check for commands requiring blank lines before them, if they
+ # aren't at the start of a block.
+ if (
+ command in WHITESPACE_BEFORE_SET
+ and previous_indentation_level is not None
+ and indentation_level == previous_indentation_level
+ and previous_line_blank is False
+ ):
+ yield (
+ line_number,
+ 'Blank line required before `%s`' % (command,)
+ )
+
+ # Check for commands where we shouldn't have blank lines before
+ # them, like `else` or the end of blocks like `endfunction`.
+ if (
+ command in WHITESPACE_FORBIDDEN_BEFORE_SET
+ and previous_line_blank is True
+ ):
+ yield (
+ line_number - 1,
+ 'Blank line forbidden before `%s`' % (command,)
+ )
+
+ # Check for commands requiring blank lines after them, if they
+ # aren't at the end of a block.
+ if (
+ previous_command is not None
+ and previous_command in WHITESPACE_AFTER_SET
+ and previous_indentation_level is not None
+ and indentation_level == previous_indentation_level
+ and previous_line_blank is False
+ ):
+ yield (
+ line_number - 1,
+ 'Blank line required after `%s`' % (command,)
+ )
+
+ previous_command = command
+ previous_line_blank = False
+ previous_indentation_level = indentation_level
+
+
+def main():
+ status = 0
+
+ for filename in sys.argv[1:]:
+ with open(filename) as vim_file:
+ line_iter = (line.rstrip() for line in vim_file)
+
+ for line_number, message in check_lines(line_iter):
+ print('%s:%d %s' % (filename, line_number, message))
+ status = 1
+
+ sys.exit(status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/script/custom-linting-rules b/test/script/custom-linting-rules
index 69c4a7a1..77e87db4 100755
--- a/test/script/custom-linting-rules
+++ b/test/script/custom-linting-rules
@@ -59,10 +59,11 @@ check_errors() {
fi
for directory in "${directories[@]}"; do
- while IFS= read -r match; do
+ # shellcheck disable=SC2086
+ while read -r; do
RETURN_CODE=1
- echo "$match $message"
- done < <(grep -n "$regex" $include_arg "$directory"/**/*.vim \
+ echo "$REPLY $message"
+ done < <(grep -H -n "$regex" $include_arg "$directory"/**/*.vim \
| grep -v 'no-custom-checks' \
| grep -o '^[^:]\+:[0-9]\+' \
| sed 's:^\./::')
@@ -77,6 +78,17 @@ if (( FIX_ERRORS )); then
sed -i 's/==?/is?/g' "$directory"/**/*.vim
sed -i 's/!=#/isnot#/g' "$directory"/**/*.vim
sed -i 's/!=?/isnot?/g' "$directory"/**/*.vim
+ # Improving type checks.
+ sed -i $'s/\\(==.\\?\\|is\\) type([\'"]\+)/is v:t_string/g' "$directory"/**/*.vim
+ sed -i 's/\(==.\?\|is\) type([0-9]\+)/is v:t_number/g' "$directory"/**/*.vim
+ sed -i 's/\(==.\?\|is\) type(\[\])/is v:t_list/g' "$directory"/**/*.vim
+ sed -i 's/\(==.\?\|is\) type({})/is v:t_dict/g' "$directory"/**/*.vim
+ sed -i 's/\(==.\?\|is\) type(function([^)]\+))/is v:t_func/g' "$directory"/**/*.vim
+ sed -i $'s/\\(!=.\\?\\|isnot\\) type([\'"]\+)/isnot v:t_string/g' "$directory"/**/*.vim
+ sed -i 's/\(!=.\?\|isnot\) type([0-9]\+)/isnot v:t_number/g' "$directory"/**/*.vim
+ sed -i 's/\(!=.\?\|isnot\) type(\[\])/isnot v:t_list/g' "$directory"/**/*.vim
+ sed -i 's/\(!=.\?\|isnot\) type({})/isnot v:t_dict/g' "$directory"/**/*.vim
+ sed -i 's/\(!=.\?\|isnot\) type(function([^)]\+))/isnot v:t_func/g' "$directory"/**/*.vim
done
fi
@@ -102,5 +114,25 @@ check_errors '!=#' "Use 'isnot#' instead of '!=#'. 0 !=# 'foobar' is false"
check_errors '!=?' "Use 'isnot?' instead of '!=?'. 0 !=? 'foobar' is false"
check_errors '^ *:\?echo' "Stray echo line. Use \`execute echo\` if you want to echo something"
check_errors $'name.:.*\'[a-z_]*[^a-z_0-9][a-z_0-9]*\',$' 'Use snake_case names for linters' '*/ale_linters/*'
+# Checks for improving type checks.
+check_errors $'\\(==.\\?\\|is\\) type([\'"]\+)' "Use 'is v:t_string' instead"
+check_errors '\(==.\?\|is\) type([0-9]\+)' "Use 'is v:t_number' instead"
+check_errors '\(==.\?\|is\) type(\[\])' "Use 'is v:t_list' instead"
+check_errors '\(==.\?\|is\) type({})' "Use 'is v:t_dict' instead"
+check_errors '\(==.\?\|is\) type(function([^)]\+))' "Use 'is v:t_func' instead"
+check_errors $'\\(!=.\\?\\|isnot\\) type([\'"]\+)' "Use 'isnot v:t_string' instead"
+check_errors '\(!=.\?\|isnot\) type([0-9]\+)' "Use 'isnot v:t_number' instead"
+check_errors '\(!=.\?\|isnot\) type(\[\])' "Use 'isnot v:t_list' instead"
+check_errors '\(!=.\?\|isnot\) type({})' "Use 'isnot v:t_dict' instead"
+check_errors '\(!=.\?\|isnot\) type(function([^)]\+))' "Use 'isnot v:t_func' instead"
+
+# Run a Python script to find lines that require padding around them. For
+# users without Python installed, we'll skip these checks. Travis CI will run
+# the script.
+if command -v python > /dev/null; then
+ if ! test/script/block-padding-checker "$directory"/**/*.vim; then
+ RETURN_CODE=1
+ fi
+fi
exit $RETURN_CODE
diff --git a/test/smoke_test.vader b/test/smoke_test.vader
index 2708c86f..c87f95b2 100644
--- a/test/smoke_test.vader
+++ b/test/smoke_test.vader
@@ -65,7 +65,7 @@ Execute(Linters should run with the default options):
" Try the test a few times over in NeoVim 0.3 or Windows,
" where tests fail randomly.
for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
- call ale#Lint()
+ call ale#Queue(0, '')
call ale#engine#WaitForJobs(2000)
let g:results = ale#test#GetLoclistWithoutModule()
@@ -109,7 +109,7 @@ Execute(Linters should run in PowerShell too):
\ 'command': 'echo foo && echo bar',
\})
- call ale#Lint()
+ call ale#Queue(0, '')
call ale#engine#WaitForJobs(4000)
AssertEqual [
@@ -139,7 +139,7 @@ Execute(Linters should run in PowerShell too):
endif
Execute(Previous errors should be removed when linters change):
- call ale#Lint()
+ call ale#Queue(0, '')
call ale#engine#WaitForJobs(2000)
call ale#linter#Reset()
@@ -166,7 +166,7 @@ Execute(Previous errors should be removed when linters change):
" Try the test a few times over in NeoVim 0.3 or Windows,
" where tests fail randomly.
for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
- call ale#Lint()
+ call ale#Queue(0, '')
call ale#engine#WaitForJobs(2000)
let g:results = ale#test#GetLoclistWithoutModule()
diff --git a/test/test_ale_info.vader b/test/test_ale_info.vader
index 39a2a85a..325c2aa8 100644
--- a/test/test_ale_info.vader
+++ b/test/test_ale_info.vader
@@ -88,14 +88,14 @@ Before:
\ 'let g:ale_lint_delay = 200',
\ 'let g:ale_lint_on_enter = 1',
\ 'let g:ale_lint_on_filetype_changed = 1',
+ \ 'let g:ale_lint_on_insert_leave = 0',
\ 'let g:ale_lint_on_save = 1',
\ 'let g:ale_lint_on_text_changed = ''always''',
- \ 'let g:ale_lint_on_insert_leave = 0',
\ 'let g:ale_linter_aliases = {}',
\ 'let g:ale_linters = {}',
\ 'let g:ale_linters_explicit = 0',
- \ 'let g:ale_list_window_size = 10',
\ 'let g:ale_list_vertical = 0',
+ \ 'let g:ale_list_window_size = 10',
\ 'let g:ale_loclist_msg_format = ''%code: %%s''',
\ 'let g:ale_max_buffer_history_size = 20',
\ 'let g:ale_max_signs = -1',
@@ -118,6 +118,7 @@ Before:
\ 'let g:ale_statusline_format = [''%d error(s)'', ''%d warning(s)'', ''OK'']',
\ 'let g:ale_type_map = {}',
\ 'let g:ale_use_global_executables = v:null',
+ \ 'let g:ale_virtualtext_cursor = 0',
\ 'let g:ale_warn_about_trailing_blank_lines = 1',
\ 'let g:ale_warn_about_trailing_whitespace = 1',
\]
diff --git a/test/test_alejobstarted_autocmd.vader b/test/test_alejobstarted_autocmd.vader
index 388e5439..6fa1ff8e 100644
--- a/test/test_alejobstarted_autocmd.vader
+++ b/test/test_alejobstarted_autocmd.vader
@@ -23,10 +23,11 @@ After:
let g:ale_run_synchronously = 0
- try
- augroup! VaderTest
- catch
- endtry
+ augroup VaderTest
+ autocmd!
+ augroup END
+
+ augroup! VaderTest
unlet! g:job_started_success
@@ -38,7 +39,7 @@ Execute(Run a lint cycle with an actual job to check for ALEJobStarted):
augroup VaderTest
autocmd!
autocmd User ALEJobStarted let g:job_started_success = 1
- augroup end
+ augroup END
ALELint
diff --git a/test/test_alelint_autocmd.vader b/test/test_alelint_autocmd.vader
index 5af1cd47..332cb36f 100644
--- a/test/test_alelint_autocmd.vader
+++ b/test/test_alelint_autocmd.vader
@@ -9,20 +9,21 @@ After:
let g:ale_run_synchronously = 0
let g:ale_buffer_info = {}
- try
- augroup! VaderTest
- catch
- endtry
+ augroup VaderTest
+ autocmd!
+ augroup END
+
+ augroup! VaderTest
-Given foobar(An empty file):
+Given testft(An empty file):
Execute(Run a lint cycle, and check that a variable is set in the autocmd):
augroup VaderTest
autocmd!
autocmd User ALELintPre let g:pre_success = 1
autocmd User ALELintPost let g:post_success = 1
- augroup end
+ augroup END
- call ale#Lint()
+ call ale#Queue(0)
AssertEqual g:pre_success, 1
AssertEqual g:post_success, 1
@@ -30,10 +31,10 @@ Execute(Run a lint cycle, and check that a variable is set in the autocmd):
Execute(b:ale_linted should be increased after each lint cycle):
AssertEqual get(b:, 'ale_linted'), 0
- call ale#Lint()
+ call ale#Queue(0)
AssertEqual get(b:, 'ale_linted'), 1
- call ale#Lint()
+ call ale#Queue(0)
AssertEqual get(b:, 'ale_linted'), 2
diff --git a/test/test_autocmd_commands.vader b/test/test_autocmd_commands.vader
index 8d5048f0..4bb894ba 100644
--- a/test/test_autocmd_commands.vader
+++ b/test/test_autocmd_commands.vader
@@ -175,10 +175,19 @@ Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event):
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''\v^FileType''')
Execute (ALECleanupGroup should include the right commands):
- AssertEqual [
- \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
- \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
- \], CheckAutocmd('ALECleanupGroup')
+ if exists('##VimSuspend')
+ AssertEqual [
+ \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
+ \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
+ \ 'VimSuspend * if exists(''*ale#engine#CleanupEveryBuffer'') | call ale#engine#CleanupEveryBuffer() | endif',
+ \], CheckAutocmd('ALECleanupGroup')
+ else
+ AssertEqual [
+ \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
+ \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
+ \], CheckAutocmd('ALECleanupGroup')
+ endif
+
Execute(Enabling completion should set up autocmd events correctly):
let g:ale_completion_enabled = 0
diff --git a/test/test_c_flag_parsing.vader b/test/test_c_flag_parsing.vader
new file mode 100644
index 00000000..8a9b7189
--- /dev/null
+++ b/test/test_c_flag_parsing.vader
@@ -0,0 +1,179 @@
+Before:
+ Save g:ale_c_parse_makefile
+
+ call ale#test#SetDirectory('/testplugin/test')
+
+ let g:ale_c_parse_makefile = 1
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The CFlags parser should be able to parse include directives):
+ call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
+
+ AssertEqual
+ \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
+ \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c'])
+
+Execute(The CFlags parser should be able to parse macro directives):
+ call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
+
+ AssertEqual
+ \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' -DTEST=1',
+ \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=1 -c file.c'])
+
+Execute(The CFlags parser should be able to parse macro directives with spaces):
+ call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
+
+ AssertEqual
+ \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' -DTEST=$(( 2 * 4 ))',
+ \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=$(( 2 * 4 )) -c file.c'])
+
+Execute(The CFlags parser should be able to parse shell directives with spaces):
+ call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
+
+ AssertEqual
+ \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=`date +%s` -c file.c'])
+
+Execute(ParseCFlags should be able to parse flags with relative paths):
+ AssertEqual
+ \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Isubdir '
+ \ . '-I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should be able to parse -Dgoal):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Isubdir '
+ \ . '-I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should ignore -T and other arguments):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir --sysroot=subdir '
+ \ . '-I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should handle paths with spaces in double quotes):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should handle paths with spaces in single quotes):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should handle paths with minuses):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash'
+ \ . ' -I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should handle -D with minuses):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' -Dmacro-with-dash'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-Dmacro-with-dash '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash'
+ \ . ' -I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
+Execute(ParseCFlags should handle flags at the end of the line):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' -Dmacro-with-dash'
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-Dmacro-with-dash '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash'
+ \ . ' -I'. ale#path#Simplify('kernel/include')
+ \ )
+
+Execute(FlagsFromCompileCommands should tolerate empty values):
+ AssertEqual '', ale#c#FlagsFromCompileCommands(bufnr(''), '')
+
+Execute(ParseCompileCommandsFlags should tolerate empty values):
+ AssertEqual '', ale#c#ParseCompileCommandsFlags(bufnr(''), '', [])
+
+Execute(ParseCompileCommandsFlags should parse some basic flags):
+ noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
+
+ AssertEqual
+ \ '-I' . ale#path#Simplify('/usr/include/xmms2'),
+ \ ale#c#ParseCompileCommandsFlags(bufnr(''), ale#path#Simplify('/foo/bar/xmms2-mpris'), [
+ \ {
+ \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
+ \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
+ \ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
+ \ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
+ \ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
+ \ },
+ \ ])
diff --git a/test/test_c_import_paths.vader b/test/test_c_import_paths.vader
deleted file mode 100644
index 0490dec6..00000000
--- a/test/test_c_import_paths.vader
+++ /dev/null
@@ -1,252 +0,0 @@
-Before:
- " Make sure the c.vim file is loaded first.
- call ale#c#FindProjectRoot(bufnr(''))
-
- Save g:ale_c_gcc_options
- Save g:ale_c_clang_options
- Save g:ale_cpp_gcc_options
- Save g:ale_cpp_clang_options
- Save g:__ale_c_project_filenames
-
- let g:original_project_filenames = g:__ale_c_project_filenames
-
- " Remove the .git/HEAD dir for C import paths for these tests.
- " The tests run inside of a git repo.
- let g:__ale_c_project_filenames = filter(
- \ copy(g:__ale_c_project_filenames),
- \ 'v:val isnot# ''.git/HEAD'''
- \)
-
- call ale#test#SetDirectory('/testplugin/test')
-
- let g:ale_c_gcc_options = ''
- let g:ale_c_clang_options = ''
- let g:ale_cpp_gcc_options = ''
- let g:ale_cpp_clang_options = ''
-
-After:
- Restore
-
- unlet! g:original_project_filenames
-
- call ale#test#RestoreDirectory()
- call ale#linter#Reset()
-
-Execute(The C GCC handler should include 'include' directories for projects with a Makefile):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#c#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C GCC handler should include 'include' directories for projects with a configure file):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/configure_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#c#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C GCC handler should include root directories for projects with .h files in them):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/h_file_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#c#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C GCC handler should include root directories for projects with .hpp files in them):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/hpp_file_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#c#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C Clang handler should include 'include' directories for projects with a Makefile):
- runtime! ale_linters/c/clang.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('clang')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#c#clang#GetCommand(bufnr(''), [])
-
-Execute(The C Clang handler should include 'include' directories for projects with a configure file):
- runtime! ale_linters/c/clang.vim
-
- call ale#test#SetFilename('test_c_projects/h_file_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('clang')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#c#clang#GetCommand(bufnr(''), [])
-
-Execute(The C Clang handler should include root directories for projects with .h files in them):
- runtime! ale_linters/c/clang.vim
-
- call ale#test#SetFilename('test_c_projects/h_file_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('clang')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#c#clang#GetCommand(bufnr(''), [])
-
-Execute(The C Clang handler should include root directories for projects with .hpp files in them):
- runtime! ale_linters/c/clang.vim
-
- call ale#test#SetFilename('test_c_projects/hpp_file_project/subdir/file.c')
-
- AssertEqual
- \ ale#Escape('clang')
- \ . ' -S -x c -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#c#clang#GetCommand(bufnr(''), [])
-
-Execute(The C++ GCC handler should include 'include' directories for projects with a Makefile):
- runtime! ale_linters/cpp/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C++ GCC handler should include 'include' directories for projects with a configure file):
- runtime! ale_linters/cpp/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/configure_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C++ GCC handler should include root directories for projects with .h files in them):
- runtime! ale_linters/cpp/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/h_file_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C++ GCC handler should include root directories for projects with .hpp files in them):
- runtime! ale_linters/cpp/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/hpp_file_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('gcc')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), [])
-
-Execute(The C++ Clang handler should include 'include' directories for projects with a Makefile):
- runtime! ale_linters/cpp/clang.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('clang++')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#clang#GetCommand(bufnr(''), [])
-
-Execute(The C++ Clang handler should include 'include' directories for projects with a configure file):
- runtime! ale_linters/cpp/clang.vim
-
- call ale#test#SetFilename('test_c_projects/configure_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('clang++')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/include')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#clang#GetCommand(bufnr(''), [])
-
-Execute(The C++ Clang handler should include root directories for projects with .h files in them):
- runtime! ale_linters/cpp/clang.vim
-
- call ale#test#SetFilename('test_c_projects/h_file_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('clang++')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#clang#GetCommand(bufnr(''), [])
-
-Execute(The C++ Clang handler should include root directories for projects with .hpp files in them):
- runtime! ale_linters/cpp/clang.vim
-
- call ale#test#SetFilename('test_c_projects/hpp_file_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('clang++')
- \ . ' -S -x c++ -fsyntax-only '
- \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' '
- \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' '
- \ . ' -'
- \ , ale_linters#cpp#clang#GetCommand(bufnr(''), [])
-
-Execute(The C++ ClangTidy handler should include json folders for projects with suitable build directory in them):
- runtime! ale_linters/cpp/clangtidy.vim
-
- call ale#test#SetFilename('test_c_projects/json_project/subdir/file.cpp')
-
- AssertEqual
- \ ale#Escape('clang-tidy')
- \ . ' -checks=' . ale#Escape('*') . ' %s '
- \ . '-p ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/json_project/build'))
- \ , ale_linters#cpp#clangtidy#GetCommand(bufnr(''))
diff --git a/test/test_c_parse_makefile.vader b/test/test_c_parse_makefile.vader
deleted file mode 100644
index 7c2fc21e..00000000
--- a/test/test_c_parse_makefile.vader
+++ /dev/null
@@ -1,184 +0,0 @@
-Before:
- Save g:ale_c_parse_makefile
- Save g:ale_c_gcc_options
- Save g:ale_c_clang_options
- Save g:ale_cpp_gcc_options
- Save g:ale_cpp_clang_options
-
- call ale#test#SetDirectory('/testplugin/test')
-
- let g:ale_c_parse_makefile=1
- let g:ale_c_gcc_options = ''
- let g:ale_c_clang_options = ''
- let g:ale_cpp_gcc_options = ''
- let g:ale_cpp_clang_options = ''
-
-After:
- Restore
-
- call ale#test#RestoreDirectory()
- call ale#linter#Reset()
-
-Execute(The CFlags parser should be able to parse include directives):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))]
- \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -c file.c')
-
-Execute(The CFlags parser should be able to parse macro directives):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ '-DTEST=1']
- \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=1 -c file.c')
-
-Execute(The CFlags parser should be able to parse macro directives with spaces):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ '-DTEST=$(( 2 * 4 ))']
- \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=$(( 2 * 4 )) -c file.c')
-
-Execute(The CFlags parser should be able to parse shell directives with spaces):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=`date +%s` -c file.c')
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Isubdir -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #2):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Isubdir ' .
- \ '-I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #3):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ['-Dgoal=9',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Dgoal=9 -Isubdir ' .
- \ '-I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #4):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ['-Dgoal=9',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
- \ '-I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #5):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ['-Dgoal=9',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
- \ '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #6):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ['-Dgoal=9',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
- \ '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #7):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ['-Dgoal=9',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
- \ '-I''dir with spaces''' . ' -Idir-with-dash' .
- \ ' -I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
-
-Execute(The CFlagsToList parser should be able to parse multiple cflags #8):
- runtime! ale_linters/c/gcc.vim
-
- call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
-
- AssertEqual
- \ ['-Dgoal=9',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
- \ '-Dmacro-with-dash',
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')),
- \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
- \ '-DTEST=`date +%s`']
- \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' .
- \ '-Dmacro-with-dash ' .
- \ '-I''dir with spaces''' . ' -Idir-with-dash' .
- \ ' -I'. ale#path#Simplify('kernel/include') .
- \ ' -DTEST=`date +%s` -c file.c', '-'))
diff --git a/test/test_checkingbuffer_autocmd.vader b/test/test_checkingbuffer_autocmd.vader
index 9e3a8188..9e642b15 100644
--- a/test/test_checkingbuffer_autocmd.vader
+++ b/test/test_checkingbuffer_autocmd.vader
@@ -31,7 +31,7 @@ After:
augroup VaderTest
autocmd!
- augroup end
+ augroup END
augroup! VaderTest
@@ -40,7 +40,7 @@ Execute(ALELintPre should not return success on ale#engine#IsCheckingBuffer):
augroup VaderTest
autocmd!
autocmd User ALELintPre let g:checking_buffer = ale#engine#IsCheckingBuffer(bufnr('')) ? 1 : 0
- augroup end
+ augroup END
ALELint
@@ -50,7 +50,7 @@ Execute(ALEJobStarted should return success on ale#engine#IsCheckingBuffer):
augroup VaderTest
autocmd!
autocmd User ALEJobStarted let g:checking_buffer = ale#engine#IsCheckingBuffer(bufnr('')) ? 1 : 0
- augroup end
+ augroup END
ALELint
diff --git a/test/test_command_chain.vader b/test/test_command_chain.vader
index 9059d630..591f6f40 100644
--- a/test/test_command_chain.vader
+++ b/test/test_command_chain.vader
@@ -62,7 +62,7 @@ Given foobar (Some imaginary filetype):
Execute(Check the results of running the chain):
AssertEqual 'foobar', &filetype
- call ale#Lint()
+ call ale#Queue(0)
Assert g:first_echo_called, 'The first chain item was not called'
Assert g:second_echo_called, 'The second chain item was not called'
diff --git a/test/test_elm_executable_detection.vader b/test/test_elm_executable_detection.vader
deleted file mode 100644
index 9146eea6..00000000
--- a/test/test_elm_executable_detection.vader
+++ /dev/null
@@ -1,36 +0,0 @@
-Before:
- call ale#test#SetDirectory('/testplugin/test')
- runtime ale_linters/elm/make.vim
-
-After:
- unlet! g:ale_elm_make_use_global
- unlet! g:ale_elm_make_executable
-
- call ale#test#RestoreDirectory()
-
-Execute(should get valid executable with default params):
- call ale#test#SetFilename('elm-test-files/app/testfile.elm')
-
- AssertEqual
- \ ale#path#Simplify(g:dir . '/elm-test-files/app/node_modules/.bin/elm'),
- \ ale_linters#elm#make#GetExecutable(bufnr(''))
-
-Execute(should get valid executable with 'use_global' params):
- let g:ale_elm_make_use_global = 1
-
- call ale#test#SetFilename('elm-test-files/app/testfile.elm')
-
- AssertEqual
- \ 'elm',
- \ ale_linters#elm#make#GetExecutable(bufnr(''))
-
-Execute(should get valid executable with 'use_global' and 'executable' params):
- let g:ale_elm_make_executable = 'other-elm'
- let g:ale_elm_make_use_global = 1
-
- call ale#test#SetFilename('elm-test-files/app/testfile.elm')
-
- AssertEqual
- \ 'other-elm',
- \ ale_linters#elm#make#GetExecutable(bufnr(''))
-
diff --git a/test/test_engine_lsp_response_handling.vader b/test/test_engine_lsp_response_handling.vader
index 517d82c0..04f12ad6 100644
--- a/test/test_engine_lsp_response_handling.vader
+++ b/test/test_engine_lsp_response_handling.vader
@@ -2,6 +2,8 @@ Before:
Save g:ale_buffer_info
Save g:ale_lsp_error_messages
+ let g:ale_buffer_info = {}
+
unlet! g:ale_lsp_error_messages
call ale#test#SetDirectory('/testplugin/test')
@@ -63,7 +65,7 @@ Execute(tsserver syntax error responses should be handled correctly):
\ 'vcol': 0,
\ 'nr': 1005,
\ 'type': 'E',
- \ 'text': ''','' expected.',
+ \ 'text': '1005: '','' expected.',
\ 'valid': 1,
\ 'pattern': '',
\ },
@@ -136,7 +138,7 @@ Execute(tsserver semantic error responses should be handled correctly):
\ 'vcol': 0,
\ 'nr': 1005,
\ 'type': 'E',
- \ 'text': 'Some semantic error',
+ \ 'text': '1005: Some semantic error',
\ 'valid': 1,
\ 'pattern': '',
\ },
diff --git a/test/test_find_references.vader b/test/test_find_references.vader
index ecced068..88b2d762 100644
--- a/test/test_find_references.vader
+++ b/test/test_find_references.vader
@@ -9,6 +9,7 @@ Before:
let g:preview_called = 0
let g:item_list = []
let g:capability_checked = ''
+ let g:conn_id = v:null
let g:WaitCallback = v:null
runtime autoload/ale/linter.vim
@@ -17,19 +18,18 @@ Before:
runtime autoload/ale/preview.vim
function! ale#lsp_linter#StartLSP(buffer, linter) abort
- let l:conn = ale#lsp#NewConnection({})
- let l:conn.id = 347
- let l:conn.open_documents = {a:buffer : -1}
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
return {
\ 'buffer': a:buffer,
- \ 'connection_id': 347,
+ \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar',
\ 'language_id': 'python',
\}
endfunction
- function! ale#lsp#WaitForCapability(conn_id, project_root, capability, callback) abort
+ function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort
let g:capability_checked = a:capability
let g:WaitCallback = a:callback
endfunction
@@ -38,7 +38,7 @@ Before:
let g:Callback = a:callback
endfunction
- function! ale#lsp#Send(conn_id, message, root) abort
+ function! ale#lsp#Send(conn_id, message) abort
call add(g:message_list, a:message)
return 42
@@ -54,7 +54,10 @@ Before:
endfunction
After:
- call ale#lsp#RemoveConnectionWithID(347)
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
call ale#references#SetMap({})
call ale#test#RestoreDirectory()
call ale#linter#Reset()
@@ -62,6 +65,7 @@ After:
unlet! g:capability_checked
unlet! g:WaitCallback
unlet! g:old_filename
+ unlet! g:conn_id
unlet! g:Callback
unlet! g:message_list
unlet! g:expr_list
@@ -168,7 +172,7 @@ Execute(tsserver reference requests should be sent):
AssertEqual type(function('type')), type(g:WaitCallback)
AssertEqual 'references', g:capability_checked
- call call(g:WaitCallback, [347, '/foo/bar'])
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual
\ 'function(''ale#references#HandleTSServerResponse'')',
@@ -249,7 +253,7 @@ Execute(LSP reference requests should be sent):
AssertEqual type(function('type')), type(g:WaitCallback)
AssertEqual 'references', g:capability_checked
- call call(g:WaitCallback, [347, '/foo/bar'])
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual
\ 'function(''ale#references#HandleLSPResponse'')',
diff --git a/test/test_go_to_definition.vader b/test/test_go_to_definition.vader
index 7f0e3fcb..66c24fb6 100644
--- a/test/test_go_to_definition.vader
+++ b/test/test_go_to_definition.vader
@@ -7,6 +7,7 @@ Before:
let g:message_list = []
let g:expr_list = []
let g:capability_checked = ''
+ let g:conn_id = v:null
let g:WaitCallback = v:null
runtime autoload/ale/linter.vim
@@ -14,19 +15,18 @@ Before:
runtime autoload/ale/util.vim
function! ale#lsp_linter#StartLSP(buffer, linter) abort
- let l:conn = ale#lsp#NewConnection({})
- let l:conn.id = 347
- let l:conn.open_documents = {a:buffer : -1}
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
return {
\ 'buffer': a:buffer,
- \ 'connection_id': 347,
+ \ 'connection_id': g:conn_id,
\ 'project_root': '/foo/bar',
\ 'language_id': 'python',
\}
endfunction
- function! ale#lsp#WaitForCapability(conn_id, project_root, capability, callback) abort
+ function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort
let g:capability_checked = a:capability
let g:WaitCallback = a:callback
endfunction
@@ -35,7 +35,7 @@ Before:
let g:Callback = a:callback
endfunction
- function! ale#lsp#Send(conn_id, message, root) abort
+ function! ale#lsp#Send(conn_id, message) abort
call add(g:message_list, a:message)
return 42
@@ -46,7 +46,10 @@ Before:
endfunction
After:
- call ale#lsp#RemoveConnectionWithID(347)
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
call ale#definition#SetMap({})
call ale#test#RestoreDirectory()
call ale#linter#Reset()
@@ -54,6 +57,7 @@ After:
unlet! g:capability_checked
unlet! g:WaitCallback
unlet! g:old_filename
+ unlet! g:conn_id
unlet! g:Callback
unlet! g:message_list
unlet! g:expr_list
@@ -111,7 +115,7 @@ Execute(Other files should be jumped to for definition responses):
AssertEqual
\ [
- \ 'edit ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
+ \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
\ ],
\ g:expr_list
AssertEqual [3, 7], getpos('.')[1:2]
@@ -136,7 +140,7 @@ Execute(Other files should be jumped to for definition responses in tabs too):
AssertEqual
\ [
- \ 'tabedit ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
+ \ 'tabedit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
\ ],
\ g:expr_list
AssertEqual [3, 7], getpos('.')[1:2]
@@ -153,7 +157,7 @@ Execute(tsserver completion requests should be sent):
AssertEqual type(function('type')), type(g:WaitCallback)
AssertEqual 'definition', g:capability_checked
- call call(g:WaitCallback, [347, '/foo/bar'])
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual
\ 'function(''ale#definition#HandleTSServerResponse'')',
@@ -174,7 +178,7 @@ Execute(tsserver tab completion requests should be sent):
AssertEqual type(function('type')), type(g:WaitCallback)
AssertEqual 'definition', g:capability_checked
- call call(g:WaitCallback, [347, '/foo/bar'])
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual
\ 'function(''ale#definition#HandleTSServerResponse'')',
@@ -206,10 +210,10 @@ Execute(Other files should be jumped to for LSP definition responses):
AssertEqual
\ [
- \ 'edit ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
+ \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
\ ],
\ g:expr_list
- AssertEqual [3, 7], getpos('.')[1:2]
+ AssertEqual [3, 8], getpos('.')[1:2]
AssertEqual {}, ale#definition#GetMap()
Execute(Locations inside the same file should be jumped to without using :edit):
@@ -231,7 +235,7 @@ Execute(Locations inside the same file should be jumped to without using :edit):
\ [
\ ],
\ g:expr_list
- AssertEqual [3, 7], getpos('.')[1:2]
+ AssertEqual [3, 8], getpos('.')[1:2]
AssertEqual {}, ale#definition#GetMap()
Execute(Other files should be jumped to in tabs for LSP definition responses):
@@ -251,10 +255,10 @@ Execute(Other files should be jumped to in tabs for LSP definition responses):
AssertEqual
\ [
- \ 'tabedit ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
+ \ 'tabedit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
\ ],
\ g:expr_list
- AssertEqual [3, 7], getpos('.')[1:2]
+ AssertEqual [3, 8], getpos('.')[1:2]
AssertEqual {}, ale#definition#GetMap()
Execute(Definition responses with lists should be handled):
@@ -282,10 +286,10 @@ Execute(Definition responses with lists should be handled):
AssertEqual
\ [
- \ 'edit ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
+ \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
\ ],
\ g:expr_list
- AssertEqual [3, 7], getpos('.')[1:2]
+ AssertEqual [3, 8], getpos('.')[1:2]
AssertEqual {}, ale#definition#GetMap()
Execute(Definition responses with null response should be handled):
@@ -306,7 +310,7 @@ Execute(LSP completion requests should be sent):
AssertEqual type(function('type')), type(g:WaitCallback)
AssertEqual 'definition', g:capability_checked
- call call(g:WaitCallback, [347, '/foo/bar'])
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual
\ 'function(''ale#definition#HandleLSPResponse'')',
@@ -342,7 +346,7 @@ Execute(LSP tab completion requests should be sent):
AssertEqual type(function('type')), type(g:WaitCallback)
AssertEqual 'definition', g:capability_checked
- call call(g:WaitCallback, [347, '/foo/bar'])
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
AssertEqual
\ 'function(''ale#definition#HandleLSPResponse'')',
diff --git a/test/test_gradle_build_classpath_command.vader b/test/test_gradle_build_classpath_command.vader
index 3c1ecebe..491c2bf0 100644
--- a/test/test_gradle_build_classpath_command.vader
+++ b/test/test_gradle_build_classpath_command.vader
@@ -25,8 +25,8 @@ Execute(Should return 'gradlew' command if project includes gradle wapper):
call ale#test#SetFilename('gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt')
AssertEqual
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/gradle-test-files/wrapped-project'))
- \ . ' && ' . ale#Escape(ale#path#Simplify(g:dir . '/gradle-test-files/wrapped-project/gradlew'))
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/gradle-test-files/wrapped-project'))
+ \ . ale#Escape(ale#path#Simplify(g:dir . '/gradle-test-files/wrapped-project/gradlew'))
\ . g:command_tail,
\ ale#gradle#BuildClasspathCommand(bufnr(''))
@@ -36,8 +36,8 @@ Execute(Should return 'gradle' command if project does not include gradle wapper
\ . ale#path#Simplify(g:dir . '/gradle-test-files')
AssertEqual
- \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/gradle-test-files/unwrapped-project'))
- \ . ' && ' . ale#Escape('gradle')
+ \ ale#path#CdString(ale#path#Simplify(g:dir . '/gradle-test-files/unwrapped-project'))
+ \ . ale#Escape('gradle')
\ . g:command_tail,
\ ale#gradle#BuildClasspathCommand(bufnr(''))
diff --git a/test/test_history_saving.vader b/test/test_history_saving.vader
index 375e96a1..d7a307b5 100644
--- a/test/test_history_saving.vader
+++ b/test/test_history_saving.vader
@@ -73,7 +73,7 @@ Execute(History should be set when commands are run):
" Retry this test until it works. This one can randomly fail.
for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
let b:ale_history = []
- call ale#Lint()
+ call ale#Queue(0)
call ale#engine#WaitForJobs(2000)
let g:history = filter(
@@ -106,7 +106,7 @@ Execute(History should be not set when disabled):
let g:ale_history_enabled = 0
- call ale#Lint()
+ call ale#Queue(0)
call ale#engine#WaitForJobs(2000)
AssertEqual [], ale#history#Get(bufnr(''))
@@ -120,7 +120,7 @@ Execute(History should include command output if logging is enabled):
" Retry this test until it works. This one can randomly fail.
for g:i in range(has('nvim-0.3') || has('win32') ? 5 : 1)
let b:ale_history = []
- call ale#Lint()
+ call ale#Queue(0)
call ale#engine#WaitForJobs(2000)
let g:history = ale#history#Get(bufnr(''))
diff --git a/test/test_ignoring_linters.vader b/test/test_ignoring_linters.vader
index af31fce3..866f9e0d 100644
--- a/test/test_ignoring_linters.vader
+++ b/test/test_ignoring_linters.vader
@@ -108,7 +108,7 @@ Before:
let g:run_linters_called = 1
endfunction
- function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort
+ function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let g:loclist = a:loclist
endfunction
@@ -138,6 +138,9 @@ After:
Given foobar(An empty file):
Execute(Global ignore lists should be applied for linters):
+ " We have to set up buffer info so RunLinters is called.
+ let g:ale_buffer_info = {bufnr(''): {}}
+
ALELint
Assert g:run_linters_called, "The mock callback wasn't called"
AssertEqual ['testlinter'], map(g:linters, 'v:val.name')
@@ -147,6 +150,9 @@ Execute(Global ignore lists should be applied for linters):
AssertEqual [], g:linters
Execute(buffer ignore lists should be applied for linters):
+ " We have to set up buffer info so RunLinters is called.
+ let g:ale_buffer_info = {bufnr(''): {}}
+
ALELint
Assert g:run_linters_called, "The mock callback wasn't called"
AssertEqual ['testlinter'], map(g:linters, 'v:val.name')
@@ -190,6 +196,7 @@ Execute(Buffer ignore lists should be applied for tsserver):
\ 'lnum': 2,
\ 'col': 14,
\ 'nr': 1005,
+ \ 'code': '1005',
\ 'type': 'E',
\ 'end_col': 15,
\ 'end_lnum': 2,
diff --git a/test/test_lint_file_linters.vader b/test/test_lint_file_linters.vader
index ca093aa8..f67fad44 100644
--- a/test/test_lint_file_linters.vader
+++ b/test/test_lint_file_linters.vader
@@ -10,7 +10,6 @@ Before:
let g:ale_run_synchronously = 1
let g:ale_set_lists_synchronously = 1
let b:ale_save_event_fired = 0
- call ale#ResetLintFileMarkers()
let g:buffer_result = [
\ {
diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader
index f0ec023a..d967761d 100644
--- a/test/test_linter_defintion_processing.vader
+++ b/test/test_linter_defintion_processing.vader
@@ -490,7 +490,7 @@ Execute(PreProcess should complain about using initialization_options and initia
AssertThrows call ale#linter#PreProcess('testft', g:linter)
AssertEqual 'Only one of `initialization_options` or `initialization_options_callback` should be set', g:vader_exception
-Execute (PreProcess should throw when initialization_options_callback is not a callback):
+Execute(PreProcess should throw when initialization_options_callback is not a callback):
AssertThrows call ale#linter#PreProcess('testft', {
\ 'name': 'foo',
\ 'lsp': 'socket',
@@ -500,3 +500,55 @@ Execute (PreProcess should throw when initialization_options_callback is not a c
\ 'initialization_options_callback': {},
\})
AssertEqual '`initialization_options_callback` must be a callback if defined', g:vader_exception
+
+Execute(PreProcess should complain about using lsp_config and lsp_config_callback together):
+ let g:linter = {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'lsp_config': 'x',
+ \ 'lsp_config_callback': 'x',
+ \}
+
+ AssertThrows call ale#linter#PreProcess('testft', g:linter)
+ AssertEqual 'Only one of `lsp_config` or `lsp_config_callback` should be set', g:vader_exception
+
+Execute(PreProcess should throw when lsp_config_callback is not a callback):
+ AssertThrows call ale#linter#PreProcess('testft', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'lsp_config_callback': {},
+ \})
+ AssertEqual '`lsp_config_callback` must be a callback if defined', g:vader_exception
+
+Execute(PreProcess should accept LSP configuration options via lsp_config):
+ let g:ale_lsp_configuration = {
+ \ 'foo': 'bar'
+ \}
+
+ let g:linter = {
+ \ 'name': 'x',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language_callback': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'lsp_config': g:ale_lsp_configuration,
+ \}
+
+ AssertEqual {'foo': 'bar'}, ale#linter#PreProcess('testft', g:linter).lsp_config
+
+Execute(PreProcess should throw when lsp_config is not a Dictionary):
+ AssertThrows call ale#linter#PreProcess('testft', {
+ \ 'name': 'foo',
+ \ 'lsp': 'socket',
+ \ 'address_callback': 'X',
+ \ 'language': 'x',
+ \ 'project_root_callback': 'x',
+ \ 'lsp_config': 'x',
+ \})
+ AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception
diff --git a/test/test_linter_retrieval.vader b/test/test_linter_retrieval.vader
index 6c402d54..a1c34622 100644
--- a/test/test_linter_retrieval.vader
+++ b/test/test_linter_retrieval.vader
@@ -130,6 +130,8 @@ Execute (The local alias option shouldn't completely replace the global one):
" global Dictionary.
let b:ale_linter_aliases = {'testft3': ['testft1']}
+ AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1')
+
Execute (Lists should be accepted for local aliases):
call ale#linter#Define('testft1', g:testlinter1)
call ale#linter#Define('testft2', g:testlinter2)
@@ -139,6 +141,15 @@ Execute (Lists should be accepted for local aliases):
AssertEqual [g:testlinter2], ale#linter#Get('anything.else')
+Execute (Strings should be accepted for local aliases):
+ call ale#linter#Define('testft1', g:testlinter1)
+ call ale#linter#Define('testft2', g:testlinter2)
+ let g:ale_linter_aliases = {'testft1': ['testft1', 'testft2']}
+ " We should load the testft2 linters for this buffer, with no duplicates.
+ let b:ale_linter_aliases = 'testft2'
+
+ AssertEqual [g:testlinter2], ale#linter#Get('anything.else')
+
Execute (Buffer-local overrides for aliases should be used):
call ale#linter#Define('testft1', g:testlinter1)
call ale#linter#Define('testft2', g:testlinter2)
diff --git a/test/test_linter_type_mapping.vader b/test/test_linter_type_mapping.vader
index 0131b5f0..0ec22a56 100644
--- a/test/test_linter_type_mapping.vader
+++ b/test/test_linter_type_mapping.vader
@@ -16,7 +16,7 @@ Execute(It should be possible to remap errors to style errors):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
- \ ale#engine#FixLocList(bufnr(''), 'foo', [
+ \ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@@ -35,7 +35,7 @@ Execute(It should be possible to remap errors to style errors with buffer-local
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
- \ ale#engine#FixLocList(bufnr(''), 'foo', [
+ \ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@@ -54,7 +54,7 @@ Execute(It should be possible to remap warnings to style warnings):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
- \ ale#engine#FixLocList(bufnr(''), 'foo', [
+ \ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@@ -73,7 +73,7 @@ Execute(It should be possible to remap style errors to errors):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
- \ ale#engine#FixLocList(bufnr(''), 'foo', [
+ \ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@@ -92,7 +92,7 @@ Execute(It should be possible to remap style warnings to warnings):
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
- \ ale#engine#FixLocList(bufnr(''), 'foo', [
+ \ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
@@ -111,7 +111,7 @@ Execute(It should be possible to info problems to warnings):
\ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'},
\ ],
- \ ale#engine#FixLocList(bufnr(''), 'foo', [
+ \ ale#engine#FixLocList(bufnr(''), 'foo', 0, [
\ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
\ {'type': 'W', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1},
diff --git a/test/test_linting_blacklist.vader b/test/test_linting_blacklist.vader
index 2d9ed585..73190b7f 100644
--- a/test/test_linting_blacklist.vader
+++ b/test/test_linting_blacklist.vader
@@ -10,7 +10,7 @@ Given unite (A Unite.vim file):
anything
Execute(Running ALE on a blacklisted file shouldn't change anything):
- call ale#Lint()
+ call ale#Queue(0)
call ale#engine#WaitForJobs(2000)
AssertEqual {}, g:ale_buffer_info
diff --git a/test/test_loclist_corrections.vader b/test/test_loclist_corrections.vader
index 48aa1f78..343620a5 100644
--- a/test/test_loclist_corrections.vader
+++ b/test/test_loclist_corrections.vader
@@ -41,6 +41,7 @@ Execute(FixLocList should set all the default values correctly):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{'text': 'a', 'lnum': 2}, {'text': 'b', 'lnum': 2}],
\ )
@@ -61,6 +62,7 @@ Execute(FixLocList should use the values we supply):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{
\ 'text': 'a',
\ 'lnum': 3,
@@ -89,6 +91,7 @@ Execute(FixLocList should set items with lines beyond the end to the last line):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{'text': 'a', 'lnum': 11}],
\ )
@@ -109,6 +112,7 @@ Execute(FixLocList should move line 0 to line 1):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{'text': 'a', 'lnum': 0}],
\ )
@@ -130,6 +134,7 @@ Execute(FixLocList should convert line and column numbers correctly):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{'text': 'a', 'lnum': '010', 'col': '010'}],
\ )
@@ -163,6 +168,7 @@ Execute(FixLocList should pass on end_col values):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [
\ {'text': 'a', 'lnum': '010', 'col': '010', 'end_col': '012'},
\ {'text': 'a', 'lnum': '010', 'col': '011', 'end_col': 12},
@@ -200,6 +206,7 @@ Execute(FixLocList should pass on end_lnum values):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [
\ {'text': 'a', 'lnum': '010', 'col': '010', 'end_col': '012', 'end_lnum': '013'},
\ {'text': 'a', 'lnum': '010', 'col': '011', 'end_col': 12, 'end_lnum': 13},
@@ -224,6 +231,7 @@ Execute(FixLocList should allow subtypes to be set):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{'text': 'a', 'lnum': 11, 'sub_type': 'style'}],
\ )
@@ -285,6 +293,7 @@ Execute(FixLocList should accept filenames):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [
\ {'text': 'a', 'lnum': 2, 'filename': expand('%:p')},
\ {'text': 'a', 'lnum': 3, 'filename': expand('%:p')},
@@ -322,6 +331,7 @@ Execute(FixLocList should interpret temporary filenames as being the current buf
\ ale#engine#FixLocList(
\ bufnr(''),
\ 'foobar',
+ \ 0,
\ [
\ {'text': 'a', 'lnum': 2, 'filename': b:temp_name},
\ {'text': 'a', 'lnum': 3, 'filename': substitute(b:temp_name, '\\', '/', 'g')},
@@ -346,9 +356,43 @@ Execute(The error code should be passed on):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [{'text': 'a', 'lnum': 11, 'code': 'some-code'}],
\ )
+Execute(FixLocList should mark problems as coming from other sources if requested):
+ AssertEqual
+ \ [
+ \ {
+ \ 'text': 'a',
+ \ 'lnum': 2,
+ \ 'col': 0,
+ \ 'bufnr': bufnr('%'),
+ \ 'vcol': 0,
+ \ 'type': 'E',
+ \ 'nr': -1,
+ \ 'linter_name': 'foobar',
+ \ 'from_other_source': 1,
+ \ },
+ \ {
+ \ 'text': 'b',
+ \ 'lnum': 2,
+ \ 'col': 0,
+ \ 'bufnr': bufnr('%'),
+ \ 'vcol': 0,
+ \ 'type': 'E',
+ \ 'nr': -1,
+ \ 'linter_name': 'foobar',
+ \ 'from_other_source': 1,
+ \ },
+ \],
+ \ ale#engine#FixLocList(
+ \ bufnr('%'),
+ \ 'foobar',
+ \ 1,
+ \ [{'text': 'a', 'lnum': 2}, {'text': 'b', 'lnum': 2}],
+ \ )
+
Given(A file with Japanese multi-byte text):
はじめまして!
-私はワープです。
@@ -367,6 +411,7 @@ Execute(character positions should be converted to byte positions):
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'foobar',
+ \ 0,
\ [
\ {'text': 'a', 'lnum': 1, 'col': 0, 'vcol': 1},
\ {'text': 'a', 'lnum': 1, 'col': 1, 'vcol': 1},
diff --git a/test/test_other_sources.vader b/test/test_other_sources.vader
new file mode 100644
index 00000000..e6f9911c
--- /dev/null
+++ b/test/test_other_sources.vader
@@ -0,0 +1,153 @@
+Before:
+ Save g:ale_buffer_info
+ Save g:ale_set_signs
+ Save g:ale_set_quickfix
+ Save g:ale_set_loclist
+ Save g:ale_set_highlights
+ Save g:ale_echo_cursor
+
+ let g:ale_buffer_info = {}
+ let g:ale_run_synchronously = 1
+ let g:ale_set_lists_synchronously = 1
+ let g:ale_set_signs = 0
+ let g:ale_set_quickfix = 0
+ let g:ale_set_loclist = 1
+ let g:ale_set_highlights = 0
+ let g:ale_echo_cursor = 0
+
+ function! TestCallback(buffer, output)
+ return []
+ endfunction
+
+ call ale#linter#Define('foobar', {
+ \ 'name': 'testlinter',
+ \ 'callback': 'TestCallback',
+ \ 'executable': has('win32') ? 'cmd' : 'echo',
+ \ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''',
+ \})
+
+After:
+ Restore
+
+ unlet! b:ale_linters
+ unlet! g:want_results_signaled
+ unlet! g:want_results_buffer_value
+ unlet! g:lint_pre_signaled
+ unlet! g:ale_run_synchronously
+ unlet! g:ale_set_lists_synchronously
+
+ delfunction TestCallback
+
+ augroup VaderTest
+ autocmd!
+ augroup END
+
+ augroup! VaderTest
+
+ call ale#linter#Reset()
+ call setloclist(0, [])
+
+Given foobar (Some imaginary filetype):
+Execute(StartChecking should mark a buffer as being actively checked):
+ Assert !ale#engine#IsCheckingBuffer(bufnr(''))
+
+ call ale#other_source#StartChecking(bufnr(''), 'other-source-linter')
+
+ Assert ale#engine#IsCheckingBuffer(bufnr(''))
+
+Execute(ShowResults sould make a buffer inactive):
+ call ale#other_source#StartChecking(bufnr(''), 'other-source-linter')
+ call ale#other_source#StartChecking(bufnr(''), 'second-other-source-linter')
+
+ call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [])
+
+ Assert ale#engine#IsCheckingBuffer(bufnr(''))
+
+ call ale#other_source#ShowResults(bufnr(''), 'second-other-source-linter', [])
+
+ Assert !ale#engine#IsCheckingBuffer(bufnr(''))
+
+Execute(ShowResults should show results at any time):
+ call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [
+ \ {'text': 'xyz', 'lnum': 1},
+ \])
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'bufnr': bufnr(''),
+ \ 'col': 0,
+ \ 'valid': 1,
+ \ 'vcol': 0,
+ \ 'nr': -1,
+ \ 'type': 'E',
+ \ 'pattern': '',
+ \ 'text': 'xyz',
+ \ },
+ \ ],
+ \ ale#test#GetLoclistWithoutModule()
+
+ call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [])
+
+ AssertEqual [], ale#test#GetLoclistWithoutModule()
+
+Execute(A regular lint cycle shouldn't clear results from other sources):
+ call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', [
+ \ {'text': 'xyz', 'lnum': 1},
+ \])
+ ALELint
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'bufnr': bufnr(''),
+ \ 'col': 0,
+ \ 'valid': 1,
+ \ 'vcol': 0,
+ \ 'nr': -1,
+ \ 'type': 'E',
+ \ 'pattern': '',
+ \ 'text': 'xyz',
+ \ },
+ \ ],
+ \ ale#test#GetLoclistWithoutModule()
+
+Execute(ALEWantResults should be signaled when a buffer is checked):
+ augroup VaderTest
+ autocmd!
+ autocmd User ALEWantResults let g:want_results_signaled = 1
+ autocmd User ALELintPre let g:lint_pre_signaled = 1
+ augroup END
+
+ " Even when all linters are disabled, we should send the signal.
+ let b:ale_linters = []
+ ALELint
+
+ Assert get(g:, 'want_results_signaled')
+ Assert !get(g:, 'lint_pre_signaled')
+
+Execute(ALEWantResults should set a variable indicating which buffer is being checked):
+ augroup VaderTest
+ autocmd!
+ autocmd User ALEWantResults let g:want_results_buffer_value = g:ale_want_results_buffer
+ augroup END
+
+ let b:ale_linters = []
+ ALELint
+
+ AssertEqual bufnr(''), g:want_results_buffer_value
+
+Execute(ALEWantResults should lead to an ALELintPre signal if another source responds):
+ augroup VaderTest
+ autocmd!
+ autocmd User ALEWantResults call ale#other_source#StartChecking(bufnr(''), 'other-source-linter')
+ autocmd User ALELintPre let g:lint_pre_signaled = 1
+ augroup END
+
+ " Even when all linters are disabled, we should send the signal.
+ let b:ale_linters = []
+ ALELint
+
+ Assert get(g:, 'lint_pre_signaled')
diff --git a/test/test_path_dirname.vader b/test/test_path_dirname.vader
new file mode 100644
index 00000000..79b78d29
--- /dev/null
+++ b/test/test_path_dirname.vader
@@ -0,0 +1,8 @@
+Execute(ale#path#Dirname should return empty strings should be returned for empty values):
+ AssertEqual '', ale#path#Dirname('')
+ AssertEqual '', ale#path#Dirname(0)
+ AssertEqual '', ale#path#Dirname(v:null)
+
+Execute(ale#path#Dirname should return the dirname of paths):
+ AssertEqual '/foo', ale#path#Dirname('/foo/bar')
+ AssertEqual '/foo', ale#path#Dirname('/foo/bar/')
diff --git a/test/test_phpcs_executable_detection.vader b/test/test_phpcs_executable_detection.vader
deleted file mode 100644
index 020bfac3..00000000
--- a/test/test_phpcs_executable_detection.vader
+++ /dev/null
@@ -1,39 +0,0 @@
-Before:
- Save g:ale_php_phpcs_executable
- Save g:ale_php_phpcs_use_global
-
- let g:ale_php_phpcs_executable = 'phpcs_test'
- let g:ale_php_phpcs_use_global = 0
-
- call ale#test#SetDirectory('/testplugin/test')
-
- runtime ale_linters/php/phpcs.vim
-
-After:
- Restore
-
- call ale#test#RestoreDirectory()
- call ale#linter#Reset()
-
-Execute(project with phpcs should use local by default):
- call ale#test#SetFilename('phpcs-test-files/project-with-phpcs/foo/test.php')
-
- AssertEqual
- \ ale#path#Simplify(g:dir . '/phpcs-test-files/project-with-phpcs/vendor/bin/phpcs'),
- \ ale_linters#php#phpcs#GetExecutable(bufnr(''))
-
-Execute(use-global should override local detection):
- let g:ale_php_phpcs_use_global = 1
-
- call ale#test#SetFilename('phpcs-test-files/project-with-phpcs/foo/test.php')
-
- AssertEqual
- \ 'phpcs_test',
- \ ale_linters#php#phpcs#GetExecutable(bufnr(''))
-
-Execute(project without phpcs should use global):
- call ale#test#SetFilename('phpcs-test-files/project-without-phpcs/foo/test.php')
-
- AssertEqual
- \ 'phpcs_test',
- \ ale_linters#php#phpcs#GetExecutable(bufnr(''))
diff --git a/test/test_python_pipenv.vader b/test/test_python_pipenv.vader
new file mode 100644
index 00000000..91d957f8
--- /dev/null
+++ b/test/test_python_pipenv.vader
@@ -0,0 +1,13 @@
+Execute(ale#python#PipenvPresent is true when a pipenv environment is present):
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py')
+
+ AssertEqual
+ \ ale#python#PipenvPresent(bufnr('%')),
+ \ 1
+
+Execute(ale#python#PipenvPresent is false true when no pipenv environment is present):
+ call ale#test#SetFilename('/testplugin/test/python_fixtures/no_pipenv/whatever.py')
+
+ AssertEqual
+ \ ale#python#PipenvPresent(bufnr('%')),
+ \ 0
diff --git a/test/test_redundant_tsserver_rendering_avoided.vader b/test/test_redundant_tsserver_rendering_avoided.vader
new file mode 100644
index 00000000..a292b014
--- /dev/null
+++ b/test/test_redundant_tsserver_rendering_avoided.vader
@@ -0,0 +1,136 @@
+Before:
+ Save g:ale_buffer_info
+
+ function! CreateError(type, message) abort
+ let l:diagnostics = []
+
+ if !empty(a:message)
+ let l:diagnostics = [{
+ \ 'start': {'line': 1, 'offset': 1},
+ \ 'end': {'line': 1, 'offset':1},
+ \ 'text': a:message,
+ \ 'code': 1005,
+ \}]
+ endif
+
+ return {
+ \ 'seq': 0,
+ \ 'type': 'event',
+ \ 'event': a:type,
+ \ 'body': {'file': expand('%:p'), 'diagnostics': l:diagnostics},
+ \}
+ endfunction
+
+ function! CreateLoclist(message) abort
+ let l:list = []
+
+ if !empty(a:message)
+ let l:list = [{
+ \ 'lnum': 1,
+ \ 'col': 1,
+ \ 'end_lnum': 1,
+ \ 'end_col': 1,
+ \ 'text': a:message,
+ \}]
+ endif
+
+ return l:list
+ endfunction
+
+ call ale#test#SetDirectory('/testplugin/test')
+ call ale#test#SetFilename('filename.ts')
+
+ runtime autoload/ale/engine.vim
+
+ let g:ale_buffer_info = {bufnr(''): {'loclist': []}}
+ let g:ale_handle_loclist_called = 0
+
+ function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
+ let g:ale_handle_loclist_called = 1
+ endfunction
+
+After:
+ Restore
+
+ delfunction CreateError
+ delfunction CreateLoclist
+
+ call ale#test#RestoreDirectory()
+
+ runtime autoload/ale/engine.vim
+
+Execute(An initial empty list of syntax errors should be ignored):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(An initial list of syntax errors should be handled):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Subsequent empty lists should be ignored):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(Empty then non-empty syntax errors should be handled):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then empty syntax errors should be handled):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', ''))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then non-empty syntax errors should be handled):
+ let g:ale_buffer_info[bufnr('')].syntax_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('syntaxDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(An initial empty list of semantic errors should be ignored):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(An initial list of semantic errors should be handled):
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Subsequent empty lists should be ignored):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
+
+ Assert !g:ale_handle_loclist_called
+
+Execute(Empty then non-empty semantic errors should be handled):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = []
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then empty semantic errors should be handled):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', ''))
+
+ Assert g:ale_handle_loclist_called
+
+Execute(Non-empty then non-empty semantic errors should be handled):
+ let g:ale_buffer_info[bufnr('')].semantic_loclist = CreateLoclist('x')
+
+ call ale#lsp_linter#HandleLSPResponse(1, CreateError('semanticDiag', 'x'))
+
+ Assert g:ale_handle_loclist_called
diff --git a/test/test_sandbox_execution.vader b/test/test_sandbox_execution.vader
index 4dbcb0db..5a4974ba 100644
--- a/test/test_sandbox_execution.vader
+++ b/test/test_sandbox_execution.vader
@@ -47,7 +47,6 @@ Execute(ALE shouldn't blow up when run from a sandbox):
sandbox call ale#Queue(0)
sandbox call ale#Queue(1)
- sandbox call ale#Lint()
Execute(ALE shouldn't blow up if file cleanup happens in a sandbox):
" Make a call to an engine function first, so the function will be defined
diff --git a/test/test_setting_problems_found_in_previous_buffers.vader b/test/test_setting_problems_found_in_previous_buffers.vader
index 4604005a..36eeb4ca 100644
--- a/test/test_setting_problems_found_in_previous_buffers.vader
+++ b/test/test_setting_problems_found_in_previous_buffers.vader
@@ -9,14 +9,14 @@ Before:
let g:ale_buffer_info = {}
call ale#engine#InitBufferInfo(bufnr('') + 1)
let g:ale_buffer_info[bufnr('') + 1].loclist =
- \ ale#engine#FixLocList(bufnr('') + 1, 'linter_one', [
+ \ ale#engine#FixLocList(bufnr('') + 1, 'linter_one', 0, [
\ {'lnum': 1, 'filename': expand('%:p'), 'text': 'foo'},
\ {'lnum': 2, 'filename': expand('%:p'), 'text': 'bar'},
\ {'lnum': 2, 'text': 'ignore this one'},
\ ])
call ale#engine#InitBufferInfo(bufnr('') + 2)
let g:ale_buffer_info[bufnr('') + 2].loclist =
- \ ale#engine#FixLocList(bufnr('') + 2, 'linter_one', [
+ \ ale#engine#FixLocList(bufnr('') + 2, 'linter_one', 0, [
\ {'lnum': 1, 'filename': expand('%:p'), 'text': 'foo'},
\ {'lnum': 3, 'filename': expand('%:p'), 'text': 'baz'},
\ {'lnum': 5, 'text': 'ignore this one'},
diff --git a/test/test_should_do_nothing_conditions.vader b/test/test_should_do_nothing_conditions.vader
index 062ab875..de2e2782 100644
--- a/test/test_should_do_nothing_conditions.vader
+++ b/test/test_should_do_nothing_conditions.vader
@@ -4,10 +4,18 @@ Before:
Save g:ale_enabled
Save &l:statusline
+ let b:fake_mode = 'n'
+
call ale#test#SetDirectory('/testplugin/test')
let b:funky_command_created = 0
+ runtime autoload/ale/util.vim
+
+ function! ale#util#Mode(...) abort
+ return b:fake_mode
+ endfunction
+
" We will test for the existence of this command, so create one if needed.
if !exists(':CtrlPFunky')
command CtrlPFunky echo
@@ -25,6 +33,9 @@ After:
endif
unlet! b:funky_command_created
+ unlet! b:fake_mode
+
+ runtime autoload/ale/util.vim
Given foobar(An empty file):
Execute(ALE shouldn't do much of anything for ctrlp-funky buffers):
@@ -44,7 +55,7 @@ Execute(ALE shouldn't try to check buffers with '.' as the filename):
Assert ale#ShouldDoNothing(bufnr(''))
-Execute(DoNothing should return 0 when the filetype is empty):
+Execute(DoNothing should return 1 when the filetype is empty):
AssertEqual
\ 0,
\ ale#ShouldDoNothing(bufnr('')),
@@ -54,6 +65,11 @@ Execute(DoNothing should return 0 when the filetype is empty):
AssertEqual 1, ale#ShouldDoNothing(bufnr(''))
+Execute(DoNothing should return 1 when an operator is pending):
+ let b:fake_mode = 'no'
+
+ AssertEqual 1, ale#ShouldDoNothing(bufnr(''))
+
Execute(The DoNothing check should work if the ALE globals aren't defined):
unlet! g:ale_filetype_blacklist
unlet! g:ale_maximum_file_size
diff --git a/test/test_symbol_search.vader b/test/test_symbol_search.vader
new file mode 100644
index 00000000..d8b7a4a6
--- /dev/null
+++ b/test/test_symbol_search.vader
@@ -0,0 +1,173 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test')
+ call ale#test#SetFilename('dummy.txt')
+
+ let g:Callback = ''
+ let g:expr_list = []
+ let g:message_list = []
+ let g:preview_called = 0
+ let g:item_list = []
+ let g:capability_checked = ''
+ let g:conn_id = v:null
+ let g:WaitCallback = v:null
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/preview.vim
+
+ function! ale#lsp_linter#StartLSP(buffer, linter) abort
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
+
+ return {
+ \ 'buffer': a:buffer,
+ \ 'connection_id': g:conn_id,
+ \ 'project_root': '/foo/bar',
+ \ 'language_id': 'python',
+ \}
+ endfunction
+
+ function! ale#lsp#WaitForCapability(conn_id, capability, callback) abort
+ let g:capability_checked = a:capability
+ let g:WaitCallback = a:callback
+ endfunction
+
+ function! ale#lsp#RegisterCallback(conn_id, callback) abort
+ let g:Callback = a:callback
+ endfunction
+
+ function! ale#lsp#Send(conn_id, message) abort
+ call add(g:message_list, a:message)
+
+ return 42
+ endfunction
+
+ function! ale#util#Execute(expr) abort
+ call add(g:expr_list, a:expr)
+ endfunction
+
+ function! ale#preview#ShowSelection(item_list) abort
+ let g:preview_called = 1
+ let g:item_list = a:item_list
+ endfunction
+
+After:
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+ unlet! g:capability_checked
+ unlet! g:WaitCallback
+ unlet! g:conn_id
+ unlet! g:Callback
+ unlet! g:message_list
+ unlet! g:expr_list
+ unlet! b:ale_linters
+ unlet! g:item_list
+ unlet! g:preview_called
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/preview.vim
+
+Execute(Other messages for the LSP handler should be ignored):
+ call ale#symbol#HandleLSPResponse(1, {'command': 'foo'})
+
+Execute(Failed symbol responses should be handled correctly):
+ call ale#symbol#SetMap({3: {}})
+ call ale#symbol#HandleLSPResponse(1, {'id': 3})
+ AssertEqual {}, ale#symbol#GetMap()
+
+Execute(LSP symbol responses should be handled):
+ call ale#symbol#SetMap({3: {}})
+ call ale#symbol#HandleLSPResponse(
+ \ 1,
+ \ {
+ \ 'id': 3,
+ \ 'result': [
+ \ {
+ \ 'name': 'foo',
+ \ 'location': {
+ \ 'uri': ale#path#ToURI(ale#path#Simplify(g:dir . '/completion_dummy_file')),
+ \ 'range': {
+ \ 'start': {'line': 2, 'character': 7},
+ \ },
+ \ },
+ \ },
+ \ {
+ \ 'name': 'foobar',
+ \ 'location': {
+ \ 'uri': ale#path#ToURI(ale#path#Simplify(g:dir . '/other_file')),
+ \ 'range': {
+ \ 'start': {'line': 7, 'character': 15},
+ \ },
+ \ },
+ \ },
+ \ ],
+ \ }
+ \)
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'filename': ale#path#Simplify(g:dir . '/completion_dummy_file'),
+ \ 'line': 3,
+ \ 'column': 8,
+ \ 'match': 'foo',
+ \ },
+ \ {
+ \ 'filename': ale#path#Simplify(g:dir . '/other_file'),
+ \ 'line': 8,
+ \ 'column': 16,
+ \ 'match': 'foobar',
+ \ },
+ \ ],
+ \ g:item_list
+ AssertEqual {}, ale#symbol#GetMap()
+
+Execute(Preview windows should not be opened for empty LSP symbol responses):
+ call ale#symbol#SetMap({3: {}})
+ call ale#symbol#HandleLSPResponse(
+ \ 1,
+ \ {
+ \ 'id': 3,
+ \ 'result': [
+ \ ],
+ \ }
+ \)
+
+ Assert !g:preview_called
+ AssertEqual {}, ale#symbol#GetMap()
+ AssertEqual ['echom ''No symbols found.'''], g:expr_list
+
+Given python(Some Python file):
+ foo
+ somelongerline
+ bazxyzxyzxyz
+
+Execute(LSP symbol requests should be sent):
+ runtime ale_linters/python/pyls.vim
+ let b:ale_linters = ['pyls']
+ call setpos('.', [bufnr(''), 1, 5, 0])
+
+ ALESymbolSearch foo bar
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual 'symbol_search', g:capability_checked
+ AssertEqual type(function('type')), type(g:WaitCallback)
+ call call(g:WaitCallback, [g:conn_id, '/foo/bar'])
+
+ AssertEqual
+ \ 'function(''ale#symbol#HandleLSPResponse'')',
+ \ string(g:Callback)
+
+ AssertEqual
+ \ [
+ \ [0, 'workspace/symbol', {'query': 'foo bar'}],
+ \ ],
+ \ g:message_list
+
+ AssertEqual {'42': {'buffer': bufnr('')}}, ale#symbol#GetMap()
diff --git a/test/test_temporary_file_management.vader b/test/test_temporary_file_management.vader
index e248331c..4847706a 100644
--- a/test/test_temporary_file_management.vader
+++ b/test/test_temporary_file_management.vader
@@ -67,7 +67,7 @@ Given foobar (Some imaginary filetype):
Execute(ALE should delete managed files/directories appropriately after linting):
AssertEqual 'foobar', &filetype
- call ale#Lint()
+ call ale#Queue(0)
call ale#engine#WaitForJobs(2000)
Assert !filereadable(g:filename), 'The temporary file was not deleted'
@@ -79,7 +79,7 @@ Execute(ALE should delete managed files even if no command is run):
let g:command = ''
- call ale#Lint()
+ call ale#Queue(0)
call ale#engine#WaitForJobs(2000)
Assert !filereadable(g:filename), 'The temporary file was not deleted'
diff --git a/test/test_tflint_config_detection.vader b/test/test_tflint_config_detection.vader
deleted file mode 100644
index 3500869b..00000000
--- a/test/test_tflint_config_detection.vader
+++ /dev/null
@@ -1,18 +0,0 @@
-Before:
- call ale#test#SetDirectory('/testplugin/test')
- runtime ale_linters/terraform/tflint.vim
-
-After:
- call ale#test#RestoreDirectory()
- call ale#linter#Reset()
-
-Execute(adjacent config file should be found):
- call ale#test#SetFilename('tflint-test-files/foo/bar.tf')
- AssertEqual
- \ (
- \ ale#Escape('tflint')
- \ . ' --config '
- \ . ale#Escape(ale#path#Simplify(g:dir . '/tflint-test-files/foo/.tflint.hcl'))
- \ . ' -f json %t'
- \ ),
- \ ale_linters#terraform#tflint#GetCommand(bufnr(''))
diff --git a/test/test_verilog_verilator_options.vader b/test/test_verilog_verilator_options.vader
index e53037b1..3ebabfcc 100644
--- a/test/test_verilog_verilator_options.vader
+++ b/test/test_verilog_verilator_options.vader
@@ -12,7 +12,7 @@ Execute(Set Verilog Verilator linter additional options to `-sv --default-langua
" Additional args for the linter
let g:ale_verilog_verilator_options = '-sv --default-language "1800-2012"'
- call ale#Lint()
+ call ale#Queue(0)
let g:run_cmd = ale_linters#verilog#verilator#GetCommand(bufnr(''))
let g:matched = match(g:run_cmd, '\s' . g:ale_verilog_verilator_options . '\s')
diff --git a/test/test_writefile_function.vader b/test/test_writefile_function.vader
index 4e4aab53..8c8a6f17 100644
--- a/test/test_writefile_function.vader
+++ b/test/test_writefile_function.vader
@@ -28,7 +28,26 @@ Execute(Carriage returns should be included for ale#util#Writefile):
AssertEqual
\ ["first\r", "second\r", "third\r", ''],
\ readfile('.newline-test', 'b')
- \
+
+Given(A file with extra carriage returns):
+ first
+ second
+ third
+ fourth
+
+Execute(Carriage returns should be de-depulicated):
+ call ale#test#SetFilename('.newline-test')
+
+ setlocal buftype=
+ noautocmd :w
+ noautocmd :e! ++ff=dos
+
+ call ale#util#Writefile(bufnr(''), getline(1, '$'), '.newline-test')
+
+ AssertEqual
+ \ ["first\r", "second\r", "third\r", "fourth\r", ''],
+ \ readfile('.newline-test', 'b')
+
Given(A file with Unix line ending characters):
first
second
diff --git a/test/util/test_cd_string_commands.vader b/test/util/test_cd_string_commands.vader
index 5f0e92fd..f2102e48 100644
--- a/test/util/test_cd_string_commands.vader
+++ b/test/util/test_cd_string_commands.vader
@@ -9,10 +9,12 @@ After:
Execute(CdString should output the correct command string):
" We will check that escaping is done correctly for each platform.
AssertEqual
- \ has('unix') ? 'cd ''/foo bar/baz'' && ' : 'cd "/foo bar/baz" && ',
+ \ has('unix') ? 'cd ''/foo bar/baz'' && ' : 'cd /d "/foo bar/baz" && ',
\ ale#path#CdString('/foo bar/baz')
Execute(BufferCdString should output the correct command string):
call ale#test#SetFilename('foo.txt')
- AssertEqual 'cd ' . ale#Escape(g:dir) . ' && ', ale#path#BufferCdString(bufnr(''))
+ AssertEqual
+ \ has('unix') ? 'cd ' . ale#Escape(g:dir) . ' && ' : 'cd /d ' . ale#Escape(g:dir) . ' && ',
+ \ ale#path#BufferCdString(bufnr(''))