Repository: dense-analysis/ale Branch: master Commit: 69c945d5daec Files: 2221 Total size: 4.0 MB Directory structure: gitextract_id28numa/ ├── AGENTS.md ├── Dockerfile ├── LICENSE ├── README.md ├── ale_linters/ │ ├── ada/ │ │ ├── adals.vim │ │ ├── cspell.vim │ │ └── gcc.vim │ ├── ansible/ │ │ ├── ansible_lint.vim │ │ └── language_server.vim │ ├── apiblueprint/ │ │ └── drafter.vim │ ├── apkbuild/ │ │ ├── apkbuild_lint.vim │ │ └── secfixes_check.vim │ ├── asciidoc/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── languagetool.vim │ │ ├── proselint.vim │ │ ├── redpen.vim │ │ ├── textlint.vim │ │ ├── vale.vim │ │ └── writegood.vim │ ├── asm/ │ │ ├── gcc.vim │ │ └── llvm_mc.vim │ ├── astro/ │ │ └── eslint.vim │ ├── avra/ │ │ └── avra.vim │ ├── awk/ │ │ └── gawk.vim │ ├── bats/ │ │ └── shellcheck.vim │ ├── bib/ │ │ └── bibclean.vim │ ├── bicep/ │ │ ├── az_bicep.vim │ │ └── bicep.vim │ ├── bindzone/ │ │ └── checkzone.vim │ ├── bitbake/ │ │ └── oelint_adv.vim │ ├── bzl/ │ │ └── buildifier.vim │ ├── c/ │ │ ├── cc.vim │ │ ├── ccls.vim │ │ ├── clangcheck.vim │ │ ├── clangd.vim │ │ ├── clangtidy.vim │ │ ├── cppcheck.vim │ │ ├── cpplint.vim │ │ ├── cquery.vim │ │ ├── cspell.vim │ │ └── flawfinder.vim │ ├── c3/ │ │ └── c3lsp.vim │ ├── cairo/ │ │ ├── scarb.vim │ │ ├── sierra.vim │ │ └── starknet.vim │ ├── chef/ │ │ ├── cookstyle.vim │ │ └── foodcritic.vim │ ├── clojure/ │ │ ├── clj_kondo.vim │ │ └── joker.vim │ ├── cloudformation/ │ │ ├── cfn_python_lint.vim │ │ └── checkov.vim │ ├── cmake/ │ │ ├── cmake_lint.vim │ │ └── cmakelint.vim │ ├── coffee/ │ │ ├── coffee.vim │ │ └── coffeelint.vim │ ├── cpp/ │ │ ├── cc.vim │ │ ├── ccls.vim │ │ ├── clangcheck.vim │ │ ├── clangd.vim │ │ ├── clangtidy.vim │ │ ├── clazy.vim │ │ ├── cppcheck.vim │ │ ├── cpplint.vim │ │ ├── cquery.vim │ │ ├── cspell.vim │ │ └── flawfinder.vim │ ├── crystal/ │ │ ├── ameba.vim │ │ └── crystal.vim │ ├── cs/ │ │ ├── csc.vim │ │ ├── cspell.vim │ │ ├── mcs.vim │ │ └── mcsc.vim │ ├── css/ │ │ ├── cspell.vim │ │ ├── csslint.vim │ │ ├── fecs.vim │ │ ├── stylelint.vim │ │ └── vscodecss.vim │ ├── cucumber/ │ │ └── cucumber.vim │ ├── cuda/ │ │ ├── clangd.vim │ │ └── nvcc.vim │ ├── cypher/ │ │ └── cypher_lint.vim │ ├── d/ │ │ ├── dls.vim │ │ └── dmd.vim │ ├── dafny/ │ │ └── dafny.vim │ ├── dart/ │ │ ├── analysis_server.vim │ │ ├── dart_analyze.vim │ │ └── language_server.vim │ ├── desktop/ │ │ └── desktop_file_validate.vim │ ├── dockerfile/ │ │ ├── dockerfile_lint.vim │ │ ├── dockerlinter.vim │ │ └── hadolint.vim │ ├── elixir/ │ │ ├── credo.vim │ │ ├── cspell.vim │ │ ├── dialyxir.vim │ │ ├── dogma.vim │ │ ├── elixir_ls.vim │ │ ├── expert.vim │ │ ├── lexical.vim │ │ └── mix.vim │ ├── elm/ │ │ ├── ls.vim │ │ └── make.vim │ ├── erlang/ │ │ ├── dialyzer.vim │ │ ├── elvis.vim │ │ ├── erlang_ls.vim │ │ ├── erlc.vim │ │ └── syntaxerl.vim │ ├── eruby/ │ │ ├── erb.vim │ │ ├── erblint.vim │ │ ├── erubi.vim │ │ ├── erubis.vim │ │ └── ruumba.vim │ ├── fish/ │ │ └── fish.vim │ ├── fortran/ │ │ ├── fortitude.vim │ │ ├── gcc.vim │ │ └── language_server.vim │ ├── fountain/ │ │ └── proselint.vim │ ├── fuse/ │ │ └── fusionlint.vim │ ├── gitcommit/ │ │ └── gitlint.vim │ ├── gleam/ │ │ └── gleamlsp.vim │ ├── glimmer/ │ │ └── embertemplatelint.vim │ ├── glsl/ │ │ ├── glslang.vim │ │ └── glslls.vim │ ├── go/ │ │ ├── bingo.vim │ │ ├── cspell.vim │ │ ├── gobuild.vim │ │ ├── gofmt.vim │ │ ├── golangci_lint.vim │ │ ├── gopls.vim │ │ ├── gosimple.vim │ │ ├── gotype.vim │ │ ├── govet.vim │ │ ├── langserver.vim │ │ ├── revive.vim │ │ └── staticcheck.vim │ ├── gohtmltmpl/ │ │ └── djlint.vim │ ├── graphql/ │ │ ├── eslint.vim │ │ └── gqlint.vim │ ├── groovy/ │ │ └── npmgroovylint.vim │ ├── hack/ │ │ ├── hack.vim │ │ └── hhast.vim │ ├── haml/ │ │ └── hamllint.vim │ ├── handlebars/ │ │ ├── djlint.vim │ │ └── embertemplatelint.vim │ ├── haskell/ │ │ ├── cabal_ghc.vim │ │ ├── cspell.vim │ │ ├── ghc.vim │ │ ├── ghc_mod.vim │ │ ├── hdevtools.vim │ │ ├── hie.vim │ │ ├── hlint.vim │ │ ├── hls.vim │ │ ├── stack_build.vim │ │ └── stack_ghc.vim │ ├── help/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── proselint.vim │ │ └── writegood.vim │ ├── html/ │ │ ├── alex.vim │ │ ├── angular.vim │ │ ├── cspell.vim │ │ ├── djlint.vim │ │ ├── eslint.vim │ │ ├── fecs.vim │ │ ├── htmlhint.vim │ │ ├── proselint.vim │ │ ├── stylelint.vim │ │ ├── superhtml.vim │ │ ├── tidy.vim │ │ ├── vscodehtml.vim │ │ └── writegood.vim │ ├── htmlangular/ │ │ └── djlint.vim │ ├── htmldjango/ │ │ └── djlint.vim │ ├── hurl/ │ │ └── hurlfmt.vim │ ├── idris/ │ │ └── idris.vim │ ├── ink/ │ │ └── ls.vim │ ├── inko/ │ │ └── inko.vim │ ├── ispc/ │ │ └── ispc.vim │ ├── java/ │ │ ├── checkstyle.vim │ │ ├── cspell.vim │ │ ├── eclipselsp.vim │ │ ├── javac.vim │ │ ├── javalsp.vim │ │ └── pmd.vim │ ├── javascript/ │ │ ├── biome.vim │ │ ├── cspell.vim │ │ ├── deno.vim │ │ ├── eslint.vim │ │ ├── fecs.vim │ │ ├── flow.vim │ │ ├── flow_ls.vim │ │ ├── jscs.vim │ │ ├── jshint.vim │ │ ├── standard.vim │ │ ├── tsserver.vim │ │ └── xo.vim │ ├── jinja/ │ │ ├── djlint.vim │ │ └── j2lint.vim │ ├── json/ │ │ ├── biome.vim │ │ ├── cspell.vim │ │ ├── eslint.vim │ │ ├── jq.vim │ │ ├── jsonlint.vim │ │ ├── spectral.vim │ │ └── vscodejson.vim │ ├── json5/ │ │ └── eslint.vim │ ├── jsonc/ │ │ ├── biome.vim │ │ └── eslint.vim │ ├── jsonnet/ │ │ ├── jsonnet_lint.vim │ │ └── jsonnetfmt.vim │ ├── julia/ │ │ └── languageserver.vim │ ├── kotlin/ │ │ ├── kotlinc.vim │ │ ├── ktlint.vim │ │ └── languageserver.vim │ ├── lean/ │ │ └── lake.vim │ ├── less/ │ │ ├── lessc.vim │ │ └── stylelint.vim │ ├── llvm/ │ │ └── llc.vim │ ├── lua/ │ │ ├── cspell.vim │ │ ├── lua_language_server.vim │ │ ├── luac.vim │ │ ├── luacheck.vim │ │ └── selene.vim │ ├── mail/ │ │ ├── alex.vim │ │ ├── languagetool.vim │ │ ├── proselint.vim │ │ └── vale.vim │ ├── make/ │ │ └── checkmake.vim │ ├── markdown/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── languagetool.vim │ │ ├── markdownlint.vim │ │ ├── marksman.vim │ │ ├── mdl.vim │ │ ├── proselint.vim │ │ ├── pymarkdown.vim │ │ ├── redpen.vim │ │ ├── remark_lint.vim │ │ ├── textlint.vim │ │ ├── vale.vim │ │ └── writegood.vim │ ├── matlab/ │ │ └── mlint.vim │ ├── mercury/ │ │ └── mmc.vim │ ├── nasm/ │ │ └── nasm.vim │ ├── nim/ │ │ ├── nimcheck.vim │ │ └── nimlsp.vim │ ├── nix/ │ │ ├── deadnix.vim │ │ ├── nix.vim │ │ ├── rnix_lsp.vim │ │ └── statix.vim │ ├── nroff/ │ │ ├── alex.vim │ │ ├── proselint.vim │ │ └── writegood.vim │ ├── nunjucks/ │ │ └── djlint.vim │ ├── objc/ │ │ ├── ccls.vim │ │ ├── clang.vim │ │ └── clangd.vim │ ├── objcpp/ │ │ ├── clang.vim │ │ └── clangd.vim │ ├── ocaml/ │ │ ├── merlin.vim │ │ ├── ocamllsp.vim │ │ └── ols.vim │ ├── ocamlinterface/ │ │ ├── merlin.vim │ │ └── ocamllsp.vim │ ├── odin/ │ │ └── ols.vim │ ├── openapi/ │ │ ├── ibm_validator.vim │ │ └── yamllint.vim │ ├── openscad/ │ │ └── sca2d.vim │ ├── perl/ │ │ ├── languageserver.vim │ │ ├── perl.vim │ │ └── perlcritic.vim │ ├── perl6/ │ │ └── perl6.vim │ ├── php/ │ │ ├── cspell.vim │ │ ├── intelephense.vim │ │ ├── langserver.vim │ │ ├── phan.vim │ │ ├── php.vim │ │ ├── phpactor.vim │ │ ├── phpcs.vim │ │ ├── phpmd.vim │ │ ├── phpstan.vim │ │ ├── psalm.vim │ │ └── tlint.vim │ ├── po/ │ │ ├── alex.vim │ │ ├── msgfmt.vim │ │ ├── proselint.vim │ │ └── writegood.vim │ ├── pod/ │ │ ├── alex.vim │ │ ├── proselint.vim │ │ └── writegood.vim │ ├── pony/ │ │ └── ponyc.vim │ ├── powershell/ │ │ ├── cspell.vim │ │ ├── powershell.vim │ │ └── psscriptanalyzer.vim │ ├── prolog/ │ │ └── swipl.vim │ ├── proto/ │ │ ├── buf_lint.vim │ │ ├── protoc_gen_lint.vim │ │ └── protolint.vim │ ├── pug/ │ │ └── puglint.vim │ ├── puppet/ │ │ ├── languageserver.vim │ │ ├── puppet.vim │ │ └── puppetlint.vim │ ├── purescript/ │ │ └── ls.vim │ ├── pyrex/ │ │ └── cython.vim │ ├── python/ │ │ ├── bandit.vim │ │ ├── cspell.vim │ │ ├── flake8.vim │ │ ├── flakehell.vim │ │ ├── jedils.vim │ │ ├── mypy.vim │ │ ├── prospector.vim │ │ ├── pycln.vim │ │ ├── pycodestyle.vim │ │ ├── pydocstyle.vim │ │ ├── pyflakes.vim │ │ ├── pylama.vim │ │ ├── pylint.vim │ │ ├── pylsp.vim │ │ ├── pyre.vim │ │ ├── pyrefly.vim │ │ ├── pyright.vim │ │ ├── refurb.vim │ │ ├── ruff.vim │ │ ├── unimport.vim │ │ └── vulture.vim │ ├── qml/ │ │ ├── qmlfmt.vim │ │ └── qmllint.vim │ ├── r/ │ │ ├── languageserver.vim │ │ └── lintr.vim │ ├── racket/ │ │ ├── langserver.vim │ │ └── raco.vim │ ├── reason/ │ │ ├── ls.vim │ │ ├── merlin.vim │ │ └── ols.vim │ ├── rego/ │ │ ├── cspell.vim │ │ └── opacheck.vim │ ├── rescript/ │ │ └── rescript_language_server.vim │ ├── review/ │ │ └── redpen.vim │ ├── robot/ │ │ └── rflint.vim │ ├── roc/ │ │ └── roc_language_server.vim │ ├── rst/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── proselint.vim │ │ ├── redpen.vim │ │ ├── rstcheck.vim │ │ ├── textlint.vim │ │ ├── vale.vim │ │ └── writegood.vim │ ├── ruby/ │ │ ├── brakeman.vim │ │ ├── cspell.vim │ │ ├── debride.vim │ │ ├── packwerk.vim │ │ ├── rails_best_practices.vim │ │ ├── reek.vim │ │ ├── rubocop.vim │ │ ├── ruby.vim │ │ ├── solargraph.vim │ │ ├── sorbet.vim │ │ ├── standardrb.vim │ │ └── steep.vim │ ├── rust/ │ │ ├── analyzer.vim │ │ ├── cargo.vim │ │ ├── cspell.vim │ │ ├── rls.vim │ │ └── rustc.vim │ ├── salt/ │ │ └── salt_lint.vim │ ├── sass/ │ │ ├── sasslint.vim │ │ └── stylelint.vim │ ├── scala/ │ │ ├── cspell.vim │ │ ├── fsc.vim │ │ ├── metals.vim │ │ ├── sbtserver.vim │ │ ├── scalac.vim │ │ └── scalastyle.vim │ ├── scss/ │ │ ├── sasslint.vim │ │ ├── scsslint.vim │ │ └── stylelint.vim │ ├── sh/ │ │ ├── bashate.vim │ │ ├── cspell.vim │ │ ├── language_server.vim │ │ ├── shell.vim │ │ └── shellcheck.vim │ ├── slim/ │ │ └── slimlint.vim │ ├── sml/ │ │ ├── smlnj.vim │ │ └── smlnj_cm.vim │ ├── solidity/ │ │ ├── solc.vim │ │ ├── solhint.vim │ │ └── solium.vim │ ├── spec/ │ │ └── rpmlint.vim │ ├── sql/ │ │ ├── sqlfluff.vim │ │ ├── sqlint.vim │ │ └── sqllint.vim │ ├── stylus/ │ │ └── stylelint.vim │ ├── sugarss/ │ │ └── stylelint.vim │ ├── svelte/ │ │ └── svelteserver.vim │ ├── swift/ │ │ ├── appleswiftformat.vim │ │ ├── cspell.vim │ │ ├── sourcekitlsp.vim │ │ └── swiftlint.vim │ ├── systemd/ │ │ └── systemd_analyze.vim │ ├── tcl/ │ │ └── nagelfar.vim │ ├── terraform/ │ │ ├── checkov.vim │ │ ├── terraform.vim │ │ ├── terraform_ls.vim │ │ ├── terraform_lsp.vim │ │ ├── tflint.vim │ │ └── tfsec.vim │ ├── testft/ │ │ └── testlinter.vim │ ├── tex/ │ │ ├── alex.vim │ │ ├── chktex.vim │ │ ├── cspell.vim │ │ ├── lacheck.vim │ │ ├── proselint.vim │ │ ├── redpen.vim │ │ ├── texlab.vim │ │ ├── textlint.vim │ │ ├── vale.vim │ │ └── writegood.vim │ ├── texinfo/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── proselint.vim │ │ └── writegood.vim │ ├── text/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── languagetool.vim │ │ ├── proselint.vim │ │ ├── redpen.vim │ │ ├── textlint.vim │ │ ├── vale.vim │ │ └── writegood.vim │ ├── thrift/ │ │ ├── thrift.vim │ │ └── thriftcheck.vim │ ├── toml/ │ │ └── tombi.vim │ ├── typescript/ │ │ ├── biome.vim │ │ ├── cspell.vim │ │ ├── deno.vim │ │ ├── eslint.vim │ │ ├── standard.vim │ │ ├── tslint.vim │ │ ├── tsserver.vim │ │ ├── typecheck.vim │ │ └── xo.vim │ ├── v/ │ │ └── v.vim │ ├── vala/ │ │ └── vala_lint.vim │ ├── verilog/ │ │ ├── hdl_checker.vim │ │ ├── iverilog.vim │ │ ├── slang.vim │ │ ├── verible_ls.vim │ │ ├── verilator.vim │ │ ├── vlog.vim │ │ ├── xvlog.vim │ │ └── yosys.vim │ ├── vhdl/ │ │ ├── ghdl.vim │ │ ├── hdl_checker.vim │ │ ├── vcom.vim │ │ └── xvhdl.vim │ ├── vim/ │ │ ├── ale_custom_linting_rules.vim │ │ ├── vimls.vim │ │ └── vint.vim │ ├── vue/ │ │ ├── cspell.vim │ │ ├── vls.vim │ │ └── volar.vim │ ├── wgsl/ │ │ └── naga.vim │ ├── xhtml/ │ │ ├── alex.vim │ │ ├── cspell.vim │ │ ├── proselint.vim │ │ └── writegood.vim │ ├── xml/ │ │ └── xmllint.vim │ ├── yaml/ │ │ ├── actionlint.vim │ │ ├── circleci.vim │ │ ├── gitlablint.vim │ │ ├── ls.vim │ │ ├── spectral.vim │ │ ├── swaglint.vim │ │ ├── yamllint.vim │ │ └── yq.vim │ ├── yang/ │ │ └── yang_lsp.vim │ ├── yara/ │ │ └── yls.vim │ ├── zeek/ │ │ └── zeek.vim │ └── zig/ │ ├── zlint.vim │ └── zls.vim ├── autoload/ │ ├── ale/ │ │ ├── ant.vim │ │ ├── args.vim │ │ ├── assert.vim │ │ ├── balloon.vim │ │ ├── c.vim │ │ ├── code_action.vim │ │ ├── codefix.vim │ │ ├── command.vim │ │ ├── completion/ │ │ │ └── python.vim │ │ ├── completion.vim │ │ ├── cursor.vim │ │ ├── d.vim │ │ ├── debugging.vim │ │ ├── definition.vim │ │ ├── dhall.vim │ │ ├── engine/ │ │ │ └── ignore.vim │ │ ├── engine.vim │ │ ├── events.vim │ │ ├── filename_mapping.vim │ │ ├── filerename.vim │ │ ├── filetypes.vim │ │ ├── fix/ │ │ │ └── registry.vim │ │ ├── fix.vim │ │ ├── fixers/ │ │ │ ├── alejandra.vim │ │ │ ├── apkbuild_fixer.vim │ │ │ ├── appleswiftformat.vim │ │ │ ├── astyle.vim │ │ │ ├── autoflake.vim │ │ │ ├── autoimport.vim │ │ │ ├── autopep8.vim │ │ │ ├── bibclean.vim │ │ │ ├── biome.vim │ │ │ ├── black.vim │ │ │ ├── brittany.vim │ │ │ ├── buf_format.vim │ │ │ ├── buildifier.vim │ │ │ ├── clangformat.vim │ │ │ ├── clangtidy.vim │ │ │ ├── cljfmt.vim │ │ │ ├── cmakeformat.vim │ │ │ ├── crystal.vim │ │ │ ├── css_beautify.vim │ │ │ ├── dart_format.vim │ │ │ ├── dartfmt.vim │ │ │ ├── deno.vim │ │ │ ├── dfmt.vim │ │ │ ├── dhall_format.vim │ │ │ ├── dhall_freeze.vim │ │ │ ├── dhall_lint.vim │ │ │ ├── djlint.vim │ │ │ ├── dotnet_format.vim │ │ │ ├── dprint.vim │ │ │ ├── dune.vim │ │ │ ├── elm_format.vim │ │ │ ├── erbformatter.vim │ │ │ ├── erblint.vim │ │ │ ├── erlang_mode.vim │ │ │ ├── erlfmt.vim │ │ │ ├── eslint.vim │ │ │ ├── fecs.vim │ │ │ ├── fish_indent.vim │ │ │ ├── fixjson.vim │ │ │ ├── floskell.vim │ │ │ ├── forge.vim │ │ │ ├── fourmolu.vim │ │ │ ├── generic.vim │ │ │ ├── generic_python.vim │ │ │ ├── gleam_format.vim │ │ │ ├── gnatpp.vim │ │ │ ├── gofmt.vim │ │ │ ├── gofumpt.vim │ │ │ ├── goimports.vim │ │ │ ├── golangci_lint.vim │ │ │ ├── golines.vim │ │ │ ├── gomod.vim │ │ │ ├── google_java_format.vim │ │ │ ├── gopls.vim │ │ │ ├── hackfmt.vim │ │ │ ├── help.vim │ │ │ ├── hfmt.vim │ │ │ ├── hindent.vim │ │ │ ├── hlint.vim │ │ │ ├── html_beautify.vim │ │ │ ├── htmlbeautifier.vim │ │ │ ├── hurlfmt.vim │ │ │ ├── importjs.vim │ │ │ ├── isort.vim │ │ │ ├── jq.vim │ │ │ ├── json_pytool.vim │ │ │ ├── jsonnetfmt.vim │ │ │ ├── ktlint.vim │ │ │ ├── kulala_fmt.vim │ │ │ ├── latexindent.vim │ │ │ ├── lua_format.vim │ │ │ ├── luafmt.vim │ │ │ ├── markdownlint.vim │ │ │ ├── mix_format.vim │ │ │ ├── nickel_format.vim │ │ │ ├── nimpretty.vim │ │ │ ├── nixfmt.vim │ │ │ ├── nixpkgsfmt.vim │ │ │ ├── npmgroovylint.vim │ │ │ ├── ocamlformat.vim │ │ │ ├── ocp_indent.vim │ │ │ ├── opafmt.vim │ │ │ ├── ormolu.vim │ │ │ ├── packer.vim │ │ │ ├── pandoc.vim │ │ │ ├── perltidy.vim │ │ │ ├── pgformatter.vim │ │ │ ├── php_cs_fixer.vim │ │ │ ├── phpcbf.vim │ │ │ ├── pint.vim │ │ │ ├── prettier.vim │ │ │ ├── prettier_eslint.vim │ │ │ ├── prettier_standard.vim │ │ │ ├── protolint.vim │ │ │ ├── ptop.vim │ │ │ ├── puppetlint.vim │ │ │ ├── purs_tidy.vim │ │ │ ├── purty.vim │ │ │ ├── pycln.vim │ │ │ ├── pyflyby.vim │ │ │ ├── pymarkdown.vim │ │ │ ├── qmlfmt.vim │ │ │ ├── raco_fmt.vim │ │ │ ├── refmt.vim │ │ │ ├── remark_lint.vim │ │ │ ├── reorder_python_imports.vim │ │ │ ├── rescript_format.vim │ │ │ ├── roc_annotate.vim │ │ │ ├── roc_format.vim │ │ │ ├── rubocop.vim │ │ │ ├── rubyfmt.vim │ │ │ ├── ruff.vim │ │ │ ├── ruff_format.vim │ │ │ ├── rufo.vim │ │ │ ├── rustfmt.vim │ │ │ ├── rustywind.vim │ │ │ ├── scadformat.vim │ │ │ ├── scalafmt.vim │ │ │ ├── shfmt.vim │ │ │ ├── sorbet.vim │ │ │ ├── sqlfluff.vim │ │ │ ├── sqlfmt.vim │ │ │ ├── sqlformat.vim │ │ │ ├── standard.vim │ │ │ ├── standardrb.vim │ │ │ ├── statix.vim │ │ │ ├── stylelint.vim │ │ │ ├── styler.vim │ │ │ ├── stylish_haskell.vim │ │ │ ├── stylua.vim │ │ │ ├── swiftformat.vim │ │ │ ├── syntax_tree.vim │ │ │ ├── terraform.vim │ │ │ ├── textlint.vim │ │ │ ├── tidy.vim │ │ │ ├── tombi_format.vim │ │ │ ├── tombi_lint.vim │ │ │ ├── tslint.vim │ │ │ ├── typstyle.vim │ │ │ ├── uncrustify.vim │ │ │ ├── unimport.vim │ │ │ ├── verible_format.vim │ │ │ ├── vfmt.vim │ │ │ ├── xmllint.vim │ │ │ ├── xo.vim │ │ │ ├── yamlfix.vim │ │ │ ├── yamlfmt.vim │ │ │ ├── yapf.vim │ │ │ ├── yq.vim │ │ │ └── zigfmt.vim │ │ ├── floating_preview.vim │ │ ├── fzf.vim │ │ ├── go.vim │ │ ├── gradle/ │ │ │ └── init.gradle │ │ ├── gradle.vim │ │ ├── handlers/ │ │ │ ├── alex.vim │ │ │ ├── atools.vim │ │ │ ├── biome.vim │ │ │ ├── c3lsp.vim │ │ │ ├── cairo.vim │ │ │ ├── ccls.vim │ │ │ ├── cppcheck.vim │ │ │ ├── cpplint.vim │ │ │ ├── cspell.vim │ │ │ ├── css.vim │ │ │ ├── deadnix.vim │ │ │ ├── deno.vim │ │ │ ├── djlint.vim │ │ │ ├── elixir.vim │ │ │ ├── embertemplatelint.vim │ │ │ ├── eslint.vim │ │ │ ├── fecs.vim │ │ │ ├── flawfinder.vim │ │ │ ├── gawk.vim │ │ │ ├── gcc.vim │ │ │ ├── go.vim │ │ │ ├── haskell.vim │ │ │ ├── haskell_stack.vim │ │ │ ├── hdl_checker.vim │ │ │ ├── hlint.vim │ │ │ ├── inko.vim │ │ │ ├── ktlint.vim │ │ │ ├── languagetool.vim │ │ │ ├── markdownlint.vim │ │ │ ├── naga.vim │ │ │ ├── ocamllsp.vim │ │ │ ├── ols.vim │ │ │ ├── openscad.vim │ │ │ ├── pony.vim │ │ │ ├── redpen.vim │ │ │ ├── ruby.vim │ │ │ ├── rust.vim │ │ │ ├── scala.vim │ │ │ ├── sh.vim │ │ │ ├── shellcheck.vim │ │ │ ├── sml.vim │ │ │ ├── spectral.vim │ │ │ ├── statix.vim │ │ │ ├── textlint.vim │ │ │ ├── tslint.vim │ │ │ ├── tsserver.vim │ │ │ ├── unix.vim │ │ │ ├── vale.vim │ │ │ ├── writegood.vim │ │ │ ├── xo.vim │ │ │ └── yamllint.vim │ │ ├── highlight.vim │ │ ├── history.vim │ │ ├── hover.vim │ │ ├── java.vim │ │ ├── job.vim │ │ ├── julia.vim │ │ ├── linter.vim │ │ ├── list.vim │ │ ├── loclist_jumping.vim │ │ ├── lsp/ │ │ │ ├── message.vim │ │ │ ├── reset.vim │ │ │ ├── response.vim │ │ │ └── tsserver_message.vim │ │ ├── lsp.vim │ │ ├── lsp_linter.vim │ │ ├── lsp_window.vim │ │ ├── lua.vim │ │ ├── maven.vim │ │ ├── node.vim │ │ ├── organize_imports.vim │ │ ├── other_source.vim │ │ ├── path.vim │ │ ├── pattern_options.vim │ │ ├── powershell.vim │ │ ├── preview.vim │ │ ├── proselint.vim │ │ ├── python.vim │ │ ├── racket.vim │ │ ├── references.vim │ │ ├── rename.vim │ │ ├── ruby.vim │ │ ├── semver.vim │ │ ├── sign.vim │ │ ├── socket.vim │ │ ├── statusline.vim │ │ ├── swift.vim │ │ ├── symbol.vim │ │ ├── test.vim │ │ ├── toggle.vim │ │ ├── uri/ │ │ │ └── jdt.vim │ │ ├── uri.vim │ │ ├── util.vim │ │ └── virtualtext.vim │ ├── ale.vim │ └── asyncomplete/ │ └── sources/ │ └── ale.vim ├── doc/ │ ├── ale-ada.txt │ ├── ale-ansible.txt │ ├── ale-apkbuild.txt │ ├── ale-asciidoc.txt │ ├── ale-asm.txt │ ├── ale-astro.txt │ ├── ale-avra.txt │ ├── ale-awk.txt │ ├── ale-bats.txt │ ├── ale-bazel.txt │ ├── ale-bib.txt │ ├── ale-bicep.txt │ ├── ale-bindzone.txt │ ├── ale-bitbake.txt │ ├── ale-c.txt │ ├── ale-c3.txt │ ├── ale-cairo.txt │ ├── ale-chef.txt │ ├── ale-clojure.txt │ ├── ale-cloudformation.txt │ ├── ale-cmake.txt │ ├── ale-cpp.txt │ ├── ale-cs.txt │ ├── ale-css.txt │ ├── ale-cuda.txt │ ├── ale-d.txt │ ├── ale-dafny.txt │ ├── ale-dart.txt │ ├── ale-desktop.txt │ ├── ale-development.txt │ ├── ale-dhall.txt │ ├── ale-dockerfile.txt │ ├── ale-elixir.txt │ ├── ale-elm.txt │ ├── ale-erlang.txt │ ├── ale-eruby.txt │ ├── ale-fish.txt │ ├── ale-fortran.txt │ ├── ale-fountain.txt │ ├── ale-fuse.txt │ ├── ale-gitcommit.txt │ ├── ale-gleam.txt │ ├── ale-glsl.txt │ ├── ale-go.txt │ ├── ale-gohtmltmpl.txt │ ├── ale-graphql.txt │ ├── ale-groovy.txt │ ├── ale-hack.txt │ ├── ale-handlebars.txt │ ├── ale-haskell.txt │ ├── ale-hcl.txt │ ├── ale-help.txt │ ├── ale-html.txt │ ├── ale-htmlangular.txt │ ├── ale-htmldjango.txt │ ├── ale-http.txt │ ├── ale-hurl.txt │ ├── ale-idris.txt │ ├── ale-ink.txt │ ├── ale-inko.txt │ ├── ale-ispc.txt │ ├── ale-java.txt │ ├── ale-javascript.txt │ ├── ale-jinja.txt │ ├── ale-json.txt │ ├── ale-json5.txt │ ├── ale-jsonc.txt │ ├── ale-jsonnet.txt │ ├── ale-julia.txt │ ├── ale-kotlin.txt │ ├── ale-latex.txt │ ├── ale-lean.txt │ ├── ale-less.txt │ ├── ale-llvm.txt │ ├── ale-lua.txt │ ├── ale-make.txt │ ├── ale-markdown.txt │ ├── ale-mercury.txt │ ├── ale-nasm.txt │ ├── ale-nickel.txt │ ├── ale-nim.txt │ ├── ale-nix.txt │ ├── ale-nroff.txt │ ├── ale-nunjucks.txt │ ├── ale-objc.txt │ ├── ale-objcpp.txt │ ├── ale-ocaml.txt │ ├── ale-odin.txt │ ├── ale-openapi.txt │ ├── ale-openscad.txt │ ├── ale-packer.txt │ ├── ale-pascal.txt │ ├── ale-pawn.txt │ ├── ale-perl.txt │ ├── ale-perl6.txt │ ├── ale-php.txt │ ├── ale-po.txt │ ├── ale-pod.txt │ ├── ale-pony.txt │ ├── ale-powershell.txt │ ├── ale-prolog.txt │ ├── ale-proto.txt │ ├── ale-pug.txt │ ├── ale-puppet.txt │ ├── ale-purescript.txt │ ├── ale-pyrex.txt │ ├── ale-python.txt │ ├── ale-qml.txt │ ├── ale-r.txt │ ├── ale-racket.txt │ ├── ale-reasonml.txt │ ├── ale-rego.txt │ ├── ale-rescript.txt │ ├── ale-rest.txt │ ├── ale-restructuredtext.txt │ ├── ale-robot.txt │ ├── ale-roc.txt │ ├── ale-ruby.txt │ ├── ale-rust.txt │ ├── ale-salt.tmt │ ├── ale-sass.txt │ ├── ale-scala.txt │ ├── ale-scss.txt │ ├── ale-sh.txt │ ├── ale-sml.txt │ ├── ale-solidity.txt │ ├── ale-spec.txt │ ├── ale-sql.txt │ ├── ale-stylus.txt │ ├── ale-sugarss.txt │ ├── ale-supported-languages-and-tools.txt │ ├── ale-svelte.txt │ ├── ale-swift.txt │ ├── ale-systemd.txt │ ├── ale-tcl.txt │ ├── ale-terraform.txt │ ├── ale-tex.txt │ ├── ale-texinfo.txt │ ├── ale-text.txt │ ├── ale-thrift.txt │ ├── ale-toml.txt │ ├── ale-typescript.txt │ ├── ale-typst.html │ ├── ale-v.txt │ ├── ale-vala.txt │ ├── ale-verilog.txt │ ├── ale-vhdl.txt │ ├── ale-vim-help.txt │ ├── ale-vim.txt │ ├── ale-vue.txt │ ├── ale-wgsl.txt │ ├── ale-xhtml.txt │ ├── ale-xml.txt │ ├── ale-yaml.txt │ ├── ale-yang.txt │ ├── ale-yara.txt │ ├── ale-zeek.txt │ ├── ale-zig.txt │ └── ale.txt ├── ftplugin/ │ ├── ale-fix-suggest.vim │ ├── ale-info.vim │ ├── ale-preview-selection.vim │ └── ale-preview.vim ├── lspconfig.vim ├── lua/ │ └── ale/ │ ├── diagnostics.lua │ ├── init.lua │ ├── lsp.lua │ └── util.lua ├── plugin/ │ └── ale.vim ├── rplugin/ │ └── python3/ │ └── deoplete/ │ └── sources/ │ └── ale.py ├── run-tests ├── run-tests.bat ├── supported-tools.md ├── syntax/ │ ├── ale-fix-suggest.vim │ ├── ale-info.vim │ └── ale-preview-selection.vim └── test/ ├── completion/ │ ├── test_ale_import_command.vader │ ├── test_complete_events.vader │ ├── test_completion_events.vader │ ├── test_completion_filtering.vader │ ├── test_completion_prefixes.vader │ ├── test_lsp_completion_messages.vader │ ├── test_lsp_completion_parsing.vader │ ├── test_omnifunc_completion.vader │ ├── test_public_completion_api.vader │ └── test_tsserver_completion_parsing.vader ├── fix/ │ ├── test_ale_fix.vader │ ├── test_ale_fix_aliases.vader │ ├── test_ale_fix_completion.vader │ ├── test_ale_fix_completion_filter.vader │ ├── test_ale_fix_ignore.vader │ └── test_ale_fix_suggest.vader ├── fixers/ │ ├── test_alejandra_fixer_callback.vader │ ├── test_apkbuild_fixer_callback.vader │ ├── test_appleswiftformat_fixer_callback.vader │ ├── test_astyle_fixer_callback.vader │ ├── test_autoflake_fixer_callback.vader │ ├── test_autoimport_fixer_callback.vader │ ├── test_autopep8_fixer_callback.vader │ ├── test_bibclean_fixer_callback.vader │ ├── test_biome_fixer_callback.vader │ ├── test_black_fixer_callback.vader │ ├── test_break_up_long_lines_python_fixer.vader │ ├── test_brittany_fixer_callback.vader │ ├── test_buf_format_fixer_callback.vader │ ├── test_buildifier_fixer_callback.vader │ ├── test_clangformat_fixer_callback.vader │ ├── test_clangtidy_fixer_callback.vader │ ├── test_cljfmt_fixer_callback.vader │ ├── test_cmakeformat_fixer_callback.vader │ ├── test_crystal_format_fixer_callback.vader │ ├── test_css_beautify_fixer_callback.vader │ ├── test_dart_format_fixer_callback.vader │ ├── test_dartfmt_fixer_callback.vader │ ├── test_dfmt_fixer_callback.vader │ ├── test_dhall_format_fixer_callback.vader │ ├── test_dhall_freeze_fixer_callback.vader │ ├── test_dhall_lint_fixer_callback.vader │ ├── test_djlint_fixer_callback.vader │ ├── test_dotnet_format_fixer_callback.vader │ ├── test_dprint_fixer_callback.vader │ ├── test_dune_fixer_callback.vader │ ├── test_elm_format_fixer_callback.vader │ ├── test_erbformatter_fixer_callback.vader │ ├── test_erblint_fixer_callback.vader │ ├── test_erlang_mode_fixer_callback.vader │ ├── test_erlfmt_fixer_callback.vader │ ├── test_eslint_fixer_callback.vader │ ├── test_fecs_fixer_callback.vader │ ├── test_fish_indent_fixer_callback.vader │ ├── test_fixjson_fixer_callback.vader │ ├── test_floskell_fixer_callback.vader │ ├── test_forge_fixer_callback.vader │ ├── test_fourmolu_fixer_callback.vader │ ├── test_gleam_format_fixer_callback.vader │ ├── test_gnatpp_fixer_callback.vader │ ├── test_gofmt_fixer_callback.vader │ ├── test_gofumpt_fixer.vader │ ├── test_goimports_fixer_callback.vader │ ├── test_golangci_lint_fixer_callback.vader │ ├── test_golines_fixer_callback.vader │ ├── test_gomod_fixer_callback.vader │ ├── test_goofle_java_format_fixer_callback.vader │ ├── test_gopls_fixer_callback.vader │ ├── test_hackfmt_fixer_callback.vader │ ├── test_hfmt_fixer_callback.vader │ ├── test_hindent_fixer_callback.vader │ ├── test_hlint_fixer_callback.vader │ ├── test_html_beautify_fixer_callback.vader │ ├── test_htmlbeautifier_fixer_callback.vader │ ├── test_hurlfmt_fixer_callback.vader │ ├── test_importjs_fixer_callback.vader │ ├── test_isort_fixer_callback.vader │ ├── test_jq_fixer_callback.vader │ ├── test_jsonnetfmt_fixer_callback.vader │ ├── test_ktlint_fixer_callback.vader │ ├── test_kulala_fmt_fixer_callback.vader │ ├── test_latexindent_fixer_callback.vader │ ├── test_lua_format_fixer_callback.vader │ ├── test_luafmt_fixer_callback.vader │ ├── test_markdownlint_fixer_callback.vader │ ├── test_mix_format_fixer_callback.vader │ ├── test_nickel_format_fixer_callback.vader │ ├── test_nimpretty_fixer_callback.vader │ ├── test_nixfmt_fixer_callback.vader │ ├── test_nixpkgsfmt_fixer_callback.vader │ ├── test_npmgroovylint_fixer_callback.vader │ ├── test_ocamlformat_fixer_callback.vader │ ├── test_ocp_indent_fixer_callback.vader │ ├── test_opa_fmt_fixer_callback.vader │ ├── test_ormolu_fixer_callback.vader │ ├── test_packer_fmt_fixer_callback.vader │ ├── test_pandoc_fixer_callback.vader │ ├── test_perltidy_fixer_callback.vader │ ├── test_pgformatter_fixer_callback.vader │ ├── test_php_cs_fixer.vader │ ├── test_phpcbf_fixer_callback.vader │ ├── test_pint_fixer.vader │ ├── test_prettier_eslint_fixer.callback.vader │ ├── test_prettier_fixer_callback.vader │ ├── test_prettier_standard_callback.vader │ ├── test_protolint_fixer_callback.vader │ ├── test_ptop_fixer_callback.vader │ ├── test_puppetlint_fixer_callback.vader │ ├── test_purs_tidy_fixer_callback.vader │ ├── test_purty_fixer_callback.vader │ ├── test_pycln_fixer_callback.vader │ ├── test_pyflyby_fixer_callback.vader │ ├── test_pymarkdown_fixer_callback.vader │ ├── test_python_add_blank_lines_fixer.vader │ ├── test_qmlfmt_fixer_callback.vader │ ├── test_raco_fmt_fixer_callback.vader │ ├── test_refmt_fixer_callback.vader │ ├── test_remark_lint_fixer_callback.vader │ ├── test_reorder_python_imports_fixer_callback.vader │ ├── test_rescript_fixer_callback.vader │ ├── test_roc_annotate_fixer_callback.vader │ ├── test_roc_format_fixer_callback.vader │ ├── test_rubocop_fixer_callback.vader │ ├── test_rubyfmt_fixer_callback.vader │ ├── test_ruff_fixer_callback.vader │ ├── test_ruff_format_fixer_callback.vader │ ├── test_rufo_fixer_callback.vader │ ├── test_rustfmt_fixer_callback.vader │ ├── test_rustywind_fixer_callback.vader │ ├── test_scadformat_fixer.vader │ ├── test_scalafmt_fixer_callback.vader │ ├── test_shfmt_fixer_callback.vader │ ├── test_sorbet_fixer_callback.vader │ ├── test_sqlfmt_fixer_callback.vader │ ├── test_sqlformat_fixer_callback.vader │ ├── test_standard_fixer_callback.vader │ ├── test_standardrb_fixer_callback.vader │ ├── test_statix_fixer.vader │ ├── test_stylelint_fixer_callback.vader │ ├── test_styler_fixer_callback.vader │ ├── test_stylish_haskell_fixer_callback.vader │ ├── test_stylua_fixer_callback.vader │ ├── test_swiftformat_fixer_callback.vader │ ├── test_syntax_tree_fixer_callback.vader │ ├── test_terraform_fmt_fixer_callback.vader │ ├── test_textlint_fixer_callback.vader │ ├── test_tidy_fixer_callback.vader │ ├── test_tombi_format_fixer_callback.vader │ ├── test_tombi_lint_fixer_callback.vader │ ├── test_trim_whitespace.vader │ ├── test_tslint_fixer_callback.vader │ ├── test_typstyle_fixer_callback.vader │ ├── test_uncrustify_fixer_callback.vader │ ├── test_unimport_fixer_callback.vader │ ├── test_verible_format_fixer_callback.vader │ ├── test_vfmt_fixer_callback.vader │ ├── test_vim_help_tags_alignment_fixer.vader │ ├── test_xmllint_fixer_callback.vader │ ├── test_xo_fixer_callback.vader │ ├── test_xots_fixer_callback.vader │ ├── test_yamlfix_fixer_callback.vader │ ├── test_yamlfmt_fixer_callback.vader │ ├── test_yapf_fixer_callback.vader │ └── test_zigfmt_fixer_callback.vader ├── handler/ │ ├── test_actionlint_handler.vader │ ├── test_ada_gcc_handler.vader │ ├── test_alex_handler.vader │ ├── test_ameba_handler.vader │ ├── test_ansible_lint_handler.vader │ ├── test_appleswiftformat_handler.vader │ ├── test_asm_handler.vader │ ├── test_atools_handler.vader │ ├── test_avra_handler.vader │ ├── test_bandit_handler.vader │ ├── test_bashate_handler.vader │ ├── test_bibclean_handler.vader │ ├── test_bicep_az_bicep_handler.vader │ ├── test_bicep_bicep_handler.vader │ ├── test_bindzone_checkzone.vader │ ├── test_bitbake_oelint_adv_handler.vader │ ├── test_brakeman_handler.vader │ ├── test_buildifier_handler.vader │ ├── test_cfn_python_lint_handler.vader │ ├── test_checkmake_handler.vader │ ├── test_checkov_handler.vader │ ├── test_checkstyle_handler.vader │ ├── test_circleci_handler.vader │ ├── test_clang_handler.vader │ ├── test_clojure_clj_kondo_handler.vader │ ├── test_clojure_joker_handler.vader │ ├── test_cloudformation_checkov_handler.vader │ ├── test_cmake_lint_handler.vader │ ├── test_coffeelint_handler.vader │ ├── test_common_handlers.vader │ ├── test_cookstyle_handler.vader │ ├── test_cppcheck_handler.vader │ ├── test_cpplint_handler.vader │ ├── test_credo_handler.vader │ ├── test_crystal_handler.vader │ ├── test_csc_handler.vader │ ├── test_cspell_handler.vader │ ├── test_cucumber_handler.vader │ ├── test_cuda_nvcc_handler.vader │ ├── test_cypher_lint_handler.vader │ ├── test_dafny_handler.vader │ ├── test_dart_analyze_handler.vader │ ├── test_deadnix_handler.vader │ ├── test_debride_handler.vader │ ├── test_desktop_file_validate_handler.vader │ ├── test_djlint_handler.vader │ ├── test_dmd_handler.vader │ ├── test_dockerfile_lint_handler.vader │ ├── test_dockerlinter_handler.vader │ ├── test_dogma_handler.vader │ ├── test_drafter_handler.vader │ ├── test_elmmake_handler.vader │ ├── test_embertemplatelint_handler.vader │ ├── test_erblint_handler.vader │ ├── test_erlang_dialyzer_handler.vader │ ├── test_erlang_elvis_handler.vader │ ├── test_eslint_handler.vader │ ├── test_eslint_json_handler.vader │ ├── test_fecs_handler.vader │ ├── test_fish_handler.vader │ ├── test_flake8_handler.vader │ ├── test_flakehell_handler.vader │ ├── test_flawfinder_handler.vader │ ├── test_flow_handler.vader │ ├── test_foodcritic_handler.vader │ ├── test_fortitude_handler.vader │ ├── test_fortran_handler.vader │ ├── test_gawk_handler.vader │ ├── test_gcc_handler.vader │ ├── test_ghc_handler.vader │ ├── test_ghc_mod_handler.vader │ ├── test_ghdl_handler.vader │ ├── test_gitlablint_handler.vader │ ├── test_gitlint_handler.vader │ ├── test_glslang_handler.vader │ ├── test_go_generic_handler.vader │ ├── test_gobuild_handler.vader │ ├── test_golangci_lint_handler.vader │ ├── test_hadolint.vader │ ├── test_haskell_stack_handler.vader │ ├── test_hlint_handler.vader │ ├── test_hurlfmt_handler.vader │ ├── test_ibm_openapi_validator_handler.vader │ ├── test_idris_handler.vader │ ├── test_inko_handler.vader │ ├── test_ispc_ispc_handler.vader │ ├── test_javac_handler.vader │ ├── test_jq_handler.vader │ ├── test_jscs_handler.vader │ ├── test_ktlint_handler.vader │ ├── test_lacheck_handler.vader │ ├── test_languagetool_handler.vader │ ├── test_lessc_handler.vader │ ├── test_llc_handler.vader │ ├── test_llvm_mc_handler.vader │ ├── test_lua_selene_handler.vader │ ├── test_luac_handler.vader │ ├── test_luacheck_handler.vader │ ├── test_markdownlint_handler.vader │ ├── test_mcs_handler.vader │ ├── test_mcsc_handler.vader │ ├── test_mdl_handler.vader │ ├── test_mercury_mmc_handler.vader │ ├── test_mix_handler.vader │ ├── test_msgfmt_hander.vader │ ├── test_mypy_handler.vader │ ├── test_naga_handler.vader │ ├── test_nagelfar_handler.vader │ ├── test_nasm_handler.vader │ ├── test_nim_handler.vader │ ├── test_nix_handler.vader │ ├── test_npmgroovylint_handler.vader │ ├── test_openscad_handler.vader │ ├── test_packwerk_handler.vader │ ├── test_perl6_handler.vader │ ├── test_perl_handler.vader │ ├── test_perlcritic_handler.vader │ ├── test_php_handler.vader │ ├── test_php_phan_handler.vader │ ├── test_php_phpmd_handler.vader │ ├── test_phpcs_handler.vader │ ├── test_phpstan_handler.vader │ ├── test_pmd_handler.vader │ ├── test_pony_handler.vader │ ├── test_powershell_handler.vader │ ├── test_prospector_handler.vader │ ├── test_psscriptanalyzer_handler.vader │ ├── test_puglint_handler.vader │ ├── test_puppet_handler.vader │ ├── test_pycodestyle_handler.vader │ ├── test_pydocstyle_handler.vader │ ├── test_pyflakes_handler.vader │ ├── test_pylama_handler.vader │ ├── test_pylint_handler.vader │ ├── test_pyrex_cython_handler.vader │ ├── test_qmlfmt_handler.vader │ ├── test_qmllint_handler.vader │ ├── test_raco_handler.vader │ ├── test_rails_best_practices_handler.vader │ ├── test_redpen_handler.vader │ ├── test_reek_handler.vader │ ├── test_remark_lint_handler.vader │ ├── test_rflint_handler.vader │ ├── test_rpmlint_handler.vader │ ├── test_rstcheck_lint_handler.vader │ ├── test_rubocop_handler.vader │ ├── test_ruby_handler.vader │ ├── test_ruff_handler.vader │ ├── test_rust_handler.vader │ ├── test_salt_salt_lint.vader │ ├── test_scala_handler.vader │ ├── test_scalastyle_handler.vader │ ├── test_scarb_handler.vader │ ├── test_shell_handler.vader │ ├── test_shellcheck_handler.vader │ ├── test_sierra_handler.vader │ ├── test_slang_handler.vader │ ├── test_slim_handler.vader │ ├── test_sml_handler.vader │ ├── test_solc_handler.vader │ ├── test_solhint_handler.vader │ ├── test_spectral_handler.vader │ ├── test_sql_sqlfluff_handler.vader │ ├── test_sqlint_handler.vader │ ├── test_sqllint_handler.vader │ ├── test_standard_handler.vader │ ├── test_starknet_handler.vader │ ├── test_statix_handler.vader │ ├── test_steep_handler.vader │ ├── test_stylelint_handler.vader │ ├── test_swaglint_handler.vader │ ├── test_swiftlint_handler.vader │ ├── test_swipl_handler.vader │ ├── test_syntaxerl_handler.vader │ ├── test_systemd_analyze_handler.vader │ ├── test_terraform_handler.vader │ ├── test_textlint_handler.vader │ ├── test_tflint_handler.vader │ ├── test_tfsec_handler.vader │ ├── test_thrift_handler.vader │ ├── test_thriftcheck_handler.vader │ ├── test_tlint_handler.vader │ ├── test_tslint_handler.vader │ ├── test_typecheck_handler.vader │ ├── test_unimport_handler.vader │ ├── test_v_handler.vader │ ├── test_vala_lint_handler.vader │ ├── test_vale_handler.vader │ ├── test_vcom_handler.vader │ ├── test_verilator_handler.vader │ ├── test_vint_handler.vader │ ├── test_vlog_handler.vader │ ├── test_vulture_handler.vader │ ├── test_write_good_handler.vader │ ├── test_xmllint_handler.vader │ ├── test_xvhdl_handler.vader │ ├── test_xvlog_handler.vader │ ├── test_yamllint_handler.vader │ ├── test_yosys_handler.vader │ ├── test_yq_handler.vader │ ├── test_zeek_handler.vader │ └── test_zlint_handler.vader ├── jsonnet_files/ │ └── testfile.jsonnet ├── linter/ │ ├── test_ada_gcc.vader │ ├── test_adals.vader │ ├── test_alex.vader │ ├── test_ameba.vader │ ├── test_angular.vader │ ├── test_ansible_language_server.vader │ ├── test_ansible_lint.vader │ ├── test_asciidoc_textlint.vader │ ├── test_asm_gcc.vader │ ├── test_avra_avra.vader │ ├── test_bandit.vader │ ├── test_bashate.vader │ ├── test_bib_bibclean.vader │ ├── test_bicep_az_bicep.vader │ ├── test_bicep_bicep.vader │ ├── test_bindzone_checkzone.vader │ ├── test_bingo.vader │ ├── test_biome.vader │ ├── test_bitbake.vader │ ├── test_brakeman.vader │ ├── test_buf_lint.vader │ ├── test_bzl_buildifier.vader │ ├── test_c3_c3lsp.vader │ ├── test_c_cc.vader │ ├── test_c_ccls.vader │ ├── test_c_clang_tidy.vader │ ├── test_c_clangcheck.vader │ ├── test_c_clangd.vader │ ├── test_c_cppcheck.vader │ ├── test_c_cquery.vader │ ├── test_c_flawfinder.vader │ ├── test_c_import_paths.vader │ ├── test_cargo.vader │ ├── test_checkmake.vader │ ├── test_checkov.vader │ ├── test_checkstyle.vader │ ├── test_circleci.vader │ ├── test_clang_tidy.vader │ ├── test_clj_kondo.vader │ ├── test_cloudformation_checkov.vader │ ├── test_cmake_cmake_lint.vader │ ├── test_cookstyle.vader │ ├── test_cpp_cc.vader │ ├── test_cpp_ccls.vader │ ├── test_cpp_clangcheck.vader │ ├── test_cpp_clazy.vader │ ├── test_cpp_cppcheck.vader │ ├── test_cpp_cquery.vader │ ├── test_cpp_flawfinder.vader │ ├── test_cpplint.vader │ ├── test_cs_csc.vader │ ├── test_cs_mcs.vader │ ├── test_cs_mcsc.vader │ ├── test_cspell.vader │ ├── test_css_csslint.vader │ ├── test_css_stylelint.vader │ ├── test_cucumber.vader │ ├── test_cuda_nvcc.vader │ ├── test_cypher_lint.vader │ ├── test_d_dls.vader │ ├── test_dart_analysis_server.vader │ ├── test_dart_language_server.vader │ ├── test_desktop_file_validate.vader │ ├── test_dialyxir.vader │ ├── test_djlint.vader │ ├── test_dmd_commandline.vader │ ├── test_dockerfile_lint.vader │ ├── test_dockerlinter.vader │ ├── test_dogma.vader │ ├── test_eclipselsp.vader │ ├── test_elixir_credo.vader │ ├── test_elixir_expert.vader │ ├── test_elixir_ls.vader │ ├── test_elixir_mix.vader │ ├── test_elm_ls.vader │ ├── test_elm_make.vader │ ├── test_embertemplatelint.vader │ ├── test_erb.vader │ ├── test_erblint.vader │ ├── test_erlang_dialyzer.vader │ ├── test_erlang_elvis.vader │ ├── test_erlang_erlang_ls.vader │ ├── test_erlang_erlc.vader │ ├── test_erlang_syntaxerl.vader │ ├── test_erubi.vader │ ├── test_erubis.vader │ ├── test_eslint.vader │ ├── test_fecs.vader │ ├── test_flake8.vader │ ├── test_flakehell.vader │ ├── test_flow.vader │ ├── test_foodcritic.vader │ ├── test_fortitude.vader │ ├── test_fortran_fortls.vader │ ├── test_fsc.vader │ ├── test_fusionlint.vader │ ├── test_gawk.vader │ ├── test_gfortran.vader │ ├── test_ghdl.vader │ ├── test_gitlint.vader │ ├── test_gleam_gleamlsp.vader │ ├── test_glslang.vader │ ├── test_glslls.vader │ ├── test_gobuild.vader │ ├── test_gofmt.vader │ ├── test_golangci_lint.vader │ ├── test_golangserver.vader │ ├── test_gopls.vader │ ├── test_gosimple.vader │ ├── test_gotype.vader │ ├── test_govet.vader │ ├── test_graphql_gqlint.vader │ ├── test_hadolint.vader │ ├── test_haml_hamllint.vader │ ├── test_haskell_cabal_ghc.vader │ ├── test_haskell_ghc.vader │ ├── test_haskell_ghc_mod.vader │ ├── test_haskell_hdevtools.vader │ ├── test_haskell_hie.vader │ ├── test_haskell_hlint.vader │ ├── test_haskell_hls.vader │ ├── test_haskell_stack_build.vader │ ├── test_haskell_stack_ghc.vader │ ├── test_hdl_checker_options.vader │ ├── test_html_stylelint.vader │ ├── test_htmlhint.vader │ ├── test_hurlfmt.vader │ ├── test_ibm_openapi_validator.vader │ ├── test_idris.vader │ ├── test_ink_ls.vader │ ├── test_inko_inko.vader │ ├── test_ispc_ispc.vader │ ├── test_iverilog.vader │ ├── test_j2lint.vader │ ├── test_javac.vader │ ├── test_javalsp.vader │ ├── test_javascript_deno_lsp.vader │ ├── test_javascript_tsserver.vader │ ├── test_jedils.vader │ ├── test_jq.vader │ ├── test_jscs.vader │ ├── test_jshint.vader │ ├── test_json_vscodejson.vader │ ├── test_jsonlint.vader │ ├── test_jsonnet_lint.vader │ ├── test_jsonnetfmt.vader │ ├── test_julia_languageserver.vader │ ├── test_kotlin_languageserver.vader │ ├── test_kotlinc.vader │ ├── test_languagetool.vader │ ├── test_lean_lake.vader │ ├── test_less_stylelint.vader │ ├── test_lessc.vader │ ├── test_lexical.vader │ ├── test_lintr.vader │ ├── test_llc.vader │ ├── test_llvm_mc.vader │ ├── test_lua_language_server.vader │ ├── test_lua_selene.vader │ ├── test_luac.vader │ ├── test_luacheck.vader │ ├── test_markdown_markdownlint.vader │ ├── test_markdown_marksman.vader │ ├── test_markdown_mdl.vader │ ├── test_markdown_vale.vader │ ├── test_mercury_mmc.vader │ ├── test_mypy.vader │ ├── test_naga.vader │ ├── test_nagelfar.vader │ ├── test_nasm_nasm.vader │ ├── test_nimlsp.vader │ ├── test_nix_deadnix.vader │ ├── test_nix_statix.vader │ ├── test_npmgroovylint.vader │ ├── test_objc_ccls.vader │ ├── test_ocaml_ocamllsp.vader │ ├── test_ocaml_ols.vader │ ├── test_ocamlinterface_ocamllsp.vader │ ├── test_odin_ols.vader │ ├── test_openscad_sca2d.vader │ ├── test_packwerk.vader │ ├── test_perl.vader │ ├── test_perl6.vader │ ├── test_perl_languageserver.vader │ ├── test_perlcritic.vader │ ├── test_php.vader │ ├── test_php_intelephense.vader │ ├── test_php_langserver.vader │ ├── test_phpactor.vader │ ├── test_phpcs.vader │ ├── test_phpmd.vader │ ├── test_phpstan.vader │ ├── test_pony_ponyc.vader │ ├── test_prospector.vader │ ├── test_proto.vader │ ├── test_protolint.vader │ ├── test_psalm.vader │ ├── test_puglint.vader │ ├── test_puppet_languageserver.vader │ ├── test_purescript_ls.vader │ ├── test_pycln.vader │ ├── test_pycodestyle.vader │ ├── test_pydocstyle.vader │ ├── test_pyflakes.vader │ ├── test_pylama.vader │ ├── test_pylint.vader │ ├── test_pylsp.vader │ ├── test_pymarkdown.vader │ ├── test_pymarkdown_handler.vader │ ├── test_pyre.vader │ ├── test_pyrefly.vader │ ├── test_pyrex_cython.vader │ ├── test_pyright.vader │ ├── test_qmlfmt.vader │ ├── test_r_languageserver.vader │ ├── test_racket_langserver.vader │ ├── test_racket_raco.vader │ ├── test_rails_best_practices.vader │ ├── test_reason_ls.vader │ ├── test_reason_ols.vader │ ├── test_redpen.vader │ ├── test_reek.vader │ ├── test_refurb.vader │ ├── test_rego_opacheck.vader │ ├── test_remark_lint.vader │ ├── test_rescript_language_server.vader │ ├── test_revive.vader │ ├── test_rflint.vader │ ├── test_rnix.vader │ ├── test_roc_roc_language_server.vader │ ├── test_rst_rstcheck.vader │ ├── test_rst_textlint.vader │ ├── test_rubocop.vader │ ├── test_ruby.vader │ ├── test_ruby_debride.vader │ ├── test_ruby_solargraph.vader │ ├── test_ruby_steep.vader │ ├── test_ruff.vader │ ├── test_rust_analyzer.vader │ ├── test_rust_rls.vader │ ├── test_rustc.vader │ ├── test_ruumba.vader │ ├── test_sass_sasslint.vader │ ├── test_scala_metals.vader │ ├── test_scala_sbtserver.vader │ ├── test_scalac.vader │ ├── test_scalastyle.vader │ ├── test_scss_sasslint.vader │ ├── test_scss_stylelint.vader │ ├── test_shellcheck.vader │ ├── test_slang.vader │ ├── test_slimlint.vader │ ├── test_solc.vader │ ├── test_solc_commit.vader │ ├── test_solhint.vader │ ├── test_sorbet.vader │ ├── test_spectral.vader │ ├── test_sql_sqlfluff.vader │ ├── test_sqllint.vader │ ├── test_standard.vader │ ├── test_standardrb.vader │ ├── test_standardts.vader │ ├── test_starknet.vader │ ├── test_staticcheck.vader │ ├── test_sugarss_stylelint.vader │ ├── test_superhtml.vader │ ├── test_svelteserver.vader │ ├── test_swaglint.vader │ ├── test_swift_appleswiftformat.vader │ ├── test_swift_sourcekitlsp.vader │ ├── test_swiftlint.vader │ ├── test_systemd_analyze.vader │ ├── test_terraform_ls.vader │ ├── test_terraform_lsp.vader │ ├── test_terraform_terraform.vader │ ├── test_terraform_tflint.vader │ ├── test_terraform_tfsec.vader │ ├── test_tex_chktex.vader │ ├── test_tex_lacheck.vader │ ├── test_tex_textlint.vader │ ├── test_texlab.vader │ ├── test_text_vale.vader │ ├── test_textlint.vader │ ├── test_thrift.vader │ ├── test_thriftcheck.vader │ ├── test_toml_tombi.vader │ ├── test_tslint.vader │ ├── test_typescript_deno_lsp.vader │ ├── test_typescript_tsserver.vader │ ├── test_unimport.vader │ ├── test_v_command_callback.vader │ ├── test_vcom.vader │ ├── test_verilator.vader │ ├── test_verilog_verible_ls.vader │ ├── test_vim_vimls.vader │ ├── test_vint.vader │ ├── test_vlog.vader │ ├── test_volar.vader │ ├── test_vulture.vader │ ├── test_write_good.vader │ ├── test_xmllint.vader │ ├── test_xo.vader │ ├── test_xots.vader │ ├── test_xvhdl.vader │ ├── test_xvlog.vader │ ├── test_yaml_actionlint.vader │ ├── test_yaml_ls.vader │ ├── test_yang_lsp.vader │ ├── test_yara_yls.vader │ ├── test_yq.vader │ ├── test_zeek.vader │ ├── test_zig_zlint.vader │ └── test_zig_zls.vader ├── lsp/ │ ├── test_closing_documents.vader │ ├── test_did_save_event.vader │ ├── test_engine_lsp_response_handling.vader │ ├── test_handling_window_requests.vader │ ├── test_lsp_address_split.vader │ ├── test_lsp_client_messages.vader │ ├── test_lsp_command_formatting.vader │ ├── test_lsp_connections.vader │ ├── test_lsp_custom_request.vader │ ├── test_lsp_error_parsing.vader │ ├── test_lsp_root_detection.vader │ ├── test_lsp_startup.vader │ ├── test_other_initialize_message_handling.vader │ ├── test_read_lsp_diagnostics.vader │ ├── test_reset_lsp.vader │ └── test_update_config.vader ├── lua/ │ ├── ale_diagnostics_spec.lua │ ├── ale_env_spec.lua │ ├── ale_get_filename_mappings_spec.lua │ ├── ale_has_spec.lua │ ├── ale_lsp_send_message_spec.lua │ ├── ale_lsp_start_spec.lua │ ├── ale_pad_spec.lua │ ├── ale_queue_spec.lua │ ├── ale_var_spec.lua │ └── windows_escaping_spec.lua ├── python/ │ └── test_deoplete_source.py ├── script/ │ ├── block-padding-checker │ ├── check-duplicate-tags │ ├── check-supported-tools-tables │ ├── check-tag-alignment │ ├── check-tag-references │ ├── check-toc │ ├── custom-checks │ ├── custom-linting-rules │ ├── dumb_named_pipe_server.py │ ├── dumb_tcp_client.py │ ├── dumb_tcp_server.py │ ├── run-lua-tests │ ├── run-vader-tests │ └── run-vint ├── sign/ │ ├── test_linting_sets_signs.vader │ ├── test_sign_column_highlighting.vader │ ├── test_sign_limits.vader │ ├── test_sign_parsing.vader │ └── test_sign_placement.vader ├── smoke_test.vader ├── test-files/ │ ├── .circleci/ │ │ └── config.yml │ ├── .gitignore │ ├── ada/ │ │ └── testfile.adb │ ├── ant/ │ │ ├── ant-project/ │ │ │ └── build.xml │ │ └── bin/ │ │ └── ant │ ├── bazel/ │ │ ├── BUILD │ │ ├── WORKSPACE │ │ └── defs.bzl │ ├── bib/ │ │ └── dummy.bib │ ├── biome/ │ │ ├── json/ │ │ │ ├── biome.json │ │ │ └── src/ │ │ │ └── test.ts │ │ └── jsonc/ │ │ ├── biome.jsonc │ │ └── src/ │ │ └── test.ts │ ├── bzl/ │ │ └── bazel-package/ │ │ └── BUILD.bazel │ ├── c/ │ │ ├── build_compile_commands_project/ │ │ │ └── build/ │ │ │ ├── bad_folder_to_test_priority │ │ │ └── compile_commands.json │ │ ├── configure_project/ │ │ │ ├── Makefile │ │ │ ├── configure │ │ │ ├── include/ │ │ │ │ └── test.h │ │ │ └── subdir/ │ │ │ └── Makefile │ │ ├── dummy.c │ │ ├── git_and_nested_makefiles/ │ │ │ ├── include/ │ │ │ │ └── test.h │ │ │ └── src/ │ │ │ └── Makefile │ │ ├── gnumakefile_project/ │ │ │ ├── GNUmakefile │ │ │ └── file.c │ │ ├── h_file_project/ │ │ │ ├── Makefile │ │ │ ├── subdir/ │ │ │ │ └── dummy │ │ │ └── test.h │ │ ├── hpp_file_project/ │ │ │ ├── Makefile │ │ │ ├── subdir/ │ │ │ │ └── dummy │ │ │ └── test.hpp │ │ ├── json_project/ │ │ │ ├── build/ │ │ │ │ └── compile_commands.json │ │ │ ├── include/ │ │ │ │ └── test.h │ │ │ └── subdir/ │ │ │ └── dummy │ │ └── makefile_project/ │ │ ├── Makefile │ │ ├── _astylerc │ │ ├── args │ │ ├── include/ │ │ │ └── test.h │ │ └── subdir/ │ │ ├── args │ │ ├── dummy │ │ └── file.c │ ├── cargo/ │ │ ├── Cargo.toml │ │ └── workspace_paths/ │ │ ├── Cargo.toml │ │ └── subpath/ │ │ └── Cargo.toml │ ├── ccls/ │ │ ├── with_build_dir/ │ │ │ └── unusual_build_dir_name/ │ │ │ └── compile_commands.json │ │ ├── with_ccls/ │ │ │ └── .ccls │ │ ├── with_ccls-root/ │ │ │ └── .ccls-root │ │ └── with_compile_commands_json/ │ │ └── compile_commands.json │ ├── checkstyle/ │ │ └── other_config.xml │ ├── clangd/ │ │ ├── with_build_dir/ │ │ │ └── unusual_build_dir_name/ │ │ │ └── compile_commands.json │ │ └── with_compile_commands/ │ │ └── compile_commands.json │ ├── clangformat/ │ │ └── with_clangformat/ │ │ └── .clang-format │ ├── cpp/ │ │ ├── .astylerc │ │ └── dummy.cpp │ ├── cppcheck/ │ │ ├── one/ │ │ │ ├── compile_commands.json │ │ │ └── two/ │ │ │ └── three/ │ │ │ ├── file.c │ │ │ └── file.cpp │ │ └── with_build_dir/ │ │ └── build/ │ │ └── compile_commands.json │ ├── cquery/ │ │ ├── build/ │ │ │ └── compile_commands.json │ │ └── with_cquery/ │ │ └── .cquery │ ├── csslint/ │ │ ├── other-app/ │ │ │ └── testfile.css │ │ └── some-app/ │ │ ├── .csslintrc │ │ └── subdir/ │ │ └── testfile.css │ ├── cucumber/ │ │ └── features/ │ │ ├── cuke.feature │ │ └── step_definitions/ │ │ └── base_steps.rb │ ├── d/ │ │ └── test.d │ ├── dart/ │ │ ├── .packages │ │ └── testfile.dart │ ├── dprint/ │ │ ├── blank.ts │ │ └── dprint.json │ ├── elixir/ │ │ ├── mix_project/ │ │ │ ├── lib/ │ │ │ │ └── app.ex │ │ │ └── mix.exs │ │ ├── testfile.ex │ │ └── umbrella_project/ │ │ ├── apps/ │ │ │ ├── app1/ │ │ │ │ ├── lib/ │ │ │ │ │ └── app.ex │ │ │ │ └── mix.exs │ │ │ └── app2/ │ │ │ ├── lib/ │ │ │ │ └── app.ex │ │ │ └── mix.exs │ │ └── mix.exs │ ├── elm/ │ │ ├── newapp/ │ │ │ ├── elm.json │ │ │ ├── src/ │ │ │ │ └── Main.elm │ │ │ └── tests/ │ │ │ └── TestSuite.elm │ │ ├── newapp-notests/ │ │ │ ├── elm.json │ │ │ └── tests/ │ │ │ └── TestMain.elm │ │ ├── oldapp/ │ │ │ ├── elm-package.json │ │ │ ├── src/ │ │ │ │ └── Main.elm │ │ │ └── tests/ │ │ │ └── TestSuite.elm │ │ └── src/ │ │ └── subdir/ │ │ └── testfile.elm │ ├── erlang/ │ │ ├── app_with_elvis_config/ │ │ │ └── elvis.config │ │ ├── app_with_erlang_ls_config/ │ │ │ ├── _build/ │ │ │ │ └── default/ │ │ │ │ └── lib/ │ │ │ │ └── dep/ │ │ │ │ └── erlang_ls.config │ │ │ ├── deps/ │ │ │ │ └── dep/ │ │ │ │ └── erlang_ls.config │ │ │ └── erlang_ls.config │ │ ├── app_with_erlfmt/ │ │ │ └── erlfmt │ │ ├── erlang_mk_app/ │ │ │ ├── deps/ │ │ │ │ └── dep/ │ │ │ │ └── erlang.mk │ │ │ └── erlang.mk │ │ ├── kerl_otp_root/ │ │ │ └── .kerl_config │ │ └── rebar3_app/ │ │ └── _checkouts/ │ │ └── dep/ │ │ └── _build/ │ │ └── .gitkeep │ ├── eruby/ │ │ └── dummy.html.erb │ ├── eslint/ │ │ ├── astro-app/ │ │ │ ├── .eslintrc.js │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ └── pages/ │ │ │ │ └── index.astro │ │ │ └── tsconfig.json │ │ ├── other-app/ │ │ │ └── subdir/ │ │ │ └── testfile.js │ │ ├── package.json │ │ ├── react-app/ │ │ │ ├── .eslintrc.js │ │ │ ├── subdir/ │ │ │ │ ├── testfile.css │ │ │ │ ├── testfile.js │ │ │ │ └── testfile.ts │ │ │ ├── subdir-with-config/ │ │ │ │ └── .eslintrc │ │ │ └── subdir-with-package-json/ │ │ │ └── package.json │ │ └── yarn2-app/ │ │ ├── .eslintrc.js │ │ ├── .yarn/ │ │ │ └── sdks/ │ │ │ └── eslint/ │ │ │ └── bin/ │ │ │ └── eslint.js │ │ └── subdir/ │ │ └── testfile.js │ ├── fecs/ │ │ └── fecs │ ├── fish/ │ │ └── testfile.fish │ ├── flow/ │ │ ├── a/ │ │ │ ├── .flowconfig │ │ │ └── sub/ │ │ │ └── dummy │ │ └── b/ │ │ └── sub/ │ │ └── dummy │ ├── fortls-project/ │ │ └── .fortls │ ├── gleam/ │ │ ├── gleam.toml │ │ └── testfile.gleam │ ├── go/ │ │ ├── go.mod │ │ ├── go1/ │ │ │ └── prj1/ │ │ │ └── file.go │ │ ├── go2/ │ │ │ └── prj2/ │ │ │ └── file.go │ │ ├── gopath/ │ │ │ └── bin/ │ │ │ ├── gopls │ │ │ └── staticcheck │ │ ├── testfile.go │ │ └── testfile2.go │ ├── gradle/ │ │ ├── build-gradle-project/ │ │ │ ├── build.gradle │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── kotlin/ │ │ │ └── dummy.kt │ │ ├── gradle │ │ ├── non-gradle-project/ │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── kotlin/ │ │ │ └── dummy.kt │ │ ├── settings-gradle-project/ │ │ │ ├── settings.gradle │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── kotlin/ │ │ │ └── dummy.kt │ │ ├── unwrapped-project/ │ │ │ ├── build.gradle │ │ │ ├── settings.gradle │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── kotlin/ │ │ │ └── dummy.kt │ │ └── wrapped-project/ │ │ ├── build.gradle │ │ ├── gradlew │ │ ├── settings.gradle │ │ └── src/ │ │ └── main/ │ │ └── kotlin/ │ │ └── dummy.kt │ ├── hamllint/ │ │ ├── haml-lint-and-rubocop/ │ │ │ ├── .haml-lint.yml │ │ │ ├── .rubocop.yml │ │ │ └── subdir/ │ │ │ └── file.haml │ │ ├── haml-lint-yml/ │ │ │ ├── .haml-lint.yml │ │ │ └── subdir/ │ │ │ └── file.haml │ │ └── rubocop-yml/ │ │ ├── .rubocop.yml │ │ └── subdir/ │ │ └── file.haml │ ├── haskell/ │ │ ├── haskell-packages-project/ │ │ │ ├── cabal.project │ │ │ └── package-a/ │ │ │ ├── package-a.cabal │ │ │ └── src/ │ │ │ └── folder/ │ │ │ └── dummy.hs │ │ └── haskell-simple-package/ │ │ └── package-a/ │ │ ├── package-a.cabal │ │ └── src/ │ │ └── folder/ │ │ └── dummy.hs │ ├── hdl_server/ │ │ ├── foo.vhd │ │ ├── with_config_file/ │ │ │ ├── .hdl_checker.config │ │ │ ├── _hdl_checker.config │ │ │ └── foo.vhd │ │ └── with_git/ │ │ └── files/ │ │ └── foo.vhd │ ├── hie_paths/ │ │ └── file.hs │ ├── html_beautify/ │ │ ├── html-beautify │ │ └── test.html │ ├── htmlhint/ │ │ └── with_config/ │ │ └── .htmlhintrc │ ├── ink/ │ │ └── story/ │ │ └── main.ink │ ├── inko/ │ │ ├── test.inko │ │ └── tests/ │ │ └── test/ │ │ └── test_foo.inko │ ├── java/ │ │ ├── no_main/ │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── something/ │ │ │ └── dummy │ │ ├── with_jaxb/ │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── something/ │ │ │ │ └── dummy │ │ │ └── jaxb/ │ │ │ └── com/ │ │ │ └── something/ │ │ │ └── dummy │ │ └── with_main/ │ │ ├── build/ │ │ │ ├── gen/ │ │ │ │ └── main/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── something/ │ │ │ │ └── dummy │ │ │ └── gen2/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── something/ │ │ │ └── dummy │ │ └── src/ │ │ ├── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── something/ │ │ │ └── dummy │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── something/ │ │ └── dummy │ ├── javascript/ │ │ └── test.js │ ├── javascript_deno/ │ │ ├── custom_import_map.json │ │ ├── import_map.json │ │ ├── main.js │ │ └── tsconfig.json │ ├── json/ │ │ └── testfile.json │ ├── jsonlint/ │ │ ├── app/ │ │ │ └── src/ │ │ │ └── app.json │ │ └── app-without-jsonlint/ │ │ └── src/ │ │ └── app.json │ ├── julia/ │ │ ├── REQUIRE │ │ └── test.jl │ ├── kotlin/ │ │ └── testfile.kt │ ├── lean/ │ │ ├── lakefile_lean/ │ │ │ ├── Main.lean │ │ │ └── lakefile.lean │ │ └── lakefile_toml/ │ │ ├── Main.lean │ │ └── lakefile.toml │ ├── long-line/ │ │ └── setup.cfg │ ├── lua/ │ │ └── testfile.lua │ ├── markdown/ │ │ └── testfile.md │ ├── maven/ │ │ ├── maven-java-project/ │ │ │ ├── module1/ │ │ │ │ ├── mvnw │ │ │ │ ├── mvnw.cmd │ │ │ │ ├── pom.xml │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ └── java/ │ │ │ │ └── dummy1.java │ │ │ └── module2/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── dummy2.java │ │ ├── maven-kotlin-project/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── kotlin/ │ │ │ └── dummy.kt │ │ ├── mvn │ │ └── non-maven-project/ │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── dummy.java │ ├── nim/ │ │ └── with-git/ │ │ └── src/ │ │ └── source.nim │ ├── ocaml/ │ │ └── testfile.ml │ ├── ocamllsp/ │ │ └── dune-project │ ├── odin/ │ │ └── main.odin │ ├── ols/ │ │ └── .merlin │ ├── openscad/ │ │ └── dummy.scad │ ├── pascal/ │ │ └── test.pas │ ├── perl/ │ │ ├── dist-zilla/ │ │ │ ├── dist.ini │ │ │ └── subdir/ │ │ │ └── empty.pl │ │ ├── extutils-makemaker/ │ │ │ ├── Makefile.PL │ │ │ └── subdir/ │ │ │ └── empty.pl │ │ └── module-build/ │ │ ├── Build.PL │ │ └── subdir/ │ │ └── empty.pl │ ├── php/ │ │ ├── project-with-php-cs-fixer/ │ │ │ ├── test.php │ │ │ └── vendor/ │ │ │ └── bin/ │ │ │ └── php-cs-fixer │ │ ├── project-with-phpcbf/ │ │ │ ├── foo/ │ │ │ │ └── test.php │ │ │ └── vendor/ │ │ │ └── bin/ │ │ │ └── phpcbf │ │ ├── project-with-pint/ │ │ │ ├── test.php │ │ │ └── vendor/ │ │ │ └── bin/ │ │ │ └── pint │ │ ├── project-without-php-cs-fixer/ │ │ │ └── test.php │ │ ├── project-without-phpcbf/ │ │ │ └── foo/ │ │ │ └── test.php │ │ ├── project-without-pint/ │ │ │ └── test.php │ │ ├── vendor/ │ │ │ └── bin/ │ │ │ └── php-language-server.php │ │ ├── with-composer/ │ │ │ ├── composer.json │ │ │ └── vendor/ │ │ │ └── bin/ │ │ │ └── php-language-server.php │ │ └── with-git/ │ │ └── vendor/ │ │ └── bin/ │ │ └── php-language-server.php │ ├── phpcs/ │ │ ├── project-with-phpcs/ │ │ │ ├── foo/ │ │ │ │ └── test.php │ │ │ └── vendor/ │ │ │ └── bin/ │ │ │ └── phpcs │ │ └── project-without-phpcs/ │ │ └── foo/ │ │ └── test.php │ ├── prettier/ │ │ ├── testfile │ │ ├── testfile.css │ │ ├── testfile.js │ │ ├── testfile.json │ │ ├── testfile.scss │ │ ├── testfile.ts │ │ ├── with_config/ │ │ │ ├── .prettierrc │ │ │ └── testfile.js │ │ └── with_prettierignore/ │ │ ├── .prettierignore │ │ └── src/ │ │ └── testfile.js │ ├── proto/ │ │ └── testfile.proto │ ├── psalm/ │ │ └── vendor/ │ │ └── bin/ │ │ └── psalm │ ├── puglint/ │ │ ├── package.json │ │ ├── puglint_rc_dir/ │ │ │ └── .pug-lintrc │ │ ├── puglint_rc_js_dir/ │ │ │ └── .pug-lintrc.js │ │ └── puglint_rc_json_dir/ │ │ └── .pug-lintrc.json │ ├── puppet/ │ │ ├── dummy.pp │ │ ├── new-style-module/ │ │ │ ├── lib/ │ │ │ │ └── puppet/ │ │ │ │ └── types/ │ │ │ │ └── exampletype.rb │ │ │ ├── metadata.json │ │ │ └── template/ │ │ │ └── template.epp │ │ └── old-style-module/ │ │ ├── manifests/ │ │ │ └── init.pp │ │ └── templates/ │ │ └── template.epp │ ├── purescript/ │ │ ├── bower/ │ │ │ ├── Foo.purs │ │ │ └── bower.json │ │ ├── psc-package/ │ │ │ ├── Foo.purs │ │ │ └── psc-package.json │ │ └── spago/ │ │ ├── Foo.purs │ │ └── spago.dhall │ ├── python/ │ │ ├── namespace_package_manifest/ │ │ │ ├── MANIFEST.in │ │ │ └── namespace/ │ │ │ └── foo/ │ │ │ ├── __init__.py │ │ │ └── bar.py │ │ ├── namespace_package_pytest/ │ │ │ ├── namespace/ │ │ │ │ └── foo/ │ │ │ │ ├── __init__.py │ │ │ │ └── bar.py │ │ │ └── pytest.ini │ │ ├── namespace_package_setup/ │ │ │ ├── namespace/ │ │ │ │ └── foo/ │ │ │ │ ├── __init__.py │ │ │ │ └── bar.py │ │ │ └── setup.cfg │ │ ├── namespace_package_tox/ │ │ │ ├── namespace/ │ │ │ │ └── foo/ │ │ │ │ ├── __init__.py │ │ │ │ └── bar.py │ │ │ └── tox.ini │ │ ├── no_virtualenv/ │ │ │ └── subdir/ │ │ │ └── foo/ │ │ │ ├── COMMIT_EDITMSG │ │ │ ├── __init__.py │ │ │ └── bar.py │ │ ├── pyre_configuration_dir/ │ │ │ ├── .pyre_configuration.local │ │ │ └── foo/ │ │ │ ├── __init__.py │ │ │ └── bar.py │ │ ├── python-package-project/ │ │ │ ├── .flake8 │ │ │ └── package-name/ │ │ │ └── module.py │ │ ├── with_bandit/ │ │ │ ├── .bandit │ │ │ └── namespace/ │ │ │ └── foo/ │ │ │ ├── __init__.py │ │ │ └── bar.py │ │ ├── with_mypy_ini_and_pytest_ini/ │ │ │ ├── mypy.ini │ │ │ └── tests/ │ │ │ ├── pytest.ini │ │ │ └── testsubfolder/ │ │ │ └── my_tests.py │ │ └── with_virtualenv/ │ │ ├── dir_with_yapf_config/ │ │ │ └── .style.yapf │ │ ├── env/ │ │ │ ├── Scripts/ │ │ │ │ └── activate │ │ │ └── bin/ │ │ │ ├── activate │ │ │ ├── autoflake │ │ │ ├── autoimport │ │ │ ├── autopep8 │ │ │ ├── black │ │ │ ├── flake8 │ │ │ ├── flakehell │ │ │ ├── gitlint │ │ │ ├── isort │ │ │ ├── jedi-language-server │ │ │ ├── mypy │ │ │ ├── pycln │ │ │ ├── pyflakes │ │ │ ├── pylama │ │ │ ├── pylint │ │ │ ├── pylsp │ │ │ ├── pyre │ │ │ ├── pyrefly │ │ │ ├── pyright-langserver │ │ │ ├── refurb │ │ │ ├── reorder-python-imports │ │ │ ├── ruff │ │ │ ├── tidy-imports │ │ │ ├── unimport │ │ │ ├── vulture │ │ │ ├── yamlfix │ │ │ └── yapf │ │ └── subdir/ │ │ └── foo/ │ │ ├── COMMIT_EDITMSG │ │ ├── __init__.py │ │ ├── bar.py │ │ └── bar.pyi │ ├── r/ │ │ └── .Rprofile │ ├── racket/ │ │ ├── many-inits/ │ │ │ ├── a/ │ │ │ │ ├── b/ │ │ │ │ │ ├── c/ │ │ │ │ │ │ ├── foo.rkt │ │ │ │ │ │ └── init.rkt │ │ │ │ │ ├── foo.rkt │ │ │ │ │ └── init.rkt │ │ │ │ ├── foo.rkt │ │ │ │ └── init.rkt │ │ │ ├── foo.rkt │ │ │ └── init.rkt │ │ └── simple-script/ │ │ └── foo.rkt │ ├── reasonml/ │ │ ├── bsconfig.json │ │ └── testfile.re │ ├── rescript/ │ │ ├── rescript.json │ │ ├── testfile-noextension │ │ ├── testfile.res │ │ └── testfile.resi │ ├── roc/ │ │ └── main.roc │ ├── ruby/ │ │ ├── dummy.rb │ │ ├── nested/ │ │ │ ├── dummy.rb │ │ │ └── foo/ │ │ │ ├── Steepfile │ │ │ ├── dummy.rb │ │ │ ├── one/ │ │ │ │ └── dummy.rb │ │ │ └── two/ │ │ │ ├── Steepfile │ │ │ ├── dummmy.rb │ │ │ └── three/ │ │ │ └── dummy.rb │ │ ├── not_a_rails_app/ │ │ │ └── file.rb │ │ ├── valid_rails_app/ │ │ │ ├── app/ │ │ │ │ ├── dummy.rb │ │ │ │ ├── models/ │ │ │ │ │ └── thing.rb │ │ │ │ └── views/ │ │ │ │ └── my_great_view.html.erb │ │ │ ├── config/ │ │ │ │ └── dummy.rb │ │ │ └── db/ │ │ │ └── dummy.rb │ │ ├── valid_ruby_app1/ │ │ │ ├── Rakefile │ │ │ └── lib/ │ │ │ └── file.rb │ │ ├── valid_ruby_app2/ │ │ │ ├── Gemfile │ │ │ └── lib/ │ │ │ └── file.rb │ │ ├── valid_ruby_app3/ │ │ │ ├── .solargraph.yml │ │ │ └── lib/ │ │ │ └── file.rb │ │ └── with_config/ │ │ ├── .rubocop.yml │ │ └── .standard.yml │ ├── rust/ │ │ ├── cargo/ │ │ │ ├── Cargo.toml │ │ │ └── testfile.rs │ │ └── rust-project/ │ │ ├── rust-project.json │ │ └── testfile.rs │ ├── rustywind/ │ │ └── test.html │ ├── scala/ │ │ ├── dummy.scala │ │ ├── invalid_sbt_project/ │ │ │ └── Main.scala │ │ └── valid_sbt_project/ │ │ ├── Main.scala │ │ └── build.sbt │ ├── slimlint/ │ │ ├── .rubocop.yml │ │ └── subdir/ │ │ └── file.slim │ ├── smlnj/ │ │ ├── cm/ │ │ │ ├── foo.sml │ │ │ ├── path/ │ │ │ │ └── to/ │ │ │ │ └── bar.sml │ │ │ └── sources.cm │ │ └── file/ │ │ └── qux.sml │ ├── solhint/ │ │ ├── Contract.sol │ │ └── package.json │ ├── spectral/ │ │ └── openapi.yaml │ ├── stack/ │ │ └── stack.yaml │ ├── stylua/ │ │ ├── stylua_config_dir/ │ │ │ └── stylua.toml │ │ └── stylua_dot_config_dir/ │ │ └── .stylua.toml │ ├── swaglint/ │ │ └── docs/ │ │ └── swagger.yaml │ ├── swift/ │ │ ├── dummy.swift │ │ ├── non-swift-package-project/ │ │ │ └── src/ │ │ │ └── folder/ │ │ │ └── dummy.swift │ │ ├── swift-package-project/ │ │ │ ├── Package.swift │ │ │ └── src/ │ │ │ └── folder/ │ │ │ └── dummy.swift │ │ └── swift-package-project-with-config/ │ │ ├── .swift-format │ │ ├── Package.swift │ │ └── src/ │ │ └── folder/ │ │ └── dummy.swift │ ├── swiftlint/ │ │ ├── cocoapods/ │ │ │ └── Pods/ │ │ │ └── SwiftLint/ │ │ │ └── swiftlint │ │ ├── cocoapods-and-react-native/ │ │ │ ├── Pods/ │ │ │ │ └── SwiftLint/ │ │ │ │ └── swiftlint │ │ │ └── ios/ │ │ │ └── Pods/ │ │ │ └── SwiftLint/ │ │ │ └── swiftlint │ │ └── react-native/ │ │ └── ios/ │ │ └── Pods/ │ │ └── SwiftLint/ │ │ └── swiftlint │ ├── terraform/ │ │ ├── .terraform/ │ │ │ └── dummy │ │ └── main.tf │ ├── tex/ │ │ ├── sample1.tex │ │ ├── sample2.tex │ │ └── testfile.tex │ ├── tflint/ │ │ └── foo/ │ │ ├── .tflint.hcl │ │ └── bar.tf │ ├── tfsec/ │ │ ├── json/ │ │ │ ├── .tfsec/ │ │ │ │ └── config.json │ │ │ └── main.tf │ │ └── yml/ │ │ ├── .tfsec/ │ │ │ └── config.yml │ │ └── main.tf │ ├── tidy/ │ │ ├── .tidyrc │ │ ├── test.html │ │ └── tidy │ ├── toml/ │ │ └── tombi/ │ │ ├── pyprojecttoml/ │ │ │ ├── pyproject.toml │ │ │ └── subdir/ │ │ │ └── file.toml │ │ └── tombitoml/ │ │ ├── subdir/ │ │ │ └── file.toml │ │ └── tombi.toml │ ├── top/ │ │ ├── ale-special-directory-name-dont-use-this-please/ │ │ │ └── empty-file │ │ ├── example.ini │ │ ├── middle/ │ │ │ └── bottom/ │ │ │ └── dummy.txt │ │ ├── needle_dir/ │ │ │ ├── needle │ │ │ └── target/ │ │ │ ├── needle/ │ │ │ │ └── .gitkeep │ │ │ └── query/ │ │ │ └── buffer.txt │ │ └── needle_file/ │ │ ├── needle/ │ │ │ └── .gitkeep │ │ └── target/ │ │ ├── needle │ │ └── query/ │ │ └── buffer.txt │ ├── tsserver/ │ │ ├── src/ │ │ │ ├── file1.ts │ │ │ └── level-1/ │ │ │ ├── file2.ts │ │ │ ├── level-2/ │ │ │ │ └── file3.ts │ │ │ └── tsconfig.json │ │ └── tsconfig.json │ ├── typescript/ │ │ ├── custom_import_map.json │ │ ├── import_map.json │ │ ├── test.ts │ │ └── tsconfig.json │ ├── verilog/ │ │ └── verible/ │ │ ├── module.sv │ │ └── verible.filelist │ ├── vim/ │ │ ├── invalid_vim_project/ │ │ │ └── test.vim │ │ ├── path_with_autoload/ │ │ │ ├── autoload/ │ │ │ │ └── test.vim │ │ │ └── test.vim │ │ ├── path_with_initvim/ │ │ │ └── init.vim │ │ ├── path_with_plugin/ │ │ │ ├── plugin/ │ │ │ │ └── test.vim │ │ │ └── test.vim │ │ └── path_with_vimrc/ │ │ └── .vimrc │ ├── volar/ │ │ ├── package.json │ │ └── src/ │ │ └── App.vue │ ├── xml/ │ │ └── dummy.xml │ ├── xo/ │ │ └── monorepo/ │ │ ├── package.json │ │ └── packages/ │ │ └── a/ │ │ ├── index.js │ │ ├── index.ts │ │ └── package.json │ ├── yaml/ │ │ └── test.yaml │ ├── yara/ │ │ └── dummy.yar │ └── zig/ │ └── build.zig ├── test_ale_has.vader ├── test_ale_info.vader ├── test_ale_info_to_clipboard.vader ├── test_ale_lint_command.vader ├── test_ale_lint_stop_command.vader ├── test_ale_populate_command.vader ├── test_ale_toggle.vader ├── test_ale_var.vader ├── test_alejobstarted_autocmd.vader ├── test_alelint_autocmd.vader ├── test_ant_build_classpath_command.vader ├── test_ant_find_project_root.vader ├── test_autocmd_commands.vader ├── test_balloon_messages.vader ├── test_c_flag_parsing.vader ├── test_cleanup.vader ├── test_code_action.vader ├── test_code_action_corner_cases.vader ├── test_codefix.vader ├── test_computed_lint_file_values.vader ├── test_cursor_warnings.vader ├── test_deferred_command_string.vader ├── test_deferred_executable_string.vader ├── test_deno_executable_detection.vader ├── test_disabling_ale.vader ├── test_env_function.vader ├── test_errors_removed_after_filetype_changed.vader ├── test_filename_mapping.vader ├── test_filerename.vader ├── test_filetype_guessing.vader ├── test_filetype_linter_defaults.vader ├── test_find_nearest_directory.vader ├── test_find_nearest_file.vader ├── test_find_nearest_file_or_directory.vader ├── test_find_references.vader ├── test_floating_preview.vader ├── test_format_command.vader ├── test_format_temporary_file_creation.vader ├── test_function_arg_count.vader ├── test_fuzzy_json_decode.vader ├── test_get_abspath.vader ├── test_get_loclist.vader ├── test_getmatches.vader ├── test_go_to_definition.vader ├── test_gradle_build_classpath_command.vader ├── test_gradle_find_executable.vader ├── test_gradle_find_project_root.vader ├── test_helptags.vader ├── test_highlight_placement.vader ├── test_highlight_position_chunking.vader ├── test_history_saving.vader ├── test_hover.vader ├── test_hover_parsing.vader ├── test_ignoring_linters.vader ├── test_line_join.vader ├── test_lint_file_linters.vader ├── test_lint_on_enter_when_file_changed.vader ├── test_lint_on_filetype_changed.vader ├── test_linter_defintion_processing.vader ├── test_linter_retrieval.vader ├── test_linter_type_mapping.vader ├── test_linting_blacklist.vader ├── test_linting_updates_loclist.vader ├── test_list_formatting.vader ├── test_list_opening.vader ├── test_list_titles.vader ├── test_load_all_linters.vader ├── test_loclist_binary_search.vader ├── test_loclist_corrections.vader ├── test_loclist_jumping.vader ├── test_loclist_sorting.vader ├── test_maven_build_classpath_command.vader ├── test_maven_find_executable.vader ├── test_maven_find_project_root.vader ├── test_neovim_diagnostics.vader ├── test_no_linting_on_write_quit.vader ├── test_organize_imports.vader ├── test_other_sources.vader ├── test_parse_command_args.vader ├── test_path_dirname.vader ├── test_path_equality.vader ├── test_path_upwards.vader ├── test_path_uri.vader ├── test_pattern_options.vader ├── test_prepare_command.vader ├── test_proselint_get_command.vader ├── test_proselint_get_executable.vader ├── test_python_pipenv.vader ├── test_python_poetry.vader ├── test_python_traceback.vader ├── test_python_uv.vader ├── test_python_virtualenv.vader ├── test_quickfix_deduplication.vader ├── test_quitting_variable.vader ├── test_redundant_tsserver_rendering_avoided.vader ├── test_regex_escaping.vader ├── test_rename.vader ├── test_resolve_local_path.vader ├── test_results_not_cleared_when_opening_loclist.vader ├── test_sandbox_execution.vader ├── test_semver_utils.vader ├── test_set_list_timers.vader ├── test_setting_loclist_from_another_buffer.vader ├── test_setting_problems_found_in_previous_buffers.vader ├── test_shell_detection.vader ├── test_should_do_nothing_conditions.vader ├── test_sml_command.vader ├── test_socket_connections.vader ├── test_statusline.vader ├── test_swift_find_project_root.vader ├── test_symbol_search.vader ├── test_temporary_file_management.vader ├── test_tmpdir_wrapper.vader ├── test_vim8_processid_parsing.vader ├── test_virtualtext.vader ├── test_windows_escaping.vader ├── test_wrap_comand.vader ├── test_writefile_function.vader ├── util/ │ └── test_cd_string_commands.vader ├── v_files/ │ └── testfile.v └── vimrc ================================================ FILE CONTENTS ================================================ ================================================ FILE: AGENTS.md ================================================ # ALE Agent instructions 1. Read documentation from `doc/ale-development.txt` to understand how to be an ALE developer. 2. Run Vader/Vim tests with `./run-tests -q --fast test/path/some_file.vader` 3. When editing Lua code run Lua tests with `./run-tests -q --lua-only` ================================================ FILE: Dockerfile ================================================ ARG TESTBED_VIM_VERSION=24 FROM testbed/vim:${TESTBED_VIM_VERSION} ENV PACKAGES="\ lua5.1 \ lua5.1-dev \ lua5.1-busted \ bash \ git \ python2 \ python3 \ py3-pip \ grep \ sed \ " RUN apk --update add $PACKAGES && \ rm -rf /var/cache/apk/* /tmp/* /var/tmp/* RUN install_vim -tag v8.0.0027 -build \ -tag v9.0.0297 -build \ -tag neovim:v0.7.0 -build \ -tag neovim:v0.8.0 -build RUN pip install vim-vint==0.3.21 RUN git clone https://github.com/junegunn/vader.vim vader && \ cd vader && git checkout c6243dd81c98350df4dec608fa972df98fa2a3af ARG GIT_VERSION LABEL Version=${GIT_VERSION} LABEL Name=denseanalysis/ale ================================================ FILE: LICENSE ================================================ Copyright (c) 2016-2023, Dense Analysis All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # Asynchronous Lint Engine [![Vim](https://img.shields.io/badge/VIM-%2311AB00.svg?style=for-the-badge&logo=vim&logoColor=white)](https://www.vim.org/) [![Neovim](https://img.shields.io/badge/NeoVim-%2357A143.svg?&style=for-the-badge&logo=neovim&logoColor=white)](https://neovim.io/) [![CI](https://img.shields.io/github/actions/workflow/status/dense-analysis/ale/main.yml?branch=master&label=CI&logo=github&style=for-the-badge)](https://github.com/dense-analysis/ale/actions?query=event%3Apush+workflow%3ACI+branch%3Amaster++) [![AppVeyor Build Status](https://img.shields.io/appveyor/build/dense-analysis/ale?label=Windows&style=for-the-badge)](https://ci.appveyor.com/project/dense-analysis/ale) [![Join the Dense Analysis Discord server](https://img.shields.io/badge/chat-Discord-5865F2?style=for-the-badge&logo=appveyor)](https://discord.gg/5zFD6pQxDk) ![ALE Logo by Mark Grealish - https://www.bhalash.com/](https://user-images.githubusercontent.com/3518142/59195920-2c339500-8b85-11e9-9c22-f6b7f69637b8.jpg) ALE (Asynchronous Lint Engine) is a plugin providing linting (syntax checking and semantic errors) in Neovim 0.7.0+ and Vim 8.0+ while you edit your text files, and acts as a Vim [Language Server Protocol](https://langserver.org/) client. 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 text is changed in Vim. This allows for displaying warnings and errors in files being edited in Vim before files have been saved back to a filesystem. In other words, this plugin allows you to lint while you type. ALE offers support for fixing code with command line tools in a non-blocking manner with the `:ALEFix` feature, supporting tools in many languages, like `prettier`, `eslint`, `autopep8`, and more. ALE acts as a "language client" to support a variety of Language Server Protocol features, including: * Diagnostics (via Language Server Protocol linters) * Go To Definition (`:ALEGoToDefinition`) * Completion (Built in completion support, or with Deoplete) * 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. **Help Wanted:** If you would like to help maintain this plugin by managing the many issues and pull requests that are submitted, please send the author an email at [dev@w0rp.com](mailto:dev@w0rp.com?subject=Helping%20with%20ALE). If you enjoy this plugin, feel free to contribute or check out the author's other content at [w0rp.com](https://w0rp.com). ## Why ALE? ALE has been around for many years, and there are many ways to run asynchronous linting and fixing of code in Vim. ALE offers the following. * No dependencies for ALE itself * Lightweight plugin architecture (No JavaScript or Python required) * Low memory footprint * Runs virtually everywhere, including remote shells, and in `git commit` * Out of the box support for running particular linters and language servers * Near-zero configuration with custom code for better defaults * Highly customizable and well-documented (`:help ale-options`) * Breaking changes for the plugin are extremely rare * Integrates with Neovim's LSP client (0.8+) and diagnostics (0.7+) * Support for older Vim and Neovim versions * Windows support * Well-integrated with other plugins ## Sponsorship If you would like to donate to Dense Analysis to say thank you for ALE, please consider visiting our [Sponsorship page](https://denseanalysis.org/sponsors/). Funds will be used to pay for our hosting fees and research. Whilst visiting our site, please feel free to make use of our educational resources and other recommended tools. ## Supported Languages and Tools ALE supports a wide variety of languages and tools. See the [full list](supported-tools.md) in the [Supported Languages and Tools](supported-tools.md) page. ## Usage ### Linting Once this plugin is installed, while editing your files in supported languages and tools which have been correctly installed, this plugin will send the contents of your text buffers to a variety of programs for checking the syntax and semantics of your programs. By default, linters will be re-run in the background to check your syntax when you open new buffers or as you make edits to your files. The behavior of linting can be configured with a variety of options, documented in [the Vim help file](doc/ale.txt). For more information on the options ALE offers, consult `:help ale-options` for global options and `:help ale-integration-options` for options specified to particular linters. ### Fixing ALE can fix files with the `ALEFix` command. Functions need to be configured either in each buffer with a `b:ale_fixers`, or globally with `g:ale_fixers`. The recommended way to configure fixers is to define a List in an ftplugin file. ```vim " In ~/.vim/ftplugin/javascript.vim, or somewhere similar. " Fix files with prettier, and then ESLint. let b:ale_fixers = ['prettier', 'eslint'] " Equivalent to the above. 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. 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'], \} ``` If you want to automatically fix files when you save them, you need to turn a setting on in vimrc. ```vim " Set this variable to 1 to fix files when you save them. let g:ale_fix_on_save = 1 ``` The `:ALEFixSuggest` command will suggest some supported tools for fixing code. Both `g:ale_fixers` and `b:ale_fixers` can also accept functions, including lambda functions, as fixers, for fixing files with custom tools. See `:help ale-fix` for complete information on how to fix files with ALE. ### Completion ALE offers some support for completion via hijacking of omnicompletion while you type. All of ALE's completion information must come from Language Server Protocol linters, or from `tsserver` for TypeScript. When running ALE in Neovim 0.8+, ALE will integrate with Neovim's LSP client by default, and any auto-completion plugin that uses the native LSP client will work when ALE runs language servers. [nvim-cmp](https://github.com/hrsh7th/nvim-cmp) is recommended as a completion plugin worth trying in Neovim. ALE integrates with [Deoplete](https://github.com/Shougo/deoplete.nvim) as a completion source, named `'ale'`. You can configure Deoplete to only use ALE as the source of completion information, or mix it with other sources. ```vim " Use ALE and also some plugin 'foobar' as completion sources for all code. call deoplete#custom#option('sources', { \ '_': ['ale', 'foobar'], \}) ``` ALE also offers its own automatic completion support, which does not require any other plugins, and can be enabled by changing a setting before ALE is loaded. ```vim " Enable completion where available. " This setting must be set before ALE is loaded. " " You should not turn this setting on if you wish to use ALE as a completion " source for other completion plugins, like Deoplete. let g:ale_completion_enabled = 1 ``` ALE provides an omni-completion function you can use for triggering completion manually with ``. ```vim set omnifunc=ale#completion#OmniFunc ``` ALE supports automatic imports from external modules. This behavior is enabled by default and can be disabled by setting: ```vim let g:ale_completion_autoimport = 0 ``` Note that disabling auto import can result in missing completion items from some LSP servers (e.g. eclipselsp). See `:help ale-completion` for more information. ### Go To Definition ALE supports jumping to the definition of words under your cursor with the `:ALEGoToDefinition` command using any enabled Language Server Protocol linters and `tsserver`. In Neovim 0.8+, you can also use Neovim's built in `gd` keybind and more. See `:help ale-go-to-definition` for more information. ### Find References ALE supports finding references for words under your cursor with the `:ALEFindReferences` command using any enabled Language Server Protocol linters and `tsserver`. See `:help ale-find-references` for more information. ### Hovering 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. Truncated information will be displayed when the cursor rests on a symbol by default, as long as there are no problems on the same line. 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. ### 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. ### Refactoring: Rename, Actions ALE supports renaming symbols in code such as variables or class names with the `ALERename` command. `ALEFileRename` will rename file and fix import paths (tsserver only). `ALECodeAction` will execute actions on the cursor or applied to a visual range selection, such as automatically fixing errors. See `:help ale-refactor` for more information. ## Installation Add ALE to your runtime path in the usual ways. If you have trouble reading `:help ale`, try the following. ```vim packloadall | silent! helptags ALL ``` #### Vim `packload`: ```bash mkdir -p ~/.vim/pack/git-plugins/start git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.vim/pack/git-plugins/start/ale ``` #### Neovim `packload`: ```bash mkdir -p ~/.local/share/nvim/site/pack/git-plugins/start git clone --depth 1 https://github.com/dense-analysis/ale.git ~/.local/share/nvim/site/pack/git-plugins/start/ale ``` #### Windows `packload`: ```bash # Run these commands in the "Git for Windows" Bash terminal mkdir -p ~/vimfiles/pack/git-plugins/start git clone --depth 1 https://github.com/dense-analysis/ale.git ~/vimfiles/pack/git-plugins/start/ale ``` #### [vim-plug](https://github.com/junegunn/vim-plug) ```vim Plug 'dense-analysis/ale' ``` #### [Vundle](https://github.com/VundleVim/Vundle.vim) ```vim Plugin 'dense-analysis/ale' ``` #### [Pathogen](https://github.com/tpope/vim-pathogen) ```vim git clone https://github.com/dense-analysis/ale ~/.vim/bundle/ale ``` #### [lazy.nvim](https://github.com/folke/lazy.nvim) ```lua { 'dense-analysis/ale', config = function() -- Configuration goes here. local g = vim.g g.ale_ruby_rubocop_auto_correct_all = 1 g.ale_linters = { ruby = {'rubocop', 'ruby'}, lua = {'lua_language_server'} } end } ``` ## Contributing If you would like to see support for more languages and tools, please [create an issue](https://github.com/dense-analysis/ale/issues) or [create a pull request](https://github.com/dense-analysis/ale/pulls). If your tool can read from stdin or you have code to suggest which is good, support can be happily added for it. If you are interested in the general direction of the project, check out the [wiki home page](https://github.com/dense-analysis/ale/wiki). The wiki includes a Roadmap for the future, and more. If you'd liked to discuss ALE and more check out the Dense Analysis Discord server here: https://discord.gg/5zFD6pQxDk ## FAQ ### How do I disable particular linters? By default, all available tools for all supported languages will be run. If you want to only select a subset of the tools, you can define `b:ale_linters` for a single buffer, or `g:ale_linters` globally. The recommended way to configure linters is to define a List in an ftplugin file. ```vim " In ~/.vim/ftplugin/javascript.vim, or somewhere similar. " Enable ESLint only for JavaScript. let b:ale_linters = ['eslint'] " Equivalent to the above. let b:ale_linters = {'javascript': ['eslint']} ``` You can also declare which linters you want to run in your vimrc file, before or after ALE has been loaded. ```vim " In ~/.vim/vimrc, or somewhere similar. let g:ale_linters = { \ 'javascript': ['eslint'], \} ``` For all languages unspecified in the dictionary, all possible linters will be run for those languages, just as when the dictionary is not defined. Running many linters should not typically obstruct editing in Vim, as they will all be executed in separate processes simultaneously. If you don't want ALE to run anything other than what you've explicitly asked for, you can set `g:ale_linters_explicit` to `1`. ```vim " Only run linters named in ale_linters settings. let g:ale_linters_explicit = 1 ``` This plugin will look for linters in the [`ale_linters`](ale_linters) directory. Each directory within corresponds to a particular filetype in Vim, and each file in each directory corresponds to the name of a particular linter. ### How do I disable a particular warning or error? Warnings and errors should be configured in project configuration files for the relevant tools. ALE supports disabling only warnings relating to trailing whitespace, which Vim users often fix automatically. ```vim " Disable whitespace warnings let g:ale_warn_about_trailing_whitespace = 0 ``` Users generally should not ignore warnings or errors in projects by changing settings in their own editor. Instead, configure tools appropriately so any other user of the same project will see the same problems. ### How can I see what ALE has configured for the current file? Run the following to see what is currently configured: ```vim :ALEInfo ``` ### How can I disable virtual text appearing at ends of lines? By default, ALE displays errors and warnings with virtual text. The problems ALE shows appear with comment-like syntax after every problem found. You can set ALE to only show problems where the cursor currently lies like so. ```vim let g:ale_virtualtext_cursor = 'current' ``` If you want to disable virtual text completely, apply the following. ```vim let g:ale_virtualtext_cursor = 'disabled' ``` ### How can I customise signs? Use these options to specify what text should be used for signs: ```vim let g:ale_sign_error = '>>' let g:ale_sign_warning = '--' ``` ALE sets some background colors automatically for warnings and errors in the sign gutter, with the names `ALEErrorSign` and `ALEWarningSign`. These colors can be customised, or even removed completely: ```vim highlight clear ALEErrorSign highlight clear ALEWarningSign ``` You can configure the sign gutter open at all times, if you wish. ```vim let g:ale_sign_column_always = 1 ``` ### How can I change or disable the highlights ALE uses? ALE's highlights problems with highlight groups which link to `SpellBad`, `SpellCap`, `error`, and `todo` groups by default. The characters that are highlighted depend on the linters being used, and the information provided to ALE. Highlighting can be disabled completely by setting `g:ale_set_highlights` to `0`. ```vim " Set this in your vimrc file to disabling highlighting let g:ale_set_highlights = 0 ``` You can control all of the highlights ALE uses, say if you are using a different color scheme which produces ugly highlights. For example: ```vim highlight ALEWarning ctermbg=DarkMagenta ``` See `:help ale-highlights` for more information. ### How can I change the format for echo messages? There are 3 global options that allow customizing the echoed message. - `g:ale_echo_msg_format` where: * `%s` is the error message itself * `%...code...%` is an optional error code, and most characters can be written between the `%` characters. * `%linter%` is the linter name * `%severity%` is the severity type - `g:ale_echo_msg_error_str` is the string used for error severity. - `g:ale_echo_msg_warning_str` is the string used for warning severity. So for example this: ```vim let g:ale_echo_msg_error_str = 'E' let g:ale_echo_msg_warning_str = 'W' let g:ale_echo_msg_format = '[%linter%] %s [%severity%]' ``` Will give you: ![Echoed message](https://user-images.githubusercontent.com/3518142/59195927-348bd000-8b85-11e9-88b6-508a094f1548.png) See `:help g:ale_echo_msg_format` for more information. ### How can I customise the statusline? #### lightline [lightline](https://github.com/itchyny/lightline.vim) does not have built-in support for ALE, nevertheless there is a plugin that adds this functionality: [maximbaz/lightline-ale](https://github.com/maximbaz/lightline-ale). For more information, check out the sources of that plugin, `:help ale#statusline#Count()` and [lightline documentation](https://github.com/itchyny/lightline.vim#advanced-configuration). #### vim-airline [vim-airline](https://github.com/vim-airline/vim-airline) integrates with ALE for displaying error information in the status bar. If you want to see the status for ALE in a nice format, it is recommended to use vim-airline with ALE. The airline extension can be enabled by adding the following to your vimrc: ```vim " Set this. Airline will handle the rest. let g:airline#extensions#ale#enabled = 1 ``` #### Custom statusline You can implement your own statusline function without adding any other plugins. ALE provides some functions to assist in this endeavour, including: * `ale#statusline#Count`: Which returns the number of problems found by ALE for a specified buffer. * `ale#statusline#FirstProblem`: Which returns a dictionary containing the full loclist details of the first problem of a specified type found by ALE in a buffer. (e.g. The first style warning in the current buffer.) This can be useful for displaying more detailed information such as the line number of the first problem in a file. Say you want to display all errors as one figure, and all non-errors as another figure. You can do the following: ```vim function! LinterStatus() abort let l:counts = ale#statusline#Count(bufnr('')) let l:all_errors = l:counts.error + l:counts.style_error let l:all_non_errors = l:counts.total - l:all_errors return l:counts.total == 0 ? 'OK' : printf( \ '%dW %dE', \ all_non_errors, \ all_errors \) endfunction set statusline=%{LinterStatus()} ``` See `:help ale#statusline#Count()` or `:help ale#statusline#FirstProblem()` for more information. ### How can I change the borders for floating preview windows? Borders for floating preview windows are enabled by default. You can use the `g:ale_floating_window_border` setting to configure them. You could disable the border with an empty list. ```vim let g:ale_floating_window_border = [] ``` If the terminal supports Unicode, you might try setting the value like below, to make it look nicer. ```vim let g:ale_floating_window_border = ['│', '─', '╭', '╮', '╯', '╰', '│', '─'] ``` Since vim's default uses nice Unicode characters when possible, you can trick ale into using that default with ```vim let g:ale_floating_window_border = repeat([''], 8) ``` ### 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 are concerned about the CPU time ALE will spend, which will of course imply some cost to battery life, you can adjust your settings to make your CPU do less work. First, consider increasing the delay before which ALE will run any linters while you type. ALE uses a timeout which is cancelled and reset every time you type, and this delay can be increased so linters are run less often. See `:help g:ale_lint_delay` for more information. If you don't wish to run linters while you type, you can disable that behavior. Set `g:ale_lint_on_text_changed` to `never`. You won't get as frequent error checking, but ALE shouldn't block your ability to edit a document after you save a file, so the asynchronous nature of the plugin will still be an advantage. If you are still concerned, you can turn the automatic linting off altogether, including the option `g:ale_lint_on_enter`, and you can run ALE manually with `:ALELint`. ### How can I use ALE with other LSP clients? ALE offers an API for letting any other plugin integrate with ALE. If you are interested in writing an integration, see `:help ale-lint-other-sources`. If you're running ALE in Neovim with [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) for configuring particular language servers, ALE will automatically disable its LSP functionality for any language servers configured with nvim-lspconfig by default. The following setting is applied by default: ```vim let g:ale_disable_lsp = 'auto' ``` If you are running ALE in combination with another LSP client, you may wish to disable ALE's LSP functionality entirely. You can change the setting to `1` to always disable all LSP functionality. ```vim let g:ale_disable_lsp = 1 ``` You can also use `b:ale_disable_lsp` in your ftplugin files to enable or disable LSP features in ALE for different filetypes. #### Neovim Diagnostics If you are running Neovim 0.7 or later, you can make ALE display errors and warnings via the Neovim diagnostics API. ```vim let g:ale_use_neovim_diagnostics_api = 1 ``` #### coc.nvim [coc.nvim](https://github.com/neoclide/coc.nvim) is a popular Vim plugin written in TypeScript and dependent on the [npm](https://www.npmjs.com/) ecosystem for providing full IDE features to Vim. Both ALE and coc.nvim implement [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) clients for supporting diagnostics (linting with a live server), and other features like auto-completion, and others listed above. ALE is primarily focused on integrating with external programs through virtually any means, provided the plugin remains almost entirely written in Vim script. coc.nvim is primarily focused on bringing IDE features to Vim. If you want to run external programs on your files to check for errors, and also use the most advanced IDE features, you might want to use both plugins at the same time. The easiest way to get both plugins to work together is to configure coc.nvim to send diagnostics to ALE, so ALE controls how all problems are presented to you, and to disable all LSP features in ALE, so ALE doesn't try to provide LSP features already provided by coc.nvim, such as auto-completion. Open your coc.nvim configuration file with `:CocConfig` and add `"diagnostic.displayByAle": true` to your settings. #### vim-lsp [vim-lsp](https://github.com/prabirshrestha/vim-lsp) is a popular plugin as implementation of Language Server Protocol (LSP) client for Vim. It provides all the LSP features including auto completion, diagnostics, go to definitions, etc. [vim-lsp-ale](https://github.com/rhysd/vim-lsp-ale) is a bridge plugin to solve the problem when using both ALE and vim-lsp. With the plugin, diagnostics are provided by vim-lsp and ALE can handle all the errors. Please read [vim-lsp-ale's documentation](https://github.com/rhysd/vim-lsp-ale/blob/master/doc/vim-lsp-ale.txt) for more details. ### How can I execute some code when ALE starts or stops linting? ALE runs its own [autocmd](http://vimdoc.sourceforge.net/htmldoc/autocmd.html) events when a lint or fix cycle are started and stopped. There is also an event that runs when a linter job has been successfully started. These events can be used to call arbitrary functions during these respective parts of the ALE's operation. ```vim augroup YourGroup autocmd! autocmd User ALELintPre call YourFunction() autocmd User ALELintPost call YourFunction() autocmd User ALEJobStarted call YourFunction() autocmd User ALEFixPre call YourFunction() autocmd User ALEFixPost call YourFunction() augroup END ``` ### How can I navigate between errors quickly? ALE offers some commands with `` keybinds for moving between warnings and errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors for example: ```vim nmap (ale_previous_wrap) nmap (ale_next_wrap) ``` For more information, consult the online documentation with `:help ale-navigation-commands`. ### How can I run linters only when I save files? ALE offers an option `g:ale_lint_on_save` for enabling running the linters when files are saved. This option is enabled by default. If you only wish to run linters when files are saved, you can turn the other options off. ```vim " Write this in your vimrc file let g:ale_lint_on_text_changed = 'never' let g:ale_lint_on_insert_leave = 0 " You can disable this option too " if you don't want linters to run on opening a file let g:ale_lint_on_enter = 0 ``` If for whatever reason you don't wish to run linters again when you save files, you can set `g:ale_lint_on_save` to `0`. ### How can I use the quickfix list instead of the loclist? The quickfix list can be enabled by turning the `g:ale_set_quickfix` option on. If you wish to also disable the loclist, you can disable the `g:ale_set_loclist` option. ```vim " Write this in your vimrc file let g:ale_set_loclist = 0 let g:ale_set_quickfix = 1 ``` If you wish to show Vim windows for the loclist or quickfix items when a file contains warnings or errors, `g:ale_open_list` can be set to `1`. `g:ale_keep_list_window_open` can be set to `1` if you wish to keep the window open even after errors disappear. ```vim let g:ale_open_list = 1 " Set this if you want to. " This can be useful if you are combining ALE with " some other plugin which sets quickfix errors, etc. let g:ale_keep_list_window_open = 1 ``` You can also set `let g:ale_list_vertical = 1` to open the windows vertically instead of the default horizontally. ### Why isn't ALE checking my filetype? #### stylelint for JSX First, install eslint and install stylelint with [stylelint-processor-styled-components](https://github.com/styled-components/stylelint-processor-styled-components). Supposing you have installed both tools correctly, configure your .jsx files so `jsx` is included in the filetype. You can use an `autocmd` for this. ```vim augroup FiletypeGroup autocmd! au BufNewFile,BufRead *.jsx set filetype=javascript.jsx augroup END ``` Supposing the filetype has been set correctly, you can set the following 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'] ``` 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']} ``` ALE will alias the `jsx` filetype so it uses the `css` filetype linters, and 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. #### Checking Vue 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']} ``` ### 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 formats for project configuration files. ALE can run compilers easily, but ALE cannot easily detect which compiler flags to use. Some tools and build configurations can generate [compile_commands.json](https://clang.llvm.org/docs/JSONCompilationDatabase.html) files. The `cppcheck`, `clangcheck`, `clangtidy` and `cquery` linters can read these files for automatically determining the appropriate compiler flags to use. For linting with compilers like `gcc` and `clang`, and with other tools, you will need to tell ALE which compiler flags to use yourself. You can use different options for different projects with the `g:ale_pattern_options` setting. Consult the documentation for that setting for more information. `b:ale_linters` can be used to select which tools you want to run, say if you want to use only `gcc` for one project, and only `clang` for another. ALE will attempt to parse `compile_commands.json` files to discover compiler flags to use when linting code. See `:help g:ale_c_parse_compile_commands` for more information. See Clang's documentation for [compile_commands.json files](https://clang.llvm.org/docs/JSONCompilationDatabase.html). You should strongly consider generating them in your builds, which is easy to do with CMake. You can also configure ALE to automatically run `make -n` to run dry runs on `Makefile`s to discover compiler flags. This can execute arbitrary code, so the option is disabled by default. See `:help g:ale_c_parse_makefile`. ### How can I run linters or fixers via Docker or a VM? ALE supports running linters or fixers via Docker, virtual machines, or in combination with any remote machine with a different file system, so long as the tools are well-integrated with ALE, and ALE is properly configured to run the correct commands and map filename paths between different file systems. See `:help ale-lint-other-machines` for the full documentation on how to configure ALE to support this. ================================================ FILE: ale_linters/ada/adals.vim ================================================ " Author: Bartek Jasicki http://github.com/thindil " Description: Support for Ada Language Server call ale#Set('ada_adals_executable', 'ada_language_server') call ale#Set('ada_adals_project', 'default.gpr') call ale#Set('ada_adals_encoding', 'utf-8') function! ale_linters#ada#adals#GetAdaLSConfig(buffer) abort return { \ 'ada.projectFile': ale#Var(a:buffer, 'ada_adals_project'), \ 'ada.defaultCharset': ale#Var(a:buffer, 'ada_adals_encoding') \} endfunction function! ale_linters#ada#adals#GetRootDirectory(buffer) abort return fnamemodify(bufname(a:buffer), ':p:h') endfunction call ale#linter#Define('ada', { \ 'name': 'adals', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'ada_adals_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#ada#adals#GetRootDirectory'), \ 'lsp_config': function('ale_linters#ada#adals#GetAdaLSConfig') \}) ================================================ FILE: ale_linters/ada/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Ada files. call ale#handlers#cspell#DefineLinter('ada') ================================================ FILE: ale_linters/ada/gcc.vim ================================================ " Author: Martino Pilia " 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#command#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 %s: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: ::: " Warning format: ::: warning: 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': {b -> ale#Var(b, 'ada_gcc_executable')}, \ 'command': function('ale_linters#ada#gcc#GetCommand'), \ 'callback': 'ale_linters#ada#gcc#Handle', \}) ================================================ FILE: ale_linters/ansible/ansible_lint.vim ================================================ " Authors: Bjorn Neergaard , Vytautas Macionis " Description: ansible-lint for ansible-yaml files call ale#Set('ansible_ansible_lint_executable', 'ansible-lint') call ale#Set('ansible_ansible_lint_auto_pipenv', 0) call ale#Set('ansible_ansible_lint_auto_poetry', 0) call ale#Set('ansible_ansible_lint_auto_uv', 0) call ale#Set('ansible_ansible_lint_change_directory', 1) function! ale_linters#ansible#ansible_lint#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') \ || ale#Var(a:buffer, 'ansible_ansible_lint_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') \ || ale#Var(a:buffer, 'ansible_ansible_lint_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') \ || ale#Var(a:buffer, 'ansible_ansible_lint_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#Var(a:buffer, 'ansible_ansible_lint_executable') endfunction function! ale_linters#ansible#ansible_lint#GetCwd(buffer) abort if ale#Var(a:buffer, 'ansible_ansible_lint_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '' endfunction function! ale_linters#ansible#ansible_lint#Handle(buffer, version, 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 let l:version_group = ale#semver#GTE(a:version, [6, 0, 0]) ? '>=6.0.0' : \ ale#semver#GTE(a:version, [5, 0, 0]) ? '>=5.0.0' : \ '<5.0.0' let l:output = [] if '>=6.0.0' is# l:version_group let l:error_codes = { 'blocker': 'E', 'critical': 'E', 'major': 'W', 'minor': 'W', 'info': 'I' } let l:linter_issues = ale#util#FuzzyJSONDecode(a:lines, []) for l:issue in l:linter_issues if ale#path#IsBufferPath(a:buffer, l:issue.location.path) if exists('l:issue.location.positions') let l:coord_keyname = 'positions' else let l:coord_keyname = 'lines' endif let l:column_member = printf( \ 'l:issue.location.%s.begin.column', l:coord_keyname \) call add(l:output, { \ 'lnum': exists(l:column_member) ? l:issue.location[l:coord_keyname].begin.line : \ l:issue.location[l:coord_keyname].begin, \ 'col': exists(l:column_member) ? l:issue.location[l:coord_keyname].begin.column : 0, \ 'text': l:issue.check_name, \ 'detail': l:issue.description, \ 'code': l:issue.severity, \ 'type': l:error_codes[l:issue.severity], \}) endif endfor endif if '>=5.0.0' is# l:version_group " Matches patterns line the following: " test.yml:3:148: syntax-check 'var' is not a valid attribute for a Play " roles/test/tasks/test.yml:8: [package-latest] [VERY_LOW] Package installs should not use latest " D:\test\tasks\test.yml:8: [package-latest] [VERY_LOW] package installs should not use latest let l:pattern = '\v^(%([a-zA-Z]:)?[^:]+):(\d+):%((\d+):)? %(\[([-[:alnum:]]+)\]) %(\[([_[:alnum:]]+)\]) (.*)$' let l:error_codes = { 'VERY_HIGH': 'E', 'HIGH': 'E', 'MEDIUM': 'W', 'LOW': 'W', 'VERY_LOW': 'W', 'INFO': 'I' } for l:match in ale#util#GetMatches(a:lines, l:pattern) if ale#path#IsBufferPath(a:buffer, l:match[1]) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[6], \ 'code': l:match[4], \ 'type': l:error_codes[l:match[5]], \}) endif endfor endif if '<5.0.0' is# l:version_group " Matches patterns line the following: " test.yml:35: [EANSIBLE0002] Trailing whitespace let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[4] if l:code is# 'EANSIBLE0002' \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if ale#path#IsBufferPath(a:buffer, l:match[1]) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[5], \ 'code': l:code, \ 'type': l:code[:0] is# 'E' ? 'E' : 'W', \}) endif endfor endif return l:output endfunction function! ale_linters#ansible#ansible_lint#GetCommand(buffer, version) abort let l:executable = ale_linters#ansible#ansible_lint#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run ansible-lint' \ : '' let l:opts_map = { \ '>=6.0.0': ' --nocolor -f json -x yaml %s', \ '>=5.0.0': ' --nocolor --parseable-severity -x yaml %s', \ '<5.0.0': ' --nocolor -p %t' \} let l:cmd_opts = ale#semver#GTE(a:version, [6, 0]) ? l:opts_map['>=6.0.0'] : \ ale#semver#GTE(a:version, [5, 0]) ? l:opts_map['>=5.0.0'] : \ l:opts_map['<5.0.0'] let l:command = ale#Escape(l:executable) . l:exec_args . l:cmd_opts return l:command endfunction function! ale_linters#ansible#ansible_lint#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#ansible#ansible_lint#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run ansible-lint' \ : '' let l:command = ale#Escape(l:executable) . l:exec_args . ' --version' return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale_linters#ansible#ansible_lint#GetCommand'), \) endfunction call ale#linter#Define('ansible', { \ 'name': 'ansible_lint', \ 'aliases': ['ansible', 'ansible-lint'], \ 'executable': function('ale_linters#ansible#ansible_lint#GetExecutable'), \ 'cwd': function('ale_linters#ansible#ansible_lint#GetCwd'), \ 'command': function('ale_linters#ansible#ansible_lint#RunWithVersionCheck'), \ 'lint_file': 1, \ 'callback': {buffer, lines -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#ansible#ansible_lint#GetExecutable(buffer), \ '%e --version', \ {buffer, version -> ale_linters#ansible#ansible_lint#Handle( \ buffer, \ l:version, \ lines)}, \ )}, \}) ================================================ FILE: ale_linters/ansible/language_server.vim ================================================ " Author: Horacio Sanson " Description: Support ansible language server https://github.com/ansible/ansible-language-server/ call ale#Set('ansible_language_server_executable', 'ansible-language-server') call ale#Set('ansible_language_server_config', {}) function! ale_linters#ansible#language_server#Executable(buffer) abort return ale#Var(a:buffer, 'ansible_language_server_executable') endfunction function! ale_linters#ansible#language_server#GetCommand(buffer) abort let l:executable = ale_linters#ansible#language_server#Executable(a:buffer) return ale#Escape(l:executable) . ' --stdio' endfunction function! ale_linters#ansible#language_server#FindProjectRoot(buffer) abort let l:dir = fnamemodify( \ ale#path#FindNearestFile(a:buffer, 'ansible.cfg'), \ ':h' \) if l:dir isnot# '.' && isdirectory(l:dir) return l:dir endif let l:dir = fnamemodify( \ ale#path#FindNearestDirectory(a:buffer, '.git'), \ ':h:h' \) if l:dir isnot# '.' && isdirectory(l:dir) return l:dir endif return '' endfunction call ale#linter#Define('ansible', { \ 'name': 'language_server', \ 'aliases': ['ansible_language_server', 'ansible-language-server'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#ansible#language_server#Executable'), \ 'command': function('ale_linters#ansible#language_server#GetCommand'), \ 'project_root': function('ale_linters#ansible#language_server#FindProjectRoot'), \ 'lsp_config': {b -> ale#Var(b, 'ansible_language_server_config')} \}) ================================================ FILE: ale_linters/apiblueprint/drafter.vim ================================================ " Author: nametake https://nametake.github.io " Description: apiblueprint parser function! ale_linters#apiblueprint#drafter#HandleErrors(buffer, lines) abort " Matches patterns line the following: " " warning: (3) unable to parse response signature, expected 'response [] [()]'; line 4, column 3k - line 4, column 22 " warning: (10) message-body asset is expected to be a pre-formatted code block, separate it by a newline and indent every of its line by 12 spaces or 3 tabs; line 30, column 5 - line 30, column 9; line 31, column 9 - line 31, column 14; line 32, column 9 - line 32, column 14 let l:pattern = '\(^.*\): (\d\+) \(.\{-\}\); line \(\d\+\), column \(\d\+\) - line \d\+, column \d\+\(.*; line \d\+, column \d\+ - line \(\d\+\), column \(\d\+\)\)\{-\}$' let l:output = [] for l:match in ale#util#GetMatches(a:lines[2:], l:pattern) let l:item = { \ 'type': l:match[1] is# 'warning' ? 'W' : 'E', \ 'text': l:match[2], \ '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 return l:output endfunction call ale#linter#Define('apiblueprint', { \ 'name': 'drafter', \ 'output_stream': 'stderr', \ 'executable': 'drafter', \ 'command': 'drafter --use-line-num --validate', \ 'callback': 'ale_linters#apiblueprint#drafter#HandleErrors', \}) ================================================ FILE: ale_linters/apkbuild/apkbuild_lint.vim ================================================ " Author: Leo " Description: apkbuild-lint from atools linter for APKBUILDs call ale#Set('apkbuild_apkbuild_lint_executable', 'apkbuild-lint') call ale#linter#Define('apkbuild', { \ 'name': 'apkbuild_lint', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'apkbuild_apkbuild_lint_executable')}, \ 'command': '%e %t', \ 'callback': 'ale#handlers#atools#Handle', \}) ================================================ FILE: ale_linters/apkbuild/secfixes_check.vim ================================================ " Author: Leo " Description: secfixes-check from atools linter for APKBUILDs call ale#Set('apkbuild_secfixes_check_executable', 'secfixes-check') call ale#linter#Define('apkbuild', { \ 'name': 'secfixes_check', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'apkbuild_secfixes_check_executable')}, \ 'command': '%e %t', \ 'callback': 'ale#handlers#atools#Handle', \}) ================================================ FILE: ale_linters/asciidoc/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for asciidoc files call ale#handlers#alex#DefineLinter('asciidoc', '--text') ================================================ FILE: ale_linters/asciidoc/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for ASCIIDoc files. call ale#handlers#cspell#DefineLinter('asciidoc') ================================================ FILE: ale_linters/asciidoc/languagetool.vim ================================================ " Author: Horacio Sanson (hsanson [ät] gmail.com) " Description: languagetool for asciidoc files, copied from markdown. call ale#handlers#languagetool#DefineLinter('asciidoc') ================================================ FILE: ale_linters/asciidoc/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for AsciiDoc files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('asciidoc', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/asciidoc/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#handlers#redpen#DefineLinter('asciidoc') ================================================ FILE: ale_linters/asciidoc/textlint.vim ================================================ " Author: TANIGUCHI Masaya " Description: textlint for AsciiDoc files call ale#linter#Define('asciidoc', { \ 'name': 'textlint', \ 'executable': function('ale#handlers#textlint#GetExecutable'), \ 'command': function('ale#handlers#textlint#GetCommand'), \ 'callback': 'ale#handlers#textlint#HandleTextlintOutput', \}) ================================================ FILE: ale_linters/asciidoc/vale.vim ================================================ " 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', \}) ================================================ FILE: ale_linters/asciidoc/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for AsciiDoc files call ale#handlers#writegood#DefineLinter('asciidoc') ================================================ FILE: ale_linters/asm/gcc.vim ================================================ " Author: Lucas Kolstad " Description: gcc linter for asm files call ale#Set('asm_gcc_executable', 'gcc') call ale#Set('asm_gcc_options', '-Wall') function! ale_linters#asm#gcc#GetCommand(buffer) abort " `-o /dev/null` or `-o null` is needed to catch all errors, " -fsyntax-only doesn't catch everything. return '%e -x assembler' \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote %s:h' \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -' endfunction function! ale_linters#asm#gcc#Handle(buffer, lines) abort 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, \ 'type': l:match[2] =~? 'error' ? 'E' : 'W', \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('asm', { \ 'name': 'gcc', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'asm_gcc_executable')}, \ 'command': function('ale_linters#asm#gcc#GetCommand'), \ 'callback': 'ale_linters#asm#gcc#Handle', \}) ================================================ FILE: ale_linters/asm/llvm_mc.vim ================================================ " Author: uidops " Description: llvm-mc linter for asm files call ale#Set('asm_llvm_mc_executable', 'llvm-mc') call ale#Set('asm_llvm_mc_options', '') function! ale_linters#asm#llvm_mc#GetCommand(buffer) abort return '%e --assemble' \ . ' --filetype=asm' \ . ' -o ' . g:ale#util#nul_file \ . ' ' . ale#Var(a:buffer, 'asm_llvm_mc_options') endfunction function! ale_linters#asm#llvm_mc#Handle(buffer, lines) abort let l:pattern = '^.\+:\(\d\+\):\(\d\+\): \([^:]\+\): \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3] =~? 'error' ? 'E' : 'W', \ 'text': l:match[4], \}) endfor return l:output endfunction call ale#linter#Define('asm', { \ 'name': 'llvm_mc', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'asm_llvm_mc_executable')}, \ 'command': function('ale_linters#asm#llvm_mc#GetCommand'), \ 'callback': 'ale_linters#asm#llvm_mc#Handle', \}) ================================================ FILE: ale_linters/astro/eslint.vim ================================================ " Author: Hyuksang Kwon " Description: eslint for astro files call ale#linter#Define('astro', { \ 'name': 'eslint', \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/avra/avra.vim ================================================ " Author: Utkarsh Verma " Description: AVRA linter for avra syntax. call ale#Set('avra_avra_executable', 'avra') call ale#Set('avra_avra_options', '') function! ale_linters#avra#avra#GetCommand(buffer) abort return '%e' \ . ' %t' \ . ale#Pad(ale#Var(a:buffer, 'avra_avra_options')) \ . ' -o ' . g:ale#util#nul_file endfunction function! ale_linters#avra#avra#Handle(buffer, lines) abort " Note that we treat 'fatal' as errors. let l:pattern = '^\S\+(\(\d\+\))\s\+:\s\+\(\S\+\)\s\+:\s\+\(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'type': l:match[2] =~? 'Error' ? 'E' : 'W', \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('avra', { \ 'name': 'avra', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'avra_avra_executable')}, \ 'command': function('ale_linters#avra#avra#GetCommand'), \ 'callback': 'ale_linters#avra#avra#Handle', \}) ================================================ FILE: ale_linters/awk/gawk.vim ================================================ " Author: kmarc " Description: This file adds support for using GNU awk with scripts. 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 '%e --source ' . ale#Escape('BEGIN { exit } END { exit 1 }') \ . ' --lint' \ . ale#Pad(ale#Var(a:buffer, 'awk_gawk_options')) \ . ' -f %t /dev/null' endfunction call ale#linter#Define('awk', { \ 'name': 'gawk', \ 'executable': {b -> ale#Var(b, 'awk_gawk_executable')}, \ 'command': function('ale_linters#awk#gawk#GetCommand'), \ 'callback': 'ale#handlers#gawk#HandleGawkFormat', \ 'output_stream': 'both' \}) ================================================ FILE: ale_linters/bats/shellcheck.vim ================================================ " Author: Ian2020 " Description: shellcheck linter for bats scripts. call ale#handlers#shellcheck#DefineLinter('bats') ================================================ FILE: ale_linters/bib/bibclean.vim ================================================ " Author: Horacio Sanson - https://github.com/hsanson " Description: Support for bibclean linter for BibTeX files. call ale#Set('bib_bibclean_executable', 'bibclean') function! ale_linters#bib#bibclean#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'bib_bibclean_executable') return ale#Escape(l:executable) . ' -file-position ' endfunction function! ale_linters#bib#bibclean#get_type(str) abort if a:str is# '??' return 'E' else return 'W' endif endfunction function! ale_linters#bib#bibclean#match_msg(line) abort " Legacy message pattern works for bibclean <= v2.11.4. If empty, try " the new message pattern for bibtex > v2.11.4 let l:matches_legacy = matchlist(a:line, '^\(.*\) "stdin", line \(\d\+\): \(.*\)$') return ! empty(l:matches_legacy) ? l:matches_legacy \ : matchlist(a:line, '^\(.*\) stdin:\(\d\+\):\(.*\)$') endfunction function! ale_linters#bib#bibclean#match_entry(line) abort return matchlist(a:line, 'Entry input byte=.* line=\(.*\) column=\(.*\) output .*$') endfunction function! ale_linters#bib#bibclean#match_value(line) abort return matchlist(a:line, 'Value input byte=.* line=\(.*\) column=\(.*\) output .*$') endfunction function! ale_linters#bib#bibclean#Handle(buffer, lines) abort let l:output = [] let l:type = 'E' let l:msg = '' for l:line in a:lines if empty(l:msg) let l:mlist = ale_linters#bib#bibclean#match_msg(l:line) if !empty(l:mlist) let l:msg = l:mlist[3] let l:type = ale_linters#bib#bibclean#get_type(l:mlist[1]) endif else if l:type is# 'E' let l:mlist = ale_linters#bib#bibclean#match_entry(l:line) else let l:mlist = ale_linters#bib#bibclean#match_value(l:line) endif if !empty(l:mlist) call add(l:output, { \ 'lnum': l:mlist[1], \ 'col': l:mlist[2], \ 'text': l:msg, \ 'type': l:type \}) let l:msg = '' endif endif endfor return l:output endfunction call ale#linter#Define('bib', { \ 'name': 'bibclean', \ 'executable': {b -> ale#Var(b, 'bib_bibclean_executable')}, \ 'command': function('ale_linters#bib#bibclean#GetCommand'), \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#bib#bibclean#Handle', \}) ================================================ FILE: ale_linters/bicep/az_bicep.vim ================================================ " Author: Carl Smedstad " Description: az_bicep for bicep files let g:ale_bicep_az_bicep_executable = \ get(g:, 'ale_bicep_az_bicep_executable', 'az') let g:ale_bicep_az_bicep_options = \ get(g:, 'ale_bicep_az_bicep_options', '') function! ale_linters#bicep#az_bicep#Executable(buffer) abort return ale#Var(a:buffer, 'bicep_az_bicep_executable') endfunction function! ale_linters#bicep#az_bicep#Command(buffer) abort let l:executable = ale_linters#bicep#az_bicep#Executable(a:buffer) let l:options = ale#Var(a:buffer, 'bicep_az_bicep_options') if has('win32') let l:nullfile = 'NUL' else let l:nullfile = '/dev/null' endif return ale#Escape(l:executable) \ . ' bicep build --outfile ' \ . l:nullfile \ . ' --file ' \ . '%s ' \ . l:options endfunction function! ale_linters#bicep#az_bicep#Handle(buffer, lines) abort let l:pattern = '\v^([A-Z]+)?(:\s)?(.*)\((\d+),(\d+)\)\s:\s([a-zA-Z]*)\s([-a-zA-Z0-9]*):\s(.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if l:match[1] is# 'ERROR' let l:type = 'E' elseif l:match[1] is# 'WARNING' let l:type = 'W' elseif l:match[6] is# 'Error' let l:type = 'E' elseif l:match[6] is# 'Warning' let l:type = 'W' else let l:type = 'I' endif call add(l:output, { \ 'filename': l:match[3], \ 'lnum': l:match[4] + 0, \ 'col': l:match[5] + 0, \ 'type': l:type, \ 'code': l:match[7], \ 'text': l:match[8], \}) endfor return l:output endfunction call ale#linter#Define('bicep', { \ 'name': 'az_bicep', \ 'executable': function('ale_linters#bicep#az_bicep#Executable'), \ 'command': function('ale_linters#bicep#az_bicep#Command'), \ 'callback': 'ale_linters#bicep#az_bicep#Handle', \ 'output_stream': 'stderr', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/bicep/bicep.vim ================================================ " Author: Carl Smedstad " Description: bicep for bicep files let g:ale_bicep_bicep_executable = \ get(g:, 'ale_bicep_bicep_executable', 'bicep') let g:ale_bicep_bicep_options = \ get(g:, 'ale_bicep_bicep_options', '') function! ale_linters#bicep#bicep#Executable(buffer) abort return ale#Var(a:buffer, 'bicep_bicep_executable') endfunction function! ale_linters#bicep#bicep#Command(buffer) abort let l:executable = ale_linters#bicep#bicep#Executable(a:buffer) let l:options = ale#Var(a:buffer, 'bicep_bicep_options') if has('win32') let l:nullfile = 'NUL' else let l:nullfile = '/dev/null' endif return ale#Escape(l:executable) \ . ' build --outfile ' \ . l:nullfile \ . ' ' \ . l:options \ . ' %s' endfunction function! ale_linters#bicep#bicep#Handle(buffer, lines) abort let l:pattern = '\v^(.*)\((\d+),(\d+)\)\s:\s([a-zA-Z]*)\s([-a-zA-Z0-9]*):\s(.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if l:match[4] is# 'Error' let l:type = 'E' elseif l:match[4] is# 'Warning' let l:type = 'W' else let l:type = 'I' endif call add(l:output, { \ 'filename': l:match[1], \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:type, \ 'code': l:match[5], \ 'text': l:match[6], \}) endfor return l:output endfunction call ale#linter#Define('bicep', { \ 'name': 'bicep', \ 'executable': function('ale_linters#bicep#bicep#Executable'), \ 'command': function('ale_linters#bicep#bicep#Command'), \ 'callback': 'ale_linters#bicep#bicep#Handle', \ 'output_stream': 'both', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/bindzone/checkzone.vim ================================================ " Description: named-checkzone for bindzone call ale#Set('bindzone_checkzone_executable', 'named-checkzone') call ale#Set('bindzone_checkzone_options', '-c IN') function! ale_linters#bindzone#checkzone#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'bindzone_checkzone_options')) \ . ' example.com %t' endfunction function! ale_linters#bindzone#checkzone#Handle(buffer, lines) abort let l:warning_pattern = '\vzone example.com/IN: (.+)$' let l:error_pattern = '\v:(\d+): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:error_pattern) let l:lnum = l:match[1] let l:text = l:match[2] call add(l:output, {'text': l:text, 'lnum': l:lnum + 0, 'type': 'E'}) endfor for l:match in ale#util#GetMatches(a:lines, l:warning_pattern) let l:text = l:match[1] " Ignore information messages let l:scrub_match = matchlist(l:text, '\v(loaded serial|not loaded due to) ') if empty(l:scrub_match) call add(l:output, {'text': l:text, 'lnum': 0, 'type': 'W'}) endif endfor return l:output endfunction call ale#linter#Define('bindzone', { \ 'name': 'checkzone', \ 'executable': {b -> ale#Var(b, 'bindzone_checkzone_executable')}, \ 'command': function('ale_linters#bindzone#checkzone#GetCommand'), \ 'callback': 'ale_linters#bindzone#checkzone#Handle', \ 'read_buffer': 0, \}) ================================================ FILE: ale_linters/bitbake/oelint_adv.vim ================================================ " Author: offa " Description: oelint-adv for BitBake files call ale#Set('bitbake_oelint_adv_executable', 'oelint-adv') call ale#Set('bitbake_oelint_adv_options', '') call ale#Set('bitbake_oelint_adv_config', '.oelint.cfg') function! ale_linters#bitbake#oelint_adv#StripAnsiCodes(line) abort return substitute(a:line, '\e\[[0-9;]\+[mK]', '', 'g') endfunction function! ale_linters#bitbake#oelint_adv#RemoveBranch(line) abort return substitute(a:line, ' \[branch:.*', '', 'g') endfunction function! ale_linters#bitbake#oelint_adv#Command(buffer) abort let l:config_file = ale#path#FindNearestFile(a:buffer, \ ale#Var(a:buffer, 'bitbake_oelint_adv_config')) return ((!empty(l:config_file)) \ ? 'OELINT_CONFIG=' . ale#Escape(l:config_file) . ' ' \ : '') \ . '%e --quiet ' \ . ale#Pad(ale#Var(a:buffer, 'bitbake_oelint_adv_options')) . '%s' endfunction function! ale_linters#bitbake#oelint_adv#Handle(buffer, lines) abort let l:pattern = '\v^(.{-}):(.{-}):(.{-}):(.{-}):(.{-})$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[2]), \ 'type': l:match[3] is# 'error' \ ? 'E' \ : (l:match[3] is# 'warning' ? 'W' : 'I'), \ 'text': ale_linters#bitbake#oelint_adv#RemoveBranch( \ ale_linters#bitbake#oelint_adv#StripAnsiCodes(l:match[5]) \ ), \ 'code': l:match[4], \}) endfor return l:output endfunction call ale#linter#Define('bitbake', { \ 'name': 'oelint_adv', \ 'output_stream': 'both', \ 'executable': {b -> ale#Var(b, 'bitbake_oelint_adv_executable')}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#bitbake#oelint_adv#Command'), \ 'callback': 'ale_linters#bitbake#oelint_adv#Handle', \ }) ================================================ FILE: ale_linters/bzl/buildifier.vim ================================================ " Author: Chuck Grindel " Description: Bazel Starlark lint support using buildifier. function! ale_linters#bzl#buildifier#GetCommand(buffer) abort let l:executable = ale#Escape(ale#fixers#buildifier#GetExecutable(a:buffer)) let l:options = ale#Var(a:buffer, 'bazel_buildifier_options') let l:filename = ale#Escape(bufname(a:buffer)) let l:command = l:executable . ' -mode check -lint warn -path %s' if l:options isnot# '' let l:command .= ' ' . l:options endif return l:command endfunction function! ale_linters#bzl#buildifier#Handle(buffer, lines) abort let l:pattern = '\v^[^:]+:(\d+):(\d+)?:?\s+(syntax error near)?(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3] . l:match[4], \ 'type': l:match[3] is# 'syntax error near' ? 'E' : 'W', \}) endfor return l:output endfunction call ale#linter#Define('bzl', { \ 'name': 'buildifier', \ 'output_stream': 'both', \ 'executable': function('ale#fixers#buildifier#GetExecutable'), \ 'command': function('ale_linters#bzl#buildifier#GetCommand'), \ 'callback': function('ale_linters#bzl#buildifier#Handle'), \}) ================================================ FILE: ale_linters/c/cc.vim ================================================ " Author: w0rp " Description: A C compiler linter for C files with gcc/clang, etc. call ale#Set('c_cc_executable', '') call ale#Set('c_cc_options', '-std=c11 -Wall') call ale#Set('c_cc_use_header_lang_flag', -1) call ale#Set('c_cc_header_exts', ['h']) function! ale_linters#c#cc#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'c_cc_executable') " Default to either clang or gcc. if l:executable is# '' if ale#engine#IsExecutable(a:buffer, 'clang') let l:executable = 'clang' else let l:executable = 'gcc' endif endif return l:executable endfunction function! ale_linters#c#cc#GetCommand(buffer, output) abort let l:cflags = ale#c#GetCFlags(a:buffer, a:output) let l:ale_flags = ale#Var(a:buffer, 'c_cc_options') if l:cflags =~# '-std=' let l:ale_flags = substitute( \ l:ale_flags, \ '-std=\(c\|gnu\)[0-9]\{2\}', \ '', \ 'g') endif " Select the correct language flag depending on the executable, options " and file extension let l:executable = ale_linters#c#cc#GetExecutable(a:buffer) let l:use_header_lang_flag = ale#Var(a:buffer, 'c_cc_use_header_lang_flag') let l:header_exts = ale#Var(a:buffer, 'c_cc_header_exts') let l:lang_flag = ale#c#GetLanguageFlag( \ a:buffer, \ l:executable, \ l:use_header_lang_flag, \ l:header_exts, \ 'c') " -iquote with the directory the file is in makes #include work for " headers in the same directory. " " `-o /dev/null` or `-o null` is needed to catch all errors, " -fsyntax-only doesn't catch everything. return '%e -S -x ' . l:lang_flag \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote %s:h' \ . ale#Pad(l:cflags) \ . ale#Pad(l:ale_flags) . ' -' endfunction call ale#linter#Define('c', { \ 'name': 'cc', \ 'aliases': ['gcc', 'clang'], \ 'output_stream': 'stderr', \ 'executable': function('ale_linters#c#cc#GetExecutable'), \ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#cc#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) ================================================ FILE: ale_linters/c/ccls.vim ================================================ " Author: Ye Jingchen , Ben Falconer , jtalowell " Description: A language server for C call ale#Set('c_ccls_executable', 'ccls') call ale#Set('c_ccls_init_options', {}) call ale#Set('c_build_dir', '') call ale#linter#Define('c', { \ 'name': 'ccls', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'c_ccls_executable')}, \ 'command': '%e', \ 'project_root': function('ale#handlers#ccls#GetProjectRoot'), \ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'c_ccls_init_options')}, \}) ================================================ FILE: ale_linters/c/clangcheck.vim ================================================ " Author: gagbo " : luibo " : Jorengarenar " Description: clang-check linter for C files " modified from cpp/clangcheck.vim to match for C call ale#Set('c_clangcheck_executable', 'clang-check') call ale#Set('c_clangcheck_options', '') call ale#Set('c_build_dir', '') function! ale_linters#c#clangcheck#GetCommand(buffer) abort let l:user_options = ale#Var(a:buffer, 'c_clangcheck_options') " Try to find compilation database to link automatically let l:build_dir = ale#Var(a:buffer, 'c_build_dir') if empty(l:build_dir) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) let l:build_dir = ale#path#Dirname(l:json_file) 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 '%e -analyze %s' \ . (empty(l:build_dir) ? ' --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics': '') \ . ale#Pad(l:user_options) \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') endfunction call ale#linter#Define('c', { \ 'name': 'clangcheck', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'c_clangcheck_executable')}, \ 'command': function('ale_linters#c#clangcheck#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/c/clangd.vim ================================================ " Author: Andrey Melentyev " Description: Clangd language server call ale#Set('c_clangd_executable', 'clangd') call ale#Set('c_clangd_options', '') call ale#Set('c_build_dir', '') function! ale_linters#c#clangd#GetCommand(buffer) abort let l:build_dir = ale#c#GetBuildDirectory(a:buffer) return '%e' \ . ale#Pad(ale#Var(a:buffer, 'c_clangd_options')) \ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '') endfunction call ale#linter#Define('c', { \ 'name': 'clangd', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'c_clangd_executable')}, \ 'command': function('ale_linters#c#clangd#GetCommand'), \ 'project_root': function('ale#c#FindProjectRoot'), \}) ================================================ FILE: ale_linters/c/clangtidy.vim ================================================ " Author: vdeurzen , w0rp , " gagbo , Andrej Radovic " Description: clang-tidy linter for c files call ale#Set('c_clangtidy_executable', 'clang-tidy') " Set this option to check the checks clang-tidy will apply. " The number of checks that can be applied to C files is limited in contrast to " C++ " " 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', []) " Set this option to manually set some options for clang-tidy to use as compile " flags. " This will disable compile_commands.json detection. call ale#Set('c_clangtidy_options', '') " Set this option to manually set options for clang-tidy directly. call ale#Set('c_clangtidy_extra_options', '') call ale#Set('c_build_dir', '') function! ale_linters#c#clangtidy#GetCommand(buffer, output) abort let l:checks = join(ale#Var(a:buffer, 'c_clangtidy_checks'), ',') let l:build_dir = ale#c#GetBuildDirectory(a:buffer) let l:options = '' " Get the extra options if we couldn't find a build directory. if empty(l:build_dir) let l:options = ale#Var(a:buffer, 'c_clangtidy_options') let l:cflags = ale#c#GetCFlags(a:buffer, a:output) let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags endif " Get the options to pass directly to clang-tidy let l:extra_options = ale#Var(a:buffer, 'c_clangtidy_extra_options') return '%e' \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') \ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '') \ . ' %s' \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:options) ? ' -- ' . l:options : '') endfunction call ale#linter#Define('c', { \ 'name': 'clangtidy', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'c_clangtidy_executable')}, \ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clangtidy#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/c/cppcheck.vim ================================================ " Author: Bart Libert " Description: cppcheck linter for c files call ale#Set('c_cppcheck_executable', 'cppcheck') call ale#Set('c_cppcheck_options', '--enable=style') function! ale_linters#c#cppcheck#GetCommand(buffer) abort let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer) let l:buffer_path_include = empty(l:compile_commands_option) \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ : '' let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') " Versions >=2.13 don't allow using --project in conjunction with an " explicit source file. let l:source_file = stridx(l:compile_commands_option, '--project=') < 0 \ ? ' %t' \ : '' return '%e -q --language=c' \ . l:template \ . ale#Pad(l:compile_commands_option) \ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options')) \ . l:buffer_path_include \ . l:source_file endfunction call ale#linter#Define('c', { \ 'name': 'cppcheck', \ 'output_stream': 'both', \ 'executable': {b -> ale#Var(b, 'c_cppcheck_executable')}, \ 'cwd': function('ale#handlers#cppcheck#GetCwd'), \ 'command': function('ale_linters#c#cppcheck#GetCommand'), \ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat', \}) ================================================ FILE: ale_linters/c/cpplint.vim ================================================ " Author: Justin Huang " Description: cpplint for c files call ale#Set('c_cpplint_executable', 'cpplint') call ale#Set('c_cpplint_options', '') function! ale_linters#c#cpplint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'c_cpplint_options') return '%e' . ale#Pad(l:options) . ' %s' endfunction call ale#linter#Define('c', { \ 'name': 'cpplint', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'c_cpplint_executable')}, \ 'command': function('ale_linters#c#cpplint#GetCommand'), \ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/c/cquery.vim ================================================ " Author: Ben Falconer , jtalowell " 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 " Try to find cquery configuration files first. let l:config = ale#path#FindNearestFile(a:buffer, '.cquery') if !empty(l:config) return fnamemodify(l:config, ':h') endif " Fall back on default project root detection. return ale#c#FindProjectRoot(a:buffer) 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': {b -> ale#Var(b, 'c_cquery_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#c#cquery#GetProjectRoot'), \ 'initialization_options': function('ale_linters#c#cquery#GetInitializationOptions'), \}) ================================================ FILE: ale_linters/c/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for C files. call ale#handlers#cspell#DefineLinter('c') ================================================ FILE: ale_linters/c/flawfinder.vim ================================================ " Author: Christian Gibbons " Description: flawfinder linter for c files call ale#Set('c_flawfinder_executable', 'flawfinder') 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#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 '%e -CDQS' \ . ale#Pad(ale#Var(a:buffer, 'c_flawfinder_options')) \ . l:minlevel \ . ' %t' endfunction call ale#linter#Define('c', { \ 'name': 'flawfinder', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'c_flawfinder_executable')}, \ 'command': function('ale_linters#c#flawfinder#GetCommand'), \ 'callback': 'ale#handlers#flawfinder#HandleFlawfinderFormat', \}) ================================================ FILE: ale_linters/c3/c3lsp.vim ================================================ " Author: Koni Marti " Description: A Language Server implementation for C3 call ale#Set('c3_c3lsp_executable', 'c3lsp') call ale#Set('c3_c3lsp_options', '') call ale#Set('c3_c3lsp_init_options', {}) function! ale_linters#c3#c3lsp#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'c3_c3lsp_executable') return ale#Escape(l:executable) . ale#Pad(ale#Var(a:buffer, 'c3_c3lsp_options')) endfunction call ale#linter#Define('c3', { \ 'name': 'c3lsp', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'c3_c3lsp_executable')}, \ 'command': function('ale_linters#c3#c3lsp#GetCommand'), \ 'project_root': function('ale#handlers#c3lsp#GetProjectRoot'), \ 'lsp_config': {b -> ale#handlers#c3lsp#GetInitOpts(b, 'c3_c3lsp_init_options')}, \}) ================================================ FILE: ale_linters/cairo/scarb.vim ================================================ " Author: 0xhyoga <0xhyoga@gmx.com>, " Description: scarb for cairo files function! ale_linters#cairo#scarb#GetScarbExecutable(bufnr) abort if ale#path#FindNearestFile(a:bufnr, 'Scarb.toml') isnot# '' return 'scarb' else " if there is no Scarb.toml file, we don't use scarb even if it exists, " so we return '', because executable('') apparently always fails return '' endif endfunction function! ale_linters#cairo#scarb#GetCommand(buffer, version) abort return 'scarb build' endfunction call ale#linter#Define('cairo', { \ 'name': 'scarb', \ 'executable': function('ale_linters#cairo#scarb#GetScarbExecutable'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#cairo#scarb#GetScarbExecutable(buffer), \ '%e --version', \ function('ale_linters#cairo#scarb#GetCommand'), \ )}, \ 'callback': 'ale#handlers#cairo#HandleCairoErrors', \ 'output_stream': 'both', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/cairo/sierra.vim ================================================ " Author: 0xHyoga <0xHyoga@gmx.com> " Description: Report Starknet compile to sierra errors in cairo 1.0 code call ale#Set('cairo_sierra_executable', 'starknet-compile') call ale#Set('cairo_sierra_options', '') function! ale_linters#cairo#sierra#Handle(buffer, lines) abort " Matches patterns like the following: " Error: Expected ';' but got '(' " --> /path/to/file/file.cairo:1:10:) let l:pattern = '\v(error|warning): (.*)$' let l:line_and_column_pattern = '\v\.cairo:(\d+):(\d+)' let l:output = [] 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:line_and_column_pattern) if len(l:match) > 0 let l:index = len(l:output) - 1 let l:output[l:index]['lnum'] = l:match[1] + 0 let l:output[l:index]['col'] = l:match[2] + 0 endif else let l:isError = l:match[1] is? 'Error' call add(l:output, { \ 'lnum': 0, \ 'col': 0, \ 'text': l:match[2], \ 'type': l:isError ? 'E' : 'W', \}) endif endfor return l:output endfunction function! ale_linters#cairo#sierra#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'cairo_sierra_executable') return l:executable . ale#Pad(ale#Var(a:buffer, 'cairo_sierra_options')) . ' %s' endfunction call ale#linter#Define('cairo', { \ 'name': 'sierra', \ 'executable': {b -> ale#Var(b, 'cairo_sierra_executable')}, \ 'command': function('ale_linters#cairo#sierra#GetCommand'), \ 'callback': 'ale_linters#cairo#sierra#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/cairo/starknet.vim ================================================ " Author: 0xHyoga <0xHyoga@gmx.com> " Description: Report starknet-compile errors in cairo code (pre-starknet " 1.0). This is deprecated but kept for backwards compatability. call ale#Set('cairo_starknet_executable', 'starknet-compile') call ale#Set('cairo_starknet_options', '') function! ale_linters#cairo#starknet#Handle(buffer, lines) abort " Error always on the first line " e.g ex01.cairo:20:6: Could not find module 'contracts.utils.ex00_base'. Searched in the following paths: let l:pattern = '\v\.cairo:(\d+):(\d+):+ (.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[1]), \ 'col': str2nr(l:match[2]), \ 'type': 'E', \ 'text': l:match[3], \}) endfor return l:output endfunction function! ale_linters#cairo#starknet#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'cairo_starknet_executable') return l:executable . ale#Pad(ale#Var(a:buffer, 'cairo_starknet_options')) . ' %s' endfunction call ale#linter#Define('cairo', { \ 'name': 'starknet', \ 'executable': {b -> ale#Var(b, 'cairo_starknet_executable')}, \ 'command': function('ale_linters#cairo#starknet#GetCommand'), \ 'callback': 'ale_linters#cairo#starknet#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/chef/cookstyle.vim ================================================ " Author: Raphael Hoegger - https://github.com/pfuender " Description: Cookstyle (RuboCop based), a code style analyzer for Ruby files call ale#Set('chef_cookstyle_executable', 'cookstyle') call ale#Set('chef_cookstyle_options', '') function! ale_linters#chef#cookstyle#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'chef_cookstyle_options') return '%e' . ale#Pad(escape(l:options, '~')) . ' --force-exclusion --format json --stdin ' . ' %s' endfunction function! ale_linters#chef#cookstyle#Handle(buffer, lines) abort if len(a:lines) == 0 return [] endif let l:errors = ale#util#FuzzyJSONDecode(a:lines[0], {}) 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 = str2nr(l:error['location']['start_column']) let l:end_col = str2nr(l:error['location']['last_column']) if !l:end_col let l:end_col = l:start_col + 1 endif call add(l:output, { \ 'lnum': str2nr(l:error['location']['line']), \ 'col': l:start_col, \ 'end_col': l:end_col, \ 'code': l:error['cop_name'], \ 'text': l:error['message'], \ 'type': l:error['severity'] is? 'convention' ? 'W' : 'E', \}) endfor return l:output endfunction call ale#linter#Define('chef', { \ 'name': 'cookstyle', \ 'executable': {b -> ale#Var(b, 'chef_cookstyle_executable')}, \ 'command': function('ale_linters#chef#cookstyle#GetCommand'), \ 'callback': 'ale_linters#chef#cookstyle#Handle', \}) ================================================ FILE: ale_linters/chef/foodcritic.vim ================================================ " Author: Edward Larkey " Author: Jose Junior " Author: w0rp " Description: This file adds the foodcritic linter for Chef files. call ale#Set('chef_foodcritic_executable', 'foodcritic') call ale#Set('chef_foodcritic_options', '') function! ale_linters#chef#foodcritic#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'chef_foodcritic_options') return '%e' . ale#Pad(escape(l:options, '~')) . ' %s' endfunction function! ale_linters#chef#foodcritic#Handle(buffer, lines) abort " Matches patterns line the following: " " FC002: Avoid string interpolation where not required: httpd.rb:13 let l:pattern = '\v([^:]+): (.+): ([a-zA-Z]?:?[^:]+):(\d+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'code': l:match[1], \ 'text': l:match[2], \ 'filename': l:match[3], \ 'lnum': l:match[4] + 0, \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('chef', { \ 'name': 'foodcritic', \ 'executable': {b -> ale#Var(b, 'chef_foodcritic_executable')}, \ 'command': function('ale_linters#chef#foodcritic#GetCommand'), \ 'callback': 'ale_linters#chef#foodcritic#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/clojure/clj_kondo.vim ================================================ " Author: Masashi Iizuka " Description: linter for clojure using clj-kondo https://github.com/borkdude/clj-kondo call ale#Set('clojure_clj_kondo_options', '--cache') function! ale_linters#clojure#clj_kondo#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'clojure_clj_kondo_options') let l:command = 'clj-kondo' \ . ale#Pad(l:options) \ . ' --lint -' \ . ' --filename %s' return l:command endfunction function! ale_linters#clojure#clj_kondo#HandleCljKondoFormat(buffer, lines) abort " output format " ::: : let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+)?:(\d+)?:? ((Exception|error|warning): ?(.+))$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:type = 'E' if l:match[4] is? 'warning' let l:type = 'W' endif call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3], \ 'type': l:type, \}) endfor return l:output endfunction call ale#linter#Define('clojure', { \ 'name': 'clj-kondo', \ 'output_stream': 'stdout', \ 'executable': 'clj-kondo', \ 'command': function('ale_linters#clojure#clj_kondo#GetCommand'), \ 'callback': 'ale_linters#clojure#clj_kondo#HandleCljKondoFormat', \}) ================================================ FILE: ale_linters/clojure/joker.vim ================================================ " Author: Nic West " Description: linter for clojure using joker https://github.com/candid82/joker function! ale_linters#clojure#joker#HandleJokerFormat(buffer, lines) abort " output format " ::: : let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+):? ((Read error|Parse error|Parse warning|Exception): ?(.+))$' let l:output = [] 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, \ 'text': l:match[3], \ 'type': l:type, \}) endfor return l:output endfunction call ale#linter#Define('clojure', { \ 'name': 'joker', \ 'output_stream': 'stderr', \ 'executable': 'joker', \ 'command': 'joker --working-dir %s --lint %t', \ 'callback': 'ale_linters#clojure#joker#HandleJokerFormat', \}) ================================================ FILE: ale_linters/cloudformation/cfn_python_lint.vim ================================================ " Author: Yasuhiro Kiyota " Description: Support cfn-python-lint for AWS Cloudformation template file function! ale_linters#cloudformation#cfn_python_lint#Handle(buffer, lines) abort " Matches patterns line the following: " " sample.template.yaml:96:7:96:15:E3012:Property Resources/Sample/Properties/FromPort should be of type Integer let l:pattern = '\v^(.*):(\d+):(\d+):(\d+):(\d+):([[:alnum:]]+):(.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[6] if ale#path#IsBufferPath(a:buffer, l:match[1]) call add(l:output, { \ 'lnum': l:match[2], \ 'col': l:match[3], \ 'end_lnum': l:match[4], \ 'end_col': l:match[5], \ 'code': l:code, \ 'type': l:code[:0] is# 'E' ? 'E' : 'W', \ 'text': l:match[7] \}) endif endfor return l:output endfunction call ale#linter#Define('cloudformation', { \ 'name': 'cloudformation', \ 'aliases': ['cfn-lint'], \ 'executable': 'cfn-lint', \ 'command': 'cfn-lint --template %t --format parseable', \ 'callback': 'ale_linters#cloudformation#cfn_python_lint#Handle', \}) ================================================ FILE: ale_linters/cloudformation/checkov.vim ================================================ " Author: J. Handsel , Thyme-87 " Description: use checkov for providing warnings for cloudformation via ale call ale#Set('cloudformation_checkov_executable', 'checkov') call ale#Set('cloudformation_checkov_options', '') function! ale_linters#cloudformation#checkov#GetExecutable(buffer) abort return ale#Var(a:buffer, 'cloudformation_checkov_executable') endfunction function! ale_linters#cloudformation#checkov#GetCommand(buffer) abort return '%e ' . '-f %t -o json --quiet --framework cloudformation ' . ale#Var(a:buffer, 'cloudformation_checkov_options') endfunction function! ale_linters#cloudformation#checkov#Handle(buffer, lines) abort let l:output = [] let l:results = get(get(ale#util#FuzzyJSONDecode(a:lines, {}), 'results', []), 'failed_checks', []) for l:violation in l:results call add(l:output, { \ 'filename': l:violation['file_path'], \ 'lnum': l:violation['file_line_range'][0], \ 'end_lnum': l:violation['file_line_range'][1], \ 'text': l:violation['check_name'] . ' [' . l:violation['check_id'] . ']', \ 'detail': l:violation['check_id'] . ': ' . l:violation['check_name'] . "\n" . \ 'For more information, see: '. l:violation['guideline'], \ 'type': 'W', \ }) endfor return l:output endfunction call ale#linter#Define('cloudformation', { \ 'name': 'checkov', \ 'output_stream': 'stdout', \ 'executable': function('ale_linters#cloudformation#checkov#GetExecutable'), \ 'command': function('ale_linters#cloudformation#checkov#GetCommand'), \ 'callback': 'ale_linters#cloudformation#checkov#Handle', \}) ================================================ FILE: ale_linters/cmake/cmake_lint.vim ================================================ " Author: Carl Smedstad " Description: cmake-lint for cmake files let g:ale_cmake_cmake_lint_executable = \ get(g:, 'ale_cmake_cmake_lint_executable', 'cmake-lint') let g:ale_cmake_cmake_lint_options = \ get(g:, 'ale_cmake_cmake_lint_options', '') function! ale_linters#cmake#cmake_lint#Executable(buffer) abort return ale#Var(a:buffer, 'cmake_cmake_lint_executable') endfunction function! ale_linters#cmake#cmake_lint#Command(buffer) abort let l:executable = ale_linters#cmake#cmake_lint#Executable(a:buffer) let l:options = ale#Var(a:buffer, 'cmake_cmake_lint_options') return ale#Escape(l:executable) . ' ' . l:options . ' %s' endfunction function! ale_linters#cmake#cmake_lint#Handle(buffer, lines) abort let l:pattern = '\v^[^:]+:(\d+),?(\d+)?:\s\[([A-Z]\d+)\]\s(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': 'W', \ 'code': l:match[3], \ 'text': l:match[4], \}) endfor return l:output endfunction call ale#linter#Define('cmake', { \ 'name': 'cmake_lint', \ 'executable': function('ale_linters#cmake#cmake_lint#Executable'), \ 'command': function('ale_linters#cmake#cmake_lint#Command'), \ 'callback': 'ale_linters#cmake#cmake_lint#Handle', \}) ================================================ FILE: ale_linters/cmake/cmakelint.vim ================================================ " Author: Kenneth Benzie " Description: cmakelint for cmake files let g:ale_cmake_cmakelint_executable = \ get(g:, 'ale_cmake_cmakelint_executable', 'cmakelint') let g:ale_cmake_cmakelint_options = \ get(g:, 'ale_cmake_cmakelint_options', '') function! ale_linters#cmake#cmakelint#Executable(buffer) abort return ale#Var(a:buffer, 'cmake_cmakelint_executable') endfunction function! ale_linters#cmake#cmakelint#Command(buffer) abort return ale_linters#cmake#cmakelint#Executable(a:buffer) \ . ' ' . ale#Var(a:buffer, 'cmake_cmakelint_options') . ' %t' endfunction call ale#linter#Define('cmake', { \ 'name': 'cmakelint', \ 'executable': function('ale_linters#cmake#cmakelint#Executable'), \ 'command': function('ale_linters#cmake#cmakelint#Command'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/coffee/coffee.vim ================================================ " Author: KabbAmine - https://github.com/KabbAmine " Description: Coffee for checking coffee files function! ale_linters#coffee#coffee#GetExecutable(buffer) abort return ale#path#ResolveLocalPath( \ a:buffer, \ 'node_modules/.bin/coffee', \ 'coffee' \) endfunction function! ale_linters#coffee#coffee#GetCommand(buffer) abort return ale_linters#coffee#coffee#GetExecutable(a:buffer) \ . ' -cp -s' endfunction call ale#linter#Define('coffee', { \ 'name': 'coffee', \ 'executable': function('ale_linters#coffee#coffee#GetExecutable'), \ 'command': function('ale_linters#coffee#coffee#GetCommand'), \ 'output_stream': 'stderr', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \}) ================================================ FILE: ale_linters/coffee/coffeelint.vim ================================================ " Author: Prashanth Chandra https://github.com/prashcr " Description: coffeelint linter for coffeescript files function! ale_linters#coffee#coffeelint#GetExecutable(buffer) abort return ale#path#ResolveLocalPath( \ a:buffer, \ 'node_modules/.bin/coffeelint', \ 'coffeelint' \) endfunction function! ale_linters#coffee#coffeelint#GetCommand(buffer) abort return ale_linters#coffee#coffeelint#GetExecutable(a:buffer) \ . ' --stdin --reporter csv' endfunction function! ale_linters#coffee#coffeelint#Handle(buffer, lines) abort " Matches patterns like the following: " " path,lineNumber,lineNumberEnd,level,message " stdin,14,,error,Throwing strings is forbidden " " Note that we currently ignore lineNumberEnd for multiline errors let l:pattern = 'stdin,\(\d\+\),\(\d*\),\(.\{-1,}\),\(.\+\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[1]), \ 'type': l:match[3] is# 'error' ? 'E' : 'W', \ 'text': l:match[4], \}) endfor return l:output endfunction call ale#linter#Define('coffee', { \ 'name': 'coffeelint', \ 'executable': function('ale_linters#coffee#coffeelint#GetExecutable'), \ 'command': function('ale_linters#coffee#coffeelint#GetCommand'), \ 'callback': 'ale_linters#coffee#coffeelint#Handle', \}) ================================================ FILE: ale_linters/cpp/cc.vim ================================================ " Author: w0rp " Description: A C++ compiler linter for C++ files with gcc/clang, etc. call ale#Set('cpp_cc_executable', '') call ale#Set('cpp_cc_options', '-std=c++14 -Wall') call ale#Set('cpp_cc_use_header_lang_flag', -1) call ale#Set('cpp_cc_header_exts', ['h', 'hpp']) function! ale_linters#cpp#cc#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'cpp_cc_executable') " Default to either clang++ or gcc. if l:executable is# '' if ale#engine#IsExecutable(a:buffer, 'clang++') let l:executable = 'clang++' else let l:executable = 'gcc' endif endif return l:executable endfunction function! ale_linters#cpp#cc#GetCommand(buffer, output) abort let l:cflags = ale#c#GetCFlags(a:buffer, a:output) let l:ale_flags = ale#Var(a:buffer, 'cpp_cc_options') if l:cflags =~# '-std=' let l:ale_flags = substitute( \ l:ale_flags, \ '-std=\(c\|gnu\)++[0-9]\{2\}', \ '', \ 'g') endif " Select the correct language flag depending on the executable, options " and file extension let l:executable = ale_linters#cpp#cc#GetExecutable(a:buffer) let l:use_header_lang_flag = ale#Var(a:buffer, 'cpp_cc_use_header_lang_flag') let l:header_exts = ale#Var(a:buffer, 'cpp_cc_header_exts') let l:lang_flag = ale#c#GetLanguageFlag( \ a:buffer, \ l:executable, \ l:use_header_lang_flag, \ l:header_exts, \ 'c++') " -iquote with the directory the file is in makes #include work for " headers in the same directory. " " `-o /dev/null` or `-o null` is needed to catch all errors, " -fsyntax-only doesn't catch everything. return '%e -S -x ' . l:lang_flag \ . ' -o ' . g:ale#util#nul_file \ . ' -iquote %s:h' \ . ale#Pad(l:cflags) \ . ale#Pad(l:ale_flags) . ' -' endfunction call ale#linter#Define('cpp', { \ 'name': 'cc', \ 'aliases': ['gcc', 'clang', 'g++', 'clang++'], \ 'output_stream': 'stderr', \ 'executable': function('ale_linters#cpp#cc#GetExecutable'), \ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#cc#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) ================================================ FILE: ale_linters/cpp/ccls.vim ================================================ " Author: Ye Jingchen , Ben Falconer , jtalowell " Description: A language server for C++ call ale#Set('cpp_ccls_executable', 'ccls') call ale#Set('cpp_ccls_init_options', {}) call ale#Set('c_build_dir', '') call ale#linter#Define('cpp', { \ 'name': 'ccls', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'cpp_ccls_executable')}, \ 'command': '%e', \ 'project_root': function('ale#handlers#ccls#GetProjectRoot'), \ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'cpp_ccls_init_options')}, \}) ================================================ FILE: ale_linters/cpp/clangcheck.vim ================================================ " Author: gagbo " Description: clang-check linter for cpp files 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#GetCommand(buffer) abort let l:user_options = ale#Var(a:buffer, 'cpp_clangcheck_options') " Try to find compilation database to link automatically let l:build_dir = ale#Var(a:buffer, 'c_build_dir') if empty(l:build_dir) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) let l:build_dir = ale#path#Dirname(l:json_file) 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 '%e -analyze %s' \ . (empty(l:build_dir) ? ' --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics': '') \ . ale#Pad(l:user_options) \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') endfunction call ale#linter#Define('cpp', { \ 'name': 'clangcheck', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'cpp_clangcheck_executable')}, \ 'command': function('ale_linters#cpp#clangcheck#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/cpp/clangd.vim ================================================ " Author: Andrey Melentyev " Description: Clangd language server call ale#Set('cpp_clangd_executable', 'clangd') call ale#Set('cpp_clangd_options', '') call ale#Set('c_build_dir', '') function! ale_linters#cpp#clangd#GetCommand(buffer) abort let l:build_dir = ale#c#GetBuildDirectory(a:buffer) return '%e' \ . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options')) \ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '') endfunction call ale#linter#Define('cpp', { \ 'name': 'clangd', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')}, \ 'command': function('ale_linters#cpp#clangd#GetCommand'), \ 'project_root': function('ale#c#FindProjectRoot'), \}) ================================================ FILE: ale_linters/cpp/clangtidy.vim ================================================ " Author: vdeurzen , w0rp , " gagbo " Description: clang-tidy linter for cpp files 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', []) " Set this option to manually set some options for clang-tidy to use as compile " flags. " This will disable compile_commands.json detection. call ale#Set('cpp_clangtidy_options', '') " Set this option to manually set options for clang-tidy directly. call ale#Set('cpp_clangtidy_extra_options', '') call ale#Set('c_build_dir', '') function! ale_linters#cpp#clangtidy#GetCommand(buffer, output) abort let l:checks = join(ale#Var(a:buffer, 'cpp_clangtidy_checks'), ',') let l:build_dir = ale#c#GetBuildDirectory(a:buffer) let l:options = '' " Get the extra options if we couldn't find a build directory. if empty(l:build_dir) let l:options = ale#Var(a:buffer, 'cpp_clangtidy_options') let l:cflags = ale#c#GetCFlags(a:buffer, a:output) let l:options .= !empty(l:options) ? ale#Pad(l:cflags) : l:cflags " Tell clang-tidy a .h header with a C++ filetype in Vim is a C++ file " only when compile-commands.json file is not there. Adding these " flags makes clang-tidy completely ignore compile commands. if expand('#' . a:buffer) =~# '\.h$' let l:options .= !empty(l:options) ? ' -x c++' : '-x c++' endif endif " Get the options to pass directly to clang-tidy let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options') return '%e' \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') \ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '') \ . ' %s' \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:options) ? ' -- ' . l:options : '') endfunction call ale#linter#Define('cpp', { \ 'name': 'clangtidy', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'cpp_clangtidy_executable')}, \ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clangtidy#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/cpp/clazy.vim ================================================ " 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) : '') \ . ale#Pad(l:options) \ . ' %s' endfunction call ale#linter#Define('cpp', { \ 'name': 'clazy', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'cpp_clazy_executable')}, \ 'command': function('ale_linters#cpp#clazy#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/cpp/cppcheck.vim ================================================ " Author: Bart Libert " Description: cppcheck linter for cpp files call ale#Set('cpp_cppcheck_executable', 'cppcheck') call ale#Set('cpp_cppcheck_options', '--enable=style') function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer) let l:buffer_path_include = empty(l:compile_commands_option) \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ : '' let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') " Versions >=2.13 don't allow using --project in conjunction with an " explicit source file. let l:source_file = stridx(l:compile_commands_option, '--project=') < 0 \ ? ' %t' \ : '' return '%e -q --language=c++' \ . l:template \ . ale#Pad(l:compile_commands_option) \ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options')) \ . l:buffer_path_include \ . l:source_file endfunction call ale#linter#Define('cpp', { \ 'name': 'cppcheck', \ 'output_stream': 'both', \ 'executable': {b -> ale#Var(b, 'cpp_cppcheck_executable')}, \ 'cwd': function('ale#handlers#cppcheck#GetCwd'), \ 'command': function('ale_linters#cpp#cppcheck#GetCommand'), \ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat', \}) ================================================ FILE: ale_linters/cpp/cpplint.vim ================================================ " Author: Dawid Kurek https://github.com/dawikur " Description: cpplint for cpp files call ale#Set('cpp_cpplint_executable', 'cpplint') call ale#Set('cpp_cpplint_options', '') function! ale_linters#cpp#cpplint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'cpp_cpplint_options') return '%e' . ale#Pad(l:options) . ' %s' endfunction call ale#linter#Define('cpp', { \ 'name': 'cpplint', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'cpp_cpplint_executable')}, \ 'command': function('ale_linters#cpp#cpplint#GetCommand'), \ 'callback': 'ale#handlers#cpplint#HandleCppLintFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/cpp/cquery.vim ================================================ " Author: Ben Falconer " Description: A language server for C++ call ale#Set('cpp_cquery_executable', 'cquery') call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery')) function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort " Try to find cquery configuration files first. let l:config = ale#path#FindNearestFile(a:buffer, '.cquery') if !empty(l:config) return fnamemodify(l:config, ':h') endif " Fall back on default project root detection. return ale#c#FindProjectRoot(a:buffer) endfunction function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort return {'cacheDirectory': ale#Var(a:buffer, 'cpp_cquery_cache_directory')} endfunction call ale#linter#Define('cpp', { \ 'name': 'cquery', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'cpp_cquery_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#cpp#cquery#GetProjectRoot'), \ 'initialization_options': function('ale_linters#cpp#cquery#GetInitializationOptions'), \}) ================================================ FILE: ale_linters/cpp/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for C++ files. call ale#handlers#cspell#DefineLinter('cpp') ================================================ FILE: ale_linters/cpp/flawfinder.vim ================================================ " Author: Christian Gibbons " Description: flawfinder linter for c++ files call ale#Set('cpp_flawfinder_executable', 'flawfinder') 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#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 '%e -CDQS' \ . ale#Var(a:buffer, 'cpp_flawfinder_options') \ . l:minlevel \ . ' %t' endfunction call ale#linter#Define('cpp', { \ 'name': 'flawfinder', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'cpp_flawfinder_executable')}, \ 'command': function('ale_linters#cpp#flawfinder#GetCommand'), \ 'callback': 'ale#handlers#flawfinder#HandleFlawfinderFormat', \}) ================================================ FILE: ale_linters/crystal/ameba.vim ================================================ " Author: Harrison Bachrach - https://github.com/HarrisonB " Description: Ameba, a linter for crystal files call ale#Set('crystal_ameba_executable', 'bin/ameba') function! ale_linters#crystal#ameba#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'crystal_ameba_executable') return ale#Escape(l:executable) \ . ' --format json ' \ . ale#Escape(expand('#' . a:buffer . ':p')) endfunction " Handle output from ameba function! ale_linters#crystal#ameba#HandleAmebaOutput(buffer, lines) abort if len(a:lines) == 0 return [] endif let l:errors = ale#util#FuzzyJSONDecode(a:lines[0], {}) if !has_key(l:errors, 'summary') \|| l:errors['summary']['issues_count'] == 0 \|| empty(l:errors['sources']) return [] endif let l:output = [] for l:error in l:errors['sources'][0]['issues'] let l:start_col = str2nr(l:error['location']['column']) let l:end_col = str2nr(l:error['end_location']['column']) if !l:end_col let l:end_col = l:start_col + 1 endif call add(l:output, { \ 'lnum': str2nr(l:error['location']['line']), \ 'col': l:start_col, \ 'end_col': l:end_col, \ 'code': l:error['rule_name'], \ 'text': l:error['message'], \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('crystal', { \ 'name': 'ameba', \ 'executable': {b -> ale#Var(b, 'crystal_ameba_executable')}, \ 'command': function('ale_linters#crystal#ameba#GetCommand'), \ 'callback': 'ale_linters#crystal#ameba#HandleAmebaOutput', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/crystal/crystal.vim ================================================ " Author: Jordan Andree , David Alexander " Description: This file adds support for checking Crystal with crystal build function! ale_linters#crystal#crystal#Handle(buffer, lines) abort let l:output = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) if !has_key(l:error, 'file') continue endif call add(l:output, { \ 'lnum': l:error.line + 0, \ 'col': l:error.column + 0, \ 'text': l:error.message, \}) endfor return l:output endfunction function! ale_linters#crystal#crystal#GetCommand(buffer) abort return 'crystal build -f json --no-codegen --no-color -o ' \ . ale#Escape(g:ale#util#nul_file) \ . ' %s' endfunction call ale#linter#Define('crystal', { \ 'name': 'crystal', \ 'executable': 'crystal', \ 'output_stream': 'both', \ 'lint_file': 1, \ 'command': function('ale_linters#crystal#crystal#GetCommand'), \ 'callback': 'ale_linters#crystal#crystal#Handle', \}) ================================================ FILE: ale_linters/cs/csc.vim ================================================ call ale#Set('cs_csc_options', '') call ale#Set('cs_csc_source', '') call ale#Set('cs_csc_assembly_path', []) call ale#Set('cs_csc_assemblies', []) function! ale_linters#cs#csc#GetCwd(buffer) abort let l:cwd = ale#Var(a:buffer, 'cs_csc_source') return !empty(l:cwd) ? l:cwd : expand('#' . a:buffer . ':p:h') endfunction function! ale_linters#cs#csc#GetCommand(buffer) abort " Pass assembly paths via the -lib: parameter. let l:path_list = ale#Var(a:buffer, 'cs_csc_assembly_path') let l:lib_option = !empty(l:path_list) \ ? '/lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',') \ : '' " Pass paths to DLL files via the -r: parameter. let l:assembly_list = ale#Var(a:buffer, 'cs_csc_assemblies') let l:r_option = !empty(l:assembly_list) \ ? '/r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',') \ : '' " register temporary module target file with ale " register temporary module target file with ALE. let l:out = ale#command#CreateFile(a:buffer) " The code is compiled as a module and the output is redirected to a " temporary file. return 'csc /unsafe' \ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options')) \ . ale#Pad(l:lib_option) \ . ale#Pad(l:r_option) \ . ' /out:' . l:out \ . ' /t:module' \ . ' /recurse:' . ale#Escape('*.cs') endfunction function! ale_linters#cs#csc#Handle(buffer, lines) abort " Look for lines like the following. " " Tests.cs(12,29): error CSXXXX: ; expected " " NOTE: pattern also captures file name as linter compiles all " files within the source tree rooted at the specified source " path and not just the file loaded in the buffer let l:patterns = [ \ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$', \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', \] let l:output = [] let l:dir = ale_linters#cs#csc#GetCwd(a:buffer) for l:match in ale#util#GetMatches(a:lines, l:patterns) if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'code': l:match[5], \ 'text': l:match[6] , \}) elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS' call add(l:output, { \ 'filename':'', \ 'lnum': -1, \ 'col': -1, \ 'type': l:match[1] is# 'error' ? 'E' : 'W', \ 'code': l:match[2], \ 'text': l:match[3], \}) endif endfor return l:output endfunction call ale#linter#Define('cs',{ \ 'name': 'csc', \ 'output_stream': 'stdout', \ 'executable': 'csc', \ 'cwd': function('ale_linters#cs#csc#GetCwd'), \ 'command': function('ale_linters#cs#csc#GetCommand'), \ 'callback': 'ale_linters#cs#csc#Handle', \ 'lint_file': 1 \}) ================================================ FILE: ale_linters/cs/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for C# files. call ale#handlers#cspell#DefineLinter('cs') ================================================ FILE: ale_linters/cs/mcs.vim ================================================ let g:ale_cs_mcs_options = get(g:, 'ale_cs_mcs_options', '') function! ale_linters#cs#mcs#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'cs_mcs_options') return 'mcs -unsafe --parse' \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale_linters#cs#mcs#Handle(buffer, lines) abort " Look for lines like the following. " " Tests.cs(12,29): error CSXXXX: ; expected let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'code': l:match[5], \ 'text': l:match[6], \}) endfor return l:output endfunction call ale#linter#Define('cs',{ \ 'name': 'mcs', \ 'output_stream': 'stderr', \ 'executable': 'mcs', \ 'command': function('ale_linters#cs#mcs#GetCommand'), \ 'callback': 'ale_linters#cs#mcs#Handle', \}) ================================================ FILE: ale_linters/cs/mcsc.vim ================================================ call ale#Set('cs_mcsc_options', '') call ale#Set('cs_mcsc_source', '') call ale#Set('cs_mcsc_assembly_path', []) call ale#Set('cs_mcsc_assemblies', []) function! ale_linters#cs#mcsc#GetCwd(buffer) abort let l:cwd = ale#Var(a:buffer, 'cs_mcsc_source') return !empty(l:cwd) ? l:cwd : expand('#' . a:buffer . ':p:h') endfunction function! ale_linters#cs#mcsc#GetCommand(buffer) abort " Pass assembly paths via the -lib: parameter. let l:path_list = ale#Var(a:buffer, 'cs_mcsc_assembly_path') let l:lib_option = !empty(l:path_list) \ ? '-lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',') \ : '' " Pass paths to DLL files via the -r: parameter. let l:assembly_list = ale#Var(a:buffer, 'cs_mcsc_assemblies') let l:r_option = !empty(l:assembly_list) \ ? '-r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',') \ : '' " register temporary module target file with ale " register temporary module target file with ALE. let l:out = ale#command#CreateFile(a:buffer) " The code is compiled as a module and the output is redirected to a " temporary file. return 'mcs -unsafe' \ . ale#Pad(ale#Var(a:buffer, 'cs_mcsc_options')) \ . ale#Pad(l:lib_option) \ . ale#Pad(l:r_option) \ . ' -out:' . l:out \ . ' -t:module' \ . ' -recurse:' . ale#Escape('*.cs') endfunction function! ale_linters#cs#mcsc#Handle(buffer, lines) abort " Look for lines like the following. " " Tests.cs(12,29): error CSXXXX: ; expected " " NOTE: pattern also captures file name as linter compiles all " files within the source tree rooted at the specified source " path and not just the file loaded in the buffer let l:patterns = [ \ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$', \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', \] let l:output = [] let l:dir = ale_linters#cs#mcsc#GetCwd(a:buffer) for l:match in ale#util#GetMatches(a:lines, l:patterns) if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'code': l:match[5], \ 'text': l:match[6] , \}) elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS' call add(l:output, { \ 'filename':'', \ 'lnum': -1, \ 'col': -1, \ 'type': l:match[1] is# 'error' ? 'E' : 'W', \ 'code': l:match[2], \ 'text': l:match[3], \}) endif endfor return l:output endfunction call ale#linter#Define('cs',{ \ 'name': 'mcsc', \ 'output_stream': 'stderr', \ 'executable': 'mcs', \ 'cwd': function('ale_linters#cs#mcsc#GetCwd'), \ 'command': function('ale_linters#cs#mcsc#GetCommand'), \ 'callback': 'ale_linters#cs#mcsc#Handle', \ 'lint_file': 1 \}) ================================================ FILE: ale_linters/css/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for CSS files. call ale#handlers#cspell#DefineLinter('css') ================================================ FILE: ale_linters/css/csslint.vim ================================================ " Author: w0rp " Description: This file adds support for checking CSS code with csslint. function! ale_linters#css#csslint#GetCommand(buffer) abort let l:csslintrc = ale#path#FindNearestFile(a:buffer, '.csslintrc') let l:config_option = !empty(l:csslintrc) \ ? '--config=' . ale#Escape(l:csslintrc) \ : '' return 'csslint --format=compact ' . l:config_option . ' %t' endfunction call ale#linter#Define('css', { \ 'name': 'csslint', \ 'executable': 'csslint', \ 'command': function('ale_linters#css#csslint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleCSSLintFormat', \}) ================================================ FILE: ale_linters/css/fecs.vim ================================================ " Author: harttle " Description: fecs for CSS files call ale#linter#Define('css', { \ 'name': 'fecs', \ 'executable': function('ale#handlers#fecs#GetExecutable'), \ 'command': function('ale#handlers#fecs#GetCommand'), \ 'callback': 'ale#handlers#fecs#Handle', \}) ================================================ FILE: ale_linters/css/stylelint.vim ================================================ " Author: diartyz 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#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'css_stylelint_options')) \ . ' --no-color --stdin-filename %s' endfunction call ale#linter#Define('css', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': {b -> ale#path#FindExecutable(b, 'css_stylelint', [ \ 'node_modules/.bin/stylelint', \ ])}, \ 'command': function('ale_linters#css#stylelint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/css/vscodecss.vim ================================================ " Author: Dalius Dobravolskas " Description: VSCode css language server function! ale_linters#css#vscodecss#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('css', { \ 'name': 'vscodecss', \ 'lsp': 'stdio', \ 'executable': 'vscode-css-language-server', \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#css#vscodecss#GetProjectRoot'), \}) ================================================ FILE: ale_linters/cucumber/cucumber.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: Cucumber, a BDD test tool function! ale_linters#cucumber#cucumber#GetCommand(buffer) abort let l:features_dir = ale#path#FindNearestDirectory(a:buffer, 'features') if !empty(l:features_dir) let l:features_arg = '-r ' . ale#Escape(l:features_dir) else let l:features_arg = '' endif return 'cucumber --dry-run --quiet --strict --format=json ' \ . l:features_arg . ' %t' endfunction function! ale_linters#cucumber#cucumber#Handle(buffer, lines) abort try let l:json = ale#util#FuzzyJSONDecode(a:lines, {})[0] catch return [] 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' call add(l:output, { \ 'lnum': l:step['line'], \ 'code': 'E', \ 'text': 'Undefined step' \}) endif endfor endfor return l:output endfunction call ale#linter#Define('cucumber', { \ 'name': 'cucumber', \ 'executable': 'cucumber', \ 'command': function('ale_linters#cucumber#cucumber#GetCommand'), \ 'callback': 'ale_linters#cucumber#cucumber#Handle' \}) ================================================ FILE: ale_linters/cuda/clangd.vim ================================================ " Author: Tommy Chiang " Description: Clangd language server for CUDA (modified from Andrey " Melentyev's implementation for C++) call ale#Set('cuda_clangd_executable', 'clangd') call ale#Set('cuda_clangd_options', '') call ale#Set('c_build_dir', '') function! ale_linters#cuda#clangd#GetCommand(buffer) abort let l:build_dir = ale#c#GetBuildDirectory(a:buffer) return '%e' \ . ale#Pad(ale#Var(a:buffer, 'cuda_clangd_options')) \ . (!empty(l:build_dir) ? ' -compile-commands-dir=' . ale#Escape(l:build_dir) : '') endfunction call ale#linter#Define('cuda', { \ 'name': 'clangd', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'cuda_clangd_executable')}, \ 'command': function('ale_linters#cuda#clangd#GetCommand'), \ 'project_root': function('ale#c#FindProjectRoot'), \}) ================================================ FILE: ale_linters/cuda/nvcc.vim ================================================ " Author: blahgeek " Description: NVCC linter for cuda files call ale#Set('cuda_nvcc_executable', 'nvcc') call ale#Set('cuda_nvcc_options', '-std=c++11') function! ale_linters#cuda#nvcc#GetCommand(buffer) abort 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 " Look for lines like the following. " " test.cu(8): error: argument of type "void *" is incompatible with parameter of type "int *" let l:pattern = '\v^([^:\(\)]+):?\(?(\d+)\)?:(\d+)?:?\s*\w*\s*(error|warning): (.+)$' 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', \ 'text': l:match[5], \ 'filename': fnamemodify(l:match[1], ':p'), \} if !empty(l:match[3]) let l:item.col = str2nr(l:match[3]) endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('cuda', { \ 'name': 'nvcc', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'cuda_nvcc_executable')}, \ 'command': function('ale_linters#cuda#nvcc#GetCommand'), \ 'callback': 'ale_linters#cuda#nvcc#HandleNVCCFormat', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/cypher/cypher_lint.vim ================================================ " Author: Francisco Lopes " Description: Linting for Neo4j's Cypher function! ale_linters#cypher#cypher_lint#Handle(buffer, lines) abort let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+): (.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \ 'type': 'E', \}) endfor return l:output endfunction call ale#linter#Define('cypher', { \ 'name': 'cypher_lint', \ 'executable': 'cypher-lint', \ 'command': 'cypher-lint', \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#cypher#cypher_lint#Handle', \}) ================================================ FILE: ale_linters/d/dls.vim ================================================ " Author: aurieh " 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': function('ale_linters#d#dls#GetExecutable'), \ 'command': function('ale_linters#d#dls#GetExecutable'), \ 'project_root': function('ale_linters#d#dls#FindProjectRoot'), \}) ================================================ FILE: ale_linters/d/dmd.vim ================================================ " Author: w0rp " Description: "dmd for D files" function! s:GetDUBCommand(buffer) abort " If we can't run dub, then skip this command. if executable('dub') " Returning an empty string skips to the DMD command. let l:config = ale#d#FindDUBConfig(a:buffer) " To support older dub versions, we just change the directory to the " directory where we found the dub config, and then run `dub describe` " from that directory. if !empty(l:config) return [fnamemodify(l:config, ':h'), 'dub describe --data-list \ --data=import-paths \ --data=string-import-paths \ --data=versions \ --data=debug-versions \'] endif endif return ['', ''] endfunction function! ale_linters#d#dmd#RunDUBCommand(buffer) abort let [l:cwd, l:command] = s:GetDUBCommand(a:buffer) if empty(l:command) " If we can't run DUB, just run DMD. return ale_linters#d#dmd#DMDCommand(a:buffer, [], {}) endif return ale#command#Run( \ a:buffer, \ l:command, \ function('ale_linters#d#dmd#DMDCommand'), \ {'cwd': l:cwd}, \) endfunction function! ale_linters#d#dmd#DMDCommand(buffer, dub_output, meta) abort let l:import_list = [] let l:str_import_list = [] let l:versions_list = [] let l:deb_versions_list = [] let l:list_ind = 1 let l:seen_line = 0 " Build a list of options generated from DUB, if available. " DUB output each path or version on a single line. " Each list is separated by a blank line. " Empty list are represented by a blank line (followed and/or " preceded by a separation blank line) for l:line in a:dub_output " line still has end of line char on windows let l:line = substitute(l:line, '[\r\n]*$', '', '') if !empty(l:line) if l:list_ind == 1 call add(l:import_list, '-I' . ale#Escape(l:line)) elseif l:list_ind == 2 call add(l:str_import_list, '-J' . ale#Escape(l:line)) elseif l:list_ind == 3 call add(l:versions_list, '-version=' . ale#Escape(l:line)) elseif l:list_ind == 4 call add(l:deb_versions_list, '-debug=' . ale#Escape(l:line)) endif let l:seen_line = 1 elseif !l:seen_line " if list is empty must skip one empty line let l:seen_line = 1 else let l:seen_line = 0 let l:list_ind += 1 endif endfor return 'dmd ' . join(l:import_list) . ' ' . \ join(l:str_import_list) . ' ' . \ join(l:versions_list) . ' ' . \ join(l:deb_versions_list) . ' -o- -wi -vcolumns -c %t' endfunction function! ale_linters#d#dmd#Handle(buffer, lines) abort " Matches patterns lines like the following: " /tmp/tmp.qclsa7qLP7/file.d(1): Error: function declaration without return type. (Note that constructors are always named 'this') " /tmp/tmp.G1L5xIizvB.d(8,8): Error: module weak_reference is in file 'dstruct/weak_reference.d' which cannot be read let l:pattern = '\v^(\f+)\((\d+)(,(\d+))?\): (\w+): (.+)$' let l:output = [] let l:dir = expand('#' . a:buffer . ':p:h') for l:match in ale#util#GetMatches(a:lines, l:pattern) " If dmd was invoked with relative path, match[1] is relative, otherwise it is absolute. " As we invoke dmd with the buffer path (in /tmp), this will generally be absolute already let l:fname = ale#path#GetAbsPath(l:dir, l:match[1]) call add(l:output, { \ 'filename': l:fname, \ 'lnum': l:match[2], \ 'col': l:match[4], \ 'type': l:match[5] is# 'Warning' || l:match[5] is# 'Deprecation' ? 'W' : 'E', \ 'text': l:match[6], \}) endfor return l:output endfunction call ale#linter#Define('d', { \ 'name': 'dmd', \ 'executable': 'dmd', \ 'command': function('ale_linters#d#dmd#RunDUBCommand'), \ 'callback': 'ale_linters#d#dmd#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/dafny/dafny.vim ================================================ " Author: Taylor Blau call ale#Set('dafny_dafny_timelimit', 10) function! ale_linters#dafny#dafny#Handle(buffer, lines) abort let l:pattern = '\v(.*)\((\d+),(\d+)\): (.*): (.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'filename': l:match[1], \ 'col': l:match[3] + 0, \ 'lnum': l:match[2] + 0, \ 'text': l:match[5], \ 'type': l:match[4] =~# '^Error' ? 'E' : 'W' \ }) endfor for l:match in ale#util#GetMatches(a:lines, '\v(.*)\((\d+),(\d+)\): (Verification of .{-} timed out after \d+ seconds)') call add(l:output, { \ 'filename': l:match[1], \ 'col': l:match[3] + 0, \ 'lnum': l:match[2] + 0, \ 'text': l:match[4], \ 'type': 'E', \ }) endfor return l:output endfunction function! ale_linters#dafny#dafny#GetCommand(buffer) abort return printf('dafny %%s /compile:0 /timeLimit:%d', ale#Var(a:buffer, 'dafny_dafny_timelimit')) endfunction call ale#linter#Define('dafny', { \ 'name': 'dafny', \ 'executable': 'dafny', \ 'command': function('ale_linters#dafny#dafny#GetCommand'), \ 'callback': 'ale_linters#dafny#dafny#Handle', \ 'lint_file': 1, \ }) ================================================ FILE: ale_linters/dart/analysis_server.vim ================================================ " Author: Nelson Yeung " Description: Check Dart files with dart analysis server LSP call ale#Set('dart_analysis_server_enable_language_server', 1) call ale#Set('dart_analysis_server_executable', 'dart') function! ale_linters#dart#analysis_server#GetProjectRoot(buffer) abort " Note: pub only looks for pubspec.yaml, there's no point in adding " support for pubspec.yml let l:pubspec = ale#path#FindNearestFile(a:buffer, 'pubspec.yaml') return !empty(l:pubspec) ? fnamemodify(l:pubspec, ':h:h') : '.' endfunction function! ale_linters#dart#analysis_server#GetCommand(buffer) abort let l:language_server = ale#Var(a:buffer, 'dart_analysis_server_enable_language_server') let l:executable = ale#Var(a:buffer, 'dart_analysis_server_executable') let l:dart = resolve(exepath(l:executable)) let l:output = '%e ' \ . fnamemodify(l:dart, ':h') . '/snapshots/analysis_server.dart.snapshot' \ . ' --lsp' " Enable new language-server command if l:language_server == 1 let l:output = '%e language-server --protocol=lsp' endif return l:output endfunction call ale#linter#Define('dart', { \ 'name': 'analysis_server', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'dart_analysis_server_executable')}, \ 'command': function('ale_linters#dart#analysis_server#GetCommand'), \ 'project_root': function('ale_linters#dart#analysis_server#GetProjectRoot'), \}) ================================================ FILE: ale_linters/dart/dart_analyze.vim ================================================ " Author: ghsang " Description: Check Dart files with dart analyze call ale#Set('dart_analyze_executable', 'dart') function! ale_linters#dart#dart_analyze#Handle(buffer, lines) abort let l:pattern = '\v([a-z]+) - (.+):(\d+):(\d+) - (.+) - (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let [l:type, l:filename, l:lnum, l:col, l:message, l:code] = l:match[1:6] call add(l:output, { \ 'type': l:type is# 'error' ? 'E' : l:type is# 'info' ? 'I' : 'W', \ 'text': l:code . ': ' . l:message, \ 'lnum': str2nr(l:lnum), \ 'col': str2nr(l:col), \}) endfor return l:output endfunction call ale#linter#Define('dart', { \ 'name': 'dart_analyze', \ 'executable': {b -> ale#Var(b, 'dart_analyze_executable')}, \ 'command': '%e analyze --fatal-infos %s', \ 'callback': 'ale_linters#dart#dart_analyze#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/dart/language_server.vim ================================================ " Author: aurieh " Description: A language server for dart call ale#Set('dart_language_server_executable', 'dart_language_server') 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 let l:pubspec = ale#path#FindNearestFile(a:buffer, 'pubspec.yaml') return !empty(l:pubspec) ? fnamemodify(l:pubspec, ':h:h') : '' endfunction call ale#linter#Define('dart', { \ 'name': 'language_server', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'dart_language_server_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#dart#language_server#GetProjectRoot'), \}) ================================================ FILE: ale_linters/desktop/desktop_file_validate.vim ================================================ call ale#Set('desktop_desktop_file_validate_options', '') " Example matches for pattern: " " foo.desktop: warning: key "TerminalOptions" in group ... " foo.desktop: error: action "new-private-window" is defined, ... let s:pattern = '\v^(.+): ([a-z]+): (.+)$' function! ale_linters#desktop#desktop_file_validate#Handle(buffer, lines) abort " The error format doesn't specify lines, so we can just put all of the " errors on line 1. return ale#util#MapMatches(a:lines, s:pattern, {match -> { \ 'lnum': 1, \ 'col': 1, \ 'type': match[2] is? 'error' ? 'E' : 'W', \ 'text': match[3], \}}) endfunction call ale#linter#Define('desktop', { \ 'name': 'desktop_file_validate', \ 'aliases': ['desktop-file-validate'], \ 'executable': 'desktop-file-validate', \ 'command': {b -> \ '%e' \ . ale#Pad(ale#Var(b, 'desktop_desktop_file_validate_options')) \ . ' %t' \ }, \ 'callback': 'ale_linters#desktop#desktop_file_validate#Handle', \ 'output_stream': 'both', \}) ================================================ FILE: ale_linters/dockerfile/dockerfile_lint.vim ================================================ " Author: Alexander Olofsson 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'] let l:link = get(l:object, 'reference_url', '') if type(l:link) == v:t_list " Somehow, reference_url is returned as two-part list. " Anchor markers in that list are sometimes duplicated. " See https://github.com/projectatomic/dockerfile_lint/issues/134 let l:link = join(l:link, '') let l:link = substitute(l:link, '##', '#', '') endif let l:detail = l:message if get(l:object, 'description', 'None') isnot# 'None' let l:detail .= "\n\n" . l:object['description'] endif let l:detail .= "\n\n" . l:link call add(l:messages, { \ 'lnum': l:line, \ 'text': l:message, \ 'type': ale_linters#dockerfile#dockerfile_lint#GetType(l:type), \ 'detail': l:detail, \}) endfor endfor 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': {b -> ale#Var(b, 'dockerfile_dockerfile_lint_executable')}, \ 'command': function('ale_linters#dockerfile#dockerfile_lint#GetCommand'), \ 'callback': 'ale_linters#dockerfile#dockerfile_lint#Handle', \}) ================================================ FILE: ale_linters/dockerfile/dockerlinter.vim ================================================ " Author: Shad " Description: dockerlinter linter for dockerfile call ale#Set('dockerfile_dockerlinter_executable', 'dockerlinter') call ale#Set('dockerfile_dockerlinter_options', '') function! ale_linters#dockerfile#dockerlinter#GetType(type) abort if a:type is? 'error' return 'E' elseif a:type is? 'warning' return 'W' endif return 'I' endfunction function! ale_linters#dockerfile#dockerlinter#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:object in l:data let l:line = get(l:object, 'lineNumber', -1) let l:message = l:object['message'] let l:type = l:object['level'] let l:detail = l:message let l:code = l:object['code'] if l:code =~# '^SC' let l:link = 'https://www.shellcheck.net/wiki/' . l:code else let l:link = 'https://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md#' . l:code endif let l:detail = l:message . "\n\n" . l:link call add(l:messages, { \ 'lnum': l:line, \ 'code': l:code, \ 'text': l:message, \ 'type': ale_linters#dockerfile#dockerlinter#GetType(l:type), \ 'detail': l:detail, \}) endfor return l:messages endfunction function! ale_linters#dockerfile#dockerlinter#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'dockerfile_dockerlinter_options')) \ . ' -j -f' \ . ' %t' endfunction call ale#linter#Define('dockerfile', { \ 'name': 'dockerlinter', \ 'executable': {b -> ale#Var(b, 'dockerfile_dockerlinter_executable')}, \ 'command': function('ale_linters#dockerfile#dockerlinter#GetCommand'), \ 'callback': 'ale_linters#dockerfile#dockerlinter#Handle', \}) ================================================ FILE: ale_linters/dockerfile/hadolint.vim ================================================ " Author: hauleth - https://github.com/hauleth " always, yes, never call ale#Set('dockerfile_hadolint_use_docker', 'never') call ale#Set('dockerfile_hadolint_docker_image', 'hadolint/hadolint') call ale#Set('dockerfile_hadolint_options', '') function! ale_linters#dockerfile#hadolint#Handle(buffer, lines) abort " Matches patterns line the following: " " -:19 DL3001 warning: Pipe chain should start with a raw value. " /dev/stdin:19:3 unexpected thing let l:pattern = '\v^%(/dev/stdin|-):(\d+):?(\d+)? ((DL|SC)(\d+) )?((.+)?: )?(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:lnum = 0 let l:colnum = 0 if l:match[1] isnot# '' let l:lnum = l:match[1] + 0 endif if l:match[2] isnot# '' let l:colnum = l:match[2] + 0 endif " Shellcheck knows a 'style' severity - pin it to info level as well. if l:match[7] is# 'style' let l:type = 'I' elseif l:match[7] is# 'info' let l:type = 'I' elseif l:match[7] is# 'warning' let l:type = 'W' else let l:type = 'E' endif let l:text = l:match[8] let l:detail = l:match[8] let l:domain = 'https://github.com/hadolint/hadolint/wiki/' let l:code = '' let l:link = '' if l:match[4] is# 'SC' let l:domain = 'https://github.com/koalaman/shellcheck/wiki/' endif if l:match[5] isnot# '' let l:code = l:match[4] . l:match[5] let l:link = ' ( ' . l:domain . l:code . ' )' let l:detail = l:code . l:link . "\n\n" . l:detail else let l:type = 'E' let l:detail = 'hadolint could not parse the file because of a syntax error.' endif let l:line_output = { \ 'lnum': l:lnum, \ 'col': l:colnum, \ 'type': l:type, \ 'text': l:text, \ 'detail': l:detail \} if l:code isnot# '' let l:line_output['code'] = l:code endif call add(l:output, l:line_output) endfor return l:output endfunction " This is a little different than the typical 'executable' callback. We want " to afford the user the chance to say always use docker, never use docker, " and use docker if the hadolint executable is not present on the system. " " In the case of neither docker nor hadolint executables being present, it " really doesn't matter which we return -- either will have the effect of " 'nope, can't use this linter!'. function! ale_linters#dockerfile#hadolint#GetExecutable(buffer) abort let l:use_docker = ale#Var(a:buffer, 'dockerfile_hadolint_use_docker') " check for mandatory directives if l:use_docker is# 'never' return 'hadolint' elseif l:use_docker is# 'always' return 'docker' endif " if we reach here, we want to use 'hadolint' if present... if executable('hadolint') return 'hadolint' endif "... and 'docker' as a fallback. return 'docker' endfunction function! ale_linters#dockerfile#hadolint#GetCommand(buffer) abort let l:command = ale_linters#dockerfile#hadolint#GetExecutable(a:buffer) let l:opts = ale#Var(a:buffer, 'dockerfile_hadolint_options') . ' --no-color -' if l:command is# 'docker' return printf('docker run --rm -i %s hadolint %s', \ ale#Var(a:buffer, 'dockerfile_hadolint_docker_image'), \ l:opts) endif return 'hadolint ' . l:opts endfunction call ale#linter#Define('dockerfile', { \ 'name': 'hadolint', \ 'executable': function('ale_linters#dockerfile#hadolint#GetExecutable'), \ 'command': function('ale_linters#dockerfile#hadolint#GetCommand'), \ 'callback': 'ale_linters#dockerfile#hadolint#Handle', \}) ================================================ FILE: ale_linters/elixir/credo.vim ================================================ " Author: hauleth - https://github.com/hauleth function! ale_linters#elixir#credo#Handle(buffer, lines) abort " Matches patterns line the following: " " lib/filename.ex:19:7: F: Pipe chain should start with a raw value. let l:pattern = '\v:(\d+):?(\d+)?: (.): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:type = l:match[3] let l:text = l:match[4] " 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, { \ 'bufnr': a:buffer, \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:type, \ 'text': l:text, \}) endfor return l:output endfunction function! ale_linters#elixir#credo#GetMode() abort if get(g:, 'ale_elixir_credo_strict', 0) return '--strict' else return 'suggest' endif endfunction function! ale_linters#elixir#credo#GetConfigFile() abort let l:config_file = get(g:, 'ale_elixir_credo_config_file', '') if empty(l:config_file) return '' endif return ' --config-file ' . l:config_file endfunction function! ale_linters#elixir#credo#GetCommand(buffer) abort return 'mix help credo && ' \ . 'mix credo ' . ale_linters#elixir#credo#GetMode() \ . ale_linters#elixir#credo#GetConfigFile() \ . ' --format=flycheck --read-from-stdin %s' endfunction call ale#linter#Define('elixir', { \ 'name': 'credo', \ 'executable': 'mix', \ 'cwd': function('ale#handlers#elixir#FindMixUmbrellaRoot'), \ 'command': function('ale_linters#elixir#credo#GetCommand'), \ 'callback': 'ale_linters#elixir#credo#Handle', \}) ================================================ FILE: ale_linters/elixir/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Elixir files. call ale#handlers#cspell#DefineLinter('elixir') ================================================ FILE: ale_linters/elixir/dialyxir.vim ================================================ " Author: Fran C. - https://github.com/franciscoj " Description: Add dialyzer support for elixir through dialyxir " https://github.com/jeremyjh/dialyxir function! ale_linters#elixir#dialyxir#Handle(buffer, lines) abort " Matches patterns line the following: " " lib/filename.ex:19: Function fname/1 has no local return let l:pattern = '\v(.+):(\d+): (.+)$' let l:output = [] let l:type = 'W' for l:match in ale#util#GetMatches(a:lines, l:pattern) if bufname(a:buffer) == l:match[1] call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:match[2] + 0, \ 'col': 0, \ 'type': l:type, \ 'text': l:match[3], \}) endif endfor return l:output endfunction call ale#linter#Define('elixir', { \ 'name': 'dialyxir', \ 'executable': 'mix', \ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'), \ 'command': 'mix help dialyzer && mix dialyzer', \ 'callback': 'ale_linters#elixir#dialyxir#Handle', \}) ================================================ FILE: ale_linters/elixir/dogma.vim ================================================ " Author: archseer - https://github.com/archSeer function! ale_linters#elixir#dogma#Handle(buffer, lines) abort " Matches patterns line the following: " " lib/filename.ex:19:7: F: Pipe chain should start with a raw value. let l:pattern = '\v:(\d+):?(\d+)?: (.): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) 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' let l:type = 'W' endif call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:type, \ 'text': l:text, \}) endfor return l:output endfunction call ale#linter#Define('elixir', { \ 'name': 'dogma', \ 'executable': 'mix', \ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'), \ 'command': 'mix help dogma && mix dogma %s --format=flycheck', \ 'lint_file': 1, \ 'callback': 'ale_linters#elixir#dogma#Handle', \}) ================================================ FILE: ale_linters/elixir/elixir_ls.vim ================================================ " Author: Jon Parise " Description: ElixirLS integration (https://github.com/elixir-lsp/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 = has('win32') ? '\language_server.bat' : '/language_server.sh' return l:dir . l:cmd endfunction call ale#linter#Define('elixir', { \ 'name': 'elixir_ls', \ 'aliases': ['elixir-ls', 'elixirls'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#elixir#elixir_ls#GetExecutable'), \ 'command': function('ale_linters#elixir#elixir_ls#GetExecutable'), \ 'project_root': function('ale#handlers#elixir#FindMixUmbrellaRoot'), \ 'lsp_config': {b -> ale#Var(b, 'elixir_elixir_ls_config')}, \}) ================================================ FILE: ale_linters/elixir/expert.vim ================================================ " Author: Paul Monson " Description: Expert integration (https://github.com/elixir-lang/expert) call ale#Set('elixir_expert_executable', 'expert') call ale#linter#Define('elixir', { \ 'name': 'expert', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'elixir_expert_executable')}, \ 'command': '%e', \ 'project_root': function('ale#handlers#elixir#FindMixUmbrellaRoot'), \}) ================================================ FILE: ale_linters/elixir/lexical.vim ================================================ " Author: Axel Clark " Description: Lexical integration (https://github.com/lexical-lsp/lexical) call ale#Set('elixir_lexical_release', 'lexical') function! ale_linters#elixir#lexical#GetExecutable(buffer) abort let l:dir = ale#path#Simplify(ale#Var(a:buffer, 'elixir_lexical_release')) let l:cmd = has('win32') ? '\start_lexical.bat' : '/start_lexical.sh' return l:dir . l:cmd endfunction call ale#linter#Define('elixir', { \ 'name': 'lexical', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#elixir#lexical#GetExecutable'), \ 'command': function('ale_linters#elixir#lexical#GetExecutable'), \ 'project_root': function('ale#handlers#elixir#FindMixUmbrellaRoot'), \}) ================================================ FILE: ale_linters/elixir/mix.vim ================================================ " Author: evnu - https://github.com/evnu " Author: colbydehart - https://github.com/colbydehart " Description: Mix compile checking for Elixir files function! ale_linters#elixir#mix#Handle(buffer, lines) abort " Matches patterns like the following: " " Error format " ** (CompileError) apps/sim/lib/sim/server.ex:87: undefined function update_in/4 " " 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 = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:type = 'E' let l:text = l:match[4] call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:match[3] + 0, \ 'col': 0, \ 'type': l:type, \ 'text': l:text, \}) endfor return l:output endfunction function! ale_linters#elixir#mix#GetCommand(buffer) abort let l:temp_dir = ale#command#CreateDirectory(a:buffer) return ale#Env('MIX_BUILD_PATH', l:temp_dir) . 'mix compile %s' endfunction call ale#linter#Define('elixir', { \ 'name': 'mix', \ 'executable': 'mix', \ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'), \ 'command': function('ale_linters#elixir#mix#GetCommand'), \ 'callback': 'ale_linters#elixir#mix#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/elm/ls.vim ================================================ " Author: antew - https://github.com/antew " Description: elm-language-server integration for elm (diagnostics, formatting, and more) call ale#Set('elm_ls_executable', 'elm-language-server') call ale#Set('elm_ls_use_global', get(g:, 'ale_use_global_executables', 1)) " elm-language-server will search for local and global binaries, if empty call ale#Set('elm_ls_elm_path', '') call ale#Set('elm_ls_elm_format_path', '') call ale#Set('elm_ls_elm_test_path', '') call ale#Set('elm_ls_elm_analyse_trigger', 'change') function! ale_linters#elm#ls#GetProjectRoot(buffer) abort let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json') return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : '' endfunction function! ale_linters#elm#ls#GetInitializationOptions(buffer) abort return { \ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'), \ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'), \ 'elmTestPath': ale#Var(a:buffer, 'elm_ls_elm_test_path'), \ 'elmAnalyseTrigger': ale#Var(a:buffer, 'elm_ls_elm_analyse_trigger'), \} endfunction call ale#linter#Define('elm', { \ 'name': 'ls', \ 'aliases': ['elm_ls'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'elm_ls', [ \ 'node_modules/.bin/elm-language-server', \ 'node_modules/.bin/elm-lsp', \ 'elm-lsp' \ ])}, \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#elm#ls#GetProjectRoot'), \ 'language': 'elm', \ 'initialization_options': function('ale_linters#elm#ls#GetInitializationOptions') \}) ================================================ FILE: ale_linters/elm/make.vim ================================================ " Author: buffalocoder - https://github.com/buffalocoder, soywod - https://github.com/soywod, hecrj - https://github.com/hecrj " Description: Elm linting in Ale. Closely follows the Syntastic checker in https://github.com/ElmCast/elm-vim. 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#Handle(buffer, lines) abort let l:output = [] let l:unparsed_lines = [] for l:line in a:lines if l:line[0] is# '{' " Elm 0.19 call ale_linters#elm#make#HandleElm019Line(l:line, l:output) elseif l:line[0] is# '[' " Elm 0.18 call ale_linters#elm#make#HandleElm018Line(l:line, l:output) elseif l:line isnot# 'Successfully generated /dev/null' call add(l:unparsed_lines, l:line) endif endfor if len(l:unparsed_lines) > 0 call add(l:output, { \ 'lnum': 1, \ 'type': 'E', \ 'text': l:unparsed_lines[0], \ 'detail': join(l:unparsed_lines, "\n") \}) endif return l:output endfunction function! ale_linters#elm#make#HandleElm019Line(line, output) abort let l:report = json_decode(a:line) if l:report.type is? 'error' " General problem let l:details = ale_linters#elm#make#ParseMessage(l:report.message) if empty(l:report.path) let l:report.path = 'Elm' endif if ale_linters#elm#make#FileIsBuffer(l:report.path) call add(a:output, { \ 'lnum': 1, \ 'type': 'E', \ 'text': l:details, \}) else call add(a:output, { \ 'lnum': 1, \ 'type': 'E', \ 'text': l:report.path .' - '. l:details, \ 'detail': l:report.path ." ----------\n\n". l:details, \}) endif else " Compilation errors for l:error in l:report.errors let l:file_is_buffer = ale_linters#elm#make#FileIsBuffer(l:error.path) for l:problem in l:error.problems let l:details = ale_linters#elm#make#ParseMessage(l:problem.message) if l:file_is_buffer " Buffer module has problems call add(a:output, { \ 'lnum': l:problem.region.start.line, \ 'col': l:problem.region.start.column, \ 'end_lnum': l:problem.region.end.line, \ 'end_col': l:problem.region.end.column, \ 'type': 'E', \ 'text': l:details, \}) else " Imported module has problems let l:location = l:error.path .':'. l:problem.region.start.line call add(a:output, { \ 'lnum': 1, \ 'type': 'E', \ 'text': l:location .' - '. l:details, \ 'detail': l:location ." ----------\n\n". l:details, \}) endif endfor endfor endif endfunction function! ale_linters#elm#make#HandleElm018Line(line, output) abort let l:errors = json_decode(a:line) for l:error in l:errors let l:file_is_buffer = ale_linters#elm#make#FileIsBuffer(l:error.file) if l:file_is_buffer " Current buffer has problems call add(a:output, { \ 'lnum': l:error.region.start.line, \ 'col': l:error.region.start.column, \ 'end_lnum': l:error.region.end.line, \ 'end_col': l:error.region.end.column, \ 'type': (l:error.type is? 'error') ? 'E' : 'W', \ 'text': l:error.overview, \ 'detail': l:error.overview . "\n\n" . l:error.details \}) elseif l:error.type is? 'error' " Imported module has errors let l:location = l:error.file .':'. l:error.region.start.line call add(a:output, { \ 'lnum': 1, \ 'type': 'E', \ 'text': l:location .' - '. l:error.overview, \ 'detail': l:location ." ----------\n\n". l:error.overview . "\n\n" . l:error.details \}) endif endfor endfunction function! ale_linters#elm#make#FileIsBuffer(path) abort return ale#path#IsTempName(a:path) endfunction function! ale_linters#elm#make#ParseMessage(message) abort return join(map(copy(a:message), 'ale_linters#elm#make#ParseMessageItem(v:val)'), '') endfunction function! ale_linters#elm#make#ParseMessageItem(item) abort if type(a:item) is v:t_string return a:item else return a:item.string endif endfunction function! ale_linters#elm#make#GetPackageFile(buffer) abort let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json') if empty(l:elm_json) " Fallback to Elm 0.18 let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm-package.json') endif return l:elm_json endfunction function! ale_linters#elm#make#IsVersionGte19(buffer) abort let l:elm_json = ale_linters#elm#make#GetPackageFile(a:buffer) if l:elm_json =~# '-package' return 0 else return 1 endif endfunction function! ale_linters#elm#make#GetRootDir(buffer) abort let l:elm_json = ale_linters#elm#make#GetPackageFile(a:buffer) if empty(l:elm_json) return '' else return fnamemodify(l:elm_json, ':p:h') endif endfunction function! ale_linters#elm#make#IsTest(buffer) abort let l:root_dir = ale_linters#elm#make#GetRootDir(a:buffer) if empty(l:root_dir) return 0 endif let l:tests_dir = join([l:root_dir, 'tests', ''], has('win32') ? '\' : '/') let l:buffer_path = fnamemodify(bufname(a:buffer), ':p') if stridx(l:buffer_path, l:tests_dir) == 0 return 1 else return 0 endif endfunction function! ale_linters#elm#make#GetCwd(buffer) abort let l:root_dir = ale_linters#elm#make#GetRootDir(a:buffer) return !empty(l:root_dir) ? l:root_dir : '' endfunction " Return the command to execute the linter in the projects directory. " If it doesn't, then this will fail when imports are needed. function! ale_linters#elm#make#GetCommand(buffer) abort let l:executable = ale_linters#elm#make#GetExecutable(a:buffer) let l:is_v19 = ale_linters#elm#make#IsVersionGte19(a:buffer) let l:is_using_elm_test = l:executable =~# 'elm-test$' " elm-test needs to know the path of elm-make if elm isn't installed globally. " https://github.com/rtfeldman/node-test-runner/blob/57728f10668f2d2ab3179e7e3208bcfa9a1f19aa/README.md#--compiler if l:is_v19 && l:is_using_elm_test let l:elm_make_executable = ale#path#FindExecutable(a:buffer, 'elm_make', ['node_modules/.bin/elm']) let l:elm_test_compiler_flag = ' --compiler ' . l:elm_make_executable . ' ' else let l:elm_test_compiler_flag = ' ' endif " The elm compiler, at the time of this writing, uses '/dev/null' as " 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 return '%e make --report=json --output=/dev/null' \ . l:elm_test_compiler_flag \ . '%t' endfunction function! ale_linters#elm#make#GetExecutable(buffer) abort let l:is_test = ale_linters#elm#make#IsTest(a:buffer) let l:is_v19 = ale_linters#elm#make#IsVersionGte19(a:buffer) if l:is_test && l:is_v19 return ale#path#FindExecutable( \ a:buffer, \ 'elm_make', \ ['node_modules/.bin/elm-test', 'node_modules/.bin/elm'] \) else return ale#path#FindExecutable(a:buffer, 'elm_make', ['node_modules/.bin/elm']) endif endfunction call ale#linter#Define('elm', { \ 'name': 'make', \ 'executable': function('ale_linters#elm#make#GetExecutable'), \ 'output_stream': 'both', \ 'cwd': function('ale_linters#elm#make#GetCwd'), \ 'command': function('ale_linters#elm#make#GetCommand'), \ 'callback': 'ale_linters#elm#make#Handle' \}) ================================================ FILE: ale_linters/erlang/dialyzer.vim ================================================ " Author: Autoine Gagne - https://github.com/AntoineGagne " Description: Define a checker that runs dialyzer on Erlang files. let g:ale_erlang_dialyzer_executable = \ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer') let g:ale_erlang_dialyzer_options = \ get(g:, 'ale_erlang_dialyzer_options', '-Wunmatched_returns' \ . ' -Werror_handling' \ . ' -Wrace_conditions' \ . ' -Wunderspecs') let g:ale_erlang_dialyzer_plt_file = \ get(g:, 'ale_erlang_dialyzer_plt_file', '') let g:ale_erlang_dialyzer_rebar3_profile = \ get(g:, 'ale_erlang_dialyzer_rebar3_profile', 'default') function! ale_linters#erlang#dialyzer#GetRebar3Profile(buffer) abort return ale#Var(a:buffer, 'erlang_dialyzer_rebar3_profile') endfunction function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort let l:plt_file = '' let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer) let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build/' . l:rebar3_profile) if !empty(l:plt_file_directory) let l:plt_file = globpath(l:plt_file_directory, '*_plt', 0, 1) endif if !empty(l:plt_file) return l:plt_file[0] endif if !empty($REBAR_PLT_DIR) return expand('$REBAR_PLT_DIR/dialyzer/plt') endif return expand('$HOME/.dialyzer_plt') endfunction function! ale_linters#erlang#dialyzer#GetPlt(buffer) abort let l:plt_file = ale#Var(a:buffer, 'erlang_dialyzer_plt_file') if !empty(l:plt_file) return l:plt_file endif return ale_linters#erlang#dialyzer#FindPlt(a:buffer) endfunction function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort return ale#Var(a:buffer, 'erlang_dialyzer_executable') endfunction function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'erlang_dialyzer_options') let l:command = ale#Escape(ale_linters#erlang#dialyzer#GetExecutable(a:buffer)) \ . ' -n' \ . ' --plt ' . ale#Escape(ale_linters#erlang#dialyzer#GetPlt(a:buffer)) \ . ' ' . l:options \ . ' %s' return l:command endfunction function! ale_linters#erlang#dialyzer#Handle(buffer, lines) abort " Match patterns like the following: " " erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available let l:pattern = '^\S\+:\(\d\+\): \(.\+\)$' let l:output = [] for l:line in a:lines let l:match = matchlist(l:line, l:pattern) if len(l:match) != 0 let l:code = l:match[2] call add(l:output, { \ 'lnum': str2nr(l:match[1]), \ 'lcol': 0, \ 'text': l:code, \ 'type': 'W' \}) endif endfor return l:output endfunction call ale#linter#Define('erlang', { \ 'name': 'dialyzer', \ 'executable': function('ale_linters#erlang#dialyzer#GetExecutable'), \ 'command': function('ale_linters#erlang#dialyzer#GetCommand'), \ 'callback': function('ale_linters#erlang#dialyzer#Handle'), \ 'lint_file': 1 \}) ================================================ FILE: ale_linters/erlang/elvis.vim ================================================ " Author: Dmitri Vereshchagin " Description: Elvis linter for Erlang files call ale#Set('erlang_elvis_executable', 'elvis') function! ale_linters#erlang#elvis#Handle(buffer, lines) abort let l:pattern = '\v:(\d+):[^:]+:(.+)' let l:loclist = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:loclist, { \ 'lnum': str2nr(l:match[1]), \ 'text': s:AbbreviateMessage(l:match[2]), \ 'type': 'W', \ 'sub_type': 'style', \}) endfor return l:loclist endfunction function! s:AbbreviateMessage(text) abort let l:pattern = '\v\c^(line \d+ is too long):.*$' return substitute(a:text, l:pattern, '\1.', '') endfunction function! s:GetCommand(buffer) abort let l:cwd = s:GetCwd(a:buffer) let l:file = !empty(l:cwd) \ ? expand('#' . a:buffer . ':p')[len(l:cwd) + 1:] \ : expand('#' . a:buffer . ':.') return '%e rock --output-format=parsable ' . ale#Escape(l:file) endfunction function! s:GetCwd(buffer) abort let l:markers = ['elvis.config', 'rebar.lock', 'erlang.mk'] for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) for l:marker in l:markers if filereadable(l:path . '/' . l:marker) return l:path endif endfor endfor return '' endfunction call ale#linter#Define('erlang', { \ 'name': 'elvis', \ 'callback': 'ale_linters#erlang#elvis#Handle', \ 'executable': {b -> ale#Var(b, 'erlang_elvis_executable')}, \ 'command': function('s:GetCommand'), \ 'cwd': function('s:GetCwd'), \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/erlang/erlang_ls.vim ================================================ " Author: Dmitri Vereshchagin " Description: LSP linter for Erlang files call ale#Set('erlang_erlang_ls_executable', 'erlang_ls') call ale#Set('erlang_erlang_ls_log_dir', '') call ale#Set('erlang_erlang_ls_log_level', 'info') function! s:GetCommand(buffer) abort let l:log_dir = ale#Var(a:buffer, 'erlang_erlang_ls_log_dir') let l:log_level = ale#Var(a:buffer, 'erlang_erlang_ls_log_level') let l:command = '%e' if !empty(l:log_dir) let l:command .= ' --log-dir=' . ale#Escape(l:log_dir) endif let l:command .= ' --log-level=' . ale#Escape(l:log_level) return l:command endfunction function! s:FindProjectRoot(buffer) abort let l:markers = [ \ '_checkouts/', \ '_build/', \ 'deps/', \ 'erlang_ls.config', \ 'rebar.lock', \ 'erlang.mk', \] " This is a way to find Erlang/OTP root (the one that is managed " by kerl or asdf). Useful if :ALEGoToDefinition takes us there. let l:markers += ['.kerl_config'] for l:marker in l:markers let l:path = l:marker[-1:] is# '/' \ ? ale#path#FindNearestDirectory(a:buffer, l:marker) \ : ale#path#FindNearestFile(a:buffer, l:marker) if !empty(l:path) return ale#path#Dirname(l:path) endif endfor return '' endfunction call ale#linter#Define('erlang', { \ 'name': 'erlang_ls', \ 'executable': {b -> ale#Var(b, 'erlang_erlang_ls_executable')}, \ 'command': function('s:GetCommand'), \ 'lsp': 'stdio', \ 'project_root': function('s:FindProjectRoot'), \ 'aliases': ['erlang-ls'], \}) ================================================ FILE: ale_linters/erlang/erlc.vim ================================================ " Author: Magnus Ottenklinger - https://github.com/evnu let g:ale_erlang_erlc_executable = get(g:, 'ale_erlang_erlc_executable', 'erlc') let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '') function! ale_linters#erlang#erlc#GetExecutable(buffer) abort return ale#Var(a:buffer, 'erlang_erlc_executable') endfunction function! ale_linters#erlang#erlc#GetCommand(buffer) abort let l:output_file = ale#util#Tempname() call ale#command#ManageFile(a:buffer, l:output_file) let l:command = ale#Escape(ale_linters#erlang#erlc#GetExecutable(a:buffer)) \ . ' -o ' . ale#Escape(l:output_file) \ . ' ' . ale#Var(a:buffer, 'erlang_erlc_options') \ . ' %t' return l:command endfunction function! ale_linters#erlang#erlc#Handle(buffer, lines) abort " Matches patterns like the following: " " error.erl:4: variable 'B' is unbound " error.erl:3: Warning: function main/0 is unused " error.erl:4: Warning: variable 'A' is unused let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+:)? (Warning: )?(.+)$' " parse_transforms are a special case. The error message does not indicate a location: " error.erl: undefined parse transform 'some_parse_transform' let l:pattern_parse_transform = '\v(undefined parse transform .*)$' let l:output = [] let l:pattern_no_module_definition = '\v(no module definition)$' let l:pattern_unused = '\v(.* is unused)$' let l:is_hrl = fnamemodify(bufname(a:buffer), ':e') is# 'hrl' for l:line in a:lines let l:match = matchlist(l:line, l:pattern) " Determine if the output indicates an error. We distinguish between two cases: " " 1) normal errors match l:pattern " 2) parse_transform errors match l:pattern_parse_transform " " If none of the patterns above match, the line can be ignored if len(l:match) == 0 " not a 'normal' warning or error let l:match_parse_transform = matchlist(l:line, l:pattern_parse_transform) if len(l:match_parse_transform) == 0 " also not a parse_transform error continue endif call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': 0, \ 'col': 0, \ 'type': 'E', \ 'text': l:match_parse_transform[0], \}) continue endif let l:line = l:match[2] let l:warning_or_text = l:match[4] let l:text = l:match[5] " If this file is a header .hrl, ignore the following expected messages: " - 'no module definition' " - 'X is unused' if l:is_hrl && ( \ match(l:text, l:pattern_no_module_definition) != -1 \ || match(l:text, l:pattern_unused) != -1 \) continue endif if !empty(l:warning_or_text) let l:type = 'W' else let l:type = 'E' endif call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:line, \ 'col': 0, \ 'type': l:type, \ 'text': l:text, \}) endfor return l:output endfunction call ale#linter#Define('erlang', { \ 'name': 'erlc', \ 'executable': function('ale_linters#erlang#erlc#GetExecutable'), \ 'command': function('ale_linters#erlang#erlc#GetCommand'), \ 'callback': 'ale_linters#erlang#erlc#Handle', \}) ================================================ FILE: ale_linters/erlang/syntaxerl.vim ================================================ " Author: Dmitri Vereshchagin " Description: SyntaxErl linter for Erlang files call ale#Set('erlang_syntaxerl_executable', 'syntaxerl') function! ale_linters#erlang#syntaxerl#Handle(buffer, lines) abort let l:pattern = '\v\C:(\d+):( warning:)? (.+)' let l:loclist = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:loclist, { \ 'lnum': str2nr(l:match[1]), \ 'text': l:match[3], \ 'type': empty(l:match[2]) ? 'E' : 'W', \}) endfor return l:loclist endfunction function! s:GetExecutable(buffer) abort return ale#Var(a:buffer, 'erlang_syntaxerl_executable') endfunction function! s:GetCommand(buffer) abort let l:Callback = function('s:GetCommandFromHelpOutput') return ale#command#Run(a:buffer, '%e -h', l:Callback, { \ 'executable': s:GetExecutable(a:buffer), \}) endfunction function! s:GetCommandFromHelpOutput(buffer, output, metadata) abort let l:has_b_option = match(a:output, '\V\C-b, --base\>') > -1 return l:has_b_option ? '%e -b %s %t' : '%e %t' endfunction call ale#linter#Define('erlang', { \ 'name': 'syntaxerl', \ 'callback': 'ale_linters#erlang#syntaxerl#Handle', \ 'executable': function('s:GetExecutable'), \ 'command': function('s:GetCommand'), \}) ================================================ FILE: ale_linters/eruby/erb.vim ================================================ " Author: Matthias Guenther - https://wikimatze.de, Eddie Lebow https://github.com/elebow " Description: ERB from the Ruby standard library, for eruby/erb files function! ale_linters#eruby#erb#GetCommand(buffer) abort let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) if empty(l:rails_root) return 'erb -P -T - -x %t | ruby -c' endif " Rails-flavored eRuby does not comply with the standard as understood by " ERB, so we'll have to do some substitution. This does not reduce the " effectiveness of the linter—the translated code is still evaluated. return 'ruby -r erb -e ' . ale#Escape('puts ERB.new($stdin.read.gsub(%{<%=},%{<%}), trim_mode: %{-}).src') . '< %t | ruby -c' endfunction call ale#linter#Define('eruby', { \ 'name': 'erb', \ 'aliases': ['erubylint'], \ 'executable': 'erb', \ 'output_stream': 'stderr', \ 'command': function('ale_linters#eruby#erb#GetCommand'), \ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors', \}) ================================================ FILE: ale_linters/eruby/erblint.vim ================================================ " Author: Roeland Moors - https://github.com/roelandmoors " based on the ale ruumba and robocop linters " Description: ERB Lint, support for https://github.com/Shopify/erb-lint call ale#Set('eruby_erblint_executable', 'erblint') call ale#Set('eruby_erblint_options', '') function! ale_linters#eruby#erblint#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'eruby_erblint_executable') return ale#ruby#EscapeExecutable(l:executable, 'erblint') \ . ' --format json ' \ . ale#Var(a:buffer, 'eruby_erblint_options') \ . ' --stdin %s' endfunction function! ale_linters#eruby#erblint#Handle(buffer, lines) abort if empty(a:lines) return [] endif let l:errors = ale#util#FuzzyJSONDecode(a:lines[0], []) if !has_key(l:errors, 'summary') \|| l:errors['summary']['offenses'] == 0 \|| empty(l:errors['files']) return [] endif let l:output = [] for l:error in l:errors['files'][0]['offenses'] call add(l:output, { \ 'lnum': l:error['location']['start_line'] + 0, \ 'col': l:error['location']['start_column'] + 0, \ 'end_col': l:error['location']['last_column'] + 0, \ 'code': l:error['linter'], \ 'text': l:error['message'], \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('eruby', { \ 'name': 'erblint', \ 'executable': {b -> ale#Var(b, 'eruby_erblint_executable')}, \ 'command': function('ale_linters#eruby#erblint#GetCommand'), \ 'callback': 'ale_linters#eruby#erblint#Handle', \}) ================================================ FILE: ale_linters/eruby/erubi.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: eruby checker using `erubi` function! ale_linters#eruby#erubi#GetCommand(buffer, output, meta) abort let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) if !empty(a:output) " The empty command in CheckErubi returns nothing if erubi runs and " emits an error if erubi is not present return '' endif if empty(l:rails_root) return 'ruby -r erubi/capture_end -e ' . ale#Escape('puts Erubi::CaptureEndEngine.new($stdin.read).src') . '< %t | ruby -c' endif " Rails-flavored eRuby does not comply with the standard as understood by " Erubi, so we'll have to do some substitution. This does not reduce the " effectiveness of the linter---the translated code is still evaluated. return 'ruby -r erubi/capture_end -e ' . ale#Escape('puts Erubi::CaptureEndEngine.new($stdin.read.gsub(%{<%=},%{<%}), nil, %{-}).src') . '< %t | ruby -c' endfunction call ale#linter#Define('eruby', { \ 'name': 'erubi', \ 'executable': 'ruby', \ 'command': {buffer -> ale#command#Run( \ buffer, \ 'ruby -r erubi/capture_end -e ' . ale#Escape('""'), \ function('ale_linters#eruby#erubi#GetCommand'), \ )}, \ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors', \}) ================================================ FILE: ale_linters/eruby/erubis.vim ================================================ " Author: Jake Zimmerman , Eddie Lebow https://github.com/elebow " Description: eruby checker using `erubis`, instead of `erb` function! ale_linters#eruby#erubis#GetCommand(buffer) abort let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) if empty(l:rails_root) return 'erubis -x %t | ruby -c' endif " Rails-flavored eRuby does not comply with the standard as understood by " Erubis, so we'll have to do some substitution. This does not reduce the " effectiveness of the linter - the translated code is still evaluated. return 'ruby -r erubis -e ' . ale#Escape('puts Erubis::Eruby.new($stdin.read.gsub(%{<%=},%{<%})).src') . '< %t | ruby -c' endfunction call ale#linter#Define('eruby', { \ 'name': 'erubis', \ 'executable': 'erubis', \ 'output_stream': 'stderr', \ 'command': function('ale_linters#eruby#erubis#GetCommand'), \ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors', \}) ================================================ FILE: ale_linters/eruby/ruumba.vim ================================================ " 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#ruby#EscapeExecutable(l:executable, 'ruumba') \ . ' --format json --force-exclusion ' \ . ale#Var(a:buffer, 'eruby_ruumba_options') \ . ' --stdin %s' 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': {b -> ale#Var(b, 'eruby_ruumba_executable')}, \ 'command': function('ale_linters#eruby#ruumba#GetCommand'), \ 'callback': 'ale_linters#eruby#ruumba#Handle', \}) ================================================ FILE: ale_linters/fish/fish.vim ================================================ " Author: Niraj Thapaliya - https://github.com/nthapaliya " Description: Lints fish files using fish -n function! ale_linters#fish#fish#Handle(buffer, lines) abort " Matches patterns such as: " " home/.config/fish/functions/foo.fish (line 1): Missing end to balance this function definition " function foo " ^ " " OR, patterns such as: " " Unsupported use of '||'. In fish, please use 'COMMAND; or COMMAND'. " /tmp/vLz620o/258/test.fish (line 2): if set -q SSH_CLIENT || set -q SSH_TTY " ^ " " fish -n can return errors in either format. let l:pattern = '^\(.* (line \(\d\+\)): \)\(.*\)$' let l:column_pattern = '^ *\^' let l:output = [] let l:column_offset = 0 let l:last_line_with_message = '' for l:line in a:lines " Look for error lines first. let l:match = matchlist(l:line, l:pattern) if !empty(l:match) if !empty(l:last_line_with_message) let l:text = l:last_line_with_message else let l:text = l:match[3] endif let l:column_offset = len(l:match[1]) let l:last_line_with_message = '' call add(l:output, { \ 'col': 0, \ 'lnum': str2nr(l:match[2]), \ 'text': l:text, \}) else " Look for column markers like ' ^' second. " The column index will be set according to how long the line is. let l:column_match = matchstr(l:line, l:column_pattern) if !empty(l:column_match) && !empty(l:output) let l:output[-1].col = len(l:column_match) - l:column_offset let l:last_line_with_message = '' else let l:last_line_with_message = l:line let l:column_offset = 0 endif endif endfor return l:output endfunction call ale#linter#Define('fish', { \ 'name': 'fish', \ 'output_stream': 'stderr', \ 'executable': 'fish', \ 'command': 'fish -n %t', \ 'callback': 'ale_linters#fish#fish#Handle', \}) ================================================ FILE: ale_linters/fortran/fortitude.vim ================================================ " Author: gomfol12 " Desciption: A linter for fortran using fortitude. call ale#Set('fortran_fortitude_executable', 'fortitude') call ale#Set('fortran_fortitude_options', '') let s:severity_map = { \ 'E': 'E', \ 'C': 'W', \ 'OB': 'I', \ 'MOD': 'I', \ 'S': 'I', \ 'PORT': 'I', \ 'FORT': 'I', \} function! ale_linters#fortran#fortitude#Handle(buffer, lines) abort let l:output = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) let l:prefix = matchstr(l:error['code'], '^\a\+') let l:type = get(s:severity_map, l:prefix, 'I') call add(l:output, { \ 'lnum': l:error['location']['row'], \ 'end_lnum': l:error['end_location']['row'], \ 'col': l:error['location']['column'], \ 'end_col': l:error['end_location']['column'], \ 'text': l:error['message'], \ 'type': l:type, \ 'code': l:error['code'], \}) endfor return l:output endfunction call ale#linter#Define('fortran', { \ 'name': 'fortitude', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'fortran_fortitude_executable')}, \ 'command': {b -> \ '%e' . ' check --output-format json' . ale#Pad(ale#Var(b, 'fortran_fortitude_options')) . ' %s' \ }, \ 'callback': 'ale_linters#fortran#fortitude#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/fortran/gcc.vim ================================================ " Author: w0rp " Description: gcc for Fortran files " This option can be set to 0 to use -ffixed-form 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. 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, " like so. " " :21.34: " Error: Expected comma in I/O list at (1) let l:line_marker_pattern = ':\(\d\+\)[.:]\=\(\d\+\)\=:\=$' let l:message_pattern = '^\(Error\|Warning\): \(.\+\)$' let l:looking_for_message = 0 let l:last_loclist_obj = {} let l:output = [] for l:line in a:lines if l:looking_for_message let l:match = matchlist(l:line, l:message_pattern) else let l:match = matchlist(l:line, l:line_marker_pattern) endif if len(l:match) == 0 continue endif if l:looking_for_message let l:looking_for_message = 0 " Now we have the text, we can set it and add the error. let l:last_loclist_obj.text = l:match[2] let l:last_loclist_obj.type = l:match[1] is# 'Warning' ? 'W' : 'E' call add(l:output, l:last_loclist_obj) else let l:last_loclist_obj = { \ 'bufnr': a:buffer, \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \} " Start looking for the message and error type. let l:looking_for_message = 1 endif endfor return l:output 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 '%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': {b -> ale#Var(b, 'fortran_gcc_executable')}, \ 'command': function('ale_linters#fortran#gcc#GetCommand'), \ 'callback': 'ale_linters#fortran#gcc#Handle', \}) ================================================ FILE: ale_linters/fortran/language_server.vim ================================================ " Author: unpairedbracket ben.spiers22@gmail.com " Description: A language server for fortran 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#GetProjectRoot(buffer) abort let l:fortls_file = ale#path#FindNearestFile(a:buffer, '.fortls') return !empty(l:fortls_file) ? fnamemodify(l:fortls_file, ':h') : '' endfunction call ale#linter#Define('fortran', { \ 'name': 'language_server', \ 'aliases': ['fortls'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'fortran_language_server_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#fortran#language_server#GetProjectRoot'), \}) ================================================ FILE: ale_linters/fountain/proselint.vim ================================================ " Author: Jansen Mitchell https://github.com/JansenMitchell " Description: proselint for Fountain files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('fountain', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/fuse/fusionlint.vim ================================================ " Author: RyanSquared " Description: `fusion-lint` linter for FusionScript files call ale#Set('fuse_fusionlint_executable', 'fusion-lint') call ale#Set('fuse_fusionlint_options', '') function! ale_linters#fuse#fusionlint#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'fuse_fusionlint_options')) \ . ' --filename %s -i' endfunction function! ale_linters#fuse#fusionlint#Handle(buffer, lines) abort let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\d\+) \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[4], \ 'type': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('fuse', { \ 'name': 'fusionlint', \ 'executable': {b -> ale#Var(b, 'fuse_fusionlint_executable')}, \ 'command': function('ale_linters#fuse#fusionlint#GetCommand'), \ 'callback': 'ale_linters#fuse#fusionlint#Handle', \}) ================================================ FILE: ale_linters/gitcommit/gitlint.vim ================================================ " Author: Nick Yamane " Description: gitlint for git commit message files 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']) endfunction function! ale_linters#gitcommit#gitlint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'gitcommit_gitlint_options') return '%e' . ale#Pad(l:options) . ' lint' endfunction function! ale_linters#gitcommit#gitlint#Handle(buffer, lines) abort " Matches patterns line the following: let l:pattern = '\v^(\d+): (\w+) (.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[2] if !ale#Var(a:buffer, 'warn_about_trailing_whitespace') if l:code is# 'T2' || l:code is# 'B2' continue endif endif let l:item = { \ 'lnum': l:match[1] + 0, \ 'text': l:match[3], \ 'code': l:code, \ 'type': 'E', \} call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('gitcommit', { \ 'name': 'gitlint', \ 'output_stream': 'stderr', \ 'executable': function('ale_linters#gitcommit#gitlint#GetExecutable'), \ 'command': function('ale_linters#gitcommit#gitlint#GetCommand'), \ 'callback': 'ale_linters#gitcommit#gitlint#Handle', \}) ================================================ FILE: ale_linters/gleam/gleamlsp.vim ================================================ " Author: Jonathan Palardt https://github.com/jpalardy " Description: Support for Gleam Language Server call ale#Set('gleam_gleamlsp_executable', 'gleam') function! ale_linters#gleam#gleamlsp#GetProjectRoot(buffer) abort let l:gleam_toml = ale#path#FindNearestFile(a:buffer, 'gleam.toml') return !empty(l:gleam_toml) ? fnamemodify(l:gleam_toml, ':p:h') : '' endfunction call ale#linter#Define('gleam', { \ 'name': 'gleamlsp', \ 'lsp': 'stdio', \ 'executable': {buffer -> ale#Var(buffer, 'gleam_gleamlsp_executable')}, \ 'command': '%e lsp', \ 'project_root': function('ale_linters#gleam#gleamlsp#GetProjectRoot'), \}) ================================================ FILE: ale_linters/glimmer/embertemplatelint.vim ================================================ " Author: Sam Saffron " Description: Ember-template-lint for checking GJS (Glimmer JS) files scriptencoding utf-8 call ale#handlers#embertemplatelint#DefineLinter('glimmer') ================================================ FILE: ale_linters/glsl/glslang.vim ================================================ " Author: Sven-Hendrik Haase " Description: glslang-based linter for glsl files " " TODO: Once https://github.com/KhronosGroup/glslang/pull/1047 is accepted, " we can use stdin. call ale#Set('glsl_glslang_executable', 'glslangValidator') call ale#Set('glsl_glslang_options', '') function! ale_linters#glsl#glslang#GetCommand(buffer) abort return '%e' \ . ale#Pad(ale#Var(a:buffer, 'glsl_glslang_options')) \ . ' -C %t' endfunction function! ale_linters#glsl#glslang#Handle(buffer, lines) abort " Matches patterns like the following: " " ERROR: 0:5: 'foo' : undeclared identifier " or when using options like -V or -G or --target-env " ERROR: filename:5: 'foo' : undeclared identifier let l:pattern = '^\(.\+\): \(.\+\):\(\d\+\): \(.\+\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[3]), \ 'col' : 0, \ 'text': l:match[4], \ 'type': l:match[1] is# 'ERROR' ? 'E' : 'W', \}) endfor return l:output endfunction call ale#linter#Define('glsl', { \ 'name': 'glslang', \ 'executable': {b -> ale#Var(b, 'glsl_glslang_executable')}, \ 'command': function('ale_linters#glsl#glslang#GetCommand'), \ 'callback': 'ale_linters#glsl#glslang#Handle', \}) ================================================ FILE: ale_linters/glsl/glslls.vim ================================================ " Author: Sven-Hendrik Haase " Description: A language server for glsl call ale#Set('glsl_glslls_executable', 'glslls') call ale#Set('glsl_glslls_logfile', '') function! ale_linters#glsl#glslls#GetCommand(buffer) abort 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 '%e' . l:logfile_args . ' --stdin' endfunction function! ale_linters#glsl#glslls#GetProjectRoot(buffer) abort let l:project_root = ale#c#FindProjectRoot(a:buffer) return !empty(l:project_root) ? fnamemodify(l:project_root, ':h:h') : '' endfunction call ale#linter#Define('glsl', { \ 'name': 'glslls', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'glsl_glslls_executable')}, \ 'command': function('ale_linters#glsl#glslls#GetCommand'), \ 'project_root': function('ale_linters#glsl#glslls#GetProjectRoot'), \}) ================================================ FILE: ale_linters/go/bingo.vim ================================================ " Author: Jerko Steiner " Description: https://github.com/saibing/bingo call ale#Set('go_bingo_executable', 'bingo') call ale#Set('go_bingo_options', '--mode stdio') function! ale_linters#go#bingo#GetCommand(buffer) abort return ale#go#EnvString(a:buffer) . '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options')) endfunction function! ale_linters#go#bingo#FindProjectRoot(buffer) abort let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off' let l:project_root = l:go_modules_off ? \ '' : ale#path#FindNearestFile(a:buffer, 'go.mod') let l:mods = ':h' if empty(l:project_root) let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git') let l:mods = ':h:h' endif return !empty(l:project_root) ? fnamemodify(l:project_root, l:mods) : '' endfunction call ale#linter#Define('go', { \ 'name': 'bingo', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'go_bingo_executable')}, \ 'command': function('ale_linters#go#bingo#GetCommand'), \ 'project_root': function('ale_linters#go#bingo#FindProjectRoot'), \}) ================================================ FILE: ale_linters/go/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Go files. call ale#handlers#cspell#DefineLinter('go') ================================================ FILE: ale_linters/go/gobuild.vim ================================================ " Author: Joshua Rubin , Ben Reedy , " Jeff Willette " Description: go build for Go files " inspired by work from dzhou121 call ale#Set('go_go_executable', 'go') call ale#Set('go_gobuild_options', '') function! ale_linters#go#gobuild#GetMatches(lines) abort " Matches patterns like the following: " " 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+)?:? (.+)$' return ale#util#GetMatches(a:lines, l:pattern) endfunction function! ale_linters#go#gobuild#Handler(buffer, lines) abort let l:dir = expand('#' . a:buffer . ':p:h') let l:output = [] for l:match in ale_linters#go#gobuild#GetMatches(a:lines) call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \ 'type': 'E', \}) endfor return l:output endfunction call ale#linter#Define('go', { \ 'name': 'gobuild', \ 'aliases': ['go build'], \ 'executable': {b -> ale#Var(b, 'go_go_executable')}, \ 'cwd': '%s:h', \ 'command': {b -> \ ale#go#EnvString(b) \ . ale#Escape(ale#Var(b, 'go_go_executable')) . ' test' \ . ale#Pad(ale#Var(b, 'go_gobuild_options')) \ . ' -c -o /dev/null ./' \ }, \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#go#gobuild#Handler', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/go/gofmt.vim ================================================ " Author: neersighted " Description: gofmt for Go files function! ale_linters#go#gofmt#GetCommand(buffer) abort return ale#go#EnvString(a:buffer) \ . '%e -e %t' endfunction call ale#linter#Define('go', { \ 'name': 'gofmt', \ 'output_stream': 'stderr', \ 'executable': 'gofmt', \ 'command': function('ale_linters#go#gofmt#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) ================================================ FILE: ale_linters/go/golangci_lint.vim ================================================ " Author: Sascha Grunert " Description: Adds support of golangci-lint call ale#Set('go_golangci_lint_options', '') call ale#Set('go_golangci_lint_executable', 'golangci-lint') call ale#Set('go_golangci_lint_package', 1) function! ale_linters#go#golangci_lint#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'go_golangci_lint_executable') return l:executable endfunction function! ale_linters#go#golangci_lint#GetCommand(buffer, version) 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 ale#semver#GTE(a:version, [2, 0, 0]) let l:options = l:options \ . ' --output.json.path stdout' \ . ' --output.text.path stderr' \ . ' --show-stats=0' else let l:options = l:options \ . ' --out-format=json' \ . ' --show-stats=0' endif if l:lint_package return ale#go#EnvString(a:buffer) \ . '%e run ' \ . l:options endif return ale#go#EnvString(a:buffer) \ . '%e run ' \ . ale#Escape(l:filename) \ . ' ' . l:options endfunction function! ale_linters#go#golangci_lint#Handler(buffer, lines) abort let l:dir = expand('#' . a:buffer . ':p:h') let l:output = [] let l:matches = ale#util#FuzzyJSONDecode(a:lines, []) if empty(l:matches) return [] endif for l:match in l:matches['Issues'] if l:match['FromLinter'] is# 'typecheck' let l:msg_type = 'E' else let l:msg_type = 'W' endif call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, fnamemodify(l:match['Pos']['Filename'], ':t')), \ 'lnum': l:match['Pos']['Line'] + 0, \ 'col': l:match['Pos']['Column'] + 0, \ 'type': l:msg_type, \ 'text': match['FromLinter'] . ' - ' . l:match['Text'], \}) endfor return l:output endfunction call ale#linter#Define('go', { \ 'name': 'golangci-lint', \ 'executable': function('ale_linters#go#golangci_lint#GetExecutable'), \ 'cwd': '%s:h', \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#go#golangci_lint#GetExecutable(buffer), \ '%e --version', \ function('ale_linters#go#golangci_lint#GetCommand'), \ )}, \ 'callback': 'ale_linters#go#golangci_lint#Handler', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/go/gopls.vim ================================================ " Author: w0rp " Author: Jerko Steiner " Description: https://github.com/saibing/gopls call ale#Set('go_gopls_executable', 'gopls') call ale#Set('go_gopls_options', '--mode stdio') call ale#Set('go_gopls_init_options', {}) call ale#Set('go_gopls_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#go#gopls#GetCommand(buffer) abort return ale#go#EnvString(a:buffer) \ . '%e' \ . ale#Pad(ale#Var(a:buffer, 'go_gopls_options')) endfunction function! ale_linters#go#gopls#FindProjectRoot(buffer) abort let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off' let l:project_root = l:go_modules_off ? \ '' : ale#path#FindNearestFile(a:buffer, 'go.mod') let l:mods = ':h' if empty(l:project_root) let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git') let l:mods = ':h:h' endif return !empty(l:project_root) ? fnamemodify(l:project_root, l:mods) : '' endfunction call ale#linter#Define('go', { \ 'name': 'gopls', \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'go_gopls', [ \ ale#go#GetGoPathExecutable('bin/gopls'), \ ])}, \ 'command': function('ale_linters#go#gopls#GetCommand'), \ 'project_root': function('ale_linters#go#gopls#FindProjectRoot'), \ 'initialization_options': {b -> ale#Var(b, 'go_gopls_init_options')}, \}) ================================================ FILE: ale_linters/go/gosimple.vim ================================================ " Author: Ben Reedy " Description: gosimple for Go files call ale#linter#Define('go', { \ 'name': 'gosimple', \ 'executable': 'gosimple', \ 'cwd': '%s:h', \ 'command': {b -> ale#go#EnvString(b) . 'gosimple .'}, \ 'callback': 'ale#handlers#go#Handler', \ 'output_stream': 'both', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/go/gotype.vim ================================================ " Author: Jelte Fennema " Description: gotype for Go files function! ale_linters#go#gotype#GetExecutable(buffer) abort if expand('#' . a:buffer . ':p') =~# '_test\.go$' return '' endif return 'gotype' endfunction function! ale_linters#go#gotype#GetCommand(buffer) abort return ale#go#EnvString(a:buffer) . 'gotype -e .' endfunction call ale#linter#Define('go', { \ 'name': 'gotype', \ 'output_stream': 'stderr', \ 'executable': function('ale_linters#go#gotype#GetExecutable'), \ 'cwd': '%s:h', \ 'command': function('ale_linters#go#gotype#GetCommand'), \ 'callback': 'ale#handlers#go#Handler', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/go/govet.vim ================================================ " Author: neersighted , John Eikenberry " Description: go vet for Go files call ale#Set('go_go_executable', 'go') call ale#Set('go_govet_options', '') call ale#linter#Define('go', { \ 'name': 'govet', \ 'aliases': ['go vet'], \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'go_go_executable')}, \ 'cwd': '%s:h', \ 'command': {b -> \ ale#go#EnvString(b) \ . '%e vet' \ . ale#Pad(ale#Var(b, 'go_govet_options')) \ . ' .' \ }, \ 'callback': 'ale#handlers#go#Handler', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/go/langserver.vim ================================================ " Author: Horacio Sanson " 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') call add(l:options, '-gocodecompletion') endif let l:options = uniq(sort(l:options)) let l:env = ale#go#EnvString(a:buffer) return l:env . join(extend(l:executable, l:options), ' ') endfunction call ale#linter#Define('go', { \ 'name': 'golangserver', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'go_langserver_executable')}, \ 'command': function('ale_linters#go#langserver#GetCommand'), \ 'project_root': function('ale#go#FindProjectRoot'), \}) ================================================ FILE: ale_linters/go/revive.vim ================================================ " Author: Penghui Liao " Description: Adds support for revive call ale#Set('go_revive_executable', 'revive') call ale#Set('go_revive_options', '') function! ale_linters#go#revive#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'go_revive_options') return ale#go#EnvString(a:buffer) . '%e' \ . ale#Pad(l:options) \ . ' %t' endfunction call ale#linter#Define('go', { \ 'name': 'revive', \ 'output_stream': 'both', \ 'executable': {b -> ale#Var(b, 'go_revive_executable')}, \ 'command': function('ale_linters#go#revive#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/go/staticcheck.vim ================================================ " Author: Ben Reedy " Description: staticcheck for Go files call ale#Set('go_staticcheck_executable', 'staticcheck') call ale#Set('go_staticcheck_options', '') call ale#Set('go_staticcheck_lint_package', 1) call ale#Set('go_staticcheck_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#go#staticcheck#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'go_staticcheck_options') let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package') let l:env = ale#go#EnvString(a:buffer) if l:lint_package return l:env . '%e' \ . ale#Pad(l:options) . ' .' endif return l:env . '%e' \ . ale#Pad(l:options) \ . ' %s:t' endfunction call ale#linter#Define('go', { \ 'name': 'staticcheck', \ 'executable': {b -> ale#path#FindExecutable(b, 'go_staticcheck', [ \ ale#go#GetGoPathExecutable('bin/staticcheck'), \ ])}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#go#staticcheck#GetCommand'), \ 'callback': 'ale#handlers#go#Handler', \ 'output_stream': 'both', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/gohtmltmpl/djlint.vim ================================================ " Author: Adrian Vollmer " Description: djlint for Django HTML template files call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('gohtmltmpl', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) ================================================ FILE: ale_linters/graphql/eslint.vim ================================================ " Author: Benjie Gillam " Description: eslint for GraphQL files call ale#linter#Define('graphql', { \ 'name': 'eslint', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/graphql/gqlint.vim ================================================ " Author: Michiel Westerbeek " Description: Linter for GraphQL Schemas call ale#linter#Define('graphql', { \ 'name': 'gqlint', \ 'executable': 'gqlint', \ 'cwd': '%s:h', \ 'command': 'gqlint --reporter=simple %t', \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/groovy/npmgroovylint.vim ================================================ " Author: lucas-str " Description: Integration of npm-groovy-lint for Groovy files. call ale#Set('groovy_npmgroovylint_executable', 'npm-groovy-lint') call ale#Set('groovy_npmgroovylint_options', '--loglevel warning') function! ale_linters#groovy#npmgroovylint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'groovy_npmgroovylint_options') return '%e --failon none --output json' \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale_linters#groovy#npmgroovylint#Handle(buffer, lines) abort let l:output = [] let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) for [l:filename, l:file] in items(get(l:json, 'files', {})) for l:error in get(l:file, 'errors', []) let l:output_line = { \ 'filename': l:filename, \ 'lnum': l:error.line, \ 'text': l:error.msg, \ 'type': toupper(l:error.severity[0]), \} if has_key(l:error, 'range') let l:output_line.col = l:error.range.start.character let l:output_line.end_col = l:error.range.end.character let l:output_line.end_lnum = l:error.range.end.line endif call add(l:output, l:output_line) endfor endfor return l:output endfunction call ale#linter#Define('groovy', { \ 'name': 'npm-groovy-lint', \ 'executable': {b -> ale#Var(b, 'groovy_npmgroovylint_executable')}, \ 'command': function('ale_linters#groovy#npmgroovylint#GetCommand'), \ 'callback': 'ale_linters#groovy#npmgroovylint#Handle', \}) ================================================ FILE: ale_linters/hack/hack.vim ================================================ " Author: Fred Emmott " 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': function('ale_linters#hack#hack#GetExecutable'), \ 'command': '%e lsp --from vim-ale', \ 'project_root': function('ale_linters#hack#hack#GetProjectRoot'), \}) ================================================ FILE: ale_linters/hack/hhast.vim ================================================ " Author: Fred Emmott " 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': function('ale_linters#hack#hhast#GetExecutable'), \ 'command': '%e --mode lsp --from vim-ale', \ 'project_root': function('ale_linters#hack#hhast#GetProjectRoot'), \ 'initialization_options': function('ale_linters#hack#hhast#GetInitializationOptions'), \}) ================================================ FILE: ale_linters/haml/hamllint.vim ================================================ " 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 = '' let l:rubocop_config_file_path = ale#path#FindNearestFile(a:buffer, '.rubocop.yml') let l:hamllint_config_file_path = ale#path#FindNearestFile(a:buffer, '.haml-lint.yml') " Set HAML_LINT_RUBOCOP_CONF variable as it is needed for haml-lint to " pick up the rubocop config. " " See https://github.com/brigade/haml-lint/blob/master/lib/haml_lint/linter/rubocop.rb#L89 " HamlLint::Linter::RuboCop#rubocop_flags if !empty(l:rubocop_config_file_path) if has('win32') let l:prefix = 'set HAML_LINT_RUBOCOP_CONF=' . ale#Escape(l:rubocop_config_file_path) . ' &&' else let l:prefix = 'HAML_LINT_RUBOCOP_CONF=' . ale#Escape(l:rubocop_config_file_path) endif endif return (!empty(l:prefix) ? l:prefix . ' ' : '') \ . ale_linters#haml#hamllint#GetExecutable(a:buffer) \ . (!empty(l:hamllint_config_file_path) ? ' --config ' . ale#Escape(l:hamllint_config_file_path) : '') \ . ' %t' endfunction function! ale_linters#haml#hamllint#Handle(buffer, lines) abort " Matches patterns like the following: " :51 [W] RuboCop: Use the new Ruby 1.9 hash syntax. let l:pattern = '\v^.*:(\d+) \[([EW])\] (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'type': l:match[2], \ 'text': l:match[3] \}) endfor return l:output endfunction call ale#linter#Define('haml', { \ 'name': 'hamllint', \ 'executable': function('ale_linters#haml#hamllint#GetExecutable'), \ 'command': function('ale_linters#haml#hamllint#GetCommand'), \ 'callback': 'ale_linters#haml#hamllint#Handle' \}) ================================================ FILE: ale_linters/handlebars/djlint.vim ================================================ " Author: Adrian Vollmer " Description: djlint for Django HTML template files call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('handlebars', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) ================================================ FILE: ale_linters/handlebars/embertemplatelint.vim ================================================ " Author: Adrian Zalewski " Description: Ember-template-lint for checking Handlebars files scriptencoding utf-8 call ale#handlers#embertemplatelint#DefineLinter('handlebars') ================================================ FILE: ale_linters/haskell/cabal_ghc.vim ================================================ " Author: Eric Wolf " Description: ghc for Haskell files called with cabal exec call ale#Set('haskell_cabal_ghc_options', '-fno-code -v0') function! ale_linters#haskell#cabal_ghc#GetCommand(buffer) abort return 'cabal exec -- ghc ' \ . ale#Var(a:buffer, 'haskell_cabal_ghc_options') \ . ' %t' endfunction call ale#linter#Define('haskell', { \ 'name': 'cabal_ghc', \ 'aliases': ['cabal-ghc'], \ 'output_stream': 'stderr', \ 'executable': 'cabal', \ 'cwd': '%s:h', \ 'command': function('ale_linters#haskell#cabal_ghc#GetCommand'), \ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \}) ================================================ FILE: ale_linters/haskell/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Haskell files. call ale#handlers#cspell#DefineLinter('haskell') ================================================ FILE: ale_linters/haskell/ghc.vim ================================================ " Author: w0rp " Description: ghc for Haskell files call ale#Set('haskell_ghc_options', '-fno-code -v0') function! ale_linters#haskell#ghc#GetCommand(buffer) abort return 'ghc ' \ . ale#Var(a:buffer, 'haskell_ghc_options') \ . ' %t' endfunction call ale#linter#Define('haskell', { \ 'name': 'ghc', \ 'output_stream': 'stderr', \ 'executable': 'ghc', \ 'command': function('ale_linters#haskell#ghc#GetCommand'), \ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \}) ================================================ FILE: ale_linters/haskell/ghc_mod.vim ================================================ " Author: wizzup " 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': {b -> ale#Var(b, 'haskell_ghc_mod_executable')}, \ 'command': function('ale_linters#haskell#ghc_mod#GetCommand'), \ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \}) ================================================ FILE: ale_linters/haskell/hdevtools.vim ================================================ " Author: rob-b, Takano Akio " Description: hdevtools for Haskell files call ale#Set('haskell_hdevtools_executable', 'hdevtools') call ale#Set('haskell_hdevtools_options', get(g:, 'hdevtools_options', '-g -Wall')) function! ale_linters#haskell#hdevtools#GetCommand(buffer) abort 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': {b -> ale#Var(b, 'haskell_hdevtools_executable')}, \ 'command': function('ale_linters#haskell#hdevtools#GetCommand'), \ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \}) ================================================ FILE: ale_linters/haskell/hie.vim ================================================ " Author: Luxed " 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) " Search all of the paths except for the root filesystem path. let l:paths = join( \ ale#path#Upwards(expand('#' . a:buffer . ':p:h'))[:-2], \ ',' \) let l:project_file = globpath(l:paths, '*.cabal') endif " If we still can't find one, use the current file. if empty(l:project_file) let l:project_file = expand('#' . a:buffer . ':p') endif return fnamemodify(l:project_file, ':h') 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': function('ale_linters#haskell#hie#GetCommand'), \ 'executable': {b -> ale#Var(b, 'haskell_hie_executable')}, \ 'project_root': function('ale_linters#haskell#hie#GetProjectRoot'), \}) ================================================ FILE: ale_linters/haskell/hlint.vim ================================================ " Author: jparoz " 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 = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) if l:error.severity is# 'Error' let l:type = 'E' elseif l:error.severity is# 'Suggestion' let l:type = 'I' else let l:type = 'W' endif call add(l:output, { \ 'lnum': str2nr(l:error.startLine), \ 'col': str2nr(l:error.startColumn), \ 'end_lnum': str2nr(l:error.endLine), \ 'end_col': str2nr(l:error.endColumn), \ 'text': l:error.severity . ': ' . l:error.hint . '. Found: ' . l:error.from . ' Why not: ' . l:error.to, \ 'type': l:type, \}) endfor 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': {b -> ale#Var(b, 'haskell_hlint_executable')}, \ 'command': function('ale_linters#haskell#hlint#GetCommand') , \ 'callback': 'ale_linters#haskell#hlint#Handle', \}) ================================================ FILE: ale_linters/haskell/hls.vim ================================================ " Author: Yen3 " Description: A language server for haskell " The file is based on hie.vim (author: Luxed " ). It search more project root files. " call ale#Set('haskell_hls_executable', 'haskell-language-server-wrapper') call ale#Set('haskell_hls_config', {}) function! ale_linters#haskell#hls#FindRootFile(buffer) abort let l:serach_root_files = [ \ 'stack.yaml', \ 'cabal.project', \ 'package.yaml', \ 'hie.yaml' \ ] for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) for l:root_file in l:serach_root_files if filereadable(l:path . '/' . l:root_file) " Add on / so fnamemodify(..., ':h') below keeps the path. return l:path . '/' endif endfor endfor return '' endfunction function! ale_linters#haskell#hls#GetProjectRoot(buffer) abort " Search for the project file first let l:project_file = ale_linters#haskell#hls#FindRootFile(a:buffer) " If it's empty, search for the cabal file if empty(l:project_file) " Search all of the paths except for the root filesystem path. let l:paths = join( \ ale#path#Upwards(expand('#' . a:buffer . ':p:h'))[:-2], \ ',' \) let l:project_file = globpath(l:paths, '*.cabal') endif " If we still can't find one, use the current file. if empty(l:project_file) let l:project_file = expand('#' . a:buffer . ':p') endif return fnamemodify(l:project_file, ':h') endfunction function! ale_linters#haskell#hls#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'haskell_hls_executable') return ale#handlers#haskell_stack#EscapeExecutable(l:executable, \ 'haskell-language-server-wrapper') \ . ' --lsp' endfunction call ale#linter#Define('haskell', { \ 'name': 'hls', \ 'lsp': 'stdio', \ 'command': function('ale_linters#haskell#hls#GetCommand'), \ 'executable': {b -> ale#Var(b, 'haskell_hls_executable')}, \ 'project_root': function('ale_linters#haskell#hls#GetProjectRoot'), \ 'lsp_config': {b -> ale#Var(b, 'haskell_hls_config')}, \}) ================================================ FILE: ale_linters/haskell/stack_build.vim ================================================ " Author: Jake Zimmerman " Description: Like stack-ghc, but for entire projects " " Note: Ideally, this would *only* typecheck. Right now, it also does codegen. " See . call ale#Set('haskell_stack_build_options', '--fast') function! ale_linters#haskell#stack_build#GetCommand(buffer) abort let l:flags = ale#Var(a:buffer, 'haskell_stack_build_options') return 'stack build ' . l:flags endfunction call ale#linter#Define('haskell', { \ 'name': 'stack_build', \ 'aliases': ['stack-build'], \ 'output_stream': 'stderr', \ 'executable': function('ale#handlers#haskell#GetStackExecutable'), \ 'command': function('ale_linters#haskell#stack_build#GetCommand'), \ 'lint_file': 1, \ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \}) ================================================ FILE: ale_linters/haskell/stack_ghc.vim ================================================ " Author: w0rp " Description: ghc for Haskell files, using Stack call ale#Set('haskell_stack_ghc_options', '-fno-code -v0') function! ale_linters#haskell#stack_ghc#GetCommand(buffer) abort return ale#handlers#haskell#GetStackExecutable(a:buffer) \ . ' ghc -- ' \ . ale#Var(a:buffer, 'haskell_stack_ghc_options') \ . ' %t' endfunction call ale#linter#Define('haskell', { \ 'name': 'stack_ghc', \ 'aliases': ['stack-ghc'], \ 'output_stream': 'stderr', \ 'executable': function('ale#handlers#haskell#GetStackExecutable'), \ 'cwd': '%s:h', \ 'command': function('ale_linters#haskell#stack_ghc#GetCommand'), \ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \}) ================================================ FILE: ale_linters/help/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for help files call ale#handlers#alex#DefineLinter('help', '--text') ================================================ FILE: ale_linters/help/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for help files. call ale#handlers#cspell#DefineLinter('help') ================================================ FILE: ale_linters/help/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for Vim help files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('help', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/help/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for vim Help files call ale#handlers#writegood#DefineLinter('help') ================================================ FILE: ale_linters/html/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for HTML files call ale#handlers#alex#DefineLinter('html', '--html') ================================================ FILE: ale_linters/html/angular.vim ================================================ " Author: w0rp " Description: tsserver integration for ALE call ale#Set('html_angular_executable', 'ngserver') call ale#Set('html_angular_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#html#angular#GetProjectRoot(buffer) abort return ale#path#Dirname( \ ale#path#FindNearestDirectory(a:buffer, 'node_modules') \) endfunction function! ale_linters#html#angular#GetExecutable(buffer) abort return 'node' endfunction function! ale_linters#html#angular#GetCommand(buffer) abort let l:language_service_dir = ale#path#Simplify( \ ale#path#FindNearestDirectory( \ a:buffer, \ 'node_modules/@angular/language-service' \ ) \) if empty(l:language_service_dir) return '' endif let l:language_service_dir = fnamemodify(l:language_service_dir, ':h') let l:typescript_dir = ale#path#Simplify( \ fnamemodify(l:language_service_dir, ':h:h') \ . '/typescript' \) let l:script = ale#path#FindExecutable(a:buffer, 'html_angular', [ \ 'node_modules/@angular/language-server/bin/ngserver', \ 'node_modules/@angular/language-server/index.js', \]) if !filereadable(l:script) return '' endif return ale#Escape('node') . ' ' . ale#Escape(l:script) \ . ' --ngProbeLocations ' . ale#Escape(l:language_service_dir) \ . ' --tsProbeLocations ' . ale#Escape(l:typescript_dir) \ . ' --stdio' endfunction call ale#linter#Define('html', { \ 'name': 'angular', \ 'aliases': ['angular-language-server', 'angularls'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#html#angular#GetExecutable'), \ 'command': function('ale_linters#html#angular#GetCommand'), \ 'project_root': function('ale_linters#html#angular#GetProjectRoot'), \}) ================================================ FILE: ale_linters/html/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for HTML files. call ale#handlers#cspell#DefineLinter('html') ================================================ FILE: ale_linters/html/djlint.vim ================================================ " Author: Vivian De Smedt " Description: Adds support for djlint call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('html', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) " vim:ts=4:sw=4:et: ================================================ FILE: ale_linters/html/eslint.vim ================================================ " Author: Victor Ananyev " Description: eslint for js snippets in HTML files call ale#linter#Define('html', { \ 'name': 'eslint', \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \ }) ================================================ FILE: ale_linters/html/fecs.vim ================================================ " Author: harttle " Description: fecs for HTMl files call ale#linter#Define('html', { \ 'name': 'fecs', \ 'executable': function('ale#handlers#fecs#GetExecutable'), \ 'command': function('ale#handlers#fecs#GetCommand'), \ 'callback': 'ale#handlers#fecs#Handle', \}) ================================================ FILE: ale_linters/html/htmlhint.vim ================================================ " Author: KabbAmine , deathmaz <00maz1987@gmail.com>, diartyz " Description: HTMLHint for checking html files 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#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'html_htmlhint_options') let l:config = l:options !~# '--config' \ ? ale#path#FindNearestFile(a:buffer, '.htmlhintrc') \ : '' if !empty(l:config) let l:options .= ' --config ' . ale#Escape(l:config) endif if !empty(l:options) let l:options = substitute(l:options, '--format=unix', '', '') endif return '%e' . ale#Pad(l:options) . ' --format=unix %t' endfunction call ale#linter#Define('html', { \ 'name': 'htmlhint', \ 'executable': {b -> ale#path#FindExecutable(b, 'html_htmlhint', [ \ 'node_modules/.bin/htmlhint', \ ])}, \ 'command': function('ale_linters#html#htmlhint#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) ================================================ FILE: ale_linters/html/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for HTML files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('html', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/html/stylelint.vim ================================================ " Author: Filipe Kiss 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#path#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) \ . ale#Pad(l:options) \ . ' --no-color --stdin-filename %s' endfunction call ale#linter#Define('html', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': function('ale_linters#html#stylelint#GetExecutable'), \ 'command': function('ale_linters#html#stylelint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/html/superhtml.vim ================================================ call ale#Set('html_superhtml_executable', 'superhtml') call ale#Set('html_superhtml_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#html#superhtml#GetCommand(buffer) abort return '%e check --stdin' endfunction function! ale_linters#html#superhtml#Handle(buffer, lines) abort let l:output = [] let l:pattern = '^\(.*\):\(\d\+\):\(\d\+\): \(.*\)$' for l:line in a:lines let l:match = matchlist(l:line, l:pattern) if !empty(l:match) call add(l:output, { \ 'lnum': str2nr(l:match[2]), \ 'col': str2nr(l:match[3]), \ 'text': l:match[4], \ 'type': 'E' \}) endif endfor return l:output endfunction call ale#linter#Define('html', { \ 'name': 'superhtml', \ 'executable': {b -> ale#Var(b, 'html_superhtml_executable')}, \ 'command': function('ale_linters#html#superhtml#GetCommand'), \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#html#superhtml#Handle', \}) ================================================ FILE: ale_linters/html/tidy.vim ================================================ " Author: KabbAmine " Description: This file adds support for checking HTML code with tidy. let g:ale_html_tidy_executable = get(g:, 'ale_html_tidy_executable', 'tidy') let g:ale_html_tidy_options = get(g:, 'ale_html_tidy_options', '-q -e -language en') function! ale_linters#html#tidy#GetCommand(buffer) abort " Specify file encoding in options " (Idea taken from https://github.com/scrooloose/syntastic/blob/master/syntax_checkers/html/tidy.vim) let l:file_encoding = get({ \ 'ascii': '-ascii', \ 'big5': '-big5', \ 'cp1252': '-win1252', \ 'cp850': '-ibm858', \ 'cp932': '-shiftjis', \ 'iso-2022-jp': '-iso-2022', \ 'latin1': '-latin1', \ 'macroman': '-mac', \ 'sjis': '-shiftjis', \ 'utf-16le': '-utf16le', \ 'utf-16': '-utf16', \ 'utf-8': '-utf8', \ }, &fileencoding, '-utf8') " 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 '' endif return printf('%s %s %s -', \ l:executable, \ ale#Var(a:buffer, 'html_tidy_options'), \ l:file_encoding \) endfunction function! ale_linters#html#tidy#Handle(buffer, lines) abort " Matches patterns lines like the following: " line 7 column 5 - Warning: missing before let l:pattern = '^line \(\d\+\) column \(\d\+\) - \(Warning\|Error\): \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:line = l:match[1] + 0 let l:col = l:match[2] + 0 let l:type = l:match[3] is# 'Error' ? 'E' : 'W' let l:text = l:match[4] call add(l:output, { \ 'lnum': l:line, \ 'col': l:col, \ 'text': l:text, \ 'type': l:type, \}) endfor return l:output endfunction call ale#linter#Define('html', { \ 'name': 'tidy', \ 'executable': {b -> ale#Var(b, 'html_tidy_executable')}, \ 'output_stream': 'stderr', \ 'command': function('ale_linters#html#tidy#GetCommand'), \ 'callback': 'ale_linters#html#tidy#Handle', \ }) ================================================ FILE: ale_linters/html/vscodehtml.vim ================================================ " Author: Dalius Dobravolskas " Description: VSCode html language server function! ale_linters#html#vscodehtml#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('html', { \ 'name': 'vscodehtml', \ 'lsp': 'stdio', \ 'executable': 'vscode-html-language-server', \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#html#vscodehtml#GetProjectRoot'), \}) ================================================ FILE: ale_linters/html/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for html files call ale#handlers#writegood#DefineLinter('html') ================================================ FILE: ale_linters/htmlangular/djlint.vim ================================================ " Author: Adrian Vollmer " Description: djlint for Django HTML template files call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('htmlangular', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) ================================================ FILE: ale_linters/htmldjango/djlint.vim ================================================ " Author: Adrian Vollmer " Description: djlint for Django HTML template files call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('htmldjango', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) ================================================ FILE: ale_linters/hurl/hurlfmt.vim ================================================ " Description: Hurl linter using hurlfmt --check. " https://hurl.dev/ call ale#Set('hurl_hurlfmt_executable', 'hurlfmt') function! ale_linters#hurl#hurlfmt#GetCommand(buffer) abort return '%e' \ . ' --check --no-color ' endfunction function! ale_linters#hurl#hurlfmt#HandleOutput(buffer, lines) abort " Matches patterns: " " error: Parsing space " --> test.hurl:11:48 " | " 8 | header "Content-Type"= "application/json; charset=utf-8" " | ^ expecting a space " | " " error: Parsing URL " --> test.hurl:11:48 " | " 11 | PUT https://jsonplaceholder.typicode.com/posts/{post_id}} " | ^ illegal character <{> " | " " Note: hurlfmt seems to report always the first error only so we assume " there is only one error to make parsing easier. let l:output = [] if empty(a:lines) return l:output endif let l:pattern = '\v(error|warning): (.+) --\> (.+):(\d+):(\d+) .+ \^ (.+) |' let l:lines = join(a:lines, ' ') for l:match in ale#util#GetMatches(l:lines, l:pattern) call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': match[4] + 0, \ 'col': match[5] + 0, \ 'end_col': match[5] + 0, \ 'text': match[2] . ' : ' . match[6], \ 'type': (match[1] is# 'error') ? 'E' : 'W' \}) endfor return l:output endfunction function! ale_linters#hurl#hurlfmt#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('hurl', { \ 'name': 'hurlfmt', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'hurl_hurlfmt_executable')}, \ 'command': function('ale_linters#hurl#hurlfmt#GetCommand'), \ 'callback': 'ale_linters#hurl#hurlfmt#HandleOutput', \}) ================================================ FILE: ale_linters/idris/idris.vim ================================================ " Author: Scott Bonds " Description: default Idris compiler call ale#Set('idris_idris_executable', 'idris') call ale#Set('idris_idris_options', '--total --warnpartial --warnreach --warnipkg') function! ale_linters#idris#idris#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'idris_idris_options') 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: let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)(-\d+)?:(.*)?$' let l:output = [] let l:corrected_lines = [] for l:line in a:lines if len(matchlist(l:line, l:pattern)) > 0 call add(l:corrected_lines, l:line) elseif len(l:corrected_lines) > 0 if l:line is# '' let l:corrected_lines[-1] .= ' ' " turn a blank line into a space else let l:corrected_lines[-1] .= l:line endif let l:corrected_lines[-1] = substitute(l:corrected_lines[-1], '\s\+', ' ', 'g') endif endfor for l:line in l:corrected_lines let l:match = matchlist(l:line, l:pattern) if len(l:match) == 0 continue endif if !ale#path#IsBufferPath(a:buffer, l:match[1]) continue endif let l:errors = matchlist(l:match[5], '\v([wW]arning|[eE]rror) - ?(.*)') if len(l:errors) > 0 let l:ghc_type = l:errors[1] let l:text = l:errors[2] else let l:ghc_type = '' let l:text = l:match[5][:0] is# ' ' ? l:match[5][1:] : l:match[5] endif if l:ghc_type is? 'Warning' let l:type = 'W' else let l:type = 'E' endif call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:text, \ 'type': l:type, \}) endfor return l:output endfunction call ale#linter#Define('idris', { \ 'name': 'idris', \ 'executable': {b -> ale#Var(b, 'idris_idris_executable')}, \ 'command': function('ale_linters#idris#idris#GetCommand'), \ 'callback': 'ale_linters#idris#idris#Handle', \}) ================================================ FILE: ale_linters/ink/ls.vim ================================================ " Author: Andreww Hayworth " Description: Integrate ALE with ink-language-server call ale#Set('ink_ls_executable', 'ink-language-server') call ale#Set('ink_ls_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('ink_ls_initialization_options', {}) function! ale_linters#ink#ls#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'ink_ls', [ \ 'ink-language-server', \ 'node_modules/.bin/ink-language-server', \]) endfunction function! ale_linters#ink#ls#GetCommand(buffer) abort let l:executable = ale_linters#ink#ls#GetExecutable(a:buffer) return ale#Escape(l:executable) . ' --stdio' endfunction function! ale_linters#ink#ls#FindProjectRoot(buffer) abort let l:main_file = get(ale#Var(a:buffer, 'ink_ls_initialization_options'), 'mainStoryPath', 'main.ink') let l:config = ale#path#ResolveLocalPath(a:buffer, l:main_file, expand('#' . a:buffer . ':p')) return ale#path#Dirname(l:config) endfunction call ale#linter#Define('ink', { \ 'name': 'ink-language-server', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#ink#ls#GetExecutable'), \ 'command': function('ale_linters#ink#ls#GetCommand'), \ 'project_root': function('ale_linters#ink#ls#FindProjectRoot'), \ 'initialization_options': {b -> ale#Var(b, 'ink_ls_initialization_options')}, \}) ================================================ FILE: ale_linters/inko/inko.vim ================================================ " Author: Yorick Peterse " Description: linting of Inko source code using the Inko compiler call ale#Set('inko_inko_executable', 'inko') function! ale_linters#inko#inko#GetCommand(buffer) abort let l:include = '' " Include the tests source directory, but only for test files. if expand('#' . a:buffer . ':p') =~? '\vtests[/\\]test[/\\]' let l:test_dir = ale#path#FindNearestDirectory(a:buffer, 'tests') if isdirectory(l:test_dir) let l:include = '--include ' . ale#Escape(l:test_dir) endif endif " We use %s instead of %t so the compiler determines the correct module " names for the file being edited. Not doing so may lead to errors in " certain cases. return '%e build --check --format=json' \ . ale#Pad(l:include) \ . ' %s' endfunction call ale#linter#Define('inko', { \ 'name': 'inko', \ 'executable': {b -> ale#Var(b, 'inko_inko_executable')}, \ 'command': function('ale_linters#inko#inko#GetCommand'), \ 'callback': 'ale#handlers#inko#Handle', \ 'output_stream': 'stderr', \ 'lint_file': 1 \}) ================================================ FILE: ale_linters/ispc/ispc.vim ================================================ " Author: Martino Pilia " 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: :: : " As far as I know, 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': {b -> ale#Var(b, 'ispc_ispc_executable')}, \ 'command': function('ale_linters#ispc#ispc#GetCommand'), \ 'callback': 'ale_linters#ispc#ispc#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/java/checkstyle.vim ================================================ " Author: Devon Meunier " Description: checkstyle for Java files call ale#Set('java_checkstyle_executable', 'checkstyle') call ale#Set('java_checkstyle_config', '/google_checks.xml') call ale#Set('java_checkstyle_options', '') function! ale_linters#java#checkstyle#Handle(buffer, lines) abort 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', \ 'sub_type': 'style', \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \ 'code': l:match[5], \}) endfor if !empty(l:output) return l:output endif " 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', \ 'sub_type': 'style', \ 'lnum': l:match[2] + 0, \ 'text': l:match[4], \}) endfor return l:output endfunction function! s:GetConfig(buffer, config) abort if ale#path#IsAbsolute(a:config) return a:config endif let s:file = ale#path#FindNearestFile(a:buffer, a:config) return !empty(s:file) ? s:file : a:config endfunction function! ale_linters#java#checkstyle#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'java_checkstyle_options') let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config') let l:config = l:options !~# '\v(^| )-c ' && !empty(l:config_option) \ ? s:GetConfig(a:buffer, l:config_option) \ : '' return '%e' \ . ale#Pad(l:options) \ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '') \ . ' %s' endfunction call ale#linter#Define('java', { \ 'name': 'checkstyle', \ 'executable': {b -> ale#Var(b, 'java_checkstyle_executable')}, \ 'command': function('ale_linters#java#checkstyle#GetCommand'), \ 'callback': 'ale_linters#java#checkstyle#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/java/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Java files. call ale#handlers#cspell#DefineLinter('java') ================================================ FILE: ale_linters/java/eclipselsp.vim ================================================ " Author: Horacio Sanson " Description: Support for the Eclipse language server https://github.com/eclipse/eclipse.jdt.ls let s:version_cache = {} call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls')) call ale#Set('java_eclipselsp_config_path', '') call ale#Set('java_eclipselsp_workspace_path', '') call ale#Set('java_eclipselsp_executable', 'java') call ale#Set('java_eclipselsp_javaagent', '') function! ale_linters#java#eclipselsp#Executable(buffer) abort return ale#Var(a:buffer, 'java_eclipselsp_executable') endfunction function! ale_linters#java#eclipselsp#TargetPath(buffer) abort return ale#Var(a:buffer, 'java_eclipselsp_path') endfunction function! ale_linters#java#eclipselsp#JarPath(buffer) abort let l:path = ale_linters#java#eclipselsp#TargetPath(a:buffer) if has('win32') let l:platform = 'win32' elseif has('macunix') let l:platform = 'macosx' else let l:platform = 'linux' endif " Search jar file within repository path when manually built using mvn let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1) if len(l:files) >= 1 return l:files[0] endif " Search jar file within VSCode extensions folder. let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1) if len(l:files) >= 1 return l:files[0] endif " Search jar file within unzipped tar.gz file let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_*\.jar', 1, 1) if len(l:files) >= 1 return l:files[0] endif " Search jar file within system package path let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_*\.jar', 1, 1) if len(l:files) >= 1 return l:files[0] endif return '' endfunction function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h') let l:config_path = ale#Var(a:buffer, 'java_eclipselsp_config_path') if !empty(l:config_path) return ale#path#Simplify(l:config_path) endif if has('win32') let l:path = l:path . '/config_win' elseif has('macunix') let l:path = l:path . '/config_mac' else let l:path = l:path . '/config_linux' endif return ale#path#Simplify(l:path) endfunction function! ale_linters#java#eclipselsp#VersionCheck(version_lines) abort return s:GetVersion('', a:version_lines) endfunction function! s:GetVersion(executable, version_lines) abort let l:version = [] for l:line in a:version_lines let l:match = matchlist(l:line, '\(\d\+\)\.\(\d\+\)\.\(\d\+\)') if !empty(l:match) let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[3] + 0] let s:version_cache[a:executable] = l:version break endif endfor return l:version endfunction function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines, meta) abort let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer) let l:version = s:GetVersion(l:executable, a:version_lines) return ale_linters#java#eclipselsp#Command(a:buffer, l:version) endfunction function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort let l:wspath = ale#Var(a:buffer, 'java_eclipselsp_workspace_path') if !empty(l:wspath) return l:wspath endif return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer)) endfunction function! ale_linters#java#eclipselsp#Javaagent(buffer) abort let l:rets = [] let l:raw = ale#Var(a:buffer, 'java_eclipselsp_javaagent') if empty(l:raw) return '' endif let l:jars = split(l:raw) for l:jar in l:jars call add(l:rets, ale#Escape('-javaagent:' . l:jar)) endfor return join(l:rets, ' ') endfunction function! ale_linters#java#eclipselsp#Command(buffer, version) abort let l:path = ale#Var(a:buffer, 'java_eclipselsp_path') let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer) let l:cmd = [ ale#Escape(l:executable), \ ale_linters#java#eclipselsp#Javaagent(a:buffer), \ '-Declipse.application=org.eclipse.jdt.ls.core.id1', \ '-Dosgi.bundles.defaultStartLevel=4', \ '-Declipse.product=org.eclipse.jdt.ls.core.product', \ '-Dlog.level=ALL', \ '-noverify', \ '-Xmx1G', \ '-jar', \ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)), \ '-configuration', \ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)), \ '-data', \ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer)) \ ] if ale#semver#GTE(a:version, [1, 9]) call add(l:cmd, '--add-modules=ALL-SYSTEM') call add(l:cmd, '--add-opens java.base/java.util=ALL-UNNAMED') call add(l:cmd, '--add-opens java.base/java.lang=ALL-UNNAMED') endif return join(l:cmd, ' ') endfunction function! ale_linters#java#eclipselsp#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#java#eclipselsp#Executable(a:buffer) if empty(l:executable) return '' endif let l:cache = s:version_cache if has_key(s:version_cache, l:executable) return ale_linters#java#eclipselsp#Command(a:buffer, s:version_cache[l:executable]) endif let l:command = ale#Escape(l:executable) . ' -version' return ale#command#Run( \ a:buffer, \ l:command, \ function('ale_linters#java#eclipselsp#CommandWithVersion'), \ { 'output_stream': 'both' } \) endfunction call ale#linter#Define('java', { \ 'name': 'eclipselsp', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#java#eclipselsp#Executable'), \ 'command': function('ale_linters#java#eclipselsp#RunWithVersionCheck'), \ 'language': 'java', \ 'project_root': function('ale#java#FindProjectRoot'), \ 'initialization_options': { \ 'extendedClientCapabilities': { \ 'classFileContentsSupport': v:true \ } \ } \}) ================================================ FILE: ale_linters/java/javac.vim ================================================ " Author: farenjihn , w0rp " Description: Lints java files using javac let s:classpath_sep = has('unix') ? ':' : ';' call ale#Set('java_javac_executable', 'javac') call ale#Set('java_javac_options', '') call ale#Set('java_javac_classpath', '') call ale#Set('java_javac_sourcepath', '') function! ale_linters#java#javac#RunWithImportPaths(buffer) abort let [l:cwd, l:command] = ale#maven#BuildClasspathCommand(a:buffer) " Try to use Gradle if Maven isn't available. if empty(l:command) let [l:cwd, l:command] = ale#gradle#BuildClasspathCommand(a:buffer) endif " Try to use Ant if Gradle and Maven aren't available if empty(l:command) let [l:cwd, l:command] = ale#ant#BuildClasspathCommand(a:buffer) endif if empty(l:command) return ale_linters#java#javac#GetCommand(a:buffer, [], {}) endif return ale#command#Run( \ a:buffer, \ l:command, \ function('ale_linters#java#javac#GetCommand'), \ {'cwd': l:cwd}, \) endfunction function! s:BuildClassPathOption(buffer, import_paths) abort " Filter out lines like [INFO], etc. let l:class_paths = filter(a:import_paths[:], 'v:val !~# ''[''') let l:cls_path = ale#Var(a:buffer, 'java_javac_classpath') if !empty(l:cls_path) && type(l:cls_path) is v:t_string call extend(l:class_paths, split(l:cls_path, s:classpath_sep)) endif if !empty(l:cls_path) && type(l:cls_path) is v:t_list call extend(l:class_paths, l:cls_path) endif return !empty(l:class_paths) \ ? '-cp ' . ale#Escape(join(l:class_paths, s:classpath_sep)) \ : '' endfunction function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort let l:cp_option = s:BuildClassPathOption(a:buffer, a:import_paths) let l:sp_option = '' " Find the src directory, for files in this project. let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java') let l:sp_dirs = [] if !empty(l:src_dir) call add(l:sp_dirs, l:src_dir) " Automatically include the jaxb directory too, if it's there. let l:jaxb_dir = fnamemodify(l:src_dir, ':h:h') \ . (has('win32') ? '\jaxb\' : '/jaxb/') if isdirectory(l:jaxb_dir) call add(l:sp_dirs, l:jaxb_dir) endif endif " Automatically include the test directory, but only for test code. if expand('#' . a:buffer . ':p') =~? '\vsrc[/\\]test[/\\]java' let l:test_dir = ale#path#FindNearestDirectory(a:buffer, 'src/test/java') if isdirectory(l:test_dir) call add(l:sp_dirs, l:test_dir) endif endif let l:source_paths = [] let l:source_path = ale#Var(a:buffer, 'java_javac_sourcepath') if !empty(l:source_path) && type(l:source_path) is v:t_string let l:source_paths = split(l:source_path, s:classpath_sep) endif if !empty(l:source_path) && type(l:source_path) is v:t_list let l:source_paths = l:source_path endif if !empty(l:source_paths) for l:path in l:source_paths let l:sp_path = ale#path#FindNearestDirectory(a:buffer, l:path) if !empty(l:sp_path) call add(l:sp_dirs, l:sp_path) endif endfor endif if !empty(l:sp_dirs) let l:sp_option = '-sourcepath ' \ . ale#Escape(join(l:sp_dirs, s:classpath_sep)) endif " Create .class files in a temporary directory, which we will delete later. let l:class_file_directory = ale#command#CreateDirectory(a:buffer) " Always run javac from the directory the file is in, so we can resolve " relative paths correctly. return '%e -Xlint' \ . ale#Pad(l:cp_option) \ . ale#Pad(l:sp_option) \ . ' -d ' . ale#Escape(l:class_file_directory) \ . ale#Pad(ale#Var(a:buffer, 'java_javac_options')) \ . ' %t' endfunction function! ale_linters#java#javac#Handle(buffer, lines) abort " Look for lines like the following. " " 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+): (.{-1,}):(.+)$' let l:col_pattern = '\v^(\s*\^)$' let l:symbol_pattern = '\v^ +symbol: *(class|method) +([^ ]+)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:col_pattern, l:symbol_pattern]) if empty(l:match[2]) && empty(l:match[3]) if !empty(l:match[1]) && !empty(l:output) let l:output[-1].col = len(l:match[1]) endif elseif empty(l:match[3]) " Add symbols to 'cannot find symbol' errors. if l:output[-1].text is# 'error: cannot find symbol' let l:output[-1].text .= ': ' . l:match[2] endif else call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:directory, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'text': l:match[3] . ':' . l:match[4], \ 'type': l:match[3] is# 'error' ? 'E' : 'W', \}) endif endfor return l:output endfunction call ale#linter#Define('java', { \ 'name': 'javac', \ 'executable': {b -> ale#Var(b, 'java_javac_executable')}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#java#javac#RunWithImportPaths'), \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#java#javac#Handle', \}) ================================================ FILE: ale_linters/java/javalsp.vim ================================================ " Author: Horacio Sanson " Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac call ale#Set('java_javalsp_executable', '') call ale#Set('java_javalsp_config', {}) function! ale_linters#java#javalsp#Executable(buffer) abort return ale#Var(a:buffer, 'java_javalsp_executable') endfunction function! ale_linters#java#javalsp#Config(buffer) abort let l:defaults = { 'java': { 'classPath': [], 'externalDependencies': [] } } let l:config = ale#Var(a:buffer, 'java_javalsp_config') " Ensure the config dictionary contains both classPath and " externalDependencies keys to avoid a NPE crash on Java Language Server. call extend(l:config, l:defaults, 'keep') call extend(l:config['java'], l:defaults['java'], 'keep') return l:config endfunction function! ale_linters#java#javalsp#Command(buffer) abort let l:executable = ale_linters#java#javalsp#Executable(a:buffer) if fnamemodify(l:executable, ':t') is# 'java' " For backward compatibility. let l:cmd = [ \ ale#Escape(l:executable), \ '--add-exports jdk.compiler/com.sun.tools.javac.api=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.code=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.comp=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.main=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.tree=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.model=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.util=javacs', \ '--add-opens jdk.compiler/com.sun.tools.javac.api=javacs', \ '-m javacs/org.javacs.Main', \] return join(l:cmd, ' ') else return ale#Escape(l:executable) endif endfunction call ale#linter#Define('java', { \ 'name': 'javalsp', \ 'aliases': ['java_language_server'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#java#javalsp#Executable'), \ 'command': function('ale_linters#java#javalsp#Command'), \ 'language': 'java', \ 'project_root': function('ale#java#FindProjectRoot'), \ 'lsp_config': function('ale_linters#java#javalsp#Config') \}) ================================================ FILE: ale_linters/java/pmd.vim ================================================ " Author: Johannes Wienke " Description: PMD for Java files function! ale_linters#java#pmd#Handle(buffer, lines) abort let l:pattern = '"\(\d\+\)",".*","\(.\+\)","\(\d\+\)","\(\d\+\)","\(.\+\)","\(.\+\)","\(.\+\)"$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'type': 'W', \ 'lnum': l:match[4] + 0, \ 'text': l:match[5], \ 'code': l:match[6] . ' - ' . l:match[7], \}) endfor return l:output endfunction function! ale_linters#java#pmd#GetCommand(buffer) abort return 'pmd ' \ . ale#Var(a:buffer, 'java_pmd_options') \ . ' -f csv' \ . ' -d %t' endfunction if !exists('g:ale_java_pmd_options') let g:ale_java_pmd_options = '-R category/java/bestpractices.xml' endif call ale#linter#Define('java', { \ 'name': 'pmd', \ 'executable': 'pmd', \ 'command': function('ale_linters#java#pmd#GetCommand'), \ 'callback': 'ale_linters#java#pmd#Handle', \}) ================================================ FILE: ale_linters/javascript/biome.vim ================================================ " Author: Filip Gospodinov " Description: biome for JavaScript files call ale#linter#Define('javascript', { \ 'name': 'biome', \ 'lsp': 'stdio', \ 'language': function('ale#handlers#biome#GetLanguage'), \ 'executable': function('ale#handlers#biome#GetExecutable'), \ 'command': '%e lsp-proxy', \ 'project_root': function('ale#handlers#biome#GetProjectRoot'), \}) ================================================ FILE: ale_linters/javascript/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for JavaScript files. call ale#handlers#cspell#DefineLinter('javascript') ================================================ FILE: ale_linters/javascript/deno.vim ================================================ " Author: Arnold Chand " Description: Deno lsp linter for JavaScript files. call ale#linter#Define('javascript', { \ 'name': 'deno', \ 'lsp': 'stdio', \ 'executable': function('ale#handlers#deno#GetExecutable'), \ 'command': '%e lsp', \ 'project_root': function('ale#handlers#deno#GetProjectRoot'), \ 'initialization_options': function('ale#handlers#deno#GetInitializationOptions'), \}) ================================================ FILE: ale_linters/javascript/eslint.vim ================================================ " Author: w0rp " Description: eslint for JavaScript files call ale#linter#Define('javascript', { \ 'name': 'eslint', \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/javascript/fecs.vim ================================================ " Author: harttle " Description: fecs for JavaScript files call ale#linter#Define('javascript', { \ 'name': 'fecs', \ 'executable': function('ale#handlers#fecs#GetExecutable'), \ 'command': function('ale#handlers#fecs#GetCommand'), \ 'read_buffer': 0, \ 'callback': 'ale#handlers#fecs#Handle', \}) ================================================ FILE: ale_linters/javascript/flow.vim ================================================ " Author: Zach Perrault -- @zperrault " Author: Florian Beeres " Description: FlowType checking for JavaScript files call ale#Set('javascript_flow_executable', 'flow') call ale#Set('javascript_flow_use_home_config', 0) call ale#Set('javascript_flow_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_flow_use_respect_pragma', 1) function! ale_linters#javascript#flow#GetExecutable(buffer) abort let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig') if empty(l:flow_config) " Don't run Flow if we can't find a .flowconfig file. return '' endif " Don't run Flow with a configuration file from the home directory by " default, which can eat all of your RAM. if fnamemodify(l:flow_config, ':h') is? $HOME \&& !ale#Var(a:buffer, 'javascript_flow_use_home_config') return '' endif return ale#path#FindExecutable(a:buffer, 'javascript_flow', [ \ 'node_modules/.bin/flow', \]) endfunction function! ale_linters#javascript#flow#GetCommand(buffer, version) abort " If we can parse the version number, then only use --respect-pragma " if the version is >= 0.36.0, which added the argument. let l:use_respect_pragma = ale#Var(a:buffer, 'javascript_flow_use_respect_pragma') \ && (empty(a:version) || ale#semver#GTE(a:version, [0, 36])) return '%e check-contents' \ . (l:use_respect_pragma ? ' --respect-pragma': '') \ . ' --json --from ale %s < %t' \ . (!has('win32') ? '; echo' : '') endfunction " Filter lines of flow output until we find the first line where the JSON " output starts. function! s:GetJSONLines(lines) abort let l:start_index = 0 for l:line in a:lines if l:line[:0] is# '{' break endif let l:start_index += 1 endfor return a:lines[l:start_index :] endfunction function! s:ExtraErrorMsg(current, new) abort let l:newMsg = '' if a:current is# '' " extra messages appear to already have a : let l:newMsg = a:new else let l:newMsg = a:current . ' ' . a:new endif return l:newMsg endfunction 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) endfor endif if has_key(l:extra_error, 'children') for l:child in l:extra_error.children for l:child_message in l:child.message let l:detail = l:detail . ' ' . l:child_message.descr endfor endfor endif endfor return l:detail endfunction function! ale_linters#javascript#flow#Handle(buffer, lines) abort let l:str = join(s:GetJSONLines(a:lines), '') if empty(l:str) return [] endif let l:flow_output = json_decode(l:str) let l:output = [] for l:error in get(l:flow_output, 'errors', []) " Each error is broken up into parts let l:text = '' let l:line = 0 let l:col = 0 for l:message in l:error.message " Comments have no line of column information, so we skip them. " In certain cases, `l:message.loc.source` points to a different path " than the buffer one, thus we skip this loc information too. if has_key(l:message, 'loc') \&& l:line is# 0 \&& ale#path#IsBufferPath(a:buffer, l:message.loc.source) let l:line = l:message.loc.start.line + 0 let l:col = l:message.loc.start.column + 0 endif if l:text is# '' let l:text = l:message.descr . ':' else let l:text = l:text . ' ' . l:message.descr endif endfor if has_key(l:error, 'operation') let l:text = l:text . ' See also: ' . l:error.operation.descr endif let l:errorToAdd = { \ 'lnum': l:line, \ 'col': l:col, \ 'text': l:text, \ 'type': has_key(l:error, 'level') && l:error.level is# 'error' ? 'E' : 'W', \} if has_key(l:error, 'extra') let l:errorToAdd.detail = l:errorToAdd.text \ . "\n" . s:GetDetails(l:error) endif call add(l:output, l:errorToAdd) endfor return l:output endfunction call ale#linter#Define('javascript', { \ 'name': 'flow', \ 'executable': function('ale_linters#javascript#flow#GetExecutable'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#javascript#flow#GetExecutable(buffer), \ '%e --version', \ function('ale_linters#javascript#flow#GetCommand'), \ )}, \ 'callback': 'ale_linters#javascript#flow#Handle', \ 'read_buffer': 0, \}) ================================================ FILE: ale_linters/javascript/flow_ls.vim ================================================ " Author: t_t " Description: Integrate ALE with flow-language-server. call ale#Set('javascript_flow_ls_executable', 'flow') call ale#Set('javascript_flow_ls_use_global', \ get(g:, 'ale_use_global_executables', 0) \) function! ale_linters#javascript#flow_ls#FindProjectRoot(buffer) abort let l:flow_config = ale#path#FindNearestFile(a:buffer, '.flowconfig') if !empty(l:flow_config) return fnamemodify(l:flow_config, ':h') endif return '' endfunction call ale#linter#Define('javascript', { \ 'name': 'flow_ls', \ 'aliaes': ['flow-language-server'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'javascript_flow_ls', [ \ 'node_modules/.bin/flow', \ ])}, \ 'command': '%e lsp --from ale-lsp', \ 'project_root': function('ale_linters#javascript#flow_ls#FindProjectRoot'), \ 'language': 'javascript', \}) ================================================ FILE: ale_linters/javascript/jscs.vim ================================================ " Author: Chris Kyrouac - https://github.com/fijshion " Description: jscs for JavaScript files 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#GetCommand(buffer) abort " Search for a local JShint config locaation, and default to a global one. let l:jscs_config = ale#path#ResolveLocalPath( \ a:buffer, \ '.jscsrc', \ get(g:, 'ale_jscs_config_loc', '') \) let l:command = '%e --reporter inline --no-colors' if !empty(l:jscs_config) let l:command .= ' --config ' . ale#Escape(l:jscs_config) endif let l:command .= ' -' return l:command endfunction function! ale_linters#javascript#jscs#Handle(buffer, lines) abort " Matches patterns looking like the following " " foobar.js: line 2, col 1, Expected indentation of 1 characters " let l:pattern = '\v^.*:\s+line (\d+),\s+col\s+(\d+),\s+(.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:obj = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3] \} let l:code_match = matchlist(l:match[3], '\v([^ :]+): (.+)$') if !empty(l:code_match) let l:obj.code = l:code_match[1] let l:obj.text = l:code_match[2] endif call add(l:output, l:obj) endfor return l:output endfunction call ale#linter#Define('javascript', { \ 'name': 'jscs', \ 'executable': {b -> ale#path#FindExecutable(b, 'javascript_jscs', [ \ 'node_modules/.bin/jscs', \ ])}, \ 'command': function('ale_linters#javascript#jscs#GetCommand'), \ 'callback': 'ale_linters#javascript#jscs#Handle', \}) ================================================ FILE: ale_linters/javascript/jshint.vim ================================================ " Author: Chris Kyrouac - https://github.com/fijshion " Description: JSHint for Javascript files 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#GetCommand(buffer) abort " Search for a local JShint config locaation, and default to a global one. let l:jshint_config = ale#path#ResolveLocalPath( \ a:buffer, \ '.jshintrc', \ get(g:, 'ale_jshint_config_loc', '') \) 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 .= ' --filename %s -' return l:command endfunction call ale#linter#Define('javascript', { \ 'name': 'jshint', \ 'executable': {b -> ale#path#FindExecutable(b, 'javascript_jshint', [ \ 'node_modules/.bin/jshint', \ ])}, \ 'command': function('ale_linters#javascript#jshint#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) ================================================ FILE: ale_linters/javascript/standard.vim ================================================ " Author: Ahmed El Gabri <@ahmedelgabri> " Description: standardjs for JavaScript files call ale#Set('javascript_standard_executable', 'standard') call ale#Set('javascript_standard_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_standard_options', '') function! ale_linters#javascript#standard#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_standard', [ \ 'node_modules/standardx/bin/cmd.js', \ 'node_modules/standard/bin/cmd.js', \ 'node_modules/semistandard/bin/cmd.js', \ 'node_modules/.bin/standard', \]) endfunction function! ale_linters#javascript#standard#GetCommand(buffer) abort let l:executable = ale_linters#javascript#standard#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_standard_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' --stdin %s' endfunction " standard uses eslint and the output format is the same call ale#linter#Define('javascript', { \ 'name': 'standard', \ 'executable': function('ale_linters#javascript#standard#GetExecutable'), \ 'command': function('ale_linters#javascript#standard#GetCommand'), \ 'callback': 'ale#handlers#eslint#Handle', \}) ================================================ FILE: ale_linters/javascript/tsserver.vim ================================================ " Author: Chaucerbao, w0rp " Description: tsserver integration for ALE 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)) call ale#linter#Define('javascript', { \ 'name': 'tsserver', \ 'lsp': 'tsserver', \ 'executable': {b -> ale#path#FindExecutable(b, 'javascript_tsserver', [ \ 'node_modules/.bin/tsserver', \ ])}, \ 'command': '%e', \ 'project_root': function('ale#handlers#tsserver#GetProjectRoot'), \ 'language': '', \}) ================================================ FILE: ale_linters/javascript/xo.vim ================================================ " Author: Daniel Lupu " Description: xo for JavaScript files call ale#linter#Define('javascript', { \ 'name': 'xo', \ 'executable': function('ale#handlers#xo#GetExecutable'), \ 'command': function('ale#handlers#xo#GetLintCommand'), \ 'callback': 'ale#handlers#xo#HandleJSON', \}) ================================================ FILE: ale_linters/jinja/djlint.vim ================================================ " Author: Adrian Vollmer " Description: djlint for Django HTML template files call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('jinja', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) ================================================ FILE: ale_linters/jinja/j2lint.vim ================================================ " Description: linter for jinja using j2lint call ale#Set('jinja_j2lint_executable', 'j2lint') call ale#Set('jinja_j2lint_options', '') call ale#Set('jinja_j2lint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('jinja_j2lint_auto_pipenv', 0) call ale#Set('jinja_j2lint_auto_poetry', 0) call ale#Set('jinja_j2lint_auto_uv', 0) function! ale_linters#jinja#j2lint#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'jinja_j2lint_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'jinja_j2lint_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'jinja_j2lint_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'jinja_j2lint', ['j2lint']) endfunction function! ale_linters#jinja#j2lint#GetCommand(buffer) abort let l:executable = ale_linters#jinja#j2lint#GetExecutable(a:buffer) let l:exec_args = l:executable =~? 'pipenv\|poetry\|uv$' \ ? ' run j2lint' \ : '' return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'jinja_j2lint_options')) \ . ' %t' endfunction call ale#linter#Define('jinja', { \ 'name': 'j2lint', \ 'executable': function('ale_linters#jinja#j2lint#GetExecutable'), \ 'command': function('ale_linters#jinja#j2lint#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) ================================================ FILE: ale_linters/json/biome.vim ================================================ " Description: biome for json files call ale#linter#Define('json', { \ 'name': 'biome', \ 'lsp': 'stdio', \ 'language': function('ale#handlers#biome#GetLanguage'), \ 'executable': function('ale#handlers#biome#GetExecutable'), \ 'command': '%e lsp-proxy', \ 'project_root': function('ale#handlers#biome#GetProjectRoot'), \}) ================================================ FILE: ale_linters/json/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for JSON files. call ale#handlers#cspell#DefineLinter('json') ================================================ FILE: ale_linters/json/eslint.vim ================================================ " Author: João Pesce " Description: eslint for JSON files. " " Requires eslint-plugin-jsonc or a similar plugin to work " " Uses the same funtcions as ale_linters/javascript/eslint.vim by w0rp " call ale#linter#Define('json', { \ 'name': 'eslint', \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/json/jq.vim ================================================ " Author: jD91mZM2 call ale#Set('json_jq_executable', 'jq') call ale#Set('json_jq_options', '') call ale#Set('json_jq_filters', '.') " Matches patterns like the following: " parse error: Expected another key-value pair at line 4, column 3 let s:pattern = 'parse error: \(.\+\) at line \(\d\+\), column \(\d\+\)$' function! ale_linters#json#jq#Handle(buffer, lines) abort return ale#util#MapMatches(a:lines, s:pattern, {match -> { \ 'text': match[1], \ 'lnum': match[2] + 0, \ 'col': match[3] + 0, \}}) endfunction call ale#linter#Define('json', { \ 'name': 'jq', \ 'executable': {b -> ale#Var(b, 'json_jq_executable')}, \ 'output_stream': 'stderr', \ 'command': '%e', \ 'callback': 'ale_linters#json#jq#Handle', \}) ================================================ FILE: ale_linters/json/jsonlint.vim ================================================ " Author: KabbAmine , David Sierra call ale#Set('json_jsonlint_executable', 'jsonlint') call ale#Set('json_jsonlint_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#json#jsonlint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'json_jsonlint', [ \ 'node_modules/.bin/jsonlint', \ 'node_modules/jsonlint/lib/cli.js', \]) endfunction function! ale_linters#json#jsonlint#GetCommand(buffer) abort let l:executable = ale_linters#json#jsonlint#GetExecutable(a:buffer) return ale#node#Executable(a:buffer, l:executable) \ . ' --compact -' endfunction 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 = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('json', { \ 'name': 'jsonlint', \ 'executable': function('ale_linters#json#jsonlint#GetExecutable'), \ 'output_stream': 'stderr', \ 'command': function('ale_linters#json#jsonlint#GetCommand'), \ 'callback': 'ale_linters#json#jsonlint#Handle', \}) ================================================ FILE: ale_linters/json/spectral.vim ================================================ " Author: t2h5 " Description: Integration of Stoplight Spectral CLI with ALE. call ale#Set('json_spectral_executable', 'spectral') call ale#Set('json_spectral_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define('json', { \ 'name': 'spectral', \ 'executable': {b -> ale#path#FindExecutable(b, 'json_spectral', [ \ 'node_modules/.bin/spectral', \ ])}, \ 'command': '%e lint --ignore-unknown-format -q -f text %t', \ 'callback': 'ale#handlers#spectral#HandleSpectralOutput' \}) ================================================ FILE: ale_linters/json/vscodejson.vim ================================================ " Author: Dalius Dobravolskas " Description: VSCode json language server call ale#Set('json_vscodejson_executable', '') function! ale_linters#json#vscodejson#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'json_vscodejson_executable') if l:executable is# '' if ale#engine#IsExecutable(a:buffer, 'vscode-json-languageserver') let l:executable = 'vscode-json-languageserver' else let l:executable = 'vscode-json-language-server' endif endif return l:executable endfunction function! ale_linters#json#vscodejson#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('json', { \ 'name': 'vscodejson', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#json#vscodejson#GetExecutable'), \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#json#vscodejson#GetProjectRoot'), \}) ================================================ FILE: ale_linters/json5/eslint.vim ================================================ " Author: João Pesce " Description: eslint for JSON5 files. " " Requires eslint-plugin-jsonc or a similar plugin to work " " Uses the same funtcions as ale_linters/javascript/eslint.vim by w0rp " call ale#linter#Define('json5', { \ 'name': 'eslint', \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/jsonc/biome.vim ================================================ " Description: biome for jsonc files call ale#linter#Define('jsonc', { \ 'name': 'biome', \ 'lsp': 'stdio', \ 'language': function('ale#handlers#biome#GetLanguage'), \ 'executable': function('ale#handlers#biome#GetExecutable'), \ 'command': '%e lsp-proxy', \ 'project_root': function('ale#handlers#biome#GetProjectRoot'), \}) ================================================ FILE: ale_linters/jsonc/eslint.vim ================================================ " Author: João Pesce " Description: eslint for JSONC files. " " Requires eslint-plugin-jsonc or a similar plugin to work " " Uses the same funtcions as ale_linters/javascript/eslint.vim by w0rp " call ale#linter#Define('jsonc', { \ 'name': 'eslint', \ 'output_stream': 'both', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/jsonnet/jsonnet_lint.vim ================================================ " Author: Trevor Whitney " Description: jsonnet-lint for jsonnet files call ale#Set('jsonnet_jsonnet_lint_executable', 'jsonnet-lint') call ale#Set('jsonnet_jsonnet_lint_options', '') function! ale_linters#jsonnet#jsonnet_lint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'jsonnet_jsonnet_lint_options') return '%e' \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale_linters#jsonnet#jsonnet_lint#Handle(buffer, lines) abort " Matches patterns line the following: " " ERROR: foo.jsonnet:22:3-12 expected token OPERATOR but got (IDENTIFIER, "bar") " ERROR: hoge.jsonnet:20:3 unexpected: "}" while parsing terminal " ERROR: main.jsonnet:212:1-14 Expected , or ; but got (IDENTIFIER, "older_cluster") let l:pattern = '^ERROR: [^:]*:\(\d\+\):\(\d\+\)\(-\d\+\)* \(.*\)' let l:output = [] for l:line in a:lines let l:match = matchlist(l:line, l:pattern) if len(l:match) == 0 continue endif let line_number = l:match[1] + 0 let column = l:match[2] + 0 " l:match[3] has optional -14, when linter is showing a range let text = l:match[4] " vcol is Needed to indicate that the column is a character. call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': line_number, \ 'vcol': 0, \ 'col': column, \ 'text': text, \ 'type': 'E', \ 'nr': -1, \}) endfor return l:output endfunction call ale#linter#Define('jsonnet', { \ 'name': 'jsonnet_lint', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'jsonnet_jsonnet_lint_executable')}, \ 'command': function('ale_linters#jsonnet#jsonnet_lint#GetCommand'), \ 'callback': 'ale_linters#jsonnet#jsonnet_lint#Handle', \}) ================================================ FILE: ale_linters/jsonnet/jsonnetfmt.vim ================================================ " Authors: Trevor Whitney and Takuya Kosugiyama " Description: jsonnetfmt for jsonnet files call ale#Set('jsonnet_jsonnetfmt_executable', 'jsonnetfmt') call ale#Set('jsonnet_jsonnetfmt_options', '') function! ale_linters#jsonnet#jsonnetfmt#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'jsonnet_jsonnetfmt_options') return '%e' \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale_linters#jsonnet#jsonnetfmt#Handle(buffer, lines) abort " Matches patterns line the following: " " STATIC ERROR: foo.jsonnet:22:3-12: expected token OPERATOR but got (IDENTIFIER, "bar") " STATIC ERROR: hoge.jsonnet:20:3: unexpected: "}" while parsing terminal let l:pattern = '^STATIC ERROR:[^:]*:\(\d\+\):\(\d\+\):*\(-\d\+\)* \(.*\)' let l:output = [] for l:line in a:lines let l:match = matchlist(l:line, l:pattern) if len(l:match) == 0 continue endif " vcol is Needed to indicate that the column is a character. call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:match[1] + 0, \ 'vcol': 0, \ 'col': l:match[2] + 0, \ 'text': l:match[4], \ 'type': 'E', \ 'nr': -1, \}) endfor return l:output endfunction call ale#linter#Define('jsonnet', { \ 'name': 'jsonnetfmt', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'jsonnet_jsonnetfmt_executable')}, \ 'command': function('ale_linters#jsonnet#jsonnetfmt#GetCommand'), \ 'callback': 'ale_linters#jsonnet#jsonnetfmt#Handle', \}) ================================================ FILE: ale_linters/julia/languageserver.vim ================================================ " Author: Bartolomeo Stellato " 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; using Pkg; import StaticLint; import SymbolServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, dirname(Pkg.Types.Context().env.project_file)); server.runlinter = true; run(server);' return ale#Escape(l:julia_executable) . ' --project=@. --startup-file=no --history-file=no -e ' . ale#Escape(l:cmd_string) endfunction call ale#linter#Define('julia', { \ 'name': 'languageserver', \ 'aliases': ['julials'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'julia_executable')}, \ 'command': function('ale_linters#julia#languageserver#GetCommand'), \ 'language': 'julia', \ 'project_root': function('ale#julia#FindProjectRoot'), \}) ================================================ FILE: ale_linters/kotlin/kotlinc.vim ================================================ " Author: Francis Agyapong " Description: A linter for the Kotlin programming language that uses kotlinc let g:ale_kotlin_kotlinc_options = get(g:, 'ale_kotlin_kotlinc_options', '') let g:ale_kotlin_kotlinc_enable_config = get(g:, 'ale_kotlin_kotlinc_enable_config', 0) let g:ale_kotlin_kotlinc_config_file = get(g:, 'ale_kotlin_kotlinc_config_file', '.ale_kotlinc_config') let g:ale_kotlin_kotlinc_classpath = get(g:, 'ale_kotlin_kotlinc_classpath', '') let g:ale_kotlin_kotlinc_sourcepath = get(g:, 'ale_kotlin_kotlinc_sourcepath', '') let g:ale_kotlin_kotlinc_use_module_file = get(g:, 'ale_kotlin_kotlinc_use_module_file', 0) let g:ale_kotlin_kotlinc_module_filename = get(g:, 'ale_kotlin_kotlinc_module_filename', 'module.xml') let s:classpath_sep = has('unix') ? ':' : ';' function! ale_linters#kotlin#kotlinc#RunWithImportPaths(buffer) abort let l:command = '' " exec maven/gradle only if classpath is not set if !empty(ale#Var(a:buffer, 'kotlin_kotlinc_classpath')) return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {}) endif let [l:cwd, l:command] = ale#maven#BuildClasspathCommand(a:buffer) " Try to use Gradle if Maven isn't available. if empty(l:command) let [l:cwd, l:command] = ale#gradle#BuildClasspathCommand(a:buffer) endif if empty(l:command) return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {}) endif return ale#command#Run( \ a:buffer, \ l:command, \ function('ale_linters#kotlin#kotlinc#GetCommand'), \ {'cwd': l:cwd}, \) endfunction function! s:BuildClassPathOption(buffer, import_paths) abort " Filter out lines like [INFO], etc. let l:class_paths = filter(a:import_paths[:], 'v:val !~# ''[''') call extend( \ l:class_paths, \ split(ale#Var(a:buffer, 'kotlin_kotlinc_classpath'), s:classpath_sep), \) return !empty(l:class_paths) \ ? ' -cp ' . ale#Escape(join(l:class_paths, s:classpath_sep)) \ : '' endfunction function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths, meta) abort let l:kotlinc_opts = ale#Var(a:buffer, 'kotlin_kotlinc_options') let l:command = 'kotlinc ' " If the config file is enabled and readable, source it if ale#Var(a:buffer, 'kotlin_kotlinc_enable_config') let l:conf = expand(ale#Var(a:buffer, 'kotlin_kotlinc_config_file'), 1) if filereadable(l:conf) execute 'source ' . fnameescape(l:conf) endif endif " If use module and module file is readable use that and return if ale#Var(a:buffer, 'kotlin_kotlinc_use_module_file') let l:module_filename = ale#Escape(expand(ale#Var(a:buffer, 'kotlin_kotlinc_module_filename'), 1)) if filereadable(l:module_filename) let l:kotlinc_opts .= ' -module ' . l:module_filename let l:command .= 'kotlinc ' . l:kotlinc_opts return l:command endif endif " We only get here if not using module or the module file not readable if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# '' let l:kotlinc_opts .= ' -cp ' . ale#Var(a:buffer, 'kotlin_kotlinc_classpath') else " get classpath from maven/gradle let l:kotlinc_opts .= s:BuildClassPathOption(a:buffer, a:import_paths) 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 let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java') \ . ' ' . ale#path#FindNearestDirectory(a:buffer, 'src/main/kotlin') endif 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 return l:command endfunction function! ale_linters#kotlin#kotlinc#Handle(buffer, lines) abort let l:code_pattern = '^\(.*\):\([0-9]\+\):\([0-9]\+\):\s\+\(error\|warning\):\s\+\(.*\)' let l:general_pattern = '^\(warning\|error\|info\):\s*\(.*\)' let l:output = [] for l:line in a:lines let l:match = matchlist(l:line, l:code_pattern) if len(l:match) == 0 continue endif let l:file = l:match[1] let l:line = l:match[2] + 0 let l:column = l:match[3] + 0 let l:type = l:match[4] let l:text = l:match[5] let l:buf_abspath = fnamemodify(l:file, ':p') let l:curbuf_abspath = expand('#' . a:buffer . ':p') " Skip if file is not loaded 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, { \ 'lnum': l:line, \ 'col': l:column, \ 'text': l:text, \ 'type': l:type_marker_str, \}) endfor " Non-code related messages for l:line in a:lines let l:match = matchlist(l:line, l:general_pattern) if len(l:match) == 0 continue endif let l:type = l:match[1] let l:text = l:match[2] let l:type_marker_str = l:type is# 'warning' || l:type is# 'info' ? 'W' : 'E' call add(l:output, { \ 'lnum': 1, \ 'text': l:text, \ 'type': l:type_marker_str, \}) endfor return l:output endfunction call ale#linter#Define('kotlin', { \ 'name': 'kotlinc', \ 'executable': 'kotlinc', \ 'output_stream': 'stderr', \ 'command': function('ale_linters#kotlin#kotlinc#RunWithImportPaths'), \ 'callback': 'ale_linters#kotlin#kotlinc#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/kotlin/ktlint.vim ================================================ " Author: Francis Agyapong " Description: Lint kotlin files using ktlint call ale#linter#Define('kotlin', { \ 'name': 'ktlint', \ 'executable': 'ktlint', \ 'command': function('ale#handlers#ktlint#GetCommand'), \ 'callback': 'ale#handlers#ktlint#Handle', \ 'output_stream': 'stderr' \}) ================================================ FILE: ale_linters/kotlin/languageserver.vim ================================================ " Author: MTDL9 " Description: Support for the Kotlin language server https://github.com/fwcd/KotlinLanguageServer call ale#Set('kotlin_languageserver_executable', 'kotlin-language-server') function! ale_linters#kotlin#languageserver#GetProjectRoot(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 call ale#linter#Define('kotlin', { \ 'name': 'languageserver', \ 'aliaes': ['kotlin_language_server'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'kotlin_languageserver_executable')}, \ 'command': '%e', \ 'language': 'kotlin', \ 'project_root': function('ale_linters#kotlin#languageserver#GetProjectRoot'), \}) ================================================ FILE: ale_linters/lean/lake.vim ================================================ " Author: Benjamin Block " Description: A language server for Lean 4. function! ale_linters#lean#lake#GetProjectRoot(buffer) abort let l:lakefile_toml = ale#path#FindNearestFile(a:buffer, 'lakefile.toml') let l:lakefile_lean = ale#path#FindNearestFile(a:buffer, 'lakefile.lean') if !empty(l:lakefile_toml) return fnamemodify(l:lakefile_toml, ':p:h') elseif !empty(l:lakefile_lean) return fnamemodify(l:lakefile_lean, ':p:h') else return fnamemodify('', ':h') endif endfunction call ale#Set('lean_lake_executable', 'lake') call ale#Set('lean_lake_config', {}) call ale#linter#Define('lean', { \ 'name': 'lake', \ 'lsp': 'stdio', \ 'language': 'lean', \ 'lsp_config': {b -> ale#Var(b, 'lean_lake_config')}, \ 'executable': {b -> ale#Var(b, 'lean_lake_executable')}, \ 'command': '%e serve', \ 'project_root': function('ale_linters#lean#lake#GetProjectRoot'), \}) ================================================ FILE: ale_linters/less/lessc.vim ================================================ " Author: zanona , w0rp " Description: This file adds support for checking Less code with lessc. 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#GetCommand(buffer) abort return '%e --no-color --lint' \ . ' --include-path=' . ale#Escape(expand('#' . a:buffer . ':p:h')) \ . ale#Pad(ale#Var(a:buffer, 'less_lessc_options')) \ . ' -' endfunction function! ale_linters#less#lessc#Handle(buffer, lines) abort let l:dir = expand('#' . a:buffer . ':p:h') " Matches patterns like the following: let l:pattern = '^\(\w\+\): \(.\{-}\) in \(.\{-}\) on line \(\d\+\), column \(\d\+\):$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': l:match[4] + 0, \ 'col': l:match[5] + 0, \ 'text': l:match[2], \ 'type': 'E', \} if l:match[3] isnot# '-' let l:item.filename = ale#path#GetAbsPath(l:dir, l:match[3]) endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('less', { \ 'name': 'lessc', \ 'executable': {b -> ale#path#FindExecutable(b, 'less_lessc', [ \ 'node_modules/.bin/lessc', \ ])}, \ 'command': function('ale_linters#less#lessc#GetCommand'), \ 'callback': 'ale_linters#less#lessc#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/less/stylelint.vim ================================================ " Author: diartyz , w0rp 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#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'less_stylelint_options') return '%e' . ale#Pad(l:options) . ' --no-color --stdin-filename %s' endfunction call ale#linter#Define('less', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': {b -> ale#path#FindExecutable(b, 'less_stylelint', [ \ 'node_modules/.bin/stylelint', \ ])}, \ 'command': function('ale_linters#less#stylelint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/llvm/llc.vim ================================================ " Author: rhysd " Description: Support for checking LLVM IR with llc call ale#Set('llvm_llc_executable', 'llc') 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+): (.+)$' return map(ale#util#GetMatches(a:lines, l:pattern), "{ \ 'lnum': str2nr(v:val[1]), \ 'col': str2nr(v:val[2]), \ 'text': v:val[3], \ 'type': 'E', \}") endfunction call ale#linter#Define('llvm', { \ 'name': 'llc', \ 'executable': {b -> ale#Var(b, 'llvm_llc_executable')}, \ 'output_stream': 'stderr', \ 'command': {-> '%e -filetype=null -o=' . g:ale#util#nul_file}, \ 'callback': 'ale_linters#llvm#llc#HandleErrors', \}) ================================================ FILE: ale_linters/lua/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Lua files. call ale#handlers#cspell#DefineLinter('lua') ================================================ FILE: ale_linters/lua/lua_language_server.vim ================================================ " Author: w0rp " Description: lua-language-server integration (https://github.com/LuaLS/lua-language-server) call ale#Set('lua_language_server_executable', 'lua-language-server') call ale#Set('lua_language_server_config', {}) call ale#linter#Define('lua', { \ 'name': 'lua_language_server', \ 'aliases': ['lua-language-server', 'lua_ls'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'lua_language_server_executable')}, \ 'command': '%e', \ 'project_root': function('ale#lua#FindProjectRoot'), \ 'lsp_config': {b -> ale#Var(b, 'lua_language_server_config')}, \}) ================================================ FILE: ale_linters/lua/luac.vim ================================================ " Author: Jon Xie https://github.com/xiejiangzhi " Description: luac linter for lua files call ale#Set('lua_luac_executable', 'luac') function! ale_linters#lua#luac#Handle(buffer, lines) abort " Matches patterns line the following: " " luac: stdin:5: '=' expected near ')' " luac: stdin:8: ')' expected (to close '(' at line 6) near '123' let l:pattern = '\v^.*:(\d+): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'type': 'E', \ 'text': l:match[2], \}) endfor return l:output endfunction call ale#linter#Define('lua', { \ 'name': 'luac', \ 'executable': {b -> ale#Var(b, 'lua_luac_executable')}, \ 'command': '%e -p -', \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#lua#luac#Handle', \}) ================================================ FILE: ale_linters/lua/luacheck.vim ================================================ " Author: Sol Bekic https://github.com/s-ol " Description: luacheck linter for lua files call ale#Set('lua_luacheck_executable', 'luacheck') call ale#Set('lua_luacheck_options', '') function! s:IsInRuntimepath(buffer) abort let l:runtimepath_dirs = split(&runtimepath, ',') for l:dir in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) for l:runtime_dir in l:runtimepath_dirs if l:dir is# l:runtime_dir return 1 endif endfor endfor return 0 endfunction function! ale_linters#lua#luacheck#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'lua_luacheck_options') " Add `--globals vim` by default if the file is in runtimepath. if l:options !~# '--globals' let l:in_runtime = getbufvar(a:buffer, 'ale_in_runtimepath', v:null) if l:in_runtime is v:null let l:in_runtime = s:IsInRuntimepath(a:buffer) " Save the result of check this buffer so we only check once. call setbufvar(a:buffer, 'ale_in_runtimepath', l:in_runtime) endif if l:in_runtime if !empty(l:options) let l:options .= ' ' endif let l:options .= '--globals vim' endif endif return '%e' . ale#Pad(l:options) \ . ' --formatter plain --codes --filename %s -' endfunction function! ale_linters#lua#luacheck#Handle(buffer, lines) abort " Matches patterns line the following: " " artal.lua:159:17: (W111) shadowing definition of loop variable 'i' on line 106 " artal.lua:182:7: (W213) unused loop variable 'i' let l:pattern = '^.*:\(\d\+\):\(\d\+\): (\([WE]\)\(\d\+\)) \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if !ale#Var(a:buffer, 'warn_about_trailing_whitespace') \ && l:match[3] is# 'W' \ && index(range(611, 614), str2nr(l:match[4])) >= 0 continue endif call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3], \ 'code': l:match[3] . l:match[4], \ 'text': l:match[5], \}) endfor return l:output endfunction call ale#linter#Define('lua', { \ 'name': 'luacheck', \ 'executable': {b -> ale#Var(b, 'lua_luacheck_executable')}, \ 'command': function('ale_linters#lua#luacheck#GetCommand'), \ 'callback': 'ale_linters#lua#luacheck#Handle', \}) ================================================ FILE: ale_linters/lua/selene.vim ================================================ call ale#Set('lua_selene_executable', 'selene') call ale#Set('lua_selene_options', '') function! ale_linters#lua#selene#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'lua_selene_options')) \ . ' --display-style=json -' endfunction function! ale_linters#lua#selene#Handle(buffer, lines) abort let l:output = [] for l:line in a:lines " as of version 0.17.0, selene has no way to suppress summary " information when outputting json, so stop processing when we hit it " (PR for this here: https://github.com/Kampfkarren/selene/pull/356) if l:line is# 'Results:' break endif let l:json = json_decode(l:line) let l:lint = { \ 'lnum': l:json.primary_label.span.start_line + 1, \ 'end_lnum': l:json.primary_label.span.end_line + 1, \ 'col': l:json.primary_label.span.start_column + 1, \ 'end_col': l:json.primary_label.span.end_column, \ 'text': l:json.message, \ 'code': l:json.code, \ 'type': l:json.severity is# 'Warning' ? 'W' : 'E', \} if has_key(l:json, 'notes') && len(l:json.notes) > 0 let l:lint.detail = l:lint.text . "\n\n" . join(l:json.notes, "\n") endif call add(l:output, l:lint) endfor return l:output endfunction call ale#linter#Define('lua', { \ 'name': 'selene', \ 'executable': {b -> ale#Var(b, 'lua_selene_executable')}, \ 'command': function('ale_linters#lua#selene#GetCommand'), \ 'callback': 'ale_linters#lua#selene#Handle', \}) ================================================ FILE: ale_linters/mail/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for mail files call ale#handlers#alex#DefineLinter('mail', '--text') ================================================ FILE: ale_linters/mail/languagetool.vim ================================================ " Author: Vincent (wahrwolf [at] wolfpit.net) " Description: languagetool for mails call ale#handlers#languagetool#DefineLinter('mail') ================================================ FILE: ale_linters/mail/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for mail files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('mail', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/mail/vale.vim ================================================ " Author: chew-z https://github.com/chew-z " Description: vale for Markdown files call ale#linter#Define('mail', { \ 'name': 'vale', \ 'executable': 'vale', \ 'command': 'vale --output=JSON %t', \ 'callback': 'ale#handlers#vale#Handle', \}) ================================================ FILE: ale_linters/make/checkmake.vim ================================================ " Author: aurieh - https://github.com/aurieh call ale#Set('make_checkmake_config', '') function! ale_linters#make#checkmake#Handle(buffer, lines) abort let l:pattern = '\v^(\d+):(.+):(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:match[1] + 0, \ 'type': 'E', \ 'code': l:match[2], \ 'text': l:match[3], \}) endfor return l:output endfunction function! ale_linters#make#checkmake#GetCommand(buffer) abort let l:config = ale#Var(a:buffer, 'make_checkmake_config') let l:cmd = 'checkmake' \ . ' --format="{{.LineNumber}}:{{.Rule}}:{{.Violation}}{{\"\r\n\"}}"' \ . (!empty(l:config) ? ' --config="' . l:config . '"' : '') \ . ' %s' return l:cmd endfunction call ale#linter#Define('make', { \ 'name': 'checkmake', \ 'executable': 'checkmake', \ 'command': function('ale_linters#make#checkmake#GetCommand'), \ 'callback': 'ale_linters#make#checkmake#Handle', \}) ================================================ FILE: ale_linters/markdown/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for markdown files call ale#handlers#alex#DefineLinter('markdown', '') ================================================ FILE: ale_linters/markdown/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Markdown files. call ale#handlers#cspell#DefineLinter('markdown') ================================================ FILE: ale_linters/markdown/languagetool.vim ================================================ " Author: Vincent (wahrwolf [at] wolfpit.net) " Description: languagetool for markdown files call ale#handlers#languagetool#DefineLinter('markdown') ================================================ FILE: ale_linters/markdown/markdownlint.vim ================================================ " Author: Ty-Lucas Kelley " Description: Adds support for markdownlint call ale#Set('markdown_markdownlint_executable', 'markdownlint') call ale#Set('markdown_markdownlint_options', '') function! ale_linters#markdown#markdownlint#GetExecutable(buffer) abort return ale#Var(a:buffer, 'markdown_markdownlint_executable') endfunction function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort let l:executable = ale_linters#markdown#markdownlint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options') return ale#Escape(l:executable) \ . ale#Pad(l:options) . ' %s' endfunction call ale#linter#Define('markdown', { \ 'name': 'markdownlint', \ 'executable': function('ale_linters#markdown#markdownlint#GetExecutable'), \ 'lint_file': 1, \ 'output_stream': 'both', \ 'command': function('ale_linters#markdown#markdownlint#GetCommand'), \ 'callback': 'ale#handlers#markdownlint#Handle' \}) ================================================ FILE: ale_linters/markdown/marksman.vim ================================================ " Author: Peter Benjamin " Description: Write Markdown with code assist and intelligence in the comfort of your favourite editor. call ale#Set('markdown_marksman_executable', 'marksman') function! ale_linters#markdown#marksman#GetCommand(buffer) abort return '%e server' endfunction function! ale_linters#markdown#marksman#GetProjectRoot(buffer) abort " Find nearest .marksman.toml let l:marksman_toml = ale#path#FindNearestFile(a:buffer, '.marksman.toml') if !empty(l:marksman_toml) return fnamemodify(l:marksman_toml, ':h') endif " Find nearest .git/ directory let l:project_root = finddir('.git/..', expand('#' . a:buffer . '...').';') if !empty(l:project_root) return l:project_root endif return '' endfunction call ale#linter#Define('markdown', { \ 'name': 'marksman', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'markdown_marksman_executable')}, \ 'command': function('ale_linters#markdown#marksman#GetCommand'), \ 'project_root': function('ale_linters#markdown#marksman#GetProjectRoot'), \ 'initialization_options': {}, \}) ================================================ FILE: ale_linters/markdown/mdl.vim ================================================ " Author: Steve Dignam , Josh Leeb-du Toit " Description: Support for mdl, a markdown linter. call ale#Set('markdown_mdl_executable', 'mdl') call ale#Set('markdown_mdl_options', '') function! ale_linters#markdown#mdl#GetExecutable(buffer) abort return ale#Var(a:buffer, 'markdown_mdl_executable') endfunction function! ale_linters#markdown#mdl#GetCommand(buffer) abort let l:executable = ale_linters#markdown#mdl#GetExecutable(a:buffer) let l:exec_args = l:executable =~? 'bundle$' \ ? ' exec mdl' \ : '' let l:options = ale#Var(a:buffer, 'markdown_mdl_options') return ale#Escape(l:executable) . l:exec_args \ . ' -j' . ale#Pad(l:options) endfunction function! ale_linters#markdown#mdl#Handle(buffer, lines) abort let l:output = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) call add(l:output, { \ 'lnum': l:error['line'], \ 'code': l:error['rule'] . '/' . join(l:error['aliases'], '/'), \ 'text': l:error['description'], \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('markdown', { \ 'name': 'mdl', \ 'executable': function('ale_linters#markdown#mdl#GetExecutable'), \ 'command': function('ale_linters#markdown#mdl#GetCommand'), \ 'callback': 'ale_linters#markdown#mdl#Handle' \}) ================================================ FILE: ale_linters/markdown/proselint.vim ================================================ " Author: poohzrn https://github.com/poohzrn " Description: proselint for Markdown files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('markdown', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/markdown/pymarkdown.vim ================================================ call ale#Set('markdown_pymarkdown_executable', 'pymarkdown') call ale#Set('markdown_pymarkdown_options', '') call ale#Set('markdown_pymarkdown_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('markdown_pymarkdown_auto_pipenv', 0) call ale#Set('markdown_pymarkdown_auto_poetry', 0) call ale#Set('markdown_pymarkdown_auto_uv', 0) function! ale_linters#markdown#pymarkdown#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'markdown_pymarkdown', ['pymarkdown']) endfunction function! ale_linters#markdown#pymarkdown#GetCommand(buffer) abort let l:executable = ale_linters#markdown#pymarkdown#GetExecutable(a:buffer) let l:exec_args = l:executable =~? 'pipenv\|poetry\|uv$' \ ? ' run pymarkdown' \ : '' return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'markdown_pymarkdown_options')) \ . ' scan-stdin' endfunction function! ale_linters#markdown#pymarkdown#Handle(buffer, lines) abort let l:pattern = '\v^(\S*):(\d+):(\d+): ([A-Z]+\d+): (.*)$' let l:output = [] " lines are formatted as follows: " sample.md:1:1: MD022: Headings should be surrounded by blank lines. [Expected: 1; Actual: 0; Below] (blanks-around-headings,blanks-around-headers) for l:match in ale#util#GetMatches(a:lines, l:pattern) if(l:match[4] is# 'MD009') \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4][0], \ 'text': l:match[5], \ 'code': l:match[4], \} call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('markdown', { \ 'name': 'pymarkdown', \ 'executable': function('ale_linters#markdown#pymarkdown#GetExecutable'), \ 'command': function('ale_linters#markdown#pymarkdown#GetCommand'), \ 'callback': 'ale_linters#markdown#pymarkdown#Handle', \}) ================================================ FILE: ale_linters/markdown/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#handlers#redpen#DefineLinter('markdown') ================================================ FILE: ale_linters/markdown/remark_lint.vim ================================================ scriptencoding utf-8 " Author rhysd https://rhysd.github.io/, Dirk Roorda (dirkroorda), Adrián González Rus (@adrigzr) " Description: remark-lint for Markdown files 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#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options') return '%e' . ale#Pad(l:options) . ' --no-stdout --no-color' endfunction function! ale_linters#markdown#remark_lint#Handle(buffer, lines) abort " matches: ' 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint' " matches: ' 18:71-19:1 error Missing new line after list item list-item-spacing remark-lint', let l:pattern = '^ \+\(\d\+\):\(\d\+\)\(-\(\d\+\):\(\d\+\)\)\? \(warning\|error\) \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ '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 return l:output endfunction call ale#linter#Define('markdown', { \ 'name': 'remark_lint', \ 'aliases': ['remark-lint'], \ 'executable': {b -> ale#path#FindExecutable(b, 'markdown_remark_lint', [ \ 'node_modules/.bin/remark', \ ])}, \ 'command': function('ale_linters#markdown#remark_lint#GetCommand'), \ 'callback': 'ale_linters#markdown#remark_lint#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/markdown/textlint.vim ================================================ " Author: tokida https://rouger.info, Yasuhiro Kiyota " Description: textlint, a proofreading tool (https://textlint.github.io/) call ale#linter#Define('markdown', { \ 'name': 'textlint', \ 'executable': function('ale#handlers#textlint#GetExecutable'), \ 'command': function('ale#handlers#textlint#GetCommand'), \ 'callback': 'ale#handlers#textlint#HandleTextlintOutput', \}) ================================================ FILE: ale_linters/markdown/vale.vim ================================================ " Author: chew-z https://github.com/chew-z " Description: vale for Markdown files call ale#Set('markdown_vale_executable', 'vale') call ale#Set('markdown_vale_input_file', '%t') call ale#Set('markdown_vale_options', '') function! ale_linters#markdown#vale#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'markdown_vale_executable') let l:input_file = ale#Var(a:buffer, 'markdown_vale_input_file') " Defaults to `vale --output=JSON %t` return ale#Escape(l:executable) \ . ' --output=JSON ' \ . ale#Var(a:buffer, 'markdown_vale_options') \ . ' ' . l:input_file endfunction call ale#linter#Define('markdown', { \ 'name': 'vale', \ 'executable': {b -> ale#Var(b, 'markdown_vale_executable')}, \ 'command': function('ale_linters#markdown#vale#GetCommand'), \ 'callback': 'ale#handlers#vale#Handle', \}) ================================================ FILE: ale_linters/markdown/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for Markdown files call ale#handlers#writegood#DefineLinter('markdown') ================================================ FILE: ale_linters/matlab/mlint.vim ================================================ " Author: awlayton " Description: mlint for MATLAB files call ale#Set('matlab_mlint_executable', 'mlint') function! ale_linters#matlab#mlint#Handle(buffer, lines) abort " Matches patterns like the following: " " L 27 (C 1): FNDEF: Terminate statement with semicolon to suppress output. " L 30 (C 13-15): FNDEF: A quoted string is unterminated. let l:pattern = '^L \(\d\+\) (C \([0-9-]\+\)): \([A-Z]\+\): \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:lnum = l:match[1] + 0 let l:col = l:match[2] + 0 let l:code = l:match[3] let l:text = l:match[4] " Suppress erroneous warning about filename " TODO: Enable this error when copying filename is supported if l:code is# 'FNDEF' continue endif call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:lnum, \ 'col': l:col, \ 'text': l:text, \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('matlab', { \ 'name': 'mlint', \ 'executable': {b -> ale#Var(b, 'matlab_mlint_executable')}, \ 'command': '%e -id %t', \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#matlab#mlint#Handle', \}) ================================================ FILE: ale_linters/mercury/mmc.vim ================================================ " Author: stewy33 " Description: Lints mercury files using mmc call ale#Set('mercury_mmc_executable', 'mmc') call ale#Set('mercury_mmc_options', '--make --output-compile-error-lines 100') function! ale_linters#mercury#mmc#GetCommand(buffer) abort return '%e --errorcheck-only ' \ . ale#Var(a:buffer, 'mercury_mmc_options') \ . ' %s:t:r' endfunction function! ale_linters#mercury#mmc#Handle(buffer, lines) abort " output format " :: : let l:pattern = '\v^\w+\.m:(\d+):\s+([W|w]arning|.*[E|e]rror.*): (.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': substitute(l:match[1], '\v^0*', '', '') + 0, \ 'type': l:match[2][0] =~? 'W' ? 'W' : 'E', \ 'text': l:match[2] . ': ' . l:match[3] \}) endfor return l:output endfunction call ale#linter#Define('mercury', { \ 'name': 'mmc', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'mercury_mmc_executable')}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#mercury#mmc#GetCommand'), \ 'callback': 'ale_linters#mercury#mmc#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/nasm/nasm.vim ================================================ " Author: Oyvind Ingvaldsen " Description: NASM linter for asmsyntax nasm. call ale#Set('nasm_nasm_executable', 'nasm') call ale#Set('nasm_nasm_options', '') function! ale_linters#nasm#nasm#GetCommand(buffer) abort " Note that NASM requires a trailing slash for the -I option. let l:separator = has('win32') ? '\' : '/' let l:output_null = has('win32') ? 'NUL' : '/dev/null' return '%e -X gnu -I %s:h' . l:separator \ . 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, \ 'type': l:match[2] =~? 'error\|fatal' ? 'E' : 'W', \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('nasm', { \ 'name': 'nasm', \ 'output_stream': 'stderr', \ 'lint_file': 1, \ 'executable': {b -> ale#Var(b, 'nasm_nasm_executable')}, \ 'command': function('ale_linters#nasm#nasm#GetCommand'), \ 'callback': 'ale_linters#nasm#nasm#Handle', \}) ================================================ FILE: ale_linters/nim/nimcheck.vim ================================================ " Author: Baabelfish " Description: Typechecking for nim files let s:end_col_patterns = [ \ '\v''([^'']+)'' is declared but not used.*', \ '\videntifier expected, but found ''([^'']+)''', \ '\vimported and not used: ''([^'']+)''.*', \ '\vundeclared identifier: ''([^'']+)''', \ '\v''([^'']+)'' cannot be assigned to', \ '\vredefinition of ''([^'']+)'';', \] function! ale_linters#nim#nimcheck#Handle(buffer, lines) abort let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p:t') let l:pattern = '^\(.\+\.nim\)(\(\d\+\), \(\d\+\)) \(.\+\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) " Only show errors of the current buffer " NOTE: Checking filename only is OK because nim enforces unique " module names. let l:temp_buffer_filename = fnamemodify(l:match[1], ':p:t') if l:buffer_filename isnot# '' && l:temp_buffer_filename isnot# l:buffer_filename continue endif let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \ 'type': 'W', \} " Extract error type from message of type 'Error: Some error message' let l:error_match = matchlist(l:item.text, '^\(.\{-}\): \(.\+\)$') if !empty(l:error_match) if l:error_match[1] is# 'Error' let l:item.type = 'E' let l:item.text = l:error_match[2] elseif l:error_match[1] is# 'Warning' \|| l:error_match[1] is# 'Hint' let l:item.text = l:error_match[2] endif endif let l:code_match = matchlist(l:item.text, '\v^(.+) \[([^ \[]+)\]$') if !empty(l:code_match) let l:item.text = l:code_match[1] let l:item.code = l:code_match[2] endif " Find position end_col. for l:col_match in ale#util#GetMatches(l:item.text, s:end_col_patterns) let l:item.end_col = l:item.col + len(l:col_match[1]) - 1 endfor call add(l:output, l:item) endfor return l:output endfunction function! ale_linters#nim#nimcheck#GetCommand(buffer) abort return 'nim check --verbosity:0 --colors:off --listFullPaths %s' endfunction call ale#linter#Define('nim', { \ 'name': 'nimcheck', \ 'executable': 'nim', \ 'output_stream': 'both', \ 'command': function('ale_linters#nim#nimcheck#GetCommand'), \ 'callback': 'ale_linters#nim#nimcheck#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/nim/nimlsp.vim ================================================ " Author: jeremija " Description: Support for nimlsp (language server for nim) call ale#Set('nim_nimlsp_nim_sources', '') function! ale_linters#nim#nimlsp#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git') if !empty(l:project_root) return fnamemodify(l:project_root, ':h:h') endif return '' endfunction function! ale_linters#nim#nimlsp#GetCommand(buffer) abort let l:nim_sources = ale#Var(a:buffer, 'nim_nimlsp_nim_sources') if !empty(l:nim_sources) let l:nim_sources = ale#Escape(l:nim_sources) endif return '%e' . ale#Pad(l:nim_sources) endfunction call ale#linter#Define('nim', { \ 'name': 'nimlsp', \ 'lsp': 'stdio', \ 'executable': 'nimlsp', \ 'command': function('ale_linters#nim#nimlsp#GetCommand'), \ 'language': 'nim', \ 'project_root': function('ale_linters#nim#nimlsp#GetProjectRoot'), \}) ================================================ FILE: ale_linters/nix/deadnix.vim ================================================ call ale#Set('nix_deadnix_executable', 'deadnix') call ale#Set('nix_deadnix_options', '') function! ale_linters#nix#deadnix#GetCommand(buffer) abort return '%e -o json' . ale#Pad(ale#Var(a:buffer, 'nix_deadnix_options')) . ' -- %t' endfunction call ale#linter#Define('nix', { \ 'name': 'deadnix', \ 'executable': {b -> ale#Var(b, 'nix_deadnix_executable')}, \ 'command': function('ale_linters#nix#deadnix#GetCommand'), \ 'callback': 'ale#handlers#deadnix#Handle', \}) ================================================ FILE: ale_linters/nix/nix.vim ================================================ " Author: Alistair Bill <@alibabzo> " Author: Maximilian Bosch " Description: nix-instantiate linter for nix files function! ale_linters#nix#nix#Command(buffer, output, meta) abort let l:version = a:output[0][22:] if l:version =~# '^\(1\|2.[0-3]\.\).*' return 'nix-instantiate --parse -' else return 'nix-instantiate --log-format internal-json --parse -' endif endfunction function! ale_linters#nix#nix#Handle(buffer, lines) abort let l:output = [] if empty(a:lines) return l:output endif if a:lines[0] =~# '^@nix .*' for l:line in a:lines if l:line =~# '^@nix .*' let l:result = json_decode(strpart(l:line, 4)) if has_key(l:result, 'column') call add(l:output, { \ 'type': 'E', \ 'lnum': l:result.line, \ 'col': l:result.column, \ 'text': substitute(l:result.raw_msg, '\e\[[0-9;]*m', '', 'g'), \}) endif endif endfor else let l:pattern = '^\(.\+\): \(.\+\) at .*:\(\d\+\):\(\d\+\)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[3] + 0, \ 'col': l:match[4] + 0, \ 'text': l:match[1] . ': ' . substitute(l:match[2], ',$', '', ''), \ 'type': l:match[1] =~# '^error' ? 'E' : 'W', \}) endfor endif return l:output endfunction call ale#linter#Define('nix', { \ 'name': 'nix', \ 'output_stream': 'stderr', \ 'executable': 'nix-instantiate', \ 'command': {buffer -> ale#command#Run( \ buffer, \ 'nix-instantiate --version', \ function('ale_linters#nix#nix#Command') \ )}, \ 'callback': 'ale_linters#nix#nix#Handle', \}) ================================================ FILE: ale_linters/nix/rnix_lsp.vim ================================================ " Author: jD91mZM2 " Description: rnix-lsp language client function! ale_linters#nix#rnix_lsp#GetProjectRoot(buffer) abort " rnix-lsp does not yet use the project root, so getting it right is not " important return fnamemodify(a:buffer, ':h') endfunction call ale#linter#Define('nix', { \ 'name': 'rnix_lsp', \ 'aliases': ['rnix'], \ 'lsp': 'stdio', \ 'executable': 'rnix-lsp', \ 'command': '%e', \ 'project_root': function('ale_linters#nix#rnix_lsp#GetProjectRoot'), \}) ================================================ FILE: ale_linters/nix/statix.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: statix analysis and suggestions for Nix files call ale#Set('nix_statix_check_executable', 'statix') call ale#Set('nix_statix_check_options', '') function! ale_linters#nix#statix#GetCommand(buffer) abort return '%e check -o errfmt --stdin' \ . ale#Pad(ale#Var(a:buffer, 'nix_statix_check_options')) endfunction call ale#linter#Define('nix', { \ 'name': 'statix', \ 'executable': {b -> ale#Var(b, 'nix_statix_check_executable')}, \ 'command': function('ale_linters#nix#statix#GetCommand'), \ 'callback': 'ale#handlers#statix#Handle', \}) ================================================ FILE: ale_linters/nroff/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for nroff files call ale#handlers#alex#DefineLinter('nroff', '--text') ================================================ FILE: ale_linters/nroff/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for nroff files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('nroff', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/nroff/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for nroff files call ale#handlers#writegood#DefineLinter('nroff') ================================================ FILE: ale_linters/nunjucks/djlint.vim ================================================ " Author: Adrian Vollmer " Description: djlint for Django HTML template files call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_options', '') call ale#linter#Define('nunjucks', { \ 'name': 'djlint', \ 'executable': function('ale#handlers#djlint#GetExecutable'), \ 'command': function('ale#handlers#djlint#GetCommand'), \ 'callback': 'ale#handlers#djlint#Handle', \}) ================================================ FILE: ale_linters/objc/ccls.vim ================================================ " Author: Ye Jingchen , Ben Falconer , jtalowell " Description: A language server for Objective-C call ale#Set('objc_ccls_executable', 'ccls') call ale#Set('objc_ccls_init_options', {}) call ale#Set('c_build_dir', '') call ale#linter#Define('objc', { \ 'name': 'ccls', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'objc_ccls_executable')}, \ 'command': '%e', \ 'project_root': function('ale#handlers#ccls#GetProjectRoot'), \ 'initialization_options': {b -> ale#handlers#ccls#GetInitOpts(b, 'objc_ccls_init_options')}, \}) ================================================ FILE: ale_linters/objc/clang.vim ================================================ " Author: Bang Lee " Description: clang linter for objc files " Set this option to change the Clang options for warnings for ObjC. if !exists('g:ale_objc_clang_options') let g:ale_objc_clang_options = '-std=c11 -Wall' endif function! ale_linters#objc#clang#GetCommand(buffer) abort " -iquote with the directory the file is in makes #include work for " headers in the same directory. return 'clang -S -x objective-c -fsyntax-only ' \ . '-iquote %s:h' \ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -' endfunction call ale#linter#Define('objc', { \ 'name': 'clang', \ 'output_stream': 'stderr', \ 'executable': 'clang', \ 'command': function('ale_linters#objc#clang#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) ================================================ FILE: ale_linters/objc/clangd.vim ================================================ " Author: Andrey Melentyev " Description: Clangd language server call ale#Set('objc_clangd_executable', 'clangd') call ale#Set('objc_clangd_options', '') 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': {b -> ale#Var(b, 'objc_clangd_executable')}, \ 'command': function('ale_linters#objc#clangd#GetCommand'), \ 'project_root': function('ale#c#FindProjectRoot'), \}) ================================================ FILE: ale_linters/objcpp/clang.vim ================================================ " Author: Bang Lee " Description: clang linter for objcpp files " Set this option to change the Clang options for warnings for ObjCPP. if !exists('g:ale_objcpp_clang_options') let g:ale_objcpp_clang_options = '-std=c++14 -Wall' endif function! ale_linters#objcpp#clang#GetCommand(buffer) abort " -iquote with the directory the file is in makes #include work for " headers in the same directory. return 'clang++ -S -x objective-c++ -fsyntax-only ' \ . '-iquote %s:h' \ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -' endfunction call ale#linter#Define('objcpp', { \ 'name': 'clang', \ 'output_stream': 'stderr', \ 'executable': 'clang++', \ 'command': function('ale_linters#objcpp#clang#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) ================================================ FILE: ale_linters/objcpp/clangd.vim ================================================ " Author: Andrey Melentyev " Description: Clangd language server call ale#Set('objcpp_clangd_executable', 'clangd') call ale#Set('objcpp_clangd_options', '') 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': {b -> ale#Var(b, 'objcpp_clangd_executable')}, \ 'command': function('ale_linters#objcpp#clangd#GetCommand'), \ 'project_root': function('ale#c#FindProjectRoot'), \}) ================================================ FILE: ale_linters/ocaml/merlin.vim ================================================ " Author: Andrey Popp -- @andreypopp " Description: Report errors in OCaml code with Merlin if !exists('g:merlin') finish endif function! ale_linters#ocaml#merlin#Handle(buffer, lines) abort return merlin#ErrorLocList() endfunction call ale#linter#Define('ocaml', { \ 'name': 'merlin', \ 'executable': 'ocamlmerlin', \ 'command': 'true', \ 'callback': 'ale_linters#ocaml#merlin#Handle', \}) ================================================ FILE: ale_linters/ocaml/ocamllsp.vim ================================================ " Author: Risto Stevcev " Description: The official language server for OCaml call ale#Set('ocaml_ocamllsp_use_opam', 1) call ale#linter#Define('ocaml', { \ 'name': 'ocamllsp', \ 'lsp': 'stdio', \ 'executable': function('ale#handlers#ocamllsp#GetExecutable'), \ 'command': function('ale#handlers#ocamllsp#GetCommand'), \ 'language': function('ale#handlers#ocamllsp#GetLanguage'), \ 'project_root': function('ale#handlers#ocamllsp#GetProjectRoot'), \}) ================================================ FILE: ale_linters/ocaml/ols.vim ================================================ " Author: Michael Jungo " Description: A language server for OCaml call ale#Set('ocaml_ols_executable', 'ocaml-language-server') call ale#Set('ocaml_ols_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define('ocaml', { \ 'name': 'ols', \ 'aliases': ['ocaml-language-server'], \ 'lsp': 'stdio', \ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'command': function('ale#handlers#ols#GetCommand'), \ 'language': function('ale#handlers#ols#GetLanguage'), \ 'project_root': function('ale#handlers#ols#GetProjectRoot'), \}) ================================================ FILE: ale_linters/ocamlinterface/merlin.vim ================================================ " Author: Andrey Popp -- @andreypopp " Description: Report errors in OCaml code with Merlin if !exists('g:merlin') finish endif function! ale_linters#ocamlinterface#merlin#Handle(buffer, lines) abort return merlin#ErrorLocList() endfunction call ale#linter#Define('ocamlinterface', { \ 'name': 'merlin', \ 'executable': 'ocamlmerlin', \ 'command': 'true', \ 'callback': 'ale_linters#ocamlinterface#merlin#Handle', \}) ================================================ FILE: ale_linters/ocamlinterface/ocamllsp.vim ================================================ " Author: Risto Stevcev " Description: The official language server for OCaml call ale#Set('ocaml_ocamllsp_use_opam', 1) call ale#linter#Define('ocamlinterface', { \ 'name': 'ocamllsp', \ 'lsp': 'stdio', \ 'executable': function('ale#handlers#ocamllsp#GetExecutable'), \ 'command': function('ale#handlers#ocamllsp#GetCommand'), \ 'language': function('ale#handlers#ocamllsp#GetLanguage'), \ 'project_root': function('ale#handlers#ocamllsp#GetProjectRoot'), \}) ================================================ FILE: ale_linters/odin/ols.vim ================================================ " Author: Benjamin Block " Description: A language server for Odin. function! ale_linters#odin#ols#GetProjectRoot(buffer) abort return fnamemodify('', ':h') endfunction call ale#Set('odin_ols_executable', 'ols') call ale#Set('odin_ols_config', {}) call ale#linter#Define('odin', { \ 'name': 'ols', \ 'lsp': 'stdio', \ 'language': 'odin', \ 'lsp_config': {b -> ale#Var(b, 'odin_ols_config')}, \ 'executable': {b -> ale#Var(b, 'odin_ols_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#odin#ols#GetProjectRoot'), \}) ================================================ FILE: ale_linters/openapi/ibm_validator.vim ================================================ " Author: Horacio Sanson call ale#Set('openapi_ibm_validator_executable', 'lint-openapi') call ale#Set('openapi_ibm_validator_options', '') function! ale_linters#openapi#ibm_validator#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'openapi_ibm_validator_options')) \ . ' %t' endfunction function! ale_linters#openapi#ibm_validator#Handle(buffer, lines) abort let l:output = [] let l:type = 'E' let l:message = '' let l:nr = -1 for l:line in a:lines let l:match = matchlist(l:line, '^errors$') if !empty(l:match) let l:type = 'E' endif let l:match = matchlist(l:line, '^warnings$') if !empty(l:match) let l:type = 'W' endif let l:match = matchlist(l:line, '^ *Message : *\(.\+\)$') if !empty(l:match) let l:message = l:match[1] endif let l:match = matchlist(l:line, '^ *Line *: *\(\d\+\)$') if !empty(l:match) let l:nr = l:match[1] call add(l:output, { \ 'lnum': l:nr + 0, \ 'col': 0, \ 'text': l:message, \ 'type': l:type, \}) endif endfor return l:output endfunction call ale#linter#Define('openapi', { \ 'name': 'ibm_validator', \ 'executable': {b -> ale#Var(b, 'openapi_ibm_validator_executable')}, \ 'command': function('ale_linters#openapi#ibm_validator#GetCommand'), \ 'callback': 'ale_linters#openapi#ibm_validator#Handle', \}) ================================================ FILE: ale_linters/openapi/yamllint.vim ================================================ call ale#Set('yaml_yamllint_executable', 'yamllint') call ale#Set('yaml_yamllint_options', '') call ale#linter#Define('openapi', { \ 'name': 'yamllint', \ 'executable': {b -> ale#Var(b, 'yaml_yamllint_executable')}, \ 'command': function('ale#handlers#yamllint#GetCommand'), \ 'callback': 'ale#handlers#yamllint#Handle', \}) ================================================ FILE: ale_linters/openscad/sca2d.vim ================================================ " Description: SCA2D linter for OpenSCAD files call ale#Set('openscad_sca2d_executable', 'sca2d') call ale#Set('openscad_sca2d_options', '') function! ale_linters#openscad#sca2d#GetExecutable(buffer) abort return ale#Var(a:buffer, 'openscad_sca2d_executable') endfunction function! ale_linters#openscad#sca2d#GetCommand(buffer) abort let l:executable = ale_linters#openscad#sca2d#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'openscad_sca2d_options') return ale#Escape(l:executable) . ale#Pad(l:options) . ' %s' endfunction call ale#linter#Define('openscad', { \ 'name': 'SCA2D', \ 'aliases': ['sca2d'], \ 'executable': function('ale_linters#openscad#sca2d#GetExecutable'), \ 'command': function('ale_linters#openscad#sca2d#GetCommand'), \ 'callback': 'ale#handlers#openscad#SCA2D_callback', \ 'lint_file': 1, \ }) ================================================ FILE: ale_linters/perl/languageserver.vim ================================================ " Authors: ophirr33 , rymdbar " Description: Perl::LanguageServer for perl, from cpan.org " This should have the same value as in perl.vim call ale#Set('perl_perl_executable', 'perl') " Please note that perl_perl_options does not exist here. function! ale_linters#perl#languageserver#GetProjectRoot(buffer) abort " Makefile.PL, https://perldoc.perl.org/ExtUtils::MakeMaker " Build.PL, https://metacpan.org/pod/Module::Build " dist.ini, https://metacpan.org/pod/Dist::Zilla let l:potential_roots = [ 'Makefile.PL', 'Build.PL', 'dist.ini' ] for l:root in l:potential_roots let l:project_root = ale#path#FindNearestFile(a:buffer, l:root) if !empty(l:project_root) return fnamemodify(l:project_root . '/', ':p:h:h') endif endfor let l:project_root = ale#path#FindNearestFileOrDirectory(a:buffer, '.git') if !empty(l:project_root) return fnamemodify(l:project_root . '/', ':p:h:h') endif return fnamemodify(expand('#' . a:buffer . ':p:h'), ':p:h') endfunction call ale#Set('perl_languageserver_config', {}) function! s:get_lsp_config(buffer) abort " This tool doesn't kick in unless workspace/didChangeConfiguration is " called, thus this function returning a fallback dict when there is no " config. let l:lsp_config = ale#Var(a:buffer, 'perl_languageserver_config') return empty(l:lsp_config) ? { 'perl': { 'enable': 1 } } : l:lsp_config endfunction call ale#linter#Define('perl', { \ 'name': 'languageserver', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'perl_perl_executable')}, \ 'command': '%e -MPerl::LanguageServer -ePerl::LanguageServer::run', \ 'lsp_config': {b -> s:get_lsp_config(b)}, \ 'project_root': function('ale_linters#perl#languageserver#GetProjectRoot'), \ }) ================================================ FILE: ale_linters/perl/perl.vim ================================================ " Author: Vincent Lequertier " Description: This file adds support for checking perl syntax 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 '%e' . ale#Pad(ale#Var(a:buffer, 'perl_perl_options')) . ' %t' endfunction let s:begin_failed_skip_pattern = '\v' . join([ \ '^Compilation failed in require', \ '^Can''t locate', \], '|') 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 let l:seen = {} for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:line = l:match[3] let l:file = l:match[2] let l:text = l:match[1] if ale#path#IsBufferPath(a:buffer, l:file) \ && !has_key(l:seen,l:line) \ && ( \ l:text isnot# 'BEGIN failed--compilation aborted' \ || empty(l:output) \ || match(l:output[-1].text, s:begin_failed_skip_pattern) < 0 \ ) call add(l:output, { \ 'lnum': l:line, \ 'text': l:text, \ 'type': l:type, \}) let l:seen[l:line] = 1 endif endfor return l:output endfunction call ale#linter#Define('perl', { \ 'name': 'perl', \ 'executable': {b -> ale#Var(b, 'perl_perl_executable')}, \ 'output_stream': 'both', \ 'command': function('ale_linters#perl#perl#GetCommand'), \ 'callback': 'ale_linters#perl#perl#Handle', \}) ================================================ FILE: ale_linters/perl/perlcritic.vim ================================================ " Author: Vincent Lequertier , Chris Weyl " Description: This file adds support for checking perl with perl critic 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 let l:profile = ale#Var(a:buffer, 'perl_perlcritic_profile') if l:profile is? '' return '' endif " otherwise, iterate upwards to find it return ale#path#FindNearestFile(a:buffer, l:profile) endfunction function! ale_linters#perl#perlcritic#GetCommand(buffer) abort let l:critic_verbosity = '%l:%c %m\n' if ale#Var(a:buffer, 'perl_perlcritic_showrules') let l:critic_verbosity = '%l:%c %m [%p]\n' endif let l:profile = ale_linters#perl#perlcritic#GetProfile(a:buffer) let l:options = ale#Var(a:buffer, 'perl_perlcritic_options') return '%e' \ . ' --verbose ' . ale#Escape(l:critic_verbosity) \ . ' --nocolor' \ . (!empty(l:profile) ? ' --profile ' . ale#Escape(l:profile) : '') \ . ale#Pad(l:options) endfunction function! ale_linters#perl#perlcritic#Handle(buffer, lines) abort let l:pattern = '\(\d\+\):\(\d\+\) \(.\+\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1], \ 'col': l:match[2], \ 'text': l:match[3], \ 'type': 'W' \}) endfor return l:output endfunction call ale#linter#Define('perl', { \ 'name': 'perlcritic', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'perl_perlcritic_executable')}, \ 'command': function('ale_linters#perl#perlcritic#GetCommand'), \ 'callback': 'ale_linters#perl#perlcritic#Handle', \}) ================================================ FILE: ale_linters/perl6/perl6.vim ================================================ " Author:Travis Gibson " 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\|E491/ 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': function('ale_linters#perl6#perl6#GetExecutable'), \ 'output_stream': 'both', \ 'command': function('ale_linters#perl6#perl6#GetCommand'), \ 'callback': 'ale_linters#perl6#perl6#Handle', \}) ================================================ FILE: ale_linters/php/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for PHP files. call ale#handlers#cspell#DefineLinter('php') ================================================ FILE: ale_linters/php/intelephense.vim ================================================ " Author: Eric Stern , " Arnold Chand " Description: Intelephense language server integration for ALE call ale#Set('php_intelephense_executable', 'intelephense') call ale#Set('php_intelephense_use_global', 1) call ale#Set('php_intelephense_config', {}) function! ale_linters#php#intelephense#GetProjectRoot(buffer) abort let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') if (!empty(l:composer_path)) return fnamemodify(l:composer_path, ':h') endif let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : '' endfunction function! ale_linters#php#intelephense#GetInitializationOptions(buffer) abort return ale#Var(a:buffer, 'php_intelephense_config') endfunction call ale#linter#Define('php', { \ 'name': 'intelephense', \ 'lsp': 'stdio', \ 'initialization_options': function('ale_linters#php#intelephense#GetInitializationOptions'), \ 'executable': {b -> ale#path#FindExecutable(b, 'php_intelephense', [])}, \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#php#intelephense#GetProjectRoot'), \}) ================================================ FILE: ale_linters/php/langserver.vim ================================================ " Author: Eric Stern " Description: PHP Language server integration for ALE 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#GetProjectRoot(buffer) abort let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') if (!empty(l:composer_path)) return fnamemodify(l:composer_path, ':h') endif 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': 'langserver', \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'php_langserver', [ \ 'vendor/bin/php-language-server.php', \ ])}, \ 'command': 'php %e', \ 'project_root': function('ale_linters#php#langserver#GetProjectRoot'), \}) ================================================ FILE: ale_linters/php/phan.vim ================================================ " Author: diegoholiveira , haginaga " Description: static analyzer for PHP " Define the minimum severity let g:ale_php_phan_minimum_severity = get(g:, 'ale_php_phan_minimum_severity', 0) let g:ale_php_phan_executable = get(g:, 'ale_php_phan_executable', 'phan') let g:ale_php_phan_use_client = get(g:, 'ale_php_phan_use_client', 0) function! ale_linters#php#phan#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'php_phan_executable') if ale#Var(a:buffer, 'php_phan_use_client') == 1 && l:executable is# 'phan' let l:executable = 'phan_client' endif return l:executable endfunction function! ale_linters#php#phan#GetCommand(buffer) abort if ale#Var(a:buffer, 'php_phan_use_client') == 1 let l:args = '-l ' \ . ' %s' else let l:args = '-y ' \ . ale#Var(a:buffer, 'php_phan_minimum_severity') \ . ' %s' endif let l:executable = ale_linters#php#phan#GetExecutable(a:buffer) return ale#Escape(l:executable) . ' ' . l:args endfunction function! ale_linters#php#phan#Handle(buffer, lines) abort " Matches against lines like the following: if ale#Var(a:buffer, 'php_phan_use_client') == 1 " Phan error: ERRORTYPE: message in /path/to/some-filename.php on line nnn let l:pattern = '^Phan error: \(\w\+\): \(.\+\) in \(.\+\) on line \(\d\+\)$' else " /path/to/some-filename.php:18 ERRORTYPE message let l:pattern = '^\(.*\):\(\d\+\)\s\(\w\+\)\s\(.\+\)$' endif let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if ale#Var(a:buffer, 'php_phan_use_client') == 1 let l:dict = { \ 'lnum': l:match[4] + 0, \ 'text': l:match[2], \ 'filename': l:match[3], \ 'type': 'W', \} else let l:dict = { \ 'lnum': l:match[2] + 0, \ 'text': l:match[4], \ 'type': 'W', \ 'filename': l:match[1], \} endif call add(l:output, l:dict) endfor return l:output endfunction call ale#linter#Define('php', { \ 'name': 'phan', \ 'executable': function('ale_linters#php#phan#GetExecutable'), \ 'command': function('ale_linters#php#phan#GetCommand'), \ 'callback': 'ale_linters#php#phan#Handle', \}) ================================================ FILE: ale_linters/php/php.vim ================================================ " Author: Spencer Wood , Adriaan Zonnenberg " 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: " " PHP 7.1<= - Parse error: syntax error, unexpected ';', expecting ']' in - on line 15 " PHP 7.2>= - Parse error: syntax error, unexpected ';', expecting ']' in Standard input code on line 15 let l:pattern = '\v^%(Fatal|Parse) error:\s+(.+unexpected ''(.+)%(expecting.+)@ ale#Var(b, 'php_php_executable')}, \ 'output_stream': 'stdout', \ 'command': '%e -l -d error_reporting=E_ALL -d display_errors=1 -d log_errors=0 --', \ 'callback': 'ale_linters#php#php#Handle', \}) ================================================ FILE: ale_linters/php/phpactor.vim ================================================ " Author: Arizard " Description: PHPactor integration for ALE call ale#Set('php_phpactor_executable', 'phpactor') call ale#Set('php_phpactor_init_options', {}) " Copied from langserver.vim function! ale_linters#php#phpactor#GetProjectRoot(buffer) abort let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') if (!empty(l:composer_path)) return fnamemodify(l:composer_path, ':h') endif 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': 'phpactor', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'php_phpactor_executable')}, \ 'command': '%e language-server', \ 'initialization_options': {b -> ale#Var(b, 'php_phpactor_init_options')}, \ 'project_root': function('ale_linters#php#phpactor#GetProjectRoot'), \}) ================================================ FILE: ale_linters/php/phpcs.vim ================================================ " Author: jwilliams108 , Eric Stern " Description: phpcs for PHP files 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#GetCommand(buffer) abort let l:standard = ale#Var(a:buffer, 'php_phpcs_standard') let l:standard_option = !empty(l:standard) \ ? '--standard=' . ale#Escape(l:standard) \ : '' return '%e -s --report=emacs --stdin-path=%s' \ . ale#Pad(l:standard_option) \ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options')) endfunction function! ale_linters#php#phpcs#Handle(buffer, lines) abort " Matches against lines like the following: " " /path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact) let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) - \(.\+\) (\(.\+\)).*$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[5] let l:text = l:match[4] . ' (' . l:code . ')' let l:type = l:match[3] call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:text, \ 'type': l:type is# 'error' ? 'E' : 'W', \ 'sub_type': 'style', \}) endfor return l:output endfunction call ale#linter#Define('php', { \ 'name': 'phpcs', \ 'executable': {b -> ale#path#FindExecutable(b, 'php_phpcs', [ \ 'vendor/bin/phpcs', \ 'phpcs' \ ])}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#php#phpcs#GetCommand'), \ 'callback': 'ale_linters#php#phpcs#Handle', \}) ================================================ FILE: ale_linters/php/phpmd.vim ================================================ " Author: medains , David Sierra " Description: phpmd for PHP files 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#GetCommand(buffer) abort return '%e %t text' \ . ale#Pad(ale#Var(a:buffer, 'php_phpmd_ruleset')) \ . ' --ignore-violations-on-exit' endfunction function! ale_linters#php#phpmd#Handle(buffer, lines) abort " Matches against lines like the following: " " /path/to/some-filename.php:18 message let l:pattern = '^.*:\(\d\+\)\s\+\(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'text': l:match[2], \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('php', { \ 'name': 'phpmd', \ 'executable': {b -> ale#Var(b, 'php_phpmd_executable')}, \ 'command': function('ale_linters#php#phpmd#GetCommand'), \ 'callback': 'ale_linters#php#phpmd#Handle', \}) ================================================ FILE: ale_linters/php/phpstan.vim ================================================ " Author: medains , ardis , Arizard " Description: phpstan for PHP files " Set to change the ruleset let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpstan') let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '') let g:ale_php_phpstan_configuration = get(g:, 'ale_php_phpstan_configuration', '') let g:ale_php_phpstan_autoload = get(g:, 'ale_php_phpstan_autoload', '') let g:ale_php_phpstan_memory_limit = get(g:, 'ale_php_phpstan_memory_limit', '') call ale#Set('php_phpstan_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#php#phpstan#GetCommand(buffer, version) abort let l:configuration = ale#Var(a:buffer, 'php_phpstan_configuration') let l:configuration_option = !empty(l:configuration) \ ? ' -c ' . ale#Escape(l:configuration) \ : '' let l:autoload = ale#Var(a:buffer, 'php_phpstan_autoload') let l:autoload_option = !empty(l:autoload) \ ? ' -a ' . ale#Escape(l:autoload) \ : '' let l:memory_limit = ale#Var(a:buffer, 'php_phpstan_memory_limit') let l:memory_limit_option = !empty(l:memory_limit) \ ? ' --memory-limit=' . ale#Escape(l:memory_limit) \ : '' let l:level = ale#Var(a:buffer, 'php_phpstan_level') if type(l:level) is v:t_number let l:level = string(l:level) endif if empty(l:level) && empty(ale_linters#php#phpstan#FindConfigFile(a:buffer)) " if no configuration file is found, then use 4 as a default level let l:level = '4' endif let l:level_option = !empty(l:level) \ ? ' -l ' . ale#Escape(l:level) \ : '' let l:error_format = ale#semver#GTE(a:version, [0, 10, 3]) \ ? ' --error-format json' \ : ' --errorFormat json' return '%e analyze --no-progress' \ . l:error_format \ . l:configuration_option \ . l:autoload_option \ . l:level_option \ . l:memory_limit_option \ . ' %s' endfunction function! ale_linters#php#phpstan#Handle(buffer, lines) abort let l:res = ale#util#FuzzyJSONDecode(a:lines, {'files': []}) let l:output = [] if type(l:res.files) is v:t_list return l:output endif for l:key in keys(l:res.files) for l:err in l:res.files[l:key].messages call add(l:output, { \ 'lnum': l:err.line, \ 'text': l:err.message, \ 'type': 'E', \}) endfor endfor return l:output endfunction function! ale_linters#php#phpstan#GetCwd(buffer) abort let l:result = ale#path#Dirname(ale_linters#php#phpstan#FindConfigFile(a:buffer)) return empty(l:result) ? v:null : l:result endfunction function! ale_linters#php#phpstan#FindConfigFile(buffer) abort let l:result = ale#path#FindNearestFile(a:buffer, 'phpstan.neon') if empty(l:result) let l:result = ale#path#FindNearestFile(a:buffer, 'phpstan.neon.dist') endif if empty(l:result) let l:result = ale#path#FindNearestFile(a:buffer, 'phpstan.dist.neon') endif return l:result endfunction call ale#linter#Define('php', { \ 'name': 'phpstan', \ 'executable': {buffer -> ale#path#FindExecutable(buffer, 'php_phpstan', [ \ 'vendor/bin/phpstan', \ 'phpstan' \ ])}, \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#path#FindExecutable(buffer, 'php_phpstan', [ \ 'vendor/bin/phpstan', \ 'phpstan' \ ]), \ '%e --version', \ function('ale_linters#php#phpstan#GetCommand'), \ )}, \ 'callback': 'ale_linters#php#phpstan#Handle', \ 'cwd': function('ale_linters#php#phpstan#GetCwd'), \}) ================================================ FILE: ale_linters/php/psalm.vim ================================================ " Author: Matt Brown " Description: plugin for Psalm, static analyzer for PHP call ale#Set('php_psalm_executable', 'psalm') call ale#Set('php_psalm_options', '') call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#php#psalm#GetProjectRoot(buffer) abort let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') if (!empty(l:composer_path)) return fnamemodify(l:composer_path, ':h') endif let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : '' endfunction function! ale_linters#php#psalm#GetCommand(buffer) abort return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'php_psalm_options')) endfunction call ale#linter#Define('php', { \ 'name': 'psalm', \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'php_psalm', [ \ 'vendor/bin/psalm', \ ])}, \ 'command': function('ale_linters#php#psalm#GetCommand'), \ 'project_root': function('ale_linters#php#psalm#GetProjectRoot'), \}) ================================================ FILE: ale_linters/php/tlint.vim ================================================ " Author: Jose Soto " " Description: Tighten Opinionated PHP Linting " Website: https://github.com/tightenco/tlint call ale#Set('php_tlint_executable', 'tlint') call ale#Set('php_tlint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('php_tlint_options', '') function! ale_linters#php#tlint#GetProjectRoot(buffer) abort let l:composer_path = ale#path#FindNearestFile(a:buffer, 'composer.json') if !empty(l:composer_path) return fnamemodify(l:composer_path, ':h') endif let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : '' endfunction function! ale_linters#php#tlint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'php_tlint', [ \ 'vendor/bin/tlint', \ 'tlint', \]) endfunction function! ale_linters#php#tlint#GetCommand(buffer) abort let l:executable = ale_linters#php#tlint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'php_tlint_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' lint %s' endfunction function! ale_linters#php#tlint#Handle(buffer, lines) abort " Matches against lines like the following: " " ! There should be 1 space around `.` concatenations, and additional lines should always start with a `.` " 22 : ` $something = 'a'.'name';` " let l:loop_count = 0 let l:messages_pattern = '^\! \(.*\)' let l:output = [] let l:pattern = '^\(\d\+\) \:' let l:temp_messages = [] for l:message in ale#util#GetMatches(a:lines, l:messages_pattern) call add(l:temp_messages, l:message) endfor let l:loop_count = 0 for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:num = l:match[1] let l:text = l:temp_messages[l:loop_count] call add(l:output, { \ 'lnum': l:num, \ 'col': 0, \ 'text': l:text, \ 'type': 'W', \ 'sub_type': 'style', \}) let l:loop_count += 1 endfor return l:output endfunction call ale#linter#Define('php', { \ 'name': 'tlint', \ 'executable': function('ale_linters#php#tlint#GetExecutable'), \ 'command': function('ale_linters#php#tlint#GetCommand'), \ 'callback': 'ale_linters#php#tlint#Handle', \ 'project_root': function('ale_linters#php#tlint#GetProjectRoot'), \}) ================================================ FILE: ale_linters/po/alex.vim ================================================ " Author: Cian Butler https://github.com/butlerx " Description: alex for PO files call ale#handlers#alex#DefineLinter('po', '--text') ================================================ FILE: ale_linters/po/msgfmt.vim ================================================ " Author: Cian Butler https://github.com/butlerx " Description: msgfmt for PO files function! ale_linters#po#msgfmt#Handle(buffer, lines) abort let l:results = ale#handlers#unix#HandleAsWarning(a:buffer, a:lines) let l:index = 0 for l:item in l:results if l:index > 0 && l:item.text =~? 'this is the location of the first definition' let l:last_item = l:results[l:index - 1] if l:last_item.text =~? 'duplicate message definition' let l:last_item.text = 'duplicate of message at line ' . l:item.lnum let l:item.text = 'first location of duplicate of message at line ' . l:last_item.lnum endif endif let l:index += 1 endfor return l:results endfunction call ale#linter#Define('po', { \ 'name': 'msgfmt', \ 'executable': 'msgfmt', \ 'output_stream': 'stderr', \ 'command': 'msgfmt --statistics --output-file=- %t', \ 'callback': 'ale_linters#po#msgfmt#Handle', \}) ================================================ FILE: ale_linters/po/proselint.vim ================================================ " Author: Cian Butler https://github.com/butlerx " Description: proselint for PO files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('po', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/po/writegood.vim ================================================ " Author: Cian Butler https://github.com/butlerx " Description: write-good for PO files call ale#handlers#writegood#DefineLinter('po') ================================================ FILE: ale_linters/pod/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for pod files call ale#handlers#alex#DefineLinter('pod', '--text') ================================================ FILE: ale_linters/pod/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for Pod files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('pod', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/pod/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for Pod files call ale#handlers#writegood#DefineLinter('pod') ================================================ FILE: ale_linters/pony/ponyc.vim ================================================ " Description: ponyc linter for pony files call ale#Set('pony_ponyc_executable', 'ponyc') call ale#Set('pony_ponyc_options', '--pass paint') function! ale_linters#pony#ponyc#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'pony_ponyc_options')) endfunction call ale#linter#Define('pony', { \ 'name': 'ponyc', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'pony_ponyc_executable')}, \ 'command': function('ale_linters#pony#ponyc#GetCommand'), \ 'callback': 'ale#handlers#pony#HandlePonycFormat', \}) ================================================ FILE: ale_linters/powershell/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for PowerShell files. call ale#handlers#cspell#DefineLinter('powershell') ================================================ FILE: ale_linters/powershell/powershell.vim ================================================ " Author: Jesse Harris - https://github.com/zigford " Description: This file adds support for powershell scripts synatax errors call ale#Set('powershell_powershell_executable', 'pwsh') function! ale_linters#powershell#powershell#GetExecutable(buffer) abort return ale#Var(a:buffer, 'powershell_powershell_executable') endfunction " Some powershell magic to show syntax errors without executing the script " thanks to keith hill: " https://rkeithhill.wordpress.com/2007/10/30/powershell-quicktip-preparsing-scripts-to-check-for-syntax-errors/ function! ale_linters#powershell#powershell#GetCommand(buffer) abort let l:script = ['Param($Script); \ $ErrorView = "Normal"; \ trap {$_;continue} & { \ $Contents = Get-Content -Path $Script; \ $Contents = [string]::Join([Environment]::NewLine, $Contents); \ [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Contents); \ };'] return ale#powershell#RunPowerShell( \ a:buffer, 'powershell_powershell', l:script) endfunction " Parse powershell error output using regex into a list of dicts function! ale_linters#powershell#powershell#Handle(buffer, lines) abort let l:output = [] " Our 3 patterns we need to scrape the data for the dicts let l:patterns = [ \ '\v^At line:(\d+) char:(\d+)', \ '\v^(At|\+| )@!.*', \ '\vFullyQualifiedErrorId : (\w+)', \] let l:matchcount = 0 for l:match in ale#util#GetMatches(a:lines, l:patterns) " We want to work with 3 matches per syntax error let l:matchcount = l:matchcount + 1 if l:matchcount == 1 || str2nr(l:match[1]) " First match consists of 2 capture groups, and " can capture the line and col if exists('l:item') " We may be here because the last syntax " didn't emit a code, and so only had 2 " matches call add(l:output, l:item) let l:matchcount = 1 endif " If the match is 0, it was a failed match " probably due to an unexpected token which " contained a newline. Reset matchcount. to " continue to the next match if !empty(l:match[1]) let l:item = { \ 'lnum': str2nr(l:match[1]), \ 'col': str2nr(l:match[2]), \ 'type': 'E', \} else let l:matchcount = 0 endif elseif l:matchcount == 2 " Second match[0] grabs the full line in order " to handles the text let l:item['text'] = l:match[0] else " Final match handles the code, however " powershell only emits 1 code for all errors " so, we get the final code on the last error " and loop over the previously added items to " append the code we now know call add(l:output, l:item) unlet l:item if len(l:match[1]) > 0 for l:i in l:output let l:i['code'] = l:match[1] endfor endif " Reset the matchcount so we can begin gathering " matches for the next syntax error let l:matchcount = 0 endif endfor return l:output endfunction call ale#linter#Define('powershell', { \ 'name': 'powershell', \ 'executable': function('ale_linters#powershell#powershell#GetExecutable'), \ 'command': function('ale_linters#powershell#powershell#GetCommand'), \ 'output_stream': 'stdout', \ 'callback': 'ale_linters#powershell#powershell#Handle', \}) ================================================ FILE: ale_linters/powershell/psscriptanalyzer.vim ================================================ " Author: Jesse Harris - https://github.com/zigford " Description: This file adds support for lintng powershell scripts " using the PSScriptAnalyzer module. " let g:ale_powershell_psscriptanalyzer_exclusions = " \ 'PSAvoidUsingWriteHost,PSAvoidGlobalVars' call ale#Set('powershell_psscriptanalyzer_exclusions', '') call ale#Set('powershell_psscriptanalyzer_executable', 'pwsh') call ale#Set('powershell_psscriptanalyzer_module', \ 'psscriptanalyzer') function! ale_linters#powershell#psscriptanalyzer#GetExecutable(buffer) abort return ale#Var(a:buffer, 'powershell_psscriptanalyzer_executable') endfunction " Run Invoke-ScriptAnalyzer and output each linting message as 4 separate lines " for each parsing function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort let l:exclude_option = ale#Var( \ a:buffer, 'powershell_psscriptanalyzer_exclusions') let l:module = ale#Var( \ a:buffer, 'powershell_psscriptanalyzer_module') let l:script = ['Param($Script); \ Invoke-ScriptAnalyzer "$Script" ' \ . (!empty(l:exclude_option) ? '-Exclude ' . l:exclude_option : '') \ . '| ForEach-Object { \ $_.Line; \ $_.Severity; \ $_.Message; \ $_.RuleName}'] return ale#powershell#RunPowerShell( \ a:buffer, \ 'powershell_psscriptanalyzer', \ l:script) endfunction " add every 4 lines to an item(Dict) and every item to a list " return the list function! ale_linters#powershell#psscriptanalyzer#Handle(buffer, lines) abort let l:output = [] let l:lcount = 0 for l:line in a:lines if l:lcount is# 0 " the very first line let l:item = {'lnum': str2nr(l:line)} elseif l:lcount is# 1 if l:line is# 'Error' let l:item['type'] = 'E' elseif l:line is# 'Information' let l:item['type'] = 'I' else let l:item['type'] = 'W' endif elseif l:lcount is# 2 let l:item['text'] = l:line elseif l:lcount is# 3 let l:item['code'] = l:line call add(l:output, l:item) let l:lcount = -1 endif let l:lcount = l:lcount + 1 endfor return l:output endfunction call ale#linter#Define('powershell', { \ 'name': 'psscriptanalyzer', \ 'executable': function('ale_linters#powershell#psscriptanalyzer#GetExecutable'), \ 'command': function('ale_linters#powershell#psscriptanalyzer#GetCommand'), \ 'output_stream': 'stdout', \ 'callback': 'ale_linters#powershell#psscriptanalyzer#Handle', \}) ================================================ FILE: ale_linters/prolog/swipl.vim ================================================ " Author: Takuya Fujiwara " 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:output = [] let l:i = 0 let l:pattern = '\v^(ERROR|Warning)+%(:\s*[^:]+:(\d+)%(:(\d+))?)?:\s*(.*)$' 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 [, ] 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 = [] let l:pattern = '\v^(ERROR|Warning)?:?(.*)$' while l:i < len(a:lines) let l:match = matchlist(a:lines[l:i], l:pattern) if empty(l:match) || empty(l:match[2]) let l:i += 1 break endif call add(l:text, s:Trim(l:match[2])) 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': {b -> ale#Var(b, 'prolog_swipl_executable')}, \ 'command': function('ale_linters#prolog#swipl#GetCommand'), \ 'callback': 'ale_linters#prolog#swipl#Handle', \}) ================================================ FILE: ale_linters/proto/buf_lint.vim ================================================ " Author: Alex McKinney " Description: Run buf lint. call ale#Set('proto_buf_lint_executable', 'buf') call ale#Set('proto_buf_lint_config', '') call ale#Set('proto_buf_lint_options', '') function! ale_linters#proto#buf_lint#GetCommand(buffer) abort let l:config = ale#Var(a:buffer, 'proto_buf_lint_config') let l:options = ale#Var(a:buffer, 'proto_buf_lint_options') return '%e lint' \ . (!empty(l:config) ? ' --config=' . ale#Escape(l:config) : '') \ . ale#Pad(l:options) \ . ' %s#include_package_files=true' endfunction call ale#linter#Define('proto', { \ 'name': 'buf_lint', \ 'aliases': ['buf-lint'], \ 'lint_file': 1, \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'proto_buf_lint_executable')}, \ 'command': function('ale_linters#proto#buf_lint#GetCommand'), \ 'callback': 'ale#handlers#go#Handler', \}) ================================================ FILE: ale_linters/proto/protoc_gen_lint.vim ================================================ " Author: Jeff Willette " Description: run the protoc-gen-lint plugin for the protoc binary call ale#Set('proto_protoc_gen_lint_options', '') function! ale_linters#proto#protoc_gen_lint#GetCommand(buffer) abort let l:dirname = expand('#' . a:buffer . ':p:h') let l:options = ['-I ' . ale#Escape(l:dirname)] if !empty(ale#Var(a:buffer, 'proto_protoc_gen_lint_options')) let l:options += [ale#Var(a:buffer, 'proto_protoc_gen_lint_options')] endif let l:options += ['--lint_out=. ' . '%s'] return 'protoc' . ' ' . join(l:options) endfunction call ale#linter#Define('proto', { \ 'name': 'protoc-gen-lint', \ 'lint_file': 1, \ 'output_stream': 'stderr', \ 'executable': 'protoc', \ 'command': function('ale_linters#proto#protoc_gen_lint#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) ================================================ FILE: ale_linters/proto/protolint.vim ================================================ " Author: Yohei Yoshimuta " Description: run the protolint for Protocol Buffer files call ale#Set('proto_protolint_executable', 'protolint') call ale#Set('proto_protolint_config', '') function! ale_linters#proto#protolint#GetCommand(buffer) abort let l:config = ale#Var(a:buffer, 'proto_protolint_config') return '%e lint' \ . (!empty(l:config) ? ' -config_path=' . ale#Escape(l:config) : '') \ . ' -reporter=unix' \ . ' %s' endfunction call ale#linter#Define('proto', { \ 'name': 'protolint', \ 'lint_file': 1, \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'proto_protolint_executable')}, \ 'command': function('ale_linters#proto#protolint#GetCommand'), \ 'callback': 'ale#handlers#unix#HandleAsError', \}) ================================================ FILE: ale_linters/pug/puglint.vim ================================================ " Author: w0rp - " Description: pug-lint for checking Pug/Jade files. 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! s:FindConfig(buffer) abort for l:filename in [ \ '.pug-lintrc', \ '.pug-lintrc.js', \ '.pug-lintrc.json', \ 'package.json', \] let l:config = ale#path#FindNearestFile(a:buffer, l:filename) if !empty(l:config) return l:config endif endfor return '' endfunction function! ale_linters#pug#puglint#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'pug_puglint_options') let l:config = s:FindConfig(a:buffer) return '%e' . ale#Pad(l:options) \ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '') \ . ' -r inline %t' endfunction function! ale_linters#pug#puglint#Handle(buffer, lines) abort for l:line in a:lines[:10] if l:line =~# '^SyntaxError: ' return [{ \ 'lnum': 1, \ 'text': 'puglint configuration error (type :ALEDetail for more information)', \ 'detail': join(a:lines, "\n"), \}] endif endfor return ale#handlers#unix#HandleAsError(a:buffer, a:lines) endfunction call ale#linter#Define('pug', { \ 'name': 'puglint', \ 'executable': {b -> ale#path#FindExecutable(b, 'pug_puglint', [ \ 'node_modules/.bin/pug-lint', \ ])}, \ 'output_stream': 'stderr', \ 'command': function('ale_linters#pug#puglint#GetCommand'), \ 'callback': 'ale_linters#pug#puglint#Handle', \}) ================================================ FILE: ale_linters/puppet/languageserver.vim ================================================ " Author: Alexander Olofsson " Description: Puppet Language Server integration for ALE call ale#Set('puppet_languageserver_executable', 'puppet-languageserver') 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 for l:test_path in [ \ 'manifests', \ '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 endfor return '' endfunction call ale#linter#Define('puppet', { \ 'name': 'languageserver', \ 'aliases': ['puppet_languageserver'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'puppet_languageserver_executable')}, \ 'command': '%e --stdio', \ 'language': 'puppet', \ 'project_root': function('ale_linters#puppet#languageserver#GetProjectRoot'), \}) ================================================ FILE: ale_linters/puppet/puppet.vim ================================================ " Author: Alexander Olofsson 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) " Error: Illegal attempt to assign to 'a Name'. Not an assignable reference (file: /tmp/modules/waffles/manifests/syrup.pp, line: 5, column: 11) " Error: Could not parse for environment production: Syntax error at end of input (file: /tmp/modules/bob/manifests/init.pp) let l:pattern = '^Error:\%(.*:\)\? \(.\+\) \((file:\|at\) .\+\.pp\(\(, line: \|:\)\(\d\+\)\(, column: \|:\)\=\(\d*\)\|)$\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[5] + 0, \ 'col': l:match[7] + 0, \ 'text': l:match[1], \}) endfor 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': {b -> ale#Var(b, 'puppet_puppet_executable')}, \ 'output_stream': 'stderr', \ 'command': function('ale_linters#puppet#puppet#GetCommand'), \ 'callback': 'ale_linters#puppet#puppet#Handle', \}) ================================================ FILE: ale_linters/puppet/puppetlint.vim ================================================ " Author: Alexander Olofsson , Robert Flechtner " Description: puppet-lint for puppet files 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 '%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': {b -> ale#Var(b, 'puppet_puppetlint_executable')}, \ 'command': function('ale_linters#puppet#puppetlint#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \}) ================================================ FILE: ale_linters/purescript/ls.vim ================================================ " Author: Drew Olson " Description: Integrate ALE with purescript-language-server. call ale#Set('purescript_ls_executable', 'purescript-language-server') call ale#Set('purescript_ls_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('purescript_ls_config', {}) function! ale_linters#purescript#ls#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'purescript_ls', [ \ 'node_modules/.bin/purescript-language-server', \]) endfunction function! ale_linters#purescript#ls#GetCommand(buffer) abort let l:executable = ale_linters#purescript#ls#GetExecutable(a:buffer) return ale#Escape(l:executable) . ' --stdio' endfunction function! ale_linters#purescript#ls#FindProjectRoot(buffer) abort let l:config = ale#path#FindNearestFile(a:buffer, 'bower.json') if !empty(l:config) return fnamemodify(l:config, ':h') endif let l:config = ale#path#FindNearestFile(a:buffer, 'psc-package.json') if !empty(l:config) return fnamemodify(l:config, ':h') endif let l:config = ale#path#FindNearestFile(a:buffer, 'spago.dhall') if !empty(l:config) return fnamemodify(l:config, ':h') endif return '' endfunction call ale#linter#Define('purescript', { \ 'name': 'purescript-language-server', \ 'aliases': ['purescriptls'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#purescript#ls#GetExecutable'), \ 'command': function('ale_linters#purescript#ls#GetCommand'), \ 'project_root': function('ale_linters#purescript#ls#FindProjectRoot'), \ 'lsp_config': {b -> ale#Var(b, 'purescript_ls_config')}, \}) ================================================ FILE: ale_linters/pyrex/cython.vim ================================================ " Author: w0rp , " Nicolas Pauss " Description: cython syntax checking for cython files. call ale#Set('pyrex_cython_executable', 'cython') call ale#Set('pyrex_cython_options', '--warning-extra') function! ale_linters#pyrex#cython#GetCommand(buffer) abort return '%e --working %s:h --include-dir %s:h' \ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options')) \ . ' --output-file ' . g:ale#util#nul_file . ' %t' endfunction function! ale_linters#pyrex#cython#Handle(buffer, lines) abort let l:pattern = '\v^(\w+: )?[^:]+:(\d+):?(\d+)?:? ?(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \ 'type': l:match[1][0] is# 'w' ? 'W' : 'E', \}) endfor return l:output endfunction call ale#linter#Define('pyrex', { \ 'name': 'cython', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'pyrex_cython_executable')}, \ 'command': function('ale_linters#pyrex#cython#GetCommand'), \ 'callback': 'ale_linters#pyrex#cython#Handle', \}) ================================================ FILE: ale_linters/python/bandit.vim ================================================ " Author: Martino Pilia " Description: bandit linting for python files call ale#Set('python_bandit_executable', 'bandit') call ale#Set('python_bandit_options', '') call ale#Set('python_bandit_use_config', 1) call ale#Set('python_bandit_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_bandit_auto_pipenv', 0) call ale#Set('python_bandit_auto_poetry', 0) call ale#Set('python_bandit_auto_uv', 0) function! ale_linters#python#bandit#GetExecutable(buffer) abort if ( \ ale#Var(a:buffer, 'python_auto_pipenv') \ || ale#Var(a:buffer, 'python_bandit_auto_pipenv') \) && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if ( \ ale#Var(a:buffer, 'python_auto_poetry') \ || ale#Var(a:buffer, 'python_bandit_auto_poetry') \) && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_bandit_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_bandit', ['bandit']) endfunction function! ale_linters#python#bandit#GetCommand(buffer) abort let l:executable = ale_linters#python#bandit#GetExecutable(a:buffer) let l:flags = ' --format custom' \ . ' --msg-template "{line}:{test_id}:{severity}:{msg}" ' if ale#Var(a:buffer, 'python_bandit_use_config') let l:config_path = ale#path#FindNearestFile(a:buffer, '.bandit') if !empty(l:config_path) let l:flags = ' --ini ' . ale#Escape(l:config_path) . l:flags endif endif let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run bandit' \ : '' return ale#Escape(l:executable) . l:exec_args \ . l:flags \ . ale#Pad(ale#Var(a:buffer, 'python_bandit_options')) \ . ' -' endfunction function! ale_linters#python#bandit#Handle(buffer, lines) abort " Custom format defined in GetCommand via --msg-template let l:pattern = '\v^([0-9]+):(B[0-9]+):([A-Z]+):(.*)$' let l:severity = {'LOW': 'I', 'MEDIUM': 'W', 'HIGH': 'E'} let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': str2nr(l:match[1]), \ 'code': l:match[2], \ 'type': l:severity[l:match[3]], \ 'text': l:match[4], \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'bandit', \ 'executable': function('ale_linters#python#bandit#GetExecutable'), \ 'command': function('ale_linters#python#bandit#GetCommand'), \ 'callback': 'ale_linters#python#bandit#Handle', \}) ================================================ FILE: ale_linters/python/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Python files. call ale#handlers#cspell#DefineLinter('python') ================================================ FILE: ale_linters/python/flake8.vim ================================================ " Author: w0rp " Description: flake8 for python files 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', 'project') call ale#Set('python_flake8_auto_pipenv', 0) call ale#Set('python_flake8_auto_poetry', 0) call ale#Set('python_flake8_auto_uv', 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 (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_flake8_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_flake8_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif if !s:UsingModule(a:buffer) return ale#python#FindExecutable(a:buffer, 'python_flake8', ['flake8']) endif return ale#Var(a:buffer, 'python_flake8_executable') endfunction function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer) let l:module_string = s:UsingModule(a:buffer) ? ' -m flake8' : '' let l:command = ale#Escape(l:executable) . l:module_string . ' --version' return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale_linters#python#flake8#GetCommand'), \) endfunction function! ale_linters#python#flake8#GetCwd(buffer) abort let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory') let l:cwd = '' if l:change_directory is# 'project' let l:project_root = ale#python#FindProjectRootIni(a:buffer) if !empty(l:project_root) let l:cwd = l:project_root endif endif if (l:change_directory is# 'project' && empty(l:cwd)) \|| l:change_directory \|| l:change_directory is# 'file' let l:cwd = '%s:h' endif return l:cwd endfunction function! ale_linters#python#flake8#GetCommand(buffer, version) abort let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run flake8' \ : '' " Only include the --stdin-display-name argument if we can parse the " flake8 version, and it is recent enough to support it. let l:display_name_args = ale#semver#GTE(a:version, [3, 0, 0]) \ ? ' --stdin-display-name %s' \ : '' let l:options = ale#Var(a:buffer, 'python_flake8_options') return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(l:options) \ . ' --format=default' \ . l:display_name_args . ' -' endfunction let s:end_col_pattern_map = { \ 'F405': '\(.\+\) may be undefined', \ 'F821': 'undefined name ''\([^'']\+\)''', \ 'F999': '^''\([^'']\+\)''', \ 'F841': 'local variable ''\([^'']\+\)''', \} function! ale_linters#python#flake8#Handle(buffer, lines) abort let l:output = ale#python#HandleTraceback(a:lines, 10) if !empty(l:output) return l:output endif " Matches patterns line the following: " " Matches patterns line the following: " " stdin:6:6: E111 indentation is not a multiple of four let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: ([[:alnum:]]+):? (.*)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[3] if (l:code is# 'W291' || l:code is# 'W293') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if l:code is# 'W391' \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines') " Skip warnings for trailing blank lines if the option is off continue endif let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'vcol': 1, \ 'text': l:match[4], \ 'code': l:code, \ 'type': 'W', \} if l:code[:0] is# 'F' if l:code isnot# 'F401' let l:item.type = 'E' endif elseif l:code[:0] is# 'E' let l:item.type = 'E' if l:code isnot# 'E999' && l:code isnot# 'E112' let l:item.sub_type = 'style' endif elseif l:code[:0] is# 'W' let l:item.sub_type = 'style' endif let l:end_col_pattern = get(s:end_col_pattern_map, l:code, '') if !empty(l:end_col_pattern) let l:end_col_match = matchlist(l:match[4], l:end_col_pattern) if !empty(l:end_col_match) let l:item.end_col = l:item.col + len(l:end_col_match[1]) - 1 endif endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'flake8', \ 'executable': function('ale_linters#python#flake8#GetExecutable'), \ 'cwd': function('ale_linters#python#flake8#GetCwd'), \ 'command': function('ale_linters#python#flake8#RunWithVersionCheck'), \ 'callback': 'ale_linters#python#flake8#Handle', \}) ================================================ FILE: ale_linters/python/flakehell.vim ================================================ " Author: w0rp " Description: flakehell for python files call ale#Set('python_flakehell_executable', 'flakehell') call ale#Set('python_flakehell_options', '') call ale#Set('python_flakehell_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_flakehell_change_directory', 'project') call ale#Set('python_flakehell_auto_pipenv', 0) call ale#Set('python_flakehell_auto_poetry', 0) call ale#Set('python_flakehell_auto_uv', 0) function! s:UsingModule(buffer) abort return ale#Var(a:buffer, 'python_flakehell_executable') is? 'python' endfunction function! ale_linters#python#flakehell#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_flakehell_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_flakehell_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_flakehell_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif if !s:UsingModule(a:buffer) return ale#python#FindExecutable(a:buffer, 'python_flakehell', ['flakehell']) endif return ale#Var(a:buffer, 'python_flakehell_executable') endfunction function! ale_linters#python#flakehell#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#python#flakehell#GetExecutable(a:buffer) let l:module_string = s:UsingModule(a:buffer) ? ' -m flakehell' : '' let l:command = ale#Escape(l:executable) . l:module_string . ' --version' return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale_linters#python#flakehell#GetCommand'), \) endfunction function! ale_linters#python#flakehell#GetCwd(buffer) abort let l:change_directory = ale#Var(a:buffer, 'python_flakehell_change_directory') let l:cwd = '' if l:change_directory is# 'project' let l:project_root = ale#python#FindProjectRootIni(a:buffer) if !empty(l:project_root) let l:cwd = l:project_root endif endif if (l:change_directory is# 'project' && empty(l:cwd)) \|| l:change_directory \|| l:change_directory is# 'file' let l:cwd = '%s:h' endif return l:cwd endfunction function! ale_linters#python#flakehell#GetCommand(buffer, version) abort let l:executable = ale_linters#python#flakehell#GetExecutable(a:buffer) if (l:executable =~? '\(pipenv\|poetry\|uv\)$') let l:exec_args = ' run flakehell' elseif (l:executable is? 'python') let l:exec_args = ' -m flakehell' else let l:exec_args = '' endif " Only include the --stdin-display-name argument if we can parse the " flakehell version, and it is recent enough to support it. let l:display_name_args = ale#semver#GTE(a:version, [0, 8, 0]) \ ? ' --stdin-display-name %s' \ : '' let l:options = ale#Var(a:buffer, 'python_flakehell_options') return ale#Escape(l:executable) \ . l:exec_args \ . (!empty(l:options) ? ' lint ' . l:options : ' lint') \ . ' --format=default' \ . l:display_name_args . ' -' endfunction let s:end_col_pattern_map = { \ 'F405': '\(.\+\) may be undefined', \ 'F821': 'undefined name ''\([^'']\+\)''', \ 'F999': '^''\([^'']\+\)''', \ 'F841': 'local variable ''\([^'']\+\)''', \} function! ale_linters#python#flakehell#Handle(buffer, lines) abort let l:output = ale#python#HandleTraceback(a:lines, 10) if !empty(l:output) return l:output endif " Matches patterns line the following: " " Matches patterns line the following: " " stdin:6:6: E111 indentation is not a multiple of four let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?: ([[:alnum:]]+):? (.*)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[3] if (l:code is# 'W291' || l:code is# 'W293') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if l:code is# 'W391' \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines') " Skip warnings for trailing blank lines if the option is off continue endif let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'vcol': 1, \ 'text': l:match[4], \ 'code': l:code, \ 'type': 'W', \} if l:code[:0] is# 'F' if l:code isnot# 'F401' let l:item.type = 'E' endif elseif l:code[:0] is# 'E' let l:item.type = 'E' if l:code isnot# 'E999' && l:code isnot# 'E112' let l:item.sub_type = 'style' endif elseif l:code[:0] is# 'W' let l:item.sub_type = 'style' endif let l:end_col_pattern = get(s:end_col_pattern_map, l:code, '') if !empty(l:end_col_pattern) let l:end_col_match = matchlist(l:match[4], l:end_col_pattern) if !empty(l:end_col_match) let l:item.end_col = l:item.col + len(l:end_col_match[1]) - 1 endif endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'flakehell', \ 'executable': function('ale_linters#python#flakehell#GetExecutable'), \ 'cwd': function('ale_linters#python#flakehell#GetCwd'), \ 'command': function('ale_linters#python#flakehell#RunWithVersionCheck'), \ 'callback': 'ale_linters#python#flakehell#Handle', \}) ================================================ FILE: ale_linters/python/jedils.vim ================================================ " Author: Dalius Dobravolskas " Description: https://github.com/pappasam/jedi-language-server call ale#Set('python_jedils_executable', 'jedi-language-server') call ale#Set('python_jedils_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_jedils_auto_pipenv', 0) call ale#Set('python_jedils_auto_poetry', 0) call ale#Set('python_jedils_auto_uv', 0) function! ale_linters#python#jedils#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_jedils_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_jedils_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_jedils_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_jedils', ['jedi-language-server']) endfunction function! ale_linters#python#jedils#GetCommand(buffer) abort let l:executable = ale_linters#python#jedils#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run jedi-language-server' \ : '' let l:env_string = '' if ale#Var(a:buffer, 'python_auto_virtualenv') let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer) endif return l:env_string . ale#Escape(l:executable) . l:exec_args endfunction call ale#linter#Define('python', { \ 'name': 'jedils', \ 'aliases': ['jedi_language_server'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#python#jedils#GetExecutable'), \ 'command': function('ale_linters#python#jedils#GetCommand'), \ 'project_root': function('ale#python#FindProjectRoot'), \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \}) ================================================ FILE: ale_linters/python/mypy.vim ================================================ " Author: Keith Smiley , w0rp " Description: mypy support for optional python typechecking call ale#Set('python_mypy_executable', 'mypy') call ale#Set('python_mypy_ignore_invalid_syntax', 0) call ale#Set('python_mypy_show_notes', 1) call ale#Set('python_mypy_options', '') call ale#Set('python_mypy_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_mypy_auto_pipenv', 0) call ale#Set('python_mypy_auto_poetry', 0) call ale#Set('python_mypy_auto_uv', 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 if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_mypy_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_mypy_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_mypy', ['mypy']) endfunction " The directory to change to before running mypy function! ale_linters#python#mypy#GetCwd(buffer) abort " If we find a directory with "mypy.ini" in it use that, " else try and find the "python project" root, or failing " that, run from the same folder as the current file for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) if filereadable(l:path . '/mypy.ini') return l:path endif endfor let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) \ ? l:project_root \ : expand('#' . a:buffer . ':p:h') endfunction function! ale_linters#python#mypy#GetCommand(buffer) abort let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run mypy' \ : '' return '%e' . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_mypy_options')) \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' endfunction function! ale_linters#python#mypy#Handle(buffer, lines) abort let l:dir = ale_linters#python#mypy#GetCwd(a:buffer) " Look for lines like the following: " " file.py:4: error: No library stub file for module 'django.db' " " Lines like these should be ignored below: " " file.py:4: note: (Stub files are from https://github.com/python/typeshed) let l:types = 'error|warning' if ale#Var(a:buffer, 'python_mypy_show_notes') let l:types = 'error|warning|note' endif let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: (' \ . l:types \ . '): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) " Skip invalid syntax errors if the option is on. if l:match[5] is# 'invalid syntax' \&& ale#Var(a:buffer, 'python_mypy_ignore_invalid_syntax') continue endif call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4] is# 'error' ? 'E' : (l:match[4] is# 'note' ? 'I': 'W'), \ 'text': l:match[5], \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'mypy', \ 'executable': function('ale_linters#python#mypy#GetExecutable'), \ 'cwd': function('ale_linters#python#mypy#GetCwd'), \ 'command': function('ale_linters#python#mypy#GetCommand'), \ 'callback': 'ale_linters#python#mypy#Handle', \ 'output_stream': 'both' \}) ================================================ FILE: ale_linters/python/prospector.vim ================================================ " Author: chocoelho " Description: prospector linter python files call ale#Set('python_prospector_auto_pipenv', 0) call ale#Set('python_prospector_auto_poetry', 0) call ale#Set('python_prospector_auto_uv', 0) let g:ale_python_prospector_executable = \ get(g:, 'ale_python_prospector_executable', 'prospector') let g:ale_python_prospector_options = \ get(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 if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_prospector_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_prospector_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_prospector', ['prospector']) endfunction function! ale_linters#python#prospector#GetCommand(buffer) abort let l:executable = ale_linters#python#prospector#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run prospector' \ : '' return ale#Escape(l:executable) \ . l:exec_args \ . ' ' . ale#Var(a:buffer, 'python_prospector_options') \ . ' --messages-only --absolute-paths --zero-exit --output-format json' \ . ' %s' endfunction function! ale_linters#python#prospector#Handle(buffer, lines) abort let l:output = [] if empty(a:lines) return [] endif let l:prospector_error = json_decode(join(a:lines, '')) for l:error in l:prospector_error.messages if (l:error.code is# 'W291' || l:error.code is# 'W293' || l:error.code is# 'trailing-whitespace') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if l:error.code is# 'W391' \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines') " Skip warnings for trailing blank lines if the option is off continue endif if l:error.source =~# '\v\[%(dodgy|mccabe|pep8|pep257|pyroma)\]$' let l:sub_type = 'style' else let l:sub_type = '' endif if l:error.source =~# '\v\[pylint\]$' let l:type = l:error.code =~? '\m^[CRW]' ? 'W' : 'E' elseif l:error.source =~# '\v\[%(frosted|pep8)\]$' let l:type = l:error.code =~? '\m^W' ? 'W' : 'E' elseif l:error.source =~# '\v\[%(dodgy|pyroma|vulture)\]$' let l:type = 'W' else let l:type = 'E' endif let l:item = { \ 'lnum': l:error.location.line, \ 'col': l:error.location.character + 1, \ 'text': l:error.message, \ 'code': printf('(%s) %s', l:error.source, l:error.code), \ 'type': l:type, \ 'sub_type': l:sub_type, \} if l:sub_type is# '' unlet l:item.sub_type endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'prospector', \ 'executable': function('ale_linters#python#prospector#GetExecutable'), \ 'command': function('ale_linters#python#prospector#GetCommand'), \ 'callback': 'ale_linters#python#prospector#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/python/pycln.vim ================================================ " Author: Yining " Description: pycln as linter for python files call ale#Set('python_pycln_executable', 'pycln') call ale#Set('python_pycln_options', '') call ale#Set('python_pycln_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pycln_change_directory', 1) call ale#Set('python_pycln_auto_pipenv', 0) call ale#Set('python_pycln_auto_poetry', 0) call ale#Set('python_pycln_auto_uv', 0) call ale#Set('python_pycln_config_file', '') function! ale_linters#python#pycln#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycln_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pycln_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pycln_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pycln', ['pycln']) endfunction function! ale_linters#python#pycln#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_pycln_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '' endfunction function! ale_linters#python#pycln#GetCommand(buffer, version) abort let l:executable = ale_linters#python#pycln#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pycln' \ : '' let l:options = ale#Var(a:buffer, 'python_pycln_options') let l:config_file = ale#Var(a:buffer, 'python_pycln_config_file') let l:config_file = l:options !~# '\v(^| )--config ' && !empty(l:config_file) \ ? ale#Escape(ale#path#Simplify(l:config_file)) \ : '' " NOTE: pycln version `1.3.0` supports liniting input from stdin return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_pycln_options')) \ . (empty(l:config_file) ? '' : ' --config ' . l:config_file) \ . ' --check' \ . (ale#semver#GTE(a:version, [1, 3, 0]) ? ' -' : ' %s') endfunction function! ale_linters#python#pycln#Handle(buffer, lines) abort " Example: tmp/test.py:3:0 'import os' would be removed! let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+):? (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'pycln', \ 'executable': function('ale_linters#python#pycln#GetExecutable'), \ 'cwd': function('ale_linters#python#pycln#GetCwd'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#python#pycln#GetExecutable(buffer), \ '%e --version', \ function('ale_linters#python#pycln#GetCommand'), \ )}, \ 'callback': 'ale_linters#python#pycln#Handle', \ 'output_stream': 'both', \ 'read_buffer': 1, \}) ================================================ FILE: ale_linters/python/pycodestyle.vim ================================================ " Author: Michael Thiesen " Description: pycodestyle linting for python files 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) call ale#Set('python_pycodestyle_auto_poetry', 0) call ale#Set('python_pycodestyle_auto_uv', 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 if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pycodestyle_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pycodestyle_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pycodestyle', ['pycodestyle']) endfunction function! ale_linters#python#pycodestyle#GetCommand(buffer) abort let l:executable = ale_linters#python#pycodestyle#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pycodestyle' \ : '' return ale#Escape(l:executable) . l:exec_args \ . ' ' \ . ale#Var(a:buffer, 'python_pycodestyle_options') \ . ' -' endfunction function! ale_linters#python#pycodestyle#Handle(buffer, lines) abort let l:pattern = '\v^(\S*):(\d*):(\d*): ([EW]\d+) (.*)$' let l:output = [] " lines are formatted as follows: " file.py:21:26: W291 trailing whitespace for l:match in ale#util#GetMatches(a:lines, l:pattern) if(l:match[4] is# 'W291' || l:match[4] is# 'W293') \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if l:match[4] is# 'W391' \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines') " Skip warnings for trailing blank lines if the option is off continue endif let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'type': l:match[4][0], \ 'sub_type': 'style', \ 'text': l:match[5], \ 'code': l:match[4], \} " E999 and E112 are syntax errors. if l:match[4] is# 'E999' || l:match[4] is# 'E112' unlet l:item.sub_type endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'pycodestyle', \ 'executable': function('ale_linters#python#pycodestyle#GetExecutable'), \ 'command': function('ale_linters#python#pycodestyle#GetCommand'), \ 'callback': 'ale_linters#python#pycodestyle#Handle', \}) ================================================ FILE: ale_linters/python/pydocstyle.vim ================================================ " Author: Pablo Acosta " Description: pydocstyle for python files call ale#Set('python_pydocstyle_executable', 'pydocstyle') call ale#Set('python_pydocstyle_options', '') call ale#Set('python_pydocstyle_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pydocstyle_auto_pipenv', 0) call ale#Set('python_pydocstyle_auto_poetry', 0) call ale#Set('python_pydocstyle_auto_uv', 0) function! ale_linters#python#pydocstyle#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pydocstyle_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pydocstyle_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pydocstyle_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pydocstyle', ['pydocstyle']) endfunction function! ale_linters#python#pydocstyle#GetCommand(buffer) abort let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pydocstyle' \ : '' return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options')) \ . ' %s' endfunction function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort " Matches patterns like the following: " mydir/myfile.py:33 in public function `myfunction`: " DXXX: Error description let l:line1_pattern = '\v^.*:\s*(\d+)\s+.*$' let l:line2_pattern = '\v^.*([a-zA-Z]\d+):\s*(.*)$' let l:output = [] let l:num_lines = len(a:lines) let l:index = 0 while l:index < l:num_lines let l:lnum = matchlist(a:lines[l:index], l:line1_pattern) if !empty(l:lnum) && (l:index + 1 < l:num_lines) let l:desc = matchlist(a:lines[l:index + 1], l:line2_pattern) if !empty(l:desc) call add(l:output, { \ 'lnum': l:lnum[1] + 0, \ 'col': 1, \ 'type': 'W', \ 'text': l:desc[2], \ 'code': l:desc[1], \}) endif let l:index = l:index + 2 else let l:index = l:index + 1 endif endwhile return l:output endfunction call ale#linter#Define('python', { \ 'name': 'pydocstyle', \ 'executable': function('ale_linters#python#pydocstyle#GetExecutable'), \ 'cwd': '%s:h', \ 'command': function('ale_linters#python#pydocstyle#GetCommand'), \ 'callback': 'ale_linters#python#pydocstyle#Handle', \}) ================================================ FILE: ale_linters/python/pyflakes.vim ================================================ " Author: w0rp " Description: pyflakes for python files 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) call ale#Set('python_pyflakes_auto_poetry', 0) call ale#Set('python_pyflakes_auto_uv', 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 if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pyflakes_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pyflakes_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pyflakes', ['pyflakes']) endfunction function! ale_linters#python#pyflakes#GetCommand(buffer) abort let l:executable = ale_linters#python#pyflakes#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pyflakes' \ : '' return ale#Escape(l:executable) \ . l:exec_args \ . ' %t' endfunction function! ale_linters#python#pyflakes#Handle(buffer, lines) abort let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+)?:? (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'pyflakes', \ 'executable': function('ale_linters#python#pyflakes#GetExecutable'), \ 'command': function('ale_linters#python#pyflakes#GetCommand'), \ 'callback': 'ale_linters#python#pyflakes#Handle', \ 'output_stream': 'both', \}) ================================================ FILE: ale_linters/python/pylama.vim ================================================ " Author: Kevin Locke " Description: pylama for python files call ale#Set('python_pylama_executable', 'pylama') call ale#Set('python_pylama_options', '') call ale#Set('python_pylama_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pylama_auto_pipenv', 0) call ale#Set('python_pylama_auto_poetry', 0) call ale#Set('python_pylama_auto_uv', 0) call ale#Set('python_pylama_change_directory', 1) function! ale_linters#python#pylama#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylama_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pylama_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pylama_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pylama', ['pylama']) endfunction function! ale_linters#python#pylama#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#python#pylama#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pylama' \ : '' let l:command = ale#Escape(l:executable) . l:exec_args . ' --version' return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale_linters#python#pylama#GetCommand'), \) endfunction function! ale_linters#python#pylama#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_pylama_change_directory') " Pylama loads its configuration from the current directory only, and " applies file masks using paths relative to the current directory. " Run from project root, if found, otherwise buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '' endfunction function! ale_linters#python#pylama#GetCommand(buffer, version) abort let l:executable = ale_linters#python#pylama#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pylama' \ : '' " json format is added in version 8.1.4 " https://github.com/klen/pylama/blob/develop/Changelog let l:format_json_args = ale#semver#GTE(a:version, [8, 1, 4]) \ ? ' --format json' \ : '' " Note: Using %t to lint changes would be preferable, but many pylama " checks use surrounding paths (e.g. C0103 module name, E0402 relative " import beyond top, etc.). Neither is ideal. return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_pylama_options')) \ . l:format_json_args \ . ' %s' endfunction function! ale_linters#python#pylama#Handle(buffer, version, lines) abort if empty(a:lines) return [] endif let l:output = ale#python#HandleTraceback(a:lines, 1) " First letter of error code is a pylint-compatible message type " http://pylint.pycqa.org/en/latest/user_guide/output.html#source-code-analysis-section " D is for Documentation (pydocstyle) let l:pylint_type_to_ale_type = { \ 'I': 'I', \ 'R': 'W', \ 'C': 'W', \ 'W': 'W', \ 'E': 'E', \ 'F': 'E', \ 'D': 'W', \} let l:pylint_type_to_ale_sub_type = { \ 'R': 'style', \ 'C': 'style', \ 'D': 'style', \} if ale#semver#GTE(a:version, [8, 1, 4]) try let l:errors = json_decode(join(a:lines, '')) catch return l:output endtry if empty(l:errors) return l:output endif for l:error in l:errors call add(l:output, { \ 'lnum': l:error['lnum'], \ 'col': l:error['col'], \ 'code': l:error['number'], \ 'type': get(l:pylint_type_to_ale_type, l:error['etype'], 'W'), \ 'sub_type': get(l:pylint_type_to_ale_sub_type, l:error['etype'], ''), \ 'text': printf('%s [%s]', l:error['message'], l:error['source']), \}) endfor else let l:pattern = '\v^.{-}:([0-9]+):([0-9]+): +%(([A-Z][0-9]+):? +)?(.*)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[1]), \ 'col': str2nr(l:match[2]), \ 'code': l:match[3], \ 'type': get(l:pylint_type_to_ale_type, l:match[3][0], 'W'), \ 'sub_type': get(l:pylint_type_to_ale_sub_type, l:match[3][0], ''), \ 'text': l:match[4], \}) endfor endif return l:output endfunction call ale#linter#Define('python', { \ 'name': 'pylama', \ 'executable': function('ale_linters#python#pylama#GetExecutable'), \ 'cwd': function('ale_linters#python#pylama#GetCwd'), \ 'command': function('ale_linters#python#pylama#RunWithVersionCheck'), \ 'callback': {buffer, lines -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#python#pylama#GetExecutable(buffer), \ '%e --version', \ {buffer, version -> ale_linters#python#pylama#Handle( \ buffer, \ l:version, \ lines)}, \ )}, \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/python/pylint.vim ================================================ " Author: keith " Description: pylint for python files 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) call ale#Set('python_pylint_auto_poetry', 0) call ale#Set('python_pylint_auto_uv', 0) call ale#Set('python_pylint_use_msg_id', 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 if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pylint_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pylint_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint']) endfunction function! ale_linters#python#pylint#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_pylint_change_directory') " pylint only checks for pylintrc in the packages above its current " directory before falling back to user and global pylintrc. " Run from project root, if found, otherwise buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '' endfunction function! ale_linters#python#pylint#GetCommand(buffer, version) abort let l:executable = ale_linters#python#pylint#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pylint' \ : '' return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_pylint_options')) \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n' \ . (ale#semver#GTE(a:version, [2, 4, 0]) ? ' --from-stdin' : '') \ . ' %s' endfunction function! ale_linters#python#pylint#Handle(buffer, lines) abort let l:output = ale#python#HandleTraceback(a:lines, 10) if !empty(l:output) return l:output endif " Matches patterns like the following: " " test.py:4:4: W0101 (unreachable) Unreachable code let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+): ([[:alnum:]]+) \(([^(]*)\) (.*)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) "let l:failed = append(0, l:match) let l:code = l:match[3] if (l:code is# 'C0303') \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if l:code is# 'I0011' " Skip 'Locally disabling' message continue endif if ale#Var(a:buffer, 'python_pylint_use_msg_id') let l:code_out = l:code else let l:code_out = l:match[4] endif let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 1, \ 'text': l:match[5], \ 'code': l:code_out, \ 'type': 'W', \} if l:code[:0] is# 'E' let l:item.type = 'E' endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'pylint', \ 'executable': function('ale_linters#python#pylint#GetExecutable'), \ 'lint_file': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'python_pylint_executable'), \ '%e --version', \ {buffer, version -> !ale#semver#GTE(version, [2, 4, 0])}, \ )}, \ 'cwd': function('ale_linters#python#pylint#GetCwd'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'python_pylint_executable'), \ '%e --version', \ function('ale_linters#python#pylint#GetCommand'), \ )}, \ 'callback': 'ale_linters#python#pylint#Handle', \}) ================================================ FILE: ale_linters/python/pylsp.vim ================================================ " Author: aurieh " Description: A language server for Python call ale#Set('python_pylsp_executable', 'pylsp') call ale#Set('python_pylsp_options', '') call ale#Set('python_pylsp_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pylsp_auto_pipenv', 0) call ale#Set('python_pylsp_auto_poetry', 0) call ale#Set('python_pylsp_auto_uv', 0) call ale#Set('python_pylsp_config', {}) function! ale_linters#python#pylsp#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylsp_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pylsp_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pylsp_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pylsp', ['pylsp']) endfunction " Force the cwd of the server to be the same as the project root to " fix issues with treating local files matching first or third party library " names being imported incorrectly. function! ale_linters#python#pylsp#GetCwd(buffer) abort let l:fake_linter = { \ 'name': 'pylsp', \ 'project_root': function('ale#python#FindProjectRoot'), \} let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, l:fake_linter) return !empty(l:root) ? l:root : v:null endfunction function! ale_linters#python#pylsp#GetCommand(buffer) abort let l:executable = ale_linters#python#pylsp#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pylsp' \ : '' let l:env_string = '' if ale#Var(a:buffer, 'python_auto_virtualenv') let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer) endif return l:env_string . ale#Escape(l:executable) . l:exec_args . ale#Pad(ale#Var(a:buffer, 'python_pylsp_options')) endfunction call ale#linter#Define('python', { \ 'name': 'pylsp', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#python#pylsp#GetExecutable'), \ 'cwd': function('ale_linters#python#pylsp#GetCwd'), \ 'command': function('ale_linters#python#pylsp#GetCommand'), \ 'project_root': function('ale#python#FindProjectRoot'), \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ 'lsp_config': {b -> ale#Var(b, 'python_pylsp_config')}, \}) ================================================ FILE: ale_linters/python/pyre.vim ================================================ " Author: dsifford " Description: A performant type-checker supporting LSP for Python 3 created by Facebook 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) call ale#Set('python_pyre_auto_poetry', 0) call ale#Set('python_pyre_auto_uv', 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 if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pyre_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pyre_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pyre', ['pyre']) endfunction function! ale_linters#python#pyre#GetCommand(buffer) abort let l:executable = ale_linters#python#pyre#GetExecutable(a:buffer) let l:exec_args = (l:executable =~? '\(pipenv\|poetry\|uv\)$' ? ' run pyre' : '') . ' persistent' return ale#Escape(l:executable) . l:exec_args endfunction function! ale_linters#python#pyre#GetCwd(buffer) abort let l:local_config = ale#path#FindNearestFile(a:buffer, '.pyre_configuration.local') return fnamemodify(l:local_config, ':h') endfunction call ale#linter#Define('python', { \ 'name': 'pyre', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#python#pyre#GetExecutable'), \ 'command': function('ale_linters#python#pyre#GetCommand'), \ 'project_root': function('ale#python#FindProjectRoot'), \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ 'cwd': function('ale_linters#python#pyre#GetCwd'), \}) ================================================ FILE: ale_linters/python/pyrefly.vim ================================================ " Author: oliverralbertini " Description: A performant type-checker supporting LSP for Python 3 created by Facebook call ale#Set('python_pyrefly_executable', 'pyrefly') call ale#Set('python_pyrefly_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pyrefly_auto_pipenv', 0) call ale#Set('python_pyrefly_auto_poetry', 0) call ale#Set('python_pyrefly_auto_uv', 0) function! ale_linters#python#pyrefly#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyrefly_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pyrefly_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pyrefly_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pyrefly', ['pyrefly']) endfunction function! ale_linters#python#pyrefly#GetCommand(buffer) abort let l:executable = ale_linters#python#pyrefly#GetExecutable(a:buffer) let l:exec_args = [ \ ale#Escape(l:executable) \ ] \ + (l:executable =~? '\(pipenv\|poetry\|uv\)$' ? ['run', 'pyrefly'] : []) \ + [ \ 'lsp', \ ] return join(l:exec_args, ' ') endfunction function! ale_linters#python#pyrefly#GetCwd(buffer) abort " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endfunction call ale#linter#Define('python', { \ 'name': 'pyrefly', \ 'lsp': 'stdio', \ 'executable': function('ale_linters#python#pyrefly#GetExecutable'), \ 'command': function('ale_linters#python#pyrefly#GetCommand'), \ 'project_root': function('ale#python#FindProjectRoot'), \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ 'cwd': function('ale_linters#python#pyrefly#GetCwd'), \}) ================================================ FILE: ale_linters/python/pyright.vim ================================================ call ale#Set('python_pyright_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pyright_executable', 'pyright-langserver') call ale#Set('python_pyright_config', {}) call ale#Set('python_pyright_auto_pipenv', 0) call ale#Set('python_pyright_auto_poetry', 0) call ale#Set('python_pyright_auto_uv', 0) " Force the cwd of the server to be the same as the project root to " fix issues with treating local files matching first or third party library " names being imported incorrectly. function! ale_linters#python#pyright#GetCwd(buffer) abort let l:fake_linter = { \ 'name': 'pyright', \ 'project_root': function('ale#python#FindProjectRoot'), \} let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, l:fake_linter) return !empty(l:root) ? l:root : v:null endfunction function! ale_linters#python#pyright#GetConfig(buffer) abort let l:config = deepcopy(ale#Var(a:buffer, 'python_pyright_config')) if !has_key(l:config, 'python') let l:config.python = {} endif if type(l:config.python) is v:t_dict " Automatically detect the virtualenv path and use it. if !has_key(l:config.python, 'venvPath') let l:venv = ale#python#FindVirtualenv(a:buffer) if !empty(l:venv) let l:config.python.venvPath = l:venv endif endif " Automatically use the version of Python in virtualenv. if type(get(l:config.python, 'venvPath')) is v:t_string \&& !empty(l:config.python.venvPath) \&& !has_key(l:config.python, 'pythonPath') let l:config.python.pythonPath = ale#path#Simplify( \ l:config.python.venvPath \ . (has('win32') ? '/Scripts/python' : '/bin/python') \) endif endif return l:config endfunction function! ale_linters#python#pyright#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyright_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pyright_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pyright_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pyright', ['pyright-langserver']) endfunction function! ale_linters#python#pyright#GetCommand(buffer) abort let l:executable = ale_linters#python#pyright#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pyright-langserver' \ : '' let l:env_string = '' if ale#Var(a:buffer, 'python_auto_virtualenv') let l:env_string = ale#python#AutoVirtualenvEnvString(a:buffer) endif return l:env_string . ale#Escape(l:executable) . l:exec_args . ' --stdio' endfunction call ale#linter#Define('python', { \ 'name': 'pyright', \ 'lsp': 'stdio', \ 'cwd': function('ale_linters#python#pyright#GetCwd'), \ 'executable': function('ale_linters#python#pyright#GetExecutable'), \ 'command': function('ale_linters#python#pyright#GetCommand'), \ 'project_root': function('ale#python#FindProjectRoot'), \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ 'lsp_config': function('ale_linters#python#pyright#GetConfig'), \}) ================================================ FILE: ale_linters/python/refurb.vim ================================================ " Author: Yining " Description: refurb as linter for python files call ale#Set('python_refurb_executable', 'refurb') call ale#Set('python_refurb_options', '') call ale#Set('python_refurb_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_refurb_change_directory', 1) call ale#Set('python_refurb_auto_pipenv', 0) call ale#Set('python_refurb_auto_poetry', 0) call ale#Set('python_refurb_auto_uv', 0) function! ale_linters#python#refurb#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_refurb_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_refurb_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_refurb_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_refurb', ['refurb']) endfunction function! ale_linters#python#refurb#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_refurb_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '' endfunction function! ale_linters#python#refurb#GetCommand(buffer) abort let l:executable = ale_linters#python#refurb#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run refurb' \ : '' return ale#Escape(l:executable) . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_refurb_options')) \ . ' %s' endfunction function! ale_linters#python#refurb#Handle(buffer, lines) abort "Example: path/to/file.py:3:17 [FURB109]: Replace `in [x, y, z]` with `in (x, y, z)` let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+)?:?\s*\[FURB(\d+)\]:\s*(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'code': l:match[3] + 0, \ 'text': l:match[4], \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'refurb', \ 'executable': function('ale_linters#python#refurb#GetExecutable'), \ 'cwd': function('ale_linters#python#refurb#GetCwd'), \ 'command': function('ale_linters#python#refurb#GetCommand'), \ 'callback': 'ale_linters#python#refurb#Handle', \ 'output_stream': 'both', \ 'read_buffer': 0, \}) ================================================ FILE: ale_linters/python/ruff.vim ================================================ " Author: Yining " Description: ruff as linter for python files call ale#Set('python_ruff_executable', 'ruff') call ale#Set('python_ruff_options', '') call ale#Set('python_ruff_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_ruff_change_directory', 1) call ale#Set('python_ruff_auto_pipenv', 0) call ale#Set('python_ruff_auto_poetry', 0) call ale#Set('python_ruff_auto_uv', 0) call ale#fix#registry#Add('ruff', \ 'ale#fixers#ruff#Fix', \ ['python'], \ 'A python linter/fixer for Python written in Rust' \) function! ale_linters#python#ruff#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_ruff_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_ruff_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_ruff_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_ruff', ['ruff']) endfunction function! ale_linters#python#ruff#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#python#ruff#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run ruff' \ : '' let l:command = ale#Escape(l:executable) . l:exec_args . ' --version' return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale_linters#python#ruff#GetCommand'), \) endfunction function! ale_linters#python#ruff#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_ruff_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '' endfunction function! ale_linters#python#ruff#GetCommand(buffer, version) abort let l:executable = ale_linters#python#ruff#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run ruff' \ : '' " NOTE: ruff 0.3.0 deprecates `ruff ` in favor of `ruff check ` let l:exec_args = l:exec_args \ . (ale#semver#GTE(a:version, [0, 3, 0]) ? ' check' : '') " NOTE: ruff version `0.0.69` supports linting input from stdin " NOTE: ruff version `0.1.0` deprecates `--format text` return ale#Escape(l:executable) . l:exec_args . ' -q' \ . ' --no-fix' \ . ale#Pad(ale#Var(a:buffer, 'python_ruff_options')) \ . (ale#semver#GTE(a:version, [0, 1, 0]) ? ' --output-format json-lines' : ' --format json-lines') \ . (ale#semver#GTE(a:version, [0, 0, 69]) ? ' --stdin-filename %s -' : ' %s') endfunction function! ale_linters#python#ruff#Handle(buffer, lines) abort let l:output = [] " Read all lines of ruff output and parse use all the valid JSONL lines. for l:line in a:lines try let l:item = json_decode(l:line) catch " If we can't decode a line, skip it. continue endtry if empty(l:item) continue endif if (l:item.code is# 'W291' || l:item.code is# 'W293') \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif if l:item.code is# 'W391' \&& !ale#Var(a:buffer, 'warn_about_trailing_blank_lines') " Skip warnings for trailing blank lines if the option is off continue endif call add(l:output, { \ 'lnum': l:item.location.row, \ 'col': l:item.location.column, \ 'end_lnum': l:item.end_location.row, \ 'end_col': l:item.end_location.column - 1, \ 'code': l:item.code, \ 'text': l:item.message, \ 'type': l:item.code =~? '\vE\d+' ? 'E' : 'W', \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'ruff', \ 'executable': function('ale_linters#python#ruff#GetExecutable'), \ 'cwd': function('ale_linters#python#ruff#GetCwd'), \ 'command': function('ale_linters#python#ruff#RunWithVersionCheck'), \ 'callback': 'ale_linters#python#ruff#Handle', \ 'output_stream': 'both', \ 'read_buffer': 1, \}) ================================================ FILE: ale_linters/python/unimport.vim ================================================ " Author: Author: Jon Parise call ale#Set('python_unimport_executable', 'unimport') call ale#Set('python_unimport_options', '') call ale#Set('python_unimport_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_unimport_auto_pipenv', 0) call ale#Set('python_unimport_auto_poetry', 0) call ale#Set('python_unimport_auto_uv', 0) function! ale_linters#python#unimport#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_unimport_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_unimport_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_unimport_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_unimport', ['unimport']) endfunction function! ale_linters#python#unimport#GetCommand(buffer) abort let l:executable = ale_linters#python#unimport#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run unimport' \ : '' return '%e' . l:exec_args \ . ale#Pad(ale#Var(a:buffer, 'python_unimport_options')) \ . ' --check' \ . ' %t' endfunction function! ale_linters#python#unimport#GetCwd(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#unimport#Handle(buffer, lines) abort let l:output = ale#python#HandleTraceback(a:lines, 10) if !empty(l:output) return l:output endif " Matches lines like: " " urllib.parse at path/to/file.py:9 let l:pattern = '\v(.+) at [^:]+:(\d+)$' for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'type': 'W', \ 'text': 'unused: ' . l:match[1], \}) endfor return l:output endfunction call ale#linter#Define('python', { \ 'name': 'unimport', \ 'executable': function('ale_linters#python#unimport#GetExecutable'), \ 'cwd': function('ale_linters#python#unimport#GetCwd'), \ 'command': function('ale_linters#python#unimport#GetCommand'), \ 'callback': 'ale_linters#python#unimport#Handle', \}) ================================================ FILE: ale_linters/python/vulture.vim ================================================ " Author: Yauheni Kirylau " 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) call ale#Set('python_vulture_auto_pipenv', 0) call ale#Set('python_vulture_auto_poetry', 0) call ale#Set('python_vulture_auto_uv', 0) " 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 if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_vulture_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_vulture_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_vulture_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_vulture', ['vulture']) endfunction function! ale_linters#python#vulture#GetCwd(buffer) abort if !ale#Var(a:buffer, 'python_vulture_change_directory') return '' endif return s:GetDir(a:buffer) endfunction function! ale_linters#python#vulture#GetCommand(buffer) abort let l:executable = ale_linters#python#vulture#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run vulture' \ : '' let l:lint_dest = ale#Var(a:buffer, 'python_vulture_change_directory') \ ? ' .' \ : ' %s' return 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 let l:output = ale#python#HandleTraceback(a:lines, 10) if !empty(l:output) return l:output endif " Matches patterns line the following: let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+): (.*)$' 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': function('ale_linters#python#vulture#GetExecutable'), \ 'cwd': function('ale_linters#python#vulture#GetCwd'), \ 'command': function('ale_linters#python#vulture#GetCommand'), \ 'callback': 'ale_linters#python#vulture#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/qml/qmlfmt.vim ================================================ " Author: pylipp (www.github.com/pylipp) " Description: qmlfmt for QML files 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+): (.+)$' 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': {b -> ale#Var(b, 'qml_qmlfmt_executable')}, \ 'command': '%e -e', \ 'callback': 'ale_linters#qml#qmlfmt#Handle', \}) ================================================ FILE: ale_linters/qml/qmllint.vim ================================================ " Author: pylipp (www.github.com/pylipp) " Description: qmllint for QML files " Find lines like " /home/foo_user42/code-base/qml/Screen.qml:11 : Expected token `}' function! ale_linters#qml#qmllint#Handle(buffer, lines) abort let l:pattern = '\v^[/_-a-zA-z0-9\. ]+:(\d+) : (.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': 0, \ 'text': l:match[2], \ 'type': 'E', \} call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('qml', { \ 'name': 'qmllint', \ 'output_stream': 'stderr', \ 'executable': 'qmllint', \ 'command': 'qmllint %t', \ 'callback': 'ale_linters#qml#qmllint#Handle', \}) ================================================ FILE: ale_linters/r/languageserver.vim ================================================ " Author: Eric Zhao <21zhaoe@protonmail.com> " Author: ourigen " Description: Implementation of the Language Server Protocol for R. call ale#Set('r_languageserver_cmd', 'languageserver::run()') call ale#Set('r_languageserver_config', {}) function! ale_linters#r#languageserver#GetCommand(buffer) abort let l:cmd_string = ale#Var(a:buffer, 'r_languageserver_cmd') return 'Rscript --no-save --no-restore --no-site-file --no-init-file -e ' . ale#Escape(l:cmd_string) endfunction function! ale_linters#r#languageserver#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile(a:buffer, '.Rprofile') return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : fnamemodify(a:buffer, ':h') endfunction call ale#linter#Define('r', { \ 'name': 'languageserver', \ 'aliases': ['r_language_server'], \ 'lsp': 'stdio', \ 'lsp_config': {b -> ale#Var(b, 'r_languageserver_config')}, \ 'executable': 'Rscript', \ 'command': function('ale_linters#r#languageserver#GetCommand'), \ 'project_root': function('ale_linters#r#languageserver#GetProjectRoot') \}) ================================================ FILE: ale_linters/r/lintr.vim ================================================ " Author: Michel Lang , w0rp , " Fenner Macrae , " ourigen " Description: This file adds support for checking R code with lintr. let g:ale_r_lintr_options = get(g:, 'ale_r_lintr_options', 'with_defaults()') " A reasonable alternative default: " get(g:, 'ale_r_lintr_options', 'with_defaults(object_usage_linter = NULL)') let g:ale_r_lintr_lint_package = get(g:, 'ale_r_lintr_lint_package', 0) function! ale_linters#r#lintr#GetCommand(buffer) abort if ale#Var(a:buffer, 'r_lintr_lint_package') let l:lint_cmd = 'lint_package(cache = FALSE, linters = ' \ . ale#Var(a:buffer, 'r_lintr_options') . ')' else let l:lint_cmd = 'lint(cache = FALSE, commandArgs(TRUE), ' \ . ale#Var(a:buffer, 'r_lintr_options') . ')' endif let l:cmd_string = 'suppressPackageStartupMessages(library(lintr));' \ . l:lint_cmd return 'Rscript --no-save --no-restore --no-site-file --no-init-file -e ' . ale#Escape(l:cmd_string) . ' %t' endfunction call ale#linter#Define('r', { \ 'name': 'lintr', \ 'executable': 'Rscript', \ 'cwd': '%s:h', \ 'command': function('ale_linters#r#lintr#GetCommand'), \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'output_stream': 'both', \}) ================================================ FILE: ale_linters/racket/langserver.vim ================================================ call ale#linter#Define('racket', { \ 'name': 'racket_langserver', \ 'lsp': 'stdio', \ 'executable': 'racket', \ 'command': '%e -l racket-langserver', \ 'project_root': function('ale#racket#FindProjectRoot'), \}) ================================================ FILE: ale_linters/racket/raco.vim ================================================ " Author: aqui18 " Description: This file adds support for checking Racket code with raco. " This is the same form of syntax-checking used by DrRacket as well. The " downside is that it will only catch the first error, but none of the " subsequent ones. This is due to how evaluation in Racket works. function! ale_linters#racket#raco#Handle(buffer, lines) abort " Matches patterns " :: " eg: " info.rkt:4:0: infotab-module: not a well-formed definition let l:pattern = '^\(\s\)\@!\(.\+\):\(\d\+\):\(\d\+\): \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'filename': l:match[2], \ 'lnum': l:match[3] + 0, \ 'col': l:match[4] + 0, \ 'type': 'E', \ 'text': l:match[5], \}) endfor return l:output endfunction call ale#linter#Define('racket', { \ 'name': 'raco', \ 'executable': 'raco', \ 'output_stream': 'stderr', \ 'command': 'raco expand %s', \ 'callback': 'ale_linters#racket#raco#Handle', \}) ================================================ FILE: ale_linters/reason/ls.vim ================================================ " Author: David Buchan-Swanson " Description: Integrate ALE with reason-language-server. call ale#Set('reason_ls_executable', '') function! ale_linters#reason#ls#FindProjectRoot(buffer) abort let l:reason_config = ale#path#FindNearestFile(a:buffer, 'bsconfig.json') if !empty(l:reason_config) return fnamemodify(l:reason_config, ':h') endif return '' endfunction call ale#linter#Define('reason', { \ 'name': 'reason-language-server', \ 'aliases': ['reason_ls'], \ 'lsp': 'stdio', \ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#reason#ls#FindProjectRoot'), \ 'language': 'reason', \}) ================================================ FILE: ale_linters/reason/merlin.vim ================================================ " Author: Andrey Popp -- @andreypopp " Description: Report errors in ReasonML code with Merlin if !exists('g:merlin') finish endif function! ale_linters#reason#merlin#Handle(buffer, lines) abort return merlin#ErrorLocList() endfunction call ale#linter#Define('reason', { \ 'name': 'merlin', \ 'executable': 'ocamlmerlin', \ 'command': 'true', \ 'callback': 'ale_linters#reason#merlin#Handle', \}) ================================================ FILE: ale_linters/reason/ols.vim ================================================ " Author: Michael Jungo " Description: A language server for Reason call ale#Set('reason_ols_executable', 'ocaml-language-server') call ale#Set('reason_ols_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define('reason', { \ 'name': 'ols', \ 'aliases': ['ocaml-language-server'], \ 'lsp': 'stdio', \ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'command': function('ale#handlers#ols#GetCommand'), \ 'language': function('ale#handlers#ols#GetLanguage'), \ 'project_root': function('ale#handlers#ols#GetProjectRoot'), \}) ================================================ FILE: ale_linters/rego/cspell.vim ================================================ scriptencoding utf-8 " Description: cspell support for rego files. call ale#handlers#cspell#DefineLinter('rego') ================================================ FILE: ale_linters/rego/opacheck.vim ================================================ " Description: opa check for rego files call ale#Set('rego_opacheck_executable', 'opa') call ale#Set('rego_opacheck_options', '') function! ale_linters#rego#opacheck#GetExecutable(buffer) abort return ale#Var(a:buffer, 'rego_opacheck_executable') endfunction function! ale_linters#rego#opacheck#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'rego_opacheck_options') return ale#Escape(ale_linters#rego#opacheck#GetExecutable(a:buffer)) \ . ' check %s:h --format json ' \ . ale#Pad(l:options) endfunction function! ale_linters#rego#opacheck#Handle(buffer, lines) abort let l:output = [] let l:errors = ale#util#FuzzyJSONDecode(a:lines, {'errors': []}) let l:dir = expand('#' . a:buffer . ':p:h') let l:file = expand('#' . a:buffer . ':p') for l:error in l:errors['errors'] if has_key(l:error, 'location') call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:error['location']['file']), \ 'lnum': l:error['location']['row'], \ 'col': l:error['location']['col'], \ 'text': l:error['message'], \ 'code': l:error['code'], \ 'type': 'E', \}) else call add(l:output, { \ 'filename': l:file, \ 'lnum': 0, \ 'col': 0, \ 'text': l:error['message'], \ 'code': l:error['code'], \ 'type': 'E', \}) endif endfor return l:output endfunction call ale#linter#Define('rego', { \ 'name': 'opacheck', \ 'output_stream': 'both', \ 'executable': function('ale_linters#rego#opacheck#GetExecutable'), \ 'command': function('ale_linters#rego#opacheck#GetCommand'), \ 'callback': 'ale_linters#rego#opacheck#Handle', \}) ================================================ FILE: ale_linters/rescript/rescript_language_server.vim ================================================ " Author: John Jackson " Description: The official language server for ReScript. call ale#Set('rescript_language_server_executable', 'rescript-language-server') call ale#Set( \ 'rescript_language_server_use_global', \ get(g:, 'ale_use_global_executables', v:true), \ ) function! s:GetProjectRoot(buffer) abort let l:config_file = ale#path#FindNearestFile(a:buffer, 'rescript.json') return !empty(l:config_file) ? fnamemodify(l:config_file, ':h') : '' endfunction call ale#linter#Define('rescript', { \ 'name': 'rescript_language_server', \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'rescript_language_server', [ \ 'node_modules/.bin/rescript-language-server' \ ])}, \ 'command': '%e --stdio', \ 'project_root': function('s:GetProjectRoot'), \}) ================================================ FILE: ale_linters/review/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#handlers#redpen#DefineLinter('review') ================================================ FILE: ale_linters/robot/rflint.vim ================================================ " Author: Samuel Branisa " Description: rflint linting for robot framework files call ale#Set('robot_rflint_executable', 'rflint') function! ale_linters#robot#rflint#GetExecutable(buffer) abort return ale#Var(a:buffer, 'robot_rflint_executable') endfunction function! ale_linters#robot#rflint#GetCommand(buffer) abort let l:executable = ale_linters#robot#rflint#GetExecutable(a:buffer) let l:flags = '--format' \ . ' "{filename}:{severity}:{linenumber}:{char}:{rulename}:{message}"' return l:executable \ . ' ' \ . l:flags \ . ' %s' endfunction function! ale_linters#robot#rflint#Handle(buffer, lines) abort let l:pattern = '\v^([[:alnum:][:punct:]]+):(W|E):([[:digit:]]+):([[:digit:]]+):([[:alnum:]]+):(.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'bufnr': a:buffer, \ 'filename': l:match[1], \ 'type': l:match[2], \ 'lnum': str2nr(l:match[3]), \ 'col': str2nr(l:match[4]), \ 'text': l:match[5], \ 'detail': l:match[6], \}) endfor return l:output endfunction call ale#linter#Define('robot', { \ 'name': 'rflint', \ 'executable': function('ale_linters#robot#rflint#GetExecutable'), \ 'command': function('ale_linters#robot#rflint#GetCommand'), \ 'callback': 'ale_linters#robot#rflint#Handle', \}) ================================================ FILE: ale_linters/roc/roc_language_server.vim ================================================ " Author: Benjamin Block " Description: A language server for Roc. function! ale_linters#roc#roc_language_server#GetProjectRoot(buffer) abort let l:roc_main_file = ale#path#FindNearestFile(a:buffer, 'main.roc') if !empty(l:roc_main_file) return fnamemodify(l:roc_main_file, ':p:h') else return fnamemodify('', ':h') endif endfunction call ale#Set('roc_roc_language_server_executable', 'roc_language_server') call ale#Set('roc_roc_language_server_config', {}) call ale#linter#Define('roc', { \ 'name': 'roc_language_server', \ 'lsp': 'stdio', \ 'language': 'roc', \ 'lsp_config': {b -> ale#Var(b, 'roc_roc_language_server_config')}, \ 'executable': {b -> ale#Var(b, 'roc_roc_language_server_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#roc#roc_language_server#GetProjectRoot'), \}) ================================================ FILE: ale_linters/rst/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for rst files call ale#handlers#alex#DefineLinter('rst', '--text') ================================================ FILE: ale_linters/rst/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for ReStructuredText files. call ale#handlers#cspell#DefineLinter('rst') ================================================ FILE: ale_linters/rst/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for reStructuredrst files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('rst', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/rst/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#handlers#redpen#DefineLinter('rst') ================================================ FILE: ale_linters/rst/rstcheck.vim ================================================ " Authors: " John Nduli https://github.com/jnduli, " Michael Goerz https://github.com/goerz call ale#Set('rst_rstcheck_executable', 'rstcheck') call ale#Set('rst_rstcheck_options', '') function! ale_linters#rst#rstcheck#GetExecutable(buffer) abort return ale#Var(a:buffer, 'rst_rstcheck_executable') endfunction function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort " matches: 'bad_rst.rst:1: (SEVERE/4) Title overline & underline " mismatch.' 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]), \ 'lnum': l:match[2] + 0, \ 'col': 0, \ 'type': l:match[3] is# 'SEVERE' ? 'E' : 'W', \ 'text': l:match[4], \}) endfor return l:output endfunction function! ale_linters#rst#rstcheck#GetCommand(buffer, version) abort let l:executable = ale_linters#rst#rstcheck#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'rst_rstcheck_options') let l:dir = expand('#' . a:buffer . ':p:h') let l:exec_args = ale#Pad(l:options) if ale#semver#GTE(a:version, [3, 4, 0]) let l:exec_args .= ' --config ' . ale#Escape(l:dir) endif return ale#Escape(l:executable) \ . l:exec_args \ . ' %t' endfunction function! ale_linters#rst#rstcheck#GetCommandWithVersionCheck(buffer) abort return ale#semver#RunWithVersionCheck( \ a:buffer, \ ale_linters#rst#rstcheck#GetExecutable(a:buffer), \ '%e --version', \ function('ale_linters#rst#rstcheck#GetCommand') \) endfunction call ale#linter#Define('rst', { \ 'name': 'rstcheck', \ 'executable': 'rstcheck', \ 'cwd': '%s:h', \ 'command': function('ale_linters#rst#rstcheck#GetCommandWithVersionCheck'), \ 'callback': 'ale_linters#rst#rstcheck#Handle', \ 'output_stream': 'both', \}) ================================================ FILE: ale_linters/rst/textlint.vim ================================================ " Author: hokorobi " Description: textlint, a proofreading tool (https://textlint.github.io/) call ale#linter#Define('rst', { \ 'name': 'textlint', \ 'executable': function('ale#handlers#textlint#GetExecutable'), \ 'command': function('ale#handlers#textlint#GetCommand'), \ 'callback': 'ale#handlers#textlint#HandleTextlintOutput', \}) ================================================ FILE: ale_linters/rst/vale.vim ================================================ " Author: chew-z https://github.com/chew-z " Description: vale for RST files call ale#linter#Define('rst', { \ 'name': 'vale', \ 'executable': 'vale', \ 'command': 'vale --output=JSON %t', \ 'callback': 'ale#handlers#vale#Handle', \}) ================================================ FILE: ale_linters/rst/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for reStructuredText files call ale#handlers#writegood#DefineLinter('rst') ================================================ FILE: ale_linters/ruby/brakeman.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: Brakeman, a static analyzer for Rails security 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 = [] let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) let l:sep = has('win32') ? '\' : '/' " Brakeman always outputs paths relative to the Rails app root let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) for l:warning in get(l:json, 'warnings', []) let l:text = l:warning.warning_type . ' ' . l:warning.message . ' (' . l:warning.confidence . ')' let l:line = l:warning.line != v:null ? l:warning.line : 1 call add(l:output, { \ 'filename': l:rails_root . l:sep . l:warning.file, \ 'lnum': l:line, \ 'type': 'W', \ 'text': l:text, \}) endfor return l:output endfunction function! ale_linters#ruby#brakeman#GetCommand(buffer) abort let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) if l:rails_root is? '' return '' endif let l:executable = ale#Var(a:buffer, 'ruby_brakeman_executable') return ale#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': {b -> ale#Var(b, 'ruby_brakeman_executable')}, \ 'command': function('ale_linters#ruby#brakeman#GetCommand'), \ 'callback': 'ale_linters#ruby#brakeman#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/ruby/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Ruby files. call ale#handlers#cspell#DefineLinter('ruby') ================================================ FILE: ale_linters/ruby/debride.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: debride, a dead method detector for Ruby files call ale#Set('ruby_debride_executable', 'debride') call ale#Set('ruby_debride_options', '') function! ale_linters#ruby#debride#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_debride_executable') return ale#ruby#EscapeExecutable(l:executable, 'debride') \ . ale#Var(a:buffer, 'ruby_debride_options') \ . ' %s' endfunction function! ale_linters#ruby#debride#HandleOutput(buffer, lines) abort let l:output = [] for l:line in a:lines if l:line !~# '^ ' continue endif let l:elements = split(l:line) let l:method_name = l:elements[0] let l:lnum = split(l:elements[1], ':')[1] call add(l:output, { \ 'lnum': 0 + l:lnum, \ 'text': 'Possible unused method: ' . l:method_name, \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('ruby', { \ 'name': 'debride', \ 'executable': {b -> ale#Var(b, 'ruby_debride_executable')}, \ 'command': function('ale_linters#ruby#debride#GetCommand'), \ 'callback': 'ale_linters#ruby#debride#HandleOutput', \}) ================================================ FILE: ale_linters/ruby/packwerk.vim ================================================ " Author: ymap - https://github.com/ymap " Description: Packwerk, a static analyzer used to enforce boundaries and modularize Rails applications. call ale#Set('ruby_packwerk_executable', 'packwerk') call ale#Set('ruby_packwerk_options', '') function! ale_linters#ruby#packwerk#Handle(buffer, lines) abort let l:pattern = '\v^[^:]+:(\d+):(\d+)$' let l:index = 0 let l:output = [] while l:index < len(a:lines) - 1 let l:cleaned_line = substitute(a:lines[l:index], '\v\e\[[0-9;]*m', '', 'g') let l:match = matchlist(l:cleaned_line, l:pattern) if len(l:match) > 0 call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': a:lines[l:index + 1], \}) endif let l:index += 1 endwhile return l:output endfunction function! ale_linters#ruby#packwerk#GetCommand(buffer) abort let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) if l:rails_root is? '' return '' endif let l:executable = ale#Var(a:buffer, 'ruby_packwerk_executable') let l:sep = has('win32') ? '\' : '/' let l:abs_path = expand('#' . a:buffer . ':p') let l:rel_path = substitute(l:abs_path, escape(l:rails_root . l:sep, '\'), '', '') return ale#ruby#EscapeExecutable(l:executable, 'packwerk') \ . ' check' \ . ale#Pad(ale#Var(a:buffer, 'ruby_packwerk_options')) \ . ' ' \ . ale#Escape(rel_path) endfunction call ale#linter#Define('ruby', { \ 'name': 'packwerk', \ 'executable': {b -> ale#Var(b, 'ruby_packwerk_executable')}, \ 'command': function('ale_linters#ruby#packwerk#GetCommand'), \ 'callback': 'ale_linters#ruby#packwerk#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/ruby/rails_best_practices.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: rails_best_practices, a code metric tool for rails projects call ale#Set('ruby_rails_best_practices_options', '') call ale#Set('ruby_rails_best_practices_executable', 'rails_best_practices') function! ale_linters#ruby#rails_best_practices#Handle(buffer, lines) abort let l:output = [] for l:warning in ale#util#FuzzyJSONDecode(a:lines, []) if !ale#path#IsBufferPath(a:buffer, l:warning.filename) continue endif call add(l:output, { \ 'lnum': l:warning.line_number + 0, \ 'type': 'W', \ 'text': l:warning.message, \}) endfor return l:output endfunction function! ale_linters#ruby#rails_best_practices#GetCommand(buffer) abort 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 = has('win32') ? '%t ' : '/dev/stdout ' let l:cat_file = has('win32') ? '; type %t' : '' return ale#ruby#EscapeExecutable(l:executable, 'rails_best_practices') \ . ' --silent -f json --output-file ' . l:output_file \ . ale#Var(a:buffer, 'ruby_rails_best_practices_options') \ . ale#Escape(l:rails_root) \ . l:cat_file endfunction call ale#linter#Define('ruby', { \ 'name': 'rails_best_practices', \ 'executable': {b -> ale#Var(b, 'ruby_rails_best_practices_executable')}, \ 'command': function('ale_linters#ruby#rails_best_practices#GetCommand'), \ 'callback': 'ale_linters#ruby#rails_best_practices#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/ruby/reek.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: Reek, a code smell detector for Ruby files 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#GetCommand(buffer, version) abort 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(a:version, [5, 0, 0]) \ ? ' --stdin-filename %s' \ : '' return ale#ruby#EscapeExecutable(l:executable, 'reek') \ . ' -f json --no-progress --no-color --force-exclusion' \ . l:display_name_args endfunction function! s:GetDocumentationLink(error) abort return get(a:error, 'documentation_link', get(a:error, 'wiki_link', '')) endfunction function! s:BuildText(buffer, error) abort let l:parts = [] if ale#Var(a:buffer, 'ruby_reek_show_context') call add(l:parts, a:error.context) endif call add(l:parts, a:error.message) if ale#Var(a:buffer, 'ruby_reek_show_wiki_link') call add(l:parts, '[' . s:GetDocumentationLink(a:error) . ']') endif return join(l:parts, ' ') endfunction function! ale_linters#ruby#reek#Handle(buffer, lines) abort let l:output = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) for l:location in l:error.lines call add(l:output, { \ 'lnum': l:location, \ 'type': 'W', \ 'text': s:BuildText(a:buffer, l:error), \ 'code': l:error.smell_type, \}) endfor endfor return l:output endfunction call ale#linter#Define('ruby', { \ 'name': 'reek', \ 'executable': {b -> ale#Var(b, 'ruby_reek_executable')}, \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'ruby_reek_executable'), \ '%e --version', \ function('ale_linters#ruby#reek#GetCommand'), \ )}, \ 'callback': 'ale_linters#ruby#reek#Handle', \}) ================================================ FILE: ale_linters/ruby/rubocop.vim ================================================ " 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#Var(a:buffer, 'ruby_rubocop_executable') return ale#ruby#EscapeExecutable(l:executable, 'rubocop') \ . ' --format json --force-exclusion ' \ . ale#Var(a:buffer, 'ruby_rubocop_options') \ . ' --stdin %s' endfunction function! ale_linters#ruby#rubocop#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('ruby', { \ 'name': 'rubocop', \ 'executable': {b -> ale#Var(b, 'ruby_rubocop_executable')}, \ 'command': function('ale_linters#ruby#rubocop#GetCommand'), \ 'callback': 'ale#ruby#HandleRubocopOutput', \}) ================================================ FILE: ale_linters/ruby/ruby.vim ================================================ " Author: Brandon Roehl - https://github.com/BrandonRoehl " Description: Ruby MRI for Ruby files call ale#Set('ruby_ruby_executable', 'ruby') call ale#linter#Define('ruby', { \ 'name': 'ruby', \ 'executable': {b -> ale#Var(b, 'ruby_ruby_executable')}, \ 'command': '%e -w -c %t', \ 'output_stream': 'stderr', \ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors', \}) ================================================ FILE: ale_linters/ruby/solargraph.vim ================================================ " Author: Horacio Sanson - https://github.com/hsanson " Description: Solargraph Language Server https://solargraph.org/ " " Author: Devon Meunier " 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 let l:executable = ale#Var(a:buffer, 'ruby_solargraph_executable') return ale#ruby#EscapeExecutable(l:executable, 'solargraph') \ . ale#Pad('stdio') endfunction call ale#linter#Define('ruby', { \ 'name': 'solargraph', \ 'lsp': 'stdio', \ 'language': 'ruby', \ 'executable': {b -> ale#Var(b, 'ruby_solargraph_executable')}, \ 'command': function('ale_linters#ruby#solargraph#GetCommand'), \ 'project_root': function('ale#ruby#FindProjectRoot'), \ 'initialization_options': {b -> ale#Var(b, 'ruby_solargraph_options')}, \}) ================================================ FILE: ale_linters/ruby/sorbet.vim ================================================ call ale#Set('ruby_sorbet_executable', 'srb') call ale#Set('ruby_sorbet_options', '') call ale#Set('ruby_sorbet_enable_watchman', 0) call ale#Set('ruby_sorbet_initialization_options', { 'highlightUntyped': v:false }) function! ale_linters#ruby#sorbet#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable') let l:options = ale#Var(a:buffer, 'ruby_sorbet_options') let l:enable_watchman = ale#Var(a:buffer, 'ruby_sorbet_enable_watchman') return ale#ruby#EscapeExecutable(l:executable, 'srb') \ . ' tc' \ . ale#Pad(l:options) \ . ' --lsp' \ . (l:enable_watchman ? '' : ' --disable-watchman') endfunction call ale#linter#Define('ruby', { \ 'name': 'sorbet', \ 'aliases': ['srb'], \ 'lsp': 'stdio', \ 'language': 'ruby', \ 'executable': {b -> ale#Var(b, 'ruby_sorbet_executable')}, \ 'command': function('ale_linters#ruby#sorbet#GetCommand'), \ 'project_root': function('ale#ruby#FindProjectRoot'), \ 'initialization_options': {b -> ale#Var(b, 'ruby_sorbet_initialization_options')} \}) ================================================ FILE: ale_linters/ruby/standardrb.vim ================================================ " Author: Justin Searls https://github.com/searls, ynonp - https://github.com/ynonp, Eddie Lebow https://github.com/elebow " based on the ale rubocop linter " Description: StandardRB - Ruby Style Guide, with linter & automatic code fixer call ale#Set('ruby_standardrb_executable', 'standardrb') call ale#Set('ruby_standardrb_options', '') function! ale_linters#ruby#standardrb#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_standardrb_executable') return ale#ruby#EscapeExecutable(l:executable, 'standardrb') \ . ' --format json --force-exclusion ' \ . ale#Var(a:buffer, 'ruby_standardrb_options') \ . ' --stdin %s' endfunction " standardrb is based on RuboCop so the callback is the same call ale#linter#Define('ruby', { \ 'name': 'standardrb', \ 'executable': {b -> ale#Var(b, 'ruby_standardrb_executable')}, \ 'command': function('ale_linters#ruby#standardrb#GetCommand'), \ 'callback': 'ale#ruby#HandleRubocopOutput', \}) ================================================ FILE: ale_linters/ruby/steep.vim ================================================ call ale#Set('ruby_steep_executable', 'steep') call ale#Set('ruby_steep_options', '') " Find the nearest dir containing a Steepfile function! ale_linters#ruby#steep#FindRoot(buffer) abort for l:name in ['Steepfile'] 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 " Rename path relative to root function! ale_linters#ruby#steep#RelativeToRoot(buffer, path) abort let l:separator = has('win32') ? '\' : '/' let l:steep_root = ale_linters#ruby#steep#FindRoot(a:buffer) " path isn't under root if l:steep_root is# '' return '' endif let l:steep_root_prefix = l:steep_root . l:separator " win32 path separators get interpreted by substitute, escape them if has('win32') let l:steep_root_pat = substitute(l:steep_root_prefix, '\\', '\\\\', 'g') else let l:steep_root_pat = l:steep_root_prefix endif return substitute(a:path, l:steep_root_pat, '', '') endfunction function! ale_linters#ruby#steep#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_steep_executable') " steep check needs to apply some config from the file path so: " - steep check can't use stdin (no path) " - steep check can't use %t (path outside of project) " => we can only use %s " somehow :ALEInfo shows that ALE still appends '< %t' to the command " => luckily steep check ignores stdin " somehow steep has a problem with absolute path to file but a path " relative to Steepfile directory works: " see https://github.com/soutaro/steep/pull/975 " => change to Steepfile directory and remove leading path let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') let l:buffer_filename = fnameescape(l:buffer_filename) let l:relative = ale_linters#ruby#steep#RelativeToRoot(a:buffer, l:buffer_filename) " if file is not under steep root, steep can't type check if l:relative is# '' " don't execute return '' endif return ale#ruby#EscapeExecutable(l:executable, 'steep') \ . ' check ' \ . ale#Var(a:buffer, 'ruby_steep_options') \ . ' ' . fnameescape(l:relative) endfunction function! ale_linters#ruby#steep#GetType(severity) abort if a:severity is? 'information' \|| a:severity is? 'hint' return 'I' endif if a:severity is? 'warning' return 'W' endif return 'E' endfunction " Handle output from steep function! ale_linters#ruby#steep#HandleOutput(buffer, lines) abort let l:output = [] let l:in = 0 let l:item = {} for l:line in a:lines " Look for first line of a message block " If not in-message (l:in == 0) that's expected " If in-message (l:in > 0) that's less expected but let's recover let l:match = matchlist(l:line, '^\([^:]*\):\([0-9]*\):\([0-9]*\): \[\([^]]*\)\] \(.*\)') if len(l:match) > 0 " Something is lingering: recover by pushing what is there if len(l:item) > 0 call add(l:output, l:item) let l:item = {} endif let l:filename = l:match[1] " Steep's reported column is offset by 1 (zero-indexed?) let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 1, \ 'type': ale_linters#ruby#steep#GetType(l:match[4]), \ 'text': l:match[5], \} " Done with this line, mark being in-message and go on with next line let l:in = 1 continue endif " We're past the first line of a message block if l:in > 0 " Look for code in subsequent lines of the message block if l:line =~# '^│ Diagnostic ID:' let l:match = matchlist(l:line, '^│ Diagnostic ID: \(.*\)') if len(l:match) > 0 let l:item.code = l:match[1] endif " Done with the line continue endif " Look for last line of the message block if l:line =~# '^└' " Done with the line, mark looking for underline and go on with the next line let l:in = 2 continue endif " Look for underline right after last line if l:in == 2 let l:match = matchlist(l:line, '\([~][~]*\)') if len(l:match) > 0 let l:item.end_col = l:item['col'] + len(l:match[1]) - 1 endif call add(l:output, l:item) " Done with the line, mark looking for first line and go on with the next line let l:in = 0 let l:item = {} continue endif endif endfor return l:output endfunction call ale#linter#Define('ruby', { \ 'name': 'steep', \ 'executable': {b -> ale#Var(b, 'ruby_steep_executable')}, \ 'language': 'ruby', \ 'command': function('ale_linters#ruby#steep#GetCommand'), \ 'project_root': function('ale_linters#ruby#steep#FindRoot'), \ 'callback': 'ale_linters#ruby#steep#HandleOutput', \}) ================================================ FILE: ale_linters/rust/analyzer.vim ================================================ " Author: Jon Gjengset " Description: The next generation language server for Rust call ale#Set('rust_analyzer_executable', 'rust-analyzer') call ale#Set('rust_analyzer_config', {}) function! ale_linters#rust#analyzer#GetCommand(buffer) abort return '%e' endfunction function! ale_linters#rust#analyzer#GetProjectRoot(buffer) abort " Try to find nearest Cargo.toml for cargo projects let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml') if !empty(l:cargo_file) return fnamemodify(l:cargo_file, ':h') endif " Try to find nearest rust-project.json for non-cargo projects let l:rust_project = ale#path#FindNearestFile(a:buffer, 'rust-project.json') if !empty(l:rust_project) return fnamemodify(l:rust_project, ':h') endif return '' endfunction call ale#linter#Define('rust', { \ 'name': 'analyzer', \ 'aliases': ['rust_analyzer'], \ 'lsp': 'stdio', \ 'initialization_options': {b -> ale#Var(b, 'rust_analyzer_config')}, \ 'executable': {b -> ale#Var(b, 'rust_analyzer_executable')}, \ 'command': function('ale_linters#rust#analyzer#GetCommand'), \ 'project_root': function('ale_linters#rust#analyzer#GetProjectRoot'), \}) ================================================ FILE: ale_linters/rust/cargo.vim ================================================ " Author: Daniel Schemala , " Ivan Petkov " Description: rustc invoked by cargo for rust files call ale#Set('rust_cargo_use_check', 1) call ale#Set('rust_cargo_check_all_targets', 0) call ale#Set('rust_cargo_check_examples', 0) 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', '') call ale#Set('rust_cargo_target_dir', '') function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort if ale#path#FindNearestFile(a:bufnr, 'Cargo.toml') isnot# '' return 'cargo' else " if there is no Cargo.toml file, we don't use cargo even if it exists, " so we return '', because executable('') apparently always fails return '' endif endfunction function! ale_linters#rust#cargo#GetCwd(buffer) abort if ale#Var(a:buffer, 'rust_cargo_avoid_whole_workspace') let l:nearest_cargo = ale#path#FindNearestFile(a:buffer, 'Cargo.toml') let l:nearest_cargo_dir = fnamemodify(l:nearest_cargo, ':h') if l:nearest_cargo_dir isnot# '.' return l:nearest_cargo_dir endif endif return '' endfunction function! ale_linters#rust#cargo#GetCommand(buffer, version) abort let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check') \ && ale#semver#GTE(a:version, [0, 17, 0]) let l:use_all_targets = ale#Var(a:buffer, 'rust_cargo_check_all_targets') \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:use_examples = ale#Var(a:buffer, 'rust_cargo_check_examples') \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests') \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:target_dir = ale#Var(a:buffer, 'rust_cargo_target_dir') let l:use_target_dir = !empty(l:target_dir) \ && ale#semver#GTE(a:version, [0, 17, 0]) let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features') if !empty(l:include_features) let l:include_features = ' --features ' . ale#Escape(l:include_features) 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' elseif l:default_feature_behavior is# 'none' let l:default_feature = ' --no-default-features' else 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') if l:clippy_options =~# '^-- ' let l:clippy_options = join(split(l:clippy_options, '-- ')) endif if l:clippy_options isnot# '' let l:clippy_options = ' -- ' . l:clippy_options endif endif return 'cargo ' \ . l:subcommand \ . (l:use_all_targets ? ' --all-targets' : '') \ . (l:use_examples ? ' --examples' : '') \ . (l:use_tests ? ' --tests' : '') \ . (l:use_target_dir ? (' --target-dir ' . ale#Escape(l:target_dir)) : '') \ . ' --frozen --message-format=json -q' \ . l:default_feature \ . l:include_features \ . l:clippy_options endfunction call ale#linter#Define('rust', { \ 'name': 'cargo', \ 'executable': function('ale_linters#rust#cargo#GetCargoExecutable'), \ 'cwd': function('ale_linters#rust#cargo#GetCwd'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#rust#cargo#GetCargoExecutable(buffer), \ '%e --version', \ function('ale_linters#rust#cargo#GetCommand'), \ )}, \ 'callback': 'ale#handlers#rust#HandleRustErrors', \ 'output_stream': 'both', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/rust/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Rust files. call ale#handlers#cspell#DefineLinter('rust') ================================================ FILE: ale_linters/rust/rls.vim ================================================ " Author: w0rp " Description: A language server for Rust call ale#Set('rust_rls_executable', 'rls') call ale#Set('rust_rls_toolchain', '') call ale#Set('rust_rls_config', {}) function! ale_linters#rust#rls#GetCommand(buffer) abort let l:toolchain = ale#Var(a:buffer, 'rust_rls_toolchain') return '%e' . (!empty(l:toolchain) ? ' +' . ale#Escape(l:toolchain) : '') endfunction function! ale_linters#rust#rls#GetProjectRoot(buffer) abort let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml') return !empty(l:cargo_file) ? fnamemodify(l:cargo_file, ':h') : '' endfunction call ale#linter#Define('rust', { \ 'name': 'rls', \ 'lsp': 'stdio', \ 'lsp_config': {b -> ale#Var(b, 'rust_rls_config')}, \ 'executable': {b -> ale#Var(b, 'rust_rls_executable')}, \ 'command': function('ale_linters#rust#rls#GetCommand'), \ 'project_root': function('ale_linters#rust#rls#GetProjectRoot'), \}) ================================================ FILE: ale_linters/rust/rustc.vim ================================================ " Author: Daniel Schemala " Description: rustc for rust files call ale#Set('rust_rustc_options', '--emit=mir -o /dev/null') function! ale_linters#rust#rustc#RustcCommand(buffer) abort " Try to guess the library search path. If the project is managed by cargo, " it's usually /target/debug/deps/ or " /target/release/deps/ let l:cargo_file = ale#path#FindNearestFile(a:buffer, 'Cargo.toml') if l:cargo_file isnot# '' let l:root = fnamemodify(l:cargo_file, ':h') let l:dependencies = ' -L ' . ale#Escape(ale#path#GetAbsPath(l:root, 'target/debug/deps')) \ . ' -L ' . ale#Escape(ale#path#GetAbsPath(l:root, 'target/release/deps')) else let l:dependencies = '' endif let l:options = ale#Var(a:buffer, 'rust_rustc_options') return 'rustc --error-format=json' \ . ale#Pad(l:options) \ . l:dependencies . ' -' endfunction call ale#linter#Define('rust', { \ 'name': 'rustc', \ 'executable': 'rustc', \ 'command': function('ale_linters#rust#rustc#RustcCommand'), \ 'callback': 'ale#handlers#rust#HandleRustErrors', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/salt/salt_lint.vim ================================================ " Author: Benjamin BINIER " Description: salt-lint, saltstack linter call ale#Set('salt_salt_lint_executable', 'salt-lint') call ale#Set('salt_salt_lint_options', '') function! ale_linters#salt#salt_lint#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'salt_salt_lint_options')) \ . ' --json' endfunction function! ale_linters#salt#salt_lint#Handle(buffer, lines) abort let l:output = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) call add(l:output, { \ 'lnum': l:error.linenumber + 0, \ 'code': l:error.id + 0, \ 'text': l:error.message, \ 'type': l:error.severity is# 'HIGH' ? 'E' : 'W', \}) endfor return l:output endfunction call ale#linter#Define('salt', { \ 'name': 'salt_lint', \ 'aliases': ['salt-lint'], \ 'executable': {b -> ale#Var(b, 'salt_salt_lint_executable')}, \ 'command': function('ale_linters#salt#salt_lint#GetCommand'), \ 'callback': 'ale_linters#salt#salt_lint#Handle' \}) ================================================ FILE: ale_linters/sass/sasslint.vim ================================================ " Author: sQVe - https://github.com/sQVe call ale#Set('sass_sasslint_executable', 'sass-lint') call ale#Set('sass_sasslint_options', '') call ale#Set('sass_sasslint_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#sass#sasslint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'sass_sasslint', [ \ 'node_modules/sass-lint/bin/sass-lint.js', \ 'node_modules/.bin/sass-lint', \]) endfunction function! ale_linters#sass#sasslint#GetCommand(buffer) abort let l:executable = ale_linters#sass#sasslint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'sass_sasslint_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' -v -q -f compact %t' endfunction call ale#linter#Define('sass', { \ 'name': 'sasslint', \ 'executable': function('ale_linters#sass#sasslint#GetExecutable'), \ 'command': function('ale_linters#sass#sasslint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleCSSLintFormat', \}) ================================================ FILE: ale_linters/sass/stylelint.vim ================================================ " Author: diartyz call ale#Set('sass_stylelint_executable', 'stylelint') call ale#Set('sass_stylelint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define('sass', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': {b -> ale#path#FindExecutable(b, 'sass_stylelint', [ \ 'node_modules/.bin/stylelint', \ ])}, \ 'command': '%e --no-color --stdin-filename %s', \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/scala/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Scala files. call ale#handlers#cspell#DefineLinter('scala') ================================================ FILE: ale_linters/scala/fsc.vim ================================================ " Author: Nils Leuzinger - https://github.com/PawkyPenguin " Description: Basic scala support using fsc function! s:IsSbt(buffer) abort return index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0 endfunction call ale#linter#Define('scala', { \ 'name': 'fsc', \ 'executable': {buf -> s:IsSbt(buf) ? '' : 'fsc'}, \ 'command': '%e -Ystop-after:parser %t', \ 'callback': 'ale#handlers#scala#HandleScalacLintFormat', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/scala/metals.vim ================================================ " Author: Jeffrey Lau - https://github.com/zoonfafer " Description: Metals Language Server for Scala https://scalameta.org/metals/ call ale#Set('scala_metals_executable', 'metals') call ale#Set('scala_metals_project_root', '') function! ale_linters#scala#metals#GetProjectRoot(buffer) abort let l:project_root = ale#Var(a:buffer, 'scala_metals_project_root') if !empty(l:project_root) return l:project_root endif let l:potential_roots = [ \ 'build.sc', \ 'build.mill', \ 'build.sbt', \ '.bloop', \ '.metals', \] for l:root in l:potential_roots let l:project_root = ale#path#ResolveLocalPath( \ a:buffer, \ l:root, \ '' \) if !empty(l:project_root) return fnamemodify( \ l:project_root, \ ':h', \) endif endfor return '' endfunction function! ale_linters#scala#metals#GetCommand(buffer) abort return '%e' . ale#Pad('stdio') endfunction call ale#linter#Define('scala', { \ 'name': 'metals', \ 'lsp': 'stdio', \ 'language': 'scala', \ 'executable': {b -> ale#Var(b, 'scala_metals_executable')}, \ 'command': function('ale_linters#scala#metals#GetCommand'), \ 'project_root': function('ale_linters#scala#metals#GetProjectRoot'), \}) ================================================ FILE: ale_linters/scala/sbtserver.vim ================================================ " Author: ophirr33 " 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': function('ale_linters#scala#sbtserver#GetAddress'), \ 'language': 'scala', \ 'project_root': function('ale_linters#scala#sbtserver#GetProjectRoot'), \}) ================================================ FILE: ale_linters/scala/scalac.vim ================================================ " Author: Zoltan Kalmar - https://github.com/kalmiz, " w0rp " Description: Basic scala support using scalac function! s:IsSbt(buffer) abort return index(split(getbufvar(a:buffer, '&filetype'), '\.'), 'sbt') >= 0 endfunction call ale#linter#Define('scala', { \ 'name': 'scalac', \ 'executable': {buf -> s:IsSbt(buf) ? '' : 'scalac'}, \ 'command': '%e -Ystop-after:parser %t', \ 'callback': 'ale#handlers#scala#HandleScalacLintFormat', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/scala/scalastyle.vim ================================================ " Author: Kevin Kays - https://github.com/okkays " Description: Support for the scalastyle checker. call ale#Set('scala_scalastyle_options', '') " TODO: Remove support for the old option name in ALE 3.0. call ale#Set('scala_scalastyle_config', \ get(g:, 'ale_scalastyle_config_loc', '') \) function! ale_linters#scala#scalastyle#Handle(buffer, lines) abort " Look for help output from scalastyle first, which indicates that no " configuration file was found. for l:line in a:lines[:10] if l:line =~# '-c, --config' return [{ \ 'lnum': 1, \ 'text': '(See :help ale-scala-scalastyle)' \ . ' No scalastyle configuration file was found.', \}] endif endfor " Matches patterns like the following: " " warning file=/home/blurble/Doop.scala message=Missing or badly formed ScalaDoc: Extra @param foobles line=190 let l:patterns = [ \ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\)$', \ '^\(.\+\) .\+ message=\(.\+\) line=\(\d\+\) column=\(\d\+\)$', \] let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:patterns) let l:args = { \ 'lnum': l:match[3] + 0, \ 'type': l:match[1] =~? 'error' ? 'E' : 'W', \ 'text': l:match[2] \} if !empty(l:match[4]) let l:args['col'] = l:match[4] + 1 endif call add(l:output, l:args) endfor return l:output endfunction function! ale_linters#scala#scalastyle#GetCommand(buffer) abort " Search for scalastyle config in parent directories. let l:scalastyle_config = '' let l:potential_configs = [ \ '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 endfor " If all else fails, try the global config. if empty(l:scalastyle_config) let l:scalastyle_config = ale#Var(a:buffer, 'scala_scalastyle_config') endif return 'scalastyle' \ . (!empty(l:scalastyle_config) ? ' --config ' . ale#Escape(l:scalastyle_config) : '') \ . ale#Pad(ale#Var(a:buffer, 'scala_scalastyle_options')) \ . ' %t' endfunction call ale#linter#Define('scala', { \ 'name': 'scalastyle', \ 'executable': 'scalastyle', \ 'output_stream': 'stdout', \ 'command': function('ale_linters#scala#scalastyle#GetCommand'), \ 'callback': 'ale_linters#scala#scalastyle#Handle', \}) ================================================ FILE: ale_linters/scss/sasslint.vim ================================================ " Author: sQVe - https://github.com/sQVe call ale#Set('scss_sasslint_executable', 'sass-lint') call ale#Set('scss_sasslint_options', '') call ale#Set('scss_sasslint_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#scss#sasslint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'scss_sasslint', [ \ 'node_modules/sass-lint/bin/sass-lint.js', \ 'node_modules/.bin/sass-lint', \]) endfunction function! ale_linters#scss#sasslint#GetCommand(buffer) abort let l:executable = ale_linters#scss#sasslint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'scss_sasslint_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' -v -q -f compact %t' endfunction call ale#linter#Define('scss', { \ 'name': 'sasslint', \ 'executable': function('ale_linters#scss#sasslint#GetExecutable'), \ 'command': function('ale_linters#scss#sasslint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleCSSLintFormat', \}) ================================================ FILE: ale_linters/scss/scsslint.vim ================================================ " Author: w0rp " Description: This file add scsslint support for SCSS support function! ale_linters#scss#scsslint#Handle(buffer, lines) abort " Matches patterns like the following: " " test.scss:2:1 [W] Indentation: Line should be indented 2 spaces, but was indented 4 spaces let l:pattern = '^.*:\(\d\+\):\(\d*\) \[\([^\]]\+\)\] \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if !ale#Var(a:buffer, 'warn_about_trailing_whitespace') \&& l:match[4] =~# '^TrailingWhitespace' " Skip trailing whitespace warnings if that option is off. continue endif call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[4], \ 'type': l:match[3] is# 'E' ? 'E' : 'W', \}) endfor return l:output endfunction call ale#linter#Define('scss', { \ 'name': 'scsslint', \ 'executable': 'scss-lint', \ 'command': 'scss-lint --stdin-file-path=%s', \ 'callback': 'ale_linters#scss#scsslint#Handle', \}) ================================================ FILE: ale_linters/scss/stylelint.vim ================================================ " Author: diartyz 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#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'scss_stylelint_options')) \ . ' --no-color --stdin-filename %s' endfunction call ale#linter#Define('scss', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': {b -> ale#path#FindExecutable(b, 'scss_stylelint', [ \ 'node_modules/.bin/stylelint', \ ])}, \ 'command': function('ale_linters#scss#stylelint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/sh/bashate.vim ================================================ " Author: hsanson " Description: Lints sh files using bashate " URL: https://github.com/openstack/bashate call ale#Set('sh_bashate_executable', 'bashate') call ale#Set('sh_bashate_options', '') function! ale_linters#sh#bashate#GetExecutable(buffer) abort return ale#Var(a:buffer, 'sh_bashate_executable') endfunction function! ale_linters#sh#bashate#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'sh_bashate_options') let l:executable = ale_linters#sh#bashate#GetExecutable(a:buffer) return ale#Escape(l:executable) . ' ' . l:options . ' ' . '%t' endfunction function! ale_linters#sh#bashate#Handle(buffer, lines) abort " Matches patterns line the following: " " /path/to/script/file:694:1: E003 Indent not multiple of 4 let l:pattern = ':\(\d\+\):\(\d\+\): \(.*\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[1]), \ 'col': str2nr(l:match[2]), \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('sh', { \ 'name': 'bashate', \ 'output_stream': 'stdout', \ 'executable': function('ale_linters#sh#bashate#GetExecutable'), \ 'command': function('ale_linters#sh#bashate#GetCommand'), \ 'callback': 'ale_linters#sh#bashate#Handle', \}) ================================================ FILE: ale_linters/sh/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for shell scripts. call ale#handlers#cspell#DefineLinter('sh') ================================================ FILE: ale_linters/sh/language_server.vim ================================================ " Author: Christian Höltje (https://docwhat.org/) " Description: BASH Language server integration for ALE scriptencoding utf-8 call ale#Set('sh_language_server_executable', 'bash-language-server') call ale#Set('sh_language_server_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#sh#language_server#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'sh_language_server', [ \ 'node_modules/.bin/bash-language-server', \]) endfunction function! ale_linters#sh#language_server#GetCommand(buffer) abort let l:exe = ale#Escape(ale_linters#sh#language_server#GetExecutable(a:buffer)) return l:exe . ' start' endfunction function! ale_linters#sh#language_server#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('sh', { \ 'name': 'language_server', \ 'aliases': ['bash-language-server'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#sh#language_server#GetExecutable'), \ 'command': function('ale_linters#sh#language_server#GetCommand'), \ 'project_root': function('ale_linters#sh#language_server#GetProjectRoot'), \}) ================================================ FILE: ale_linters/sh/shell.vim ================================================ " Author: w0rp " Description: Lints shell files by invoking the shell with -n " This option can be changed to change the default shell when the shell " cannot be taken from the hashbang line. if !exists('g:ale_sh_shell_default_shell') let g:ale_sh_shell_default_shell = fnamemodify($SHELL, ':t') if g:ale_sh_shell_default_shell is# '' || g:ale_sh_shell_default_shell is# 'fish' let g:ale_sh_shell_default_shell = 'bash' endif endif function! ale_linters#sh#shell#GetExecutable(buffer) abort let l:shell_type = ale#handlers#sh#GetShellType(a:buffer) if !empty(l:shell_type) return l:shell_type endif return ale#Var(a:buffer, 'sh_shell_default_shell') endfunction function! ale_linters#sh#shell#GetCommand(buffer) abort return ale_linters#sh#shell#GetExecutable(a:buffer) . ' -n %t' endfunction function! ale_linters#sh#shell#Handle(buffer, lines) abort " Matches patterns line the following: " " bash: line 13: syntax error near unexpected token `d' " bash:行0: 未预期的符号“done”附近有语法错误 " bash: 列 90: 尋找匹配的「"」時遇到了未預期的檔案結束符 " sh: 11: Syntax error: "(" unexpected let l:pattern = '\v([^:]+:\D*)(\d+): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': str2nr(l:match[2]), \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('sh', { \ 'name': 'shell', \ 'output_stream': 'stderr', \ 'executable': function('ale_linters#sh#shell#GetExecutable'), \ 'command': function('ale_linters#sh#shell#GetCommand'), \ 'callback': 'ale_linters#sh#shell#Handle', \}) ================================================ FILE: ale_linters/sh/shellcheck.vim ================================================ " Author: w0rp " Description: shellcheck linter for shell scripts. call ale#handlers#shellcheck#DefineLinter('sh') ================================================ FILE: ale_linters/slim/slimlint.vim ================================================ " Author: Markus Doits - https://github.com/doits " Description: slim-lint for Slim files function! ale_linters#slim#slimlint#GetCommand(buffer) abort let l:command = 'slim-lint %t' let l:rubocop_config = ale#path#FindNearestFile(a:buffer, '.rubocop.yml') " Set SLIM_LINT_RUBOCOP_CONF variable as it is needed for slim-lint to " pick up the rubocop config. " " See https://github.com/sds/slim-lint/blob/master/lib/slim_lint/linter/README.md#rubocop if !empty(l:rubocop_config) if has('win32') let l:command = 'set SLIM_LINT_RUBOCOP_CONF=' . ale#Escape(l:rubocop_config) . ' && ' . l:command else let l:command = 'SLIM_LINT_RUBOCOP_CONF=' . ale#Escape(l:rubocop_config) . ' ' . l:command endif endif return l:command endfunction function! ale_linters#slim#slimlint#Handle(buffer, lines) abort " Matches patterns like the following: " :5 [W] LineLength: Line is too long. [150/120] let l:pattern = '\v^.*:(\d+) \[([EW])\] (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': l:match[1] + 0, \ 'type': l:match[2], \ 'text': l:match[3] \} let l:code_match = matchlist(l:item.text, '\v^([^:]+): (.+)$') if !empty(l:code_match) let l:item.code = l:code_match[1] let l:item.text = l:code_match[2] endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('slim', { \ 'name': 'slimlint', \ 'executable': 'slim-lint', \ 'command': function('ale_linters#slim#slimlint#GetCommand'), \ 'callback': 'ale_linters#slim#slimlint#Handle' \}) ================================================ FILE: ale_linters/sml/smlnj.vim ================================================ " Author: Paulo Alem , Jake Zimmerman " Description: Single-file SML checking with SML/NJ compiler call ale#linter#Define('sml', { \ 'name': 'smlnj', \ 'executable': function('ale#handlers#sml#GetExecutableSmlnjFile'), \ 'command': 'sml', \ 'callback': 'ale#handlers#sml#Handle', \}) ================================================ FILE: ale_linters/sml/smlnj_cm.vim ================================================ " Author: Jake Zimmerman " Description: SML checking with SML/NJ Compilation Manager 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 " Using CM requires that we set "lint_file: 1", since it reads the files " from the disk itself. call ale#linter#Define('sml', { \ 'name': 'smlnj_cm', \ 'aliases': ['smlnj-cm'], \ 'executable': function('ale#handlers#sml#GetExecutableSmlnjCm'), \ 'lint_file': 1, \ 'command': function('ale_linters#sml#smlnj_cm#GetCommand'), \ 'callback': 'ale#handlers#sml#Handle', \}) " vim:ts=4:sts=4:sw=4 ================================================ FILE: ale_linters/solidity/solc.vim ================================================ " Author: Karl Bartel - http://karl.berlin/ " Description: Report solc compiler errors in Solidity code call ale#Set('solidity_solc_executable', 'solc') call ale#Set('solidity_solc_options', '') function! ale_linters#solidity#solc#Handle(buffer, lines) abort " Matches patterns like the following: " Error: Expected ';' but got '(' " --> /path/to/file/file.sol:1:10:) let l:pattern = '\v(Error|Warning): (.*)$' let l:line_and_column_pattern = '\v\.sol:(\d+):(\d+):' let l:output = [] 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:line_and_column_pattern) if len(l:match) > 0 let l:index = len(l:output) - 1 let l:output[l:index]['lnum'] = l:match[1] + 0 let l:output[l:index]['col'] = l:match[2] + 0 endif else let l:isError = l:match[1] is? 'Error' call add(l:output, { \ 'lnum': 0, \ 'col': 0, \ 'text': l:match[2], \ 'type': l:isError ? 'E' : 'W', \}) endif endfor return l:output endfunction function! ale_linters#solidity#solc#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'solidity_solc_executable') return l:executable . ale#Pad(ale#Var(a:buffer, 'solidity_solc_options')) . ' %s' endfunction call ale#linter#Define('solidity', { \ 'name': 'solc', \ 'executable': {b -> ale#Var(b, 'solidity_solc_executable')}, \ 'command': function('ale_linters#solidity#solc#GetCommand'), \ 'callback': 'ale_linters#solidity#solc#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/solidity/solhint.vim ================================================ " Authors: Franco Victorio <@fvictorio>, Henrique Barcelos <@hbarcelos> " Description: Report errors in Solidity code with solhint call ale#Set('solidity_solhint_options', '') call ale#Set('solidity_solhint_executable', 'solhint') call ale#Set('solidity_solhint_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#solidity#solhint#Handle(buffer, lines) abort let l:output = [] " Matches lines like the following: " contracts/Bounty.sol:14:3: Expected indentation of 4 spaces but found 2 [Error/indent] let l:lint_pattern = '\v^[^:]+:(\d+):(\d+): %(Parse error: )@ \ ale#node#Executable(b, ale_linters#solidity#solhint#GetExecutable(b)) \ . ale#Pad(ale#Var(b, 'solidity_solhint_options')) \ . ' --formatter unix %s' \ }, \ 'callback': 'ale_linters#solidity#solhint#Handle', \}) ================================================ FILE: ale_linters/solidity/solium.vim ================================================ " Author: Jeff Sutherland - https://github.com/jdsutherland " Description: Report errors in Solidity code with solium call ale#linter#Define('solidity', { \ 'name': 'solium', \ 'executable': 'solium', \ 'command': 'solium --reporter gcc --file %t', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \}) ================================================ FILE: ale_linters/spec/rpmlint.vim ================================================ " Author: Jason Tibbitts " Description: Adds support for checking RPM spec files with rpmlint " rpmlint will produce varions types of output: " " Lines like the following are output when the file is simply not able to be " parsed by rpmspec -P: " apcupsd.spec: E: specfile-error warning: bogus date in %changelog: Mon Oct 1 2005 - Foo " apcupsd.spec: E: specfile-error error: %changelog not in descending chronological order " They do not contain a line number, and there's not a whole lot that can be " done to locate them besides grep for them. rpmlint is just passing the " output from rpm along with the filename, an error indicator, and an error " type. " " Lines like the following: " cyrus-imapd.spec:23: W: macro-in-comment %version " cyrus-imapd.spec:18: E: hardcoded-library-path in %_prefix/lib/%name " indicate warnings and errors, respectively. No column numbers are provided " " Lines like: " apcupsd.spec: I: checking " apcupsd.spec: I: checking-url https://downloads.sourceforge.net/apcupsd/apcupsd-3.14.14.tar.gz (timeout 10 seconds) " are merely informational and are only output when -v is passed. But they " may be useful in a log to know why things are taking so long. " " And this is always output at the end and should just be ignored: " 0 packages and 1 specfiles checked; 4 errors, 0 warnings. call ale#Set('spec_rpmlint_executable', 'rpmlint') call ale#Set('spec_rpmlint_options', '') function! ale_linters#spec#rpmlint#GetCommand(buffer, version) abort if ale#semver#GTE(a:version, [2, 0, 0]) " The -o/--option flag was removed in version 2.0.0 let l:version_dependent_args = '' else let l:version_dependent_args = ' -o "NetworkEnabled False"' endif return '%e' \ . ale#Pad(ale#Var(a:buffer, 'spec_rpmlint_options')) \ . ' -v' \ . l:version_dependent_args \ . ' %t' endfunction function! ale_linters#spec#rpmlint#Handle(buffer, lines) abort " let l:pat_inform = '^.\+: I: \(.+\)' let l:pat_errwarn = '^.\+:\(\d\+\): \([EW]\): \(.\+\)' let l:pat_baderr = '^.\+: E: \(.\+\)' let l:output = [] for l:line in a:lines let l:match_errwarn = matchlist(l:line, l:pat_errwarn) let l:match_baderr = matchlist(l:line, l:pat_baderr) if len(l:match_errwarn) > 0 let l:text = l:match_errwarn[3] let l:type = l:match_errwarn[2] let l:lnum = l:match_errwarn[1] + 0 elseif len(l:match_baderr) > 0 let l:text = l:match_baderr[1] let l:type = 'E' let l:lnum = 1 else continue endif call add(l:output, { \ 'bufnr': a:buffer, \ 'lnum': l:lnum, \ 'text': l:text, \ 'type': l:type, \}) endfor return l:output endfunction call ale#linter#Define('spec', { \ 'name': 'rpmlint', \ 'executable': {b -> ale#Var(b, 'spec_rpmlint_executable')}, \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'spec_rpmlint_executable'), \ '%e --version', \ function('ale_linters#spec#rpmlint#GetCommand'), \ )}, \ 'callback': 'ale_linters#spec#rpmlint#Handle', \}) ================================================ FILE: ale_linters/sql/sqlfluff.vim ================================================ " Author: Carl Smedstad " Description: sqlfluff for SQL files let g:ale_sql_sqlfluff_executable = \ get(g:, 'ale_sql_sqlfluff_executable', 'sqlfluff') let g:ale_sql_sqlfluff_options = \ get(g:, 'ale_sql_sqlfluff_options', '') function! ale_linters#sql#sqlfluff#Executable(buffer) abort return ale#Var(a:buffer, 'sql_sqlfluff_executable') endfunction function! ale_linters#sql#sqlfluff#Command(buffer, version) abort let l:executable = ale_linters#sql#sqlfluff#Executable(a:buffer) let l:options = ale#Var(a:buffer, 'sql_sqlfluff_options') let l:cmd = \ ale#Escape(l:executable) \ . ' lint' let l:config_file = ale#path#FindNearestFile(a:buffer, '.sqlfluff') if !empty(l:config_file) let l:cmd .= ' --config ' . ale#Escape(l:config_file) else let l:cmd .= ' --dialect ansi' endif let l:cmd .= \ ' --format json ' \ . l:options \ . ' %t' return l:cmd endfunction function! ale_linters#sql#sqlfluff#Handle(buffer, version, lines) abort let l:output = [] let l:json_lines = ale#util#FuzzyJSONDecode(a:lines, []) if empty(l:json_lines) return l:output endif let l:json = l:json_lines[0] " if there's no warning, 'result' is `null`. if empty(get(l:json, 'violations')) return l:output endif if ale#semver#GTE(a:version, [3, 0, 0]) for l:violation in get(l:json, 'violations', []) let l:err = { \ 'filename': l:json.filepath, \ 'lnum': l:violation.start_line_no, \ 'col': l:violation.start_line_pos, \ 'text': l:violation.description, \ 'code': l:violation.code, \ 'type': 'W', \} if has_key(l:violation, 'end_line_no') let l:err.end_lnum = l:violation.end_line_no endif if has_key(l:violation, 'end_line_pos') let l:err.end_col = l:violation.end_line_pos endif call add(l:output, l:err) endfor else for l:violation in get(l:json, 'violations', []) call add(l:output, { \ 'filename': l:json.filepath, \ 'lnum': l:violation.line_no, \ 'col': l:violation.line_pos, \ 'text': l:violation.description, \ 'code': l:violation.code, \ 'type': 'W', \}) endfor endif return l:output endfunction call ale#linter#Define('sql', { \ 'name': 'sqlfluff', \ 'executable': function('ale_linters#sql#sqlfluff#Executable'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#sql#sqlfluff#Executable(buffer), \ '%e --version', \ function('ale_linters#sql#sqlfluff#Command'), \ )}, \ 'callback': {buffer, lines -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#sql#sqlfluff#Executable(buffer), \ '%e --version', \ {buffer, version -> ale_linters#sql#sqlfluff#Handle( \ buffer, \ l:version, \ lines)}, \ )}, \}) ================================================ FILE: ale_linters/sql/sqlint.vim ================================================ " Author: Adriaan Zonnenberg " Description: sqlint for SQL files function! ale_linters#sql#sqlint#Handle(buffer, lines) abort " Matches patterns like the following: " " stdin:3:1:ERROR syntax error at or near "WIBBLE" let l:pattern = '\v^[^:]+:(\d+):(\d+):(\u+) (.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3][0], \ 'text': l:match[4], \}) endfor return l:output endfunction call ale#linter#Define('sql', { \ 'name': 'sqlint', \ 'executable': 'sqlint', \ 'command': 'sqlint', \ 'callback': 'ale_linters#sql#sqlint#Handle', \}) ================================================ FILE: ale_linters/sql/sqllint.vim ================================================ " ale_linters/sql/sqllint.vim " Author: Joe Reynolds " Description: sql-lint for SQL files. " sql-lint can be found at " https://www.npmjs.com/package/sql-lint " https://github.com/joereynolds/sql-lint function! ale_linters#sql#sqllint#Handle(buffer, lines) abort " Matches patterns like the following: " " stdin:1 [ER_NO_DB_ERROR] No database selected let l:pattern = '\v^[^:]+:(\d+) (.*)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3][0], \ 'text': l:match[0], \}) endfor return l:output endfunction call ale#linter#Define('sql', { \ 'name': 'sqllint', \ 'aliases': ['sql-lint'], \ 'executable': 'sql-lint', \ 'command': 'sql-lint', \ 'callback': 'ale_linters#sql#sqllint#Handle', \}) ================================================ FILE: ale_linters/stylus/stylelint.vim ================================================ " Author: diartyz , w0rp 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#GetCommand(buffer) abort return '%e' \ . ale#Pad(ale#Var(a:buffer, 'stylus_stylelint_options')) \ . ' --no-color --stdin-filename %s' endfunction call ale#linter#Define('stylus', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': {b -> ale#path#FindExecutable(b, 'stylus_stylelint', [ \ 'node_modules/.bin/stylelint', \ ])}, \ 'command': function('ale_linters#stylus#stylelint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/sugarss/stylelint.vim ================================================ " Author: toastal " Description: `stylelint` linter for SugarSS files call ale#Set('sugarss_stylelint_executable', 'stylelint') call ale#Set('sugarss_stylelint_options', '') call ale#Set('sugarss_stylelint_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#sugarss#stylelint#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'sugarss_stylelint_options')) \ . ' --syntax=sugarss' \ . ' --no-color --stdin-filename %s' endfunction call ale#linter#Define('sugarss', { \ 'name': 'stylelint', \ 'output_stream': 'both', \ 'executable': {b -> ale#path#FindExecutable(b, 'sugarss_stylelint', [ \ 'node_modules/.bin/stylelint', \ ])}, \ 'command': function('ale_linters#sugarss#stylelint#GetCommand'), \ 'callback': 'ale#handlers#css#HandleStyleLintFormat', \}) ================================================ FILE: ale_linters/svelte/svelteserver.vim ================================================ " Author: Joakim Repomaa " Description: Svelte Language Server integration for ALE call ale#Set('svelte_svelteserver_executable', 'svelteserver') call ale#Set('svelte_svelteserver_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#svelte#svelteserver#GetProjectRoot(buffer) abort let l:package_path = ale#path#FindNearestFile(a:buffer, 'package.json') return !empty(l:package_path) ? fnamemodify(l:package_path, ':h') : '' endfunction call ale#linter#Define('svelte', { \ 'name': 'svelteserver', \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'svelte_svelteserver', [ \ 'node_modules/.bin/svelteserver', \ ])}, \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#svelte#svelteserver#GetProjectRoot'), \}) ================================================ FILE: ale_linters/swift/appleswiftformat.vim ================================================ " Authors: Klaas Pieter Annema , bosr " Description: Support for swift-format https://github.com/apple/swift-format function! ale_linters#swift#appleswiftformat#GetLinterCommand(buffer) abort let l:command_args = ale#swift#GetAppleSwiftFormatCommand(a:buffer) . ' lint %t' let l:config_args = ale#swift#GetAppleSwiftFormatConfigArgs(a:buffer) if l:config_args isnot# '' let l:command_args = l:command_args . ' ' . l:config_args endif return l:command_args endfunction function! ale_linters#swift#appleswiftformat#Handle(buffer, lines) abort " Matches the typical output of swift-format, that is lines of the following pattern: " " Sources/main.swift:4:21: warning: [DoNotUseSemicolons] remove ';' and move the next statement to the new line " Sources/main.swift:3:12: warning: [Spacing] remove 1 space let l:pattern = '\v^.*:(\d+):(\d+): (\S+): \[(\S+)\] (.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3] is# 'error' ? 'E' : 'W', \ 'code': l:match[4], \ 'text': l:match[5], \}) endfor return l:output endfunction call ale#linter#Define('swift', { \ 'name': 'apple-swift-format', \ 'executable': function('ale#swift#GetAppleSwiftFormatExecutable'), \ 'command': function('ale_linters#swift#appleswiftformat#GetLinterCommand'), \ 'output_stream': 'stderr', \ 'language': 'swift', \ 'callback': 'ale_linters#swift#appleswiftformat#Handle' \}) ================================================ FILE: ale_linters/swift/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Swift files. call ale#handlers#cspell#DefineLinter('swift') ================================================ FILE: ale_linters/swift/sourcekitlsp.vim ================================================ " Author: Dan Loman " Description: Support for sourcekit-lsp https://github.com/apple/sourcekit-lsp call ale#Set('sourcekit_lsp_executable', 'sourcekit-lsp') call ale#linter#Define('swift', { \ 'name': 'sourcekitlsp', \ 'aliases': ['sourcekit'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'sourcekit_lsp_executable')}, \ 'command': '%e', \ 'project_root': function('ale#swift#FindProjectRoot'), \ 'language': 'swift', \}) ================================================ FILE: ale_linters/swift/swiftlint.vim ================================================ " Author: David Mohundro , Gordon Fontenot " Description: swiftlint for swift files call ale#Set('swift_swiftlint_executable', 'swiftlint') call ale#Set('swift_swiftlint_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale_linters#swift#swiftlint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'swift_swiftlint', [ \ 'Pods/SwiftLint/swiftlint', \ 'ios/Pods/SwiftLint/swiftlint', \ 'swiftlint', \]) endfunction function! ale_linters#swift#swiftlint#GetCommand(buffer) abort let l:executable = ale_linters#swift#swiftlint#GetExecutable(a:buffer) let l:args = 'lint --use-stdin' return ale#Escape(l:executable) \ . ' ' .l:args endfunction function! ale_linters#swift#swiftlint#Handle(buffer, lines) abort let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': str2nr(l:match[2]), \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'text': l:match[5], \} if l:match[4] is# 'error' let l:item.type = 'E' elseif l:match[4] is# 'note' let l:item.type = 'I' endif if !empty(l:match[3]) let l:item.col = str2nr(l:match[3]) endif " If the filename is something like , or -, then " this is an error for the file we checked. if l:match[1] isnot# '-' && l:match[1][0] isnot# '<' let l:item['filename'] = l:match[1] endif " Parse the code if it's there. let l:code_match = matchlist(l:item.text, '\v^(.+) \(([^ (]+)\)$') if !empty(l:code_match) let l:item.text = l:code_match[1] let l:item.code = l:code_match[2] endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('swift', { \ 'name': 'swiftlint', \ 'executable': function('ale_linters#swift#swiftlint#GetExecutable'), \ 'command': function('ale_linters#swift#swiftlint#GetCommand'), \ 'callback': 'ale_linters#swift#swiftlint#Handle', \}) ================================================ FILE: ale_linters/systemd/systemd_analyze.vim ================================================ function! ale_linters#systemd#systemd_analyze#Handle(buffer, lines) abort return ale#util#MapMatches(a:lines, '\v(.+):([0-9]+): (.+)', {match -> { \ 'lnum': str2nr(match[2]), \ 'col': 1, \ 'type': 'W', \ 'text': match[3], \}}) endfunction call ale#linter#Define('systemd', { \ 'name': 'systemd_analyze', \ 'aliases': ['systemd-analyze'], \ 'executable': 'systemd-analyze', \ 'command': 'SYSTEMD_LOG_COLOR=0 %e --user verify %s', \ 'callback': 'ale_linters#systemd#systemd_analyze#Handle', \ 'output_stream': 'both', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/tcl/nagelfar.vim ================================================ " Author: Nick James " Description: nagelfar linter for tcl files call ale#Set('tcl_nagelfar_executable', 'nagelfar.tcl') call ale#Set('tcl_nagelfar_options', '') function! ale_linters#tcl#nagelfar#GetCommand(buffer) abort let l:options = ale#Var(a:buffer, 'tcl_nagelfar_options') return '%e' . ale#Pad(l:options) . ' %s' endfunction function! ale_linters#tcl#nagelfar#Handle(buffer, lines) abort " Matches patterns like the following: " 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 = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'type': l:match[2] is# 'N' ? 'W' : l:match[2], \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('tcl', { \ 'name': 'nagelfar', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'tcl_nagelfar_executable')}, \ 'command': function('ale_linters#tcl#nagelfar#GetCommand'), \ 'callback': 'ale_linters#tcl#nagelfar#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/terraform/checkov.vim ================================================ " Author: Thyme-87 " Description: use checkov for providing warnings via ale call ale#Set('terraform_checkov_executable', 'checkov') call ale#Set('terraform_checkov_options', '') function! ale_linters#terraform#checkov#GetExecutable(buffer) abort return ale#Var(a:buffer, 'terraform_checkov_executable') endfunction function! ale_linters#terraform#checkov#GetCommand(buffer) abort return '%e ' . '-f %t -o json --quiet ' . ale#Var(a:buffer, 'terraform_checkov_options') endfunction function! ale_linters#terraform#checkov#Handle(buffer, lines) abort let l:output = [] let l:results = get(get(ale#util#FuzzyJSONDecode(a:lines, {}), 'results', []), 'failed_checks', []) for l:violation in l:results call add(l:output, { \ 'filename': l:violation['file_path'], \ 'lnum': l:violation['file_line_range'][0], \ 'end_lnum': l:violation['file_line_range'][1], \ 'text': l:violation['check_name'] . ' [' . l:violation['check_id'] . ']', \ 'detail': l:violation['check_id'] . ': ' . l:violation['check_name'] . "\n" . \ 'For more information, see: '. l:violation['guideline'], \ 'type': 'W', \ }) endfor return l:output endfunction call ale#linter#Define('terraform', { \ 'name': 'checkov', \ 'output_stream': 'stdout', \ 'executable': function('ale_linters#terraform#checkov#GetExecutable'), \ 'command': function('ale_linters#terraform#checkov#GetCommand'), \ 'callback': 'ale_linters#terraform#checkov#Handle', \}) ================================================ FILE: ale_linters/terraform/terraform.vim ================================================ " Author: Keith Maxwell " Description: terraform fmt to check for errors call ale#Set('terraform_terraform_executable', 'terraform') function! ale_linters#terraform#terraform#GetExecutable(buffer) abort return ale#Var(a:buffer, 'terraform_terraform_executable') endfunction function! ale_linters#terraform#terraform#GetCommand(buffer) abort return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer)) \ . ' validate -no-color -json ' endfunction function! ale_linters#terraform#terraform#GetType(severity) abort if a:severity is? 'warning' return 'W' endif return 'E' endfunction function! ale_linters#terraform#terraform#GetDetail(error) abort let l:detail = get(a:error, 'detail', '') if strlen(l:detail) > 0 return l:detail else return get(a:error, 'summary', '') endif endfunction function! ale_linters#terraform#terraform#Handle(buffer, lines) abort let l:output = [] let l:errors = ale#util#FuzzyJSONDecode(a:lines, {'diagnostics': []}) let l:dir = expand('#' . a:buffer . ':p:h') let l:file = expand('#' . a:buffer . ':p') for l:error in l:errors['diagnostics'] if has_key(l:error, 'range') call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:error['range']['filename']), \ 'lnum': l:error['range']['start']['line'], \ 'col': l:error['range']['start']['column'], \ 'text': ale_linters#terraform#terraform#GetDetail(l:error), \ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']), \}) else call add(l:output, { \ 'filename': l:file, \ 'lnum': 0, \ 'col': 0, \ 'text': ale_linters#terraform#terraform#GetDetail(l:error), \ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']), \}) endif endfor return l:output endfunction call ale#linter#Define('terraform', { \ 'name': 'terraform', \ 'output_stream': 'stdout', \ 'executable': function('ale_linters#terraform#terraform#GetExecutable'), \ 'command': function('ale_linters#terraform#terraform#GetCommand'), \ 'callback': 'ale_linters#terraform#terraform#Handle', \}) ================================================ FILE: ale_linters/terraform/terraform_ls.vim ================================================ " Author: Horacio Sanson " Description: terraform-ls integration for ALE (cf. https://github.com/hashicorp/terraform-ls) call ale#Set('terraform_terraform_executable', 'terraform') call ale#Set('terraform_ls_executable', 'terraform-ls') call ale#Set('terraform_ls_options', '') function! ale_linters#terraform#terraform_ls#GetTerraformExecutable(buffer) abort let l:terraform_executable = ale#Var(a:buffer, 'terraform_terraform_executable') if(ale#path#IsAbsolute(l:terraform_executable)) return '-tf-exec ' . l:terraform_executable endif return '' endfunction function! ale_linters#terraform#terraform_ls#GetCommand(buffer) abort return '%e' \ . ale#Pad('serve') \ . ale#Pad(ale_linters#terraform#terraform_ls#GetTerraformExecutable(a:buffer)) \ . ale#Pad(ale#Var(a:buffer, 'terraform_ls_options')) endfunction function! ale_linters#terraform#terraform_ls#GetProjectRoot(buffer) abort let l:tf_dir = ale#path#FindNearestDirectory(a:buffer, '.terraform') return !empty(l:tf_dir) ? fnamemodify(l:tf_dir, ':h:h') : '' endfunction call ale#linter#Define('terraform', { \ 'name': 'terraform_ls', \ 'aliases': ['terraformls'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'terraform_ls_executable')}, \ 'command': function('ale_linters#terraform#terraform_ls#GetCommand'), \ 'project_root': function('ale_linters#terraform#terraform_ls#GetProjectRoot'), \ 'language': 'terraform', \}) ================================================ FILE: ale_linters/terraform/terraform_lsp.vim ================================================ " Author: OJFord " Description: terraform-lsp integration for ALE (cf. https://github.com/juliosueiras/terraform-lsp) call ale#Set('terraform_langserver_executable', 'terraform-lsp') call ale#Set('terraform_langserver_options', '') function! ale_linters#terraform#terraform_lsp#GetCommand(buffer) abort return '%e' \ . ale#Pad(ale#Var(a:buffer, 'terraform_langserver_options')) endfunction function! ale_linters#terraform#terraform_lsp#GetProjectRoot(buffer) abort let l:tf_dir = ale#path#FindNearestDirectory(a:buffer, '.terraform') return !empty(l:tf_dir) ? fnamemodify(l:tf_dir, ':h:h') : '' endfunction call ale#linter#Define('terraform', { \ 'name': 'terraform_lsp', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'terraform_langserver_executable')}, \ 'command': function('ale_linters#terraform#terraform_lsp#GetCommand'), \ 'project_root': function('ale_linters#terraform#terraform_lsp#GetProjectRoot'), \ 'language': 'terraform', \}) ================================================ FILE: ale_linters/terraform/tflint.vim ================================================ " Author: Nat Williams " Description: tflint for Terraform files " " See: https://www.terraform.io/ " https://github.com/wata727/tflint call ale#Set('terraform_tflint_options', '') call ale#Set('terraform_tflint_executable', 'tflint') function! ale_linters#terraform#tflint#Handle(buffer, lines) abort let l:output = [] let l:pattern = '\v^(.*):(\d+),(\d+)-(\d+)?,?(\d+): (.{-1,}); (.+)$' let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) " This is a rough test for tflint's output format " On versions prior to 0.11 it outputs all errors as a single level list if type(l:json) is v:t_list for l:error in l:json if l:error.type is# 'ERROR' let l:type = 'E' elseif l:error.type is# 'NOTICE' let l:type = 'I' else let l:type = 'W' endif call add(l:output, { \ 'lnum': l:error.line, \ 'text': l:error.message, \ 'type': l:type, \ 'code': l:error.detector, \}) endfor else for l:error in get(l:json, 'errors', []) for l:match in ale#util#GetMatches(l:error.message, [l:pattern]) if l:match[4] is# '' let l:match[4] = l:match[2] endif call add(l:output, { \ 'filename': l:match[1], \ 'lnum': str2nr(l:match[2]), \ 'col': str2nr(l:match[3]), \ 'end_lnum': str2nr(l:match[4]), \ 'end_col': str2nr(l:match[5]), \ 'text': l:match[7], \ 'code': l:match[6], \ 'type': 'E', \}) endfor endfor for l:error in get(l:json, 'issues', []) if l:error.rule.severity is# 'ERROR' let l:type = 'E' elseif l:error.rule.severity is# 'NOTICE' let l:type = 'I' else let l:type = 'W' endif call add(l:output, { \ 'filename': l:error.range.filename, \ 'lnum': l:error.range.start.line, \ 'col': l:error.range.start.column, \ 'end_lnum': l:error.range.end.line, \ 'end_col': l:error.range.end.column, \ 'text': l:error.message, \ 'code': l:error.rule.name, \ 'type': l:type, \}) endfor endif return l:output endfunction function! ale_linters#terraform#tflint#GetCommand(buffer) abort 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 let l:cmd .= ' -f json' return l:cmd endfunction call ale#linter#Define('terraform', { \ 'name': 'tflint', \ 'executable': {b -> ale#Var(b, 'terraform_tflint_executable')}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#terraform#tflint#GetCommand'), \ 'callback': 'ale_linters#terraform#tflint#Handle', \}) ================================================ FILE: ale_linters/terraform/tfsec.vim ================================================ " Description: tfsec for Terraform files " " See: https://www.terraform.io/ " https://github.com/aquasecurity/tfsec call ale#Set('terraform_tfsec_options', '') call ale#Set('terraform_tfsec_executable', 'tfsec') let s:separator = has('win32') ? '\' : '/' function! ale_linters#terraform#tfsec#Handle(buffer, lines) abort let l:output = [] let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) " if there's no warning, 'result' is `null`. if empty(get(l:json, 'results')) return l:output endif for l:result in get(l:json, 'results', []) if l:result.severity is# 'LOW' let l:type = 'I' elseif l:result.severity is# 'CRITICAL' let l:type = 'E' else let l:type = 'W' endif call add(l:output, { \ 'filename': l:result.location.filename, \ 'lnum': l:result.location.start_line, \ 'end_lnum': l:result.location.end_line, \ 'text': l:result.description, \ 'code': l:result.long_id, \ 'type': l:type, \}) endfor return l:output endfunction " Construct command arguments to tfsec with `terraform_tfsec_options`. function! ale_linters#terraform#tfsec#GetCommand(buffer) abort let l:cmd = '%e' let l:config = ale_linters#terraform#tfsec#FindConfig(a:buffer) if !empty(l:config) let l:cmd .= ' --config-file ' . l:config endif let l:opts = ale#Var(a:buffer, 'terraform_tfsec_options') if !empty(l:opts) let l:cmd .= ' ' . l:opts endif let l:cmd .= ' --format json' return l:cmd endfunction " Find the nearest configuration file of tfsec. function! ale_linters#terraform#tfsec#FindConfig(buffer) abort let l:config_dir = ale#path#FindNearestDirectory(a:buffer, '.tfsec') if !empty(l:config_dir) " https://aquasecurity.github.io/tfsec/v1.28.0/guides/configuration/config/ for l:basename in ['config.yml', 'config.json'] let l:config = ale#path#Simplify(join([l:config_dir, l:basename], s:separator)) if filereadable(l:config) return ale#Escape(l:config) endif endfor endif return '' endfunction call ale#linter#Define('terraform', { \ 'name': 'tfsec', \ 'executable': {b -> ale#Var(b, 'terraform_tfsec_executable')}, \ 'cwd': '%s:h', \ 'command': function('ale_linters#terraform#tfsec#GetCommand'), \ 'callback': 'ale_linters#terraform#tfsec#Handle', \}) ================================================ FILE: ale_linters/testft/testlinter.vim ================================================ " Author: neersighted " Description: dummy linter to use in tests call ale#linter#Define('testft', { \ 'name': 'testlinter', \ 'output_stream': 'stdout', \ 'executable': 'testlinter', \ 'command': 'testlinter', \ 'callback': 'testCB', \}) ================================================ FILE: ale_linters/tex/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for TeX files call ale#handlers#alex#DefineLinter('tex', '--text') ================================================ FILE: ale_linters/tex/chktex.vim ================================================ " Author: Andrew Balmos - " Description: chktex for LaTeX files call ale#Set('tex_chktex_executable', 'chktex') call ale#Set('tex_chktex_options', '-I') function! ale_linters#tex#chktex#GetExecutable(buffer) abort return ale#Var(a:buffer, 'tex_chktex_executable') endfunction function! ale_linters#tex#chktex#GetCommand(buffer, version) abort let l:options = '' " Avoid bug when used without -p (last warning has gibberish for a filename) let l:options .= ' -v0 -p stdin -q' " Avoid bug of reporting wrong column when using tabs (issue #723) if ale#semver#GTE(a:version, [1, 7, 7]) let l:options .= ' -S TabSize=1' endif " Check for optional .chktexrc let l:chktex_config = ale#path#FindNearestFile(a:buffer, '.chktexrc') if !empty(l:chktex_config) let l:options .= ' -l ' . ale#Escape(l:chktex_config) endif let l:options .= ' ' . ale#Var(a:buffer, 'tex_chktex_options') return '%e' . l:options endfunction function! ale_linters#tex#chktex#Handle(buffer, lines) abort " Mattes lines like: " " stdin:499:2:24:Delete this space to maintain correct pagereferences. " stdin:507:81:3:You should enclose the previous parenthesis with `{}'. let l:pattern = '^stdin:\(\d\+\):\(\d\+\):\(\d\+\):\(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[4] . ' (' . (l:match[3]+0) . ')', \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('tex', { \ 'name': 'chktex', \ 'executable': function('ale_linters#tex#chktex#GetExecutable'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale_linters#tex#chktex#GetExecutable(buffer), \ '%e --version', \ function('ale_linters#tex#chktex#GetCommand'), \ )}, \ 'callback': 'ale_linters#tex#chktex#Handle' \}) ================================================ FILE: ale_linters/tex/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for TeX files. call ale#handlers#cspell#DefineLinter('tex') ================================================ FILE: ale_linters/tex/lacheck.vim ================================================ " Author: Andrew Balmos - " Description: lacheck for LaTeX files 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 = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) " lacheck follows `\input{}` commands. If the cwd is not the same as the " file in the buffer then it will fail to find the inputted items. We do not " want warnings from those items anyway if !empty(matchstr(l:match[3], '^Could not open ".\+"$')) continue endif " lacheck follows `\input{}` commands. We are only interested in " reporting errors for the current buffer only. if empty(matchstr(fnamemodify(l:match[1], ':t'), fnamemodify(bufname(a:buffer), ':t'))) continue endif call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'text': l:match[3], \ 'type': 'W', \}) endfor return l:output endfunction call ale#linter#Define('tex', { \ 'name': 'lacheck', \ 'executable': {b -> ale#Var(b, 'tex_lacheck_executable')}, \ 'command': '%e %t', \ 'callback': 'ale_linters#tex#lacheck#Handle' \}) ================================================ FILE: ale_linters/tex/proselint.vim ================================================ " Author: poohzrn https://github.com/poohzrn " Description: proselint for TeX files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('tex', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/tex/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#handlers#redpen#DefineLinter('tex') ================================================ FILE: ale_linters/tex/texlab.vim ================================================ " Author: Ricardo Liang " Author: ourigen " Description: Texlab language server (Rust rewrite) call ale#Set('tex_texlab_executable', 'texlab') call ale#Set('tex_texlab_options', '') call ale#Set('tex_texlab_config', {}) function! ale_linters#tex#texlab#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 function! ale_linters#tex#texlab#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'tex_texlab_options')) endfunction call ale#linter#Define('tex', { \ 'name': 'texlab', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'tex_texlab_executable')}, \ 'command': function('ale_linters#tex#texlab#GetCommand'), \ 'project_root': function('ale_linters#tex#texlab#GetProjectRoot'), \ 'lsp_config': {b -> ale#Var(b, 'tex_texlab_config')}, \}) ================================================ FILE: ale_linters/tex/textlint.vim ================================================ " Author: TANIGUCHI Masaya " Description: textlint for LaTeX files call ale#linter#Define('tex', { \ 'name': 'textlint', \ 'executable': function('ale#handlers#textlint#GetExecutable'), \ 'command': function('ale#handlers#textlint#GetCommand'), \ 'callback': 'ale#handlers#textlint#HandleTextlintOutput', \}) ================================================ FILE: ale_linters/tex/vale.vim ================================================ " Author: chew-z https://github.com/chew-z " Description: vale for LaTeX files call ale#linter#Define('tex', { \ 'name': 'vale', \ 'executable': 'vale', \ 'command': 'vale --output=JSON %t', \ 'callback': 'ale#handlers#vale#Handle', \}) ================================================ FILE: ale_linters/tex/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for TeX files call ale#handlers#writegood#DefineLinter('tex') ================================================ FILE: ale_linters/texinfo/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for texinfo files call ale#handlers#alex#DefineLinter('texinfo', '--text') ================================================ FILE: ale_linters/texinfo/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for TeXInfo files. call ale#handlers#cspell#DefineLinter('texinfo') ================================================ FILE: ale_linters/texinfo/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for Texinfo files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('texinfo', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/texinfo/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for Texinfo files call ale#handlers#writegood#DefineLinter('texinfo') ================================================ FILE: ale_linters/text/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for text files call ale#handlers#alex#DefineLinter('text', '--text') ================================================ FILE: ale_linters/text/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for general text files. call ale#handlers#cspell#DefineLinter('text') ================================================ FILE: ale_linters/text/languagetool.vim ================================================ " Author: Vincent (wahrwolf [ät] wolfpit.net) " Description: languagetool for text files call ale#handlers#languagetool#DefineLinter('text') ================================================ FILE: ale_linters/text/proselint.vim ================================================ " Author: poohzrn https://github.com/poohzrn " Description: proselint for text files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('text', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/text/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#handlers#redpen#DefineLinter('text') ================================================ FILE: ale_linters/text/textlint.vim ================================================ " Author: Yasuhiro Kiyota " Description: textlint, a proofreading tool (https://textlint.github.io/) call ale#linter#Define('text', { \ 'name': 'textlint', \ 'executable': function('ale#handlers#textlint#GetExecutable'), \ 'command': function('ale#handlers#textlint#GetCommand'), \ 'callback': 'ale#handlers#textlint#HandleTextlintOutput', \}) ================================================ FILE: ale_linters/text/vale.vim ================================================ " Author: chew-z https://github.com/chew-z " Description: vale for text files call ale#Set('vale_executable', 'vale') call ale#Set('vale_options', '') function! ale_linters#text#vale#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'vale_executable') let l:options = ale#Var(a:buffer, 'vale_options') return ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' --output=JSON %t' endfunction call ale#linter#Define('text', { \ 'name': 'vale', \ 'executable': 'vale', \ 'command': function('ale_linters#text#vale#GetCommand'), \ 'callback': 'ale#handlers#vale#Handle', \}) ================================================ FILE: ale_linters/text/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for text files call ale#handlers#writegood#DefineLinter('text') ================================================ FILE: ale_linters/thrift/thrift.vim ================================================ " Author: Jon Parise 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_options', '-strict') 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') " The thrift compiler requires at least one generator. If none are set, " fall back to our default value to avoid silently failing. We could also " `throw` here, but that seems even less helpful. if empty(l:generators) let l:generators = ['cpp'] endif let l:output_dir = ale#command#CreateDirectory(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')) \ . ' -out ' . ale#Escape(l:output_dir) \ . ' %t' endfunction function! ale_linters#thrift#thrift#Handle(buffer, lines) abort " Matches lines like the following: " " [SEVERITY:/path/filename.thrift:31] Message text " [ERROR:/path/filename.thrift:31] (last token was ';') let l:pattern = '\v^\[(\u+):(.*):(\d+)\] (.*)$' let l:index = 0 let l:output = [] " Roll our own output-matching loop instead of using ale#util#GetMatches " because we need to support error messages that span multiple lines. while l:index < len(a:lines) 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 let l:type = 'E' endif " 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) endif call add(l:output, { \ 'lnum': l:match[3] + 0, \ 'col': 0, \ 'type': l:type, \ 'text': l:text, \}) let l:index += 1 endwhile return l:output endfunction call ale#linter#Define('thrift', { \ 'name': 'thrift', \ 'output_stream': 'both', \ 'executable': {b -> ale#Var(b, 'thrift_thrift_executable')}, \ 'command': function('ale_linters#thrift#thrift#GetCommand'), \ 'callback': 'ale_linters#thrift#thrift#Handle', \}) ================================================ FILE: ale_linters/thrift/thriftcheck.vim ================================================ " Author: Jon Parise call ale#Set('thrift_thriftcheck_executable', 'thriftcheck') call ale#Set('thrift_thriftcheck_options', '') function! ale_linters#thrift#thriftcheck#GetCommand(buffer) abort return '%e' \ . ale#Pad(ale#Var(a:buffer, 'thrift_thriftcheck_options')) \ . ' --stdin-filename %s' \ . ' %t' endfunction function! ale_linters#thrift#thriftcheck#Handle(buffer, lines) abort " Matches lines like the following: " " file.thrift:1:1: error: "py" namespace must match "^idl\\." (namespace.pattern) " file.thrift:3:5: warning: 64-bit integer constant -2147483649 may not work in all languages (int.64bit) let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):(\d+): ?([^:]+): (.+) \(([^\)]+)\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if l:match[3] is# 'warning' let l:type = 'W' else let l:type = 'E' endif call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:type, \ 'text': l:match[4], \ 'code': l:match[5], \}) endfor return l:output endfunction call ale#linter#Define('thrift', { \ 'name': 'thriftcheck', \ 'executable': {b -> ale#Var(b, 'thrift_thriftcheck_executable')}, \ 'command': function('ale_linters#thrift#thriftcheck#GetCommand'), \ 'callback': 'ale_linters#thrift#thriftcheck#Handle', \}) ================================================ FILE: ale_linters/toml/tombi.vim ================================================ " Author: Ben Boeckel " Description: TOML Formatter / Linter / Language Server call ale#Set('toml_tombi_executable', 'tombi') call ale#Set('toml_tombi_lsp_options', '') call ale#Set('toml_tombi_online', 0) function! ale_linters#toml#tombi#GetCommand(buffer) abort let l:offline = '' if !ale#Var(a:buffer, 'toml_tombi_online') let l:offline = '--offline' endif return '%e lsp' \ . ale#Pad(l:offline) \ . ale#Pad(ale#Var(a:buffer, 'toml_tombi_lsp_options')) endfunction function! ale_linters#toml#tombi#GetProjectRoot(buffer) abort " Try to find nearest tombi.toml let l:tombiconfig_file = ale#path#FindNearestFile(a:buffer, 'tombi.toml') if !empty(l:tombiconfig_file) return fnamemodify(l:tombiconfig_file . '/', ':p:h:h') endif " Try to find nearest pyproject.toml let l:pyproject_file = ale#path#FindNearestFile(a:buffer, 'pyproject.toml') if !empty(l:pyproject_file) return fnamemodify(l:pyproject_file . '/', ':p:h:h') endif " Try to find nearest `git` directory let l:gitdir = ale#path#FindNearestFile(a:buffer, '.git') if !empty(l:gitdir) return fnamemodify(l:gitdir . '/', ':p:h:h') endif return '' endfunction call ale#linter#Define('toml', { \ 'name': 'tombi', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'toml_tombi_executable')}, \ 'command': function('ale_linters#toml#tombi#GetCommand'), \ 'project_root': function('ale_linters#toml#tombi#GetProjectRoot'), \}) ================================================ FILE: ale_linters/typescript/biome.vim ================================================ " Author: Filip Gospodinov " Description: biome for TypeScript files call ale#linter#Define('typescript', { \ 'name': 'biome', \ 'lsp': 'stdio', \ 'language': function('ale#handlers#biome#GetLanguage'), \ 'executable': function('ale#handlers#biome#GetExecutable'), \ 'command': '%e lsp-proxy', \ 'project_root': function('ale#handlers#biome#GetProjectRoot'), \}) ================================================ FILE: ale_linters/typescript/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for TypeScript files. call ale#handlers#cspell#DefineLinter('typescript') ================================================ FILE: ale_linters/typescript/deno.vim ================================================ " Author: Mohammed Chelouti - https://github.com/motato1 " Arnold Chand " Description: Deno lsp linter for TypeScript files. call ale#linter#Define('typescript', { \ 'name': 'deno', \ 'lsp': 'stdio', \ 'executable': function('ale#handlers#deno#GetExecutable'), \ 'command': '%e lsp', \ 'project_root': function('ale#handlers#deno#GetProjectRoot'), \ 'initialization_options': function('ale#handlers#deno#GetInitializationOptions'), \}) ================================================ FILE: ale_linters/typescript/eslint.vim ================================================ " Author: w0rp " Description: eslint for JavaScript files call ale#linter#Define('typescript', { \ 'name': 'eslint', \ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'cwd': function('ale#handlers#eslint#GetCwd'), \ 'command': function('ale#handlers#eslint#GetCommand'), \ 'callback': 'ale#handlers#eslint#HandleJSON', \}) ================================================ FILE: ale_linters/typescript/standard.vim ================================================ " Author: Ahmed El Gabri <@ahmedelgabri> " Description: standardjs for typescript files call ale#Set('typescript_standard_executable', 'standard') call ale#Set('typescript_standard_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('typescript_standard_options', '') function! ale_linters#typescript#standard#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'typescript_standard', [ \ 'node_modules/standardx/bin/cmd.js', \ 'node_modules/standard/bin/cmd.js', \ 'node_modules/.bin/standard', \]) endfunction function! ale_linters#typescript#standard#GetCommand(buffer) abort let l:executable = ale_linters#typescript#standard#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'typescript_standard_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' --stdin %s' endfunction " standard uses eslint and the output format is the same call ale#linter#Define('typescript', { \ 'name': 'standard', \ 'executable': function('ale_linters#typescript#standard#GetExecutable'), \ 'command': function('ale_linters#typescript#standard#GetCommand'), \ 'callback': 'ale#handlers#eslint#Handle', \}) ================================================ FILE: ale_linters/typescript/tslint.vim ================================================ " Author: Prashanth Chandra , Jonathan Clem " Description: tslint for TypeScript files call ale#handlers#tslint#InitVariables() function! ale_linters#typescript#tslint#Handle(buffer, lines) abort " Do not output any errors for empty files if the option is on. if ale#Var(a:buffer, 'typescript_tslint_ignore_empty_files') \&& getbufline(a:buffer, 1, '$') == [''] return [] endif let l:dir = expand('#' . a:buffer . ':p:h') let l:output = [] for l:error in ale#util#FuzzyJSONDecode(a:lines, []) if get(l:error, 'ruleName', '') is# 'no-implicit-dependencies' continue endif let l:item = { \ 'type': (get(l:error, 'ruleSeverity', '') is# 'WARNING' ? 'W' : 'E'), \ 'text': l:error.failure, \ 'lnum': l:error.startPosition.line + 1, \ 'col': l:error.startPosition.character + 1, \ 'end_lnum': l:error.endPosition.line + 1, \ 'end_col': l:error.endPosition.character + 1, \} let l:filename = ale#path#GetAbsPath(l:dir, l:error.name) " Assume temporary files are this file. if !ale#path#IsTempName(l:filename) let l:item.filename = l:filename endif if has_key(l:error, 'ruleName') let l:item.code = l:error.ruleName endif call add(l:output, l:item) endfor return l:output endfunction function! ale_linters#typescript#tslint#GetCommand(buffer) abort let l:tslint_config_path = ale#path#ResolveLocalPath( \ a:buffer, \ 'tslint.json', \ ale#Var(a:buffer, 'typescript_tslint_config_path') \) let l:tslint_config_option = !empty(l:tslint_config_path) \ ? ' -c ' . ale#Escape(l:tslint_config_path) \ : '' let l:tslint_rules_dir = ale#Var(a:buffer, 'typescript_tslint_rules_dir') let l:tslint_rules_option = !empty(l:tslint_rules_dir) \ ? ' -r ' . ale#Escape(l:tslint_rules_dir) \ : '' return ale#Escape(ale#handlers#tslint#GetExecutable(a:buffer)) \ . ' --format json' \ . l:tslint_config_option \ . l:tslint_rules_option \ . ' %t' endfunction call ale#linter#Define('typescript', { \ 'name': 'tslint', \ 'executable': function('ale#handlers#tslint#GetExecutable'), \ 'cwd': '%s:h', \ 'command': function('ale_linters#typescript#tslint#GetCommand'), \ 'callback': 'ale_linters#typescript#tslint#Handle', \}) ================================================ FILE: ale_linters/typescript/tsserver.vim ================================================ " Author: w0rp " Description: tsserver integration for ALE 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)) call ale#linter#Define('typescript', { \ 'name': 'tsserver', \ 'lsp': 'tsserver', \ 'executable': {b -> ale#path#FindExecutable(b, 'typescript_tsserver', [ \ '.yarn/sdks/typescript/bin/tsserver', \ 'node_modules/.bin/tsserver', \ ])}, \ 'command': '%e', \ 'project_root': function('ale#handlers#tsserver#GetProjectRoot'), \ 'language': '', \}) ================================================ FILE: ale_linters/typescript/typecheck.vim ================================================ " Author: Prashanth Chandra https://github.com/prashcr, Aleh Kashnikau https://github.com/mkusher " Description: type checker for TypeScript files function! ale_linters#typescript#typecheck#Handle(buffer, lines) abort " Matches patterns like the following: " " hello.ts[7, 41]: Property 'a' does not exist on type 'A' " hello.ts[16, 7]: Type 'A' is not assignable to type 'B' " let l:pattern = '.\+\.ts\[\(\d\+\), \(\d\+\)\]: \(.\+\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:line = l:match[1] + 0 let l:column = l:match[2] + 0 let l:text = l:match[3] call add(l:output, { \ 'lnum': l:line, \ 'col': l:column, \ 'text': l:text, \}) endfor return l:output endfunction call ale#linter#Define('typescript', { \ 'name': 'typecheck', \ 'executable': 'typecheck', \ 'command': 'typecheck %s', \ 'callback': 'ale_linters#typescript#typecheck#Handle', \}) ================================================ FILE: ale_linters/typescript/xo.vim ================================================ call ale#linter#Define('typescript', { \ 'name': 'xo', \ 'executable': function('ale#handlers#xo#GetExecutable'), \ 'command': function('ale#handlers#xo#GetLintCommand'), \ 'callback': 'ale#handlers#xo#HandleJSON', \}) ================================================ FILE: ale_linters/v/v.vim ================================================ " Author: fiatjaf " Description: v build for V files call ale#Set('v_v_executable', 'v') call ale#Set('v_v_options', '') function! ale_linters#v#v#Handler(buffer, lines) abort let l:dir = expand('#' . a:buffer . ':p:h') let l:output = [] " Matches patterns like the following: " " ./const.v:4:3: warning: const names cannot contain uppercase letters, use snake_case instead " 2 | " 3 | const ( " 4 | BUTTON_TEXT = 'OK' " | ~~~~~~~~~~~ " 5 | ) " ./main.v:4:8: warning: module 'os' is imported but never used " 2 | " 3 | import ui " 4 | import os " | ~~ " 5 | " 6 | const ( " ./main.v:20:10: error: undefined ident: `win_widt` " 18 | mut app := &App{} " 19 | app.window = ui.window({ " 20 | width: win_widt " | ~~~~~~~~ " 21 | height: win_height " 22 | title: 'Counter' let l:current = {} for l:line in a:lines " matches basic error description let l:match = matchlist(l:line, \ '\([^:]\+\):\([^:]\+\):\([^:]\+\): \([^:]\+\): \(.*\)') if !empty(l:match) let l:current = { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[5], \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \} call add(l:output, l:current) continue endif " try to get information about the ending column let l:tildematch = matchstr(l:line, '\~\+') if !empty(l:tildematch) let l:current['end_col'] = l:current['col'] + len(l:tildematch) endif endfor return l:output endfunction call ale#linter#Define('v', { \ 'name': 'v', \ 'executable': {b -> ale#Var(b, 'v_v_executable')}, \ 'command': {b -> \ '%e' . ale#Pad(ale#Var(b, 'v_v_options')) \ . ' . -o /tmp/vim-ale-v' \ }, \ 'output_stream': 'stderr', \ 'callback': 'ale_linters#v#v#Handler', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/vala/vala_lint.vim ================================================ " Author: Atsuya Takagi " Description: A linter for Vala using Vala-Lint. call ale#Set('vala_vala_lint_config_filename', 'vala-lint.conf') call ale#Set('vala_vala_lint_executable', 'io.elementary.vala-lint') function! ale_linters#vala#vala_lint#GetExecutable(buffer) abort return ale#Var(a:buffer, 'vala_vala_lint_executable') endfunction function! ale_linters#vala#vala_lint#GetCommand(buffer) abort let l:command = ale_linters#vala#vala_lint#GetExecutable(a:buffer) let l:config_filename = ale#Var(a:buffer, 'vala_vala_lint_config_filename') let l:config_path = ale#path#FindNearestFile(a:buffer, l:config_filename) if !empty(l:config_path) let l:command .= ' -c ' . l:config_path endif return l:command . ' %s' endfunction function! ale_linters#vala#vala_lint#Handle(buffer, lines) abort let l:pattern = '^\s*\(\d\+\)\.\(\d\+\)\s\+\(error\|warn\)\s\+\(.\+\)\s\([A-Za-z0-9_\-]\+\)' let l:output = [] for l:line in a:lines " remove color escape sequences since vala-lint doesn't support " output without colors let l:cleaned_line = substitute(l:line, '\e\[[0-9;]\+[mK]', '', 'g') let l:match = matchlist(l:cleaned_line, l:pattern) if len(l:match) == 0 continue endif let l:refined_type = l:match[3] is# 'warn' ? 'W' : 'E' let l:cleaned_text = substitute(l:match[4], '^\s*\(.\{-}\)\s*$', '\1', '') let l:lnum = l:match[1] + 0 let l:column = l:match[2] + 0 let l:type = l:refined_type let l:text = l:cleaned_text let l:code = l:match[5] call add(l:output, { \ 'lnum': l:lnum, \ 'col': l:column, \ 'text': l:text, \ 'type': l:type, \ 'code': l:code, \}) endfor return l:output endfunction call ale#linter#Define('vala', { \ 'name': 'vala_lint', \ 'output_stream': 'stdout', \ 'executable': function('ale_linters#vala#vala_lint#GetExecutable'), \ 'command': function('ale_linters#vala#vala_lint#GetCommand'), \ 'callback': 'ale_linters#vala#vala_lint#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/verilog/hdl_checker.vim ================================================ " Author: suoto " Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl " or xvhdl. More info on https://github.com/suoto/hdl_checker call ale#handlers#hdl_checker#DefineLinter('verilog') ================================================ FILE: ale_linters/verilog/iverilog.vim ================================================ " Author: Masahiro H https://github.com/mshr-h " Description: iverilog for verilog files call ale#Set('verilog_iverilog_options', '') function! ale_linters#verilog#iverilog#GetCommand(buffer) abort return 'iverilog -t null -Wall ' \ . '-y%s:h ' \ . ale#Var(a:buffer, 'verilog_iverilog_options') \ . ' %t' endfunction function! ale_linters#verilog#iverilog#Handle(buffer, lines) abort " Look for lines like the following. " " tb_me_top.v:37: warning: Instantiating module me_top with dangling input port 1 (rst_n) floating. " tb_me_top.v:17: syntax error " memory_single_port.v:2: syntax error " tb_me_top.v:17: error: Invalid module instantiation let l:pattern = '^[^:]\+:\(\d\+\): \(warning\|error\|syntax error\)\(: \(.\+\)\)\?' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:line = l:match[1] + 0 let l:type = l:match[2] =~# 'error' ? 'E' : 'W' let l:text = l:match[2] is# 'syntax error' ? 'syntax error' : l:match[4] call add(l:output, { \ 'lnum': l:line, \ 'text': l:text, \ 'type': l:type, \}) endfor return l:output endfunction call ale#linter#Define('verilog', { \ 'name': 'iverilog', \ 'output_stream': 'stderr', \ 'executable': 'iverilog', \ 'command': function('ale_linters#verilog#iverilog#GetCommand'), \ 'callback': 'ale_linters#verilog#iverilog#Handle', \}) ================================================ FILE: ale_linters/verilog/slang.vim ================================================ " Author: Alvin Rolling " Description: slang for verilog files " Set this option to change Slang lint options if !exists('g:ale_verilog_slang_options') let g:ale_verilog_slang_options = '' endif " --lint-only function! ale_linters#verilog#slang#GetCommand(buffer) abort return 'slang -Weverything ' \ . '--diag-abs-paths ' \ . '-I%s:h ' \ . '-y%s:h ' \ . ale#Var(a:buffer, 'verilog_slang_options') .' ' \ . '%t' endfunction function! s:RemoveUnicodeQuotes(text) abort let l:text = a:text let l:text = substitute(l:text, '[`´‘’]', '''', 'g') let l:text = substitute(l:text, '[“”]', '"', 'g') return l:text endfunction function! ale_linters#verilog#slang#Handle(buffer, lines) abort let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+)?:?(\d+)?:? ([^:]+): (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'filename': l:match[1], \ 'lnum': str2nr(l:match[2]), \ 'type': (l:match[4] is# 'error') ? 'E' : 'W', \ 'text': s:RemoveUnicodeQuotes(l:match[5]), \} if !empty(l:match[3]) let l:item.col = str2nr(l:match[3]) endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('verilog', { \ 'name': 'slang', \ 'output_stream': 'stderr', \ 'executable': 'slang', \ 'command': function('ale_linters#verilog#slang#GetCommand'), \ 'callback': 'ale_linters#verilog#slang#Handle', \ 'read_buffer': 0, \}) ================================================ FILE: ale_linters/verilog/verible_ls.vim ================================================ " Author: Nicolas Derumigny " Description: Verible LSP for verilog call ale#Set('verilog_verible_ls_options', '--rules_config_search') call ale#Set('verilog_verible_ls_rules', '') call ale#Set('verilog_verible_ls_executable', 'verible-verilog-ls') call ale#Set('verilog_verible_ls_config', {}) function! ale_linters#verilog#verible_ls#GetProjectRoot(buffer) abort let l:git_dir = ale#path#FindNearestFile(a:buffer, 'verible.filelist') if !empty(l:git_dir) return fnamemodify(l:git_dir, ':p:h') else return fnamemodify('', ':h') endif endfunction function! ale_linters#verilog#verible_ls#GetCommand(buffer) abort let l:command = ale#Escape(ale#Var(a:buffer, 'verilog_verible_ls_executable')) let l:options = ale#Var(a:buffer, 'verilog_verible_ls_options') let l:rules = ale#Var(a:buffer, 'verilog_verible_ls_rules') if l:options isnot# '' let l:command .= ' ' . l:options endif if l:rules isnot# '' let l:command .= ' --rules=' . l:rules endif return l:command endfunction call ale#linter#Define('verilog', { \ 'name': 'verible_ls', \ 'lsp': 'stdio', \ 'lsp_config': {b -> ale#Var(b, 'verilog_verible_ls_config')}, \ 'executable': {b -> ale#Var(b, 'verilog_verible_ls_executable')}, \ 'command': function('ale_linters#verilog#verible_ls#GetCommand') , \ 'project_root': function('ale_linters#verilog#verible_ls#GetProjectRoot'), \}) ================================================ FILE: ale_linters/verilog/verilator.vim ================================================ " Author: Masahiro H https://github.com/mshr-h " Description: verilator for verilog files " Set this option to change Verilator lint options if !exists('g:ale_verilog_verilator_options') let g:ale_verilog_verilator_options = '' endif function! ale_linters#verilog#verilator#GetCommand(buffer) abort " the path to the current file is systematically added to the search path return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' \ . '-I%s:h ' \ . '-y %s:h ' \ . ale#Var(a:buffer, 'verilog_verilator_options') .' ' \ . '%t' endfunction function! ale_linters#verilog#verilator#Handle(buffer, lines) abort " Look for lines like the following. " " %Error: addr_gen.v:3: syntax error, unexpected IDENTIFIER " %Warning-WIDTH: addr_gen.v:26: Operator ASSIGNDLY expects 12 bits on the Assign RHS, but Assign RHS's CONST '20'h0' generates 20 bits. " %Warning-UNUSED: test.v:3: Signal is not used: a " %Warning-UNDRIVEN: test.v:3: Signal is not driven: clk " %Warning-UNUSED: test.v:4: Signal is not used: dout " %Warning-BLKSEQ: test.v:10: Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=). " Since version 4.032 (04/2020) verilator linter messages also contain the column number, " and look like: " %Error: /tmp/test.sv:3:1: syntax error, unexpected endmodule, expecting ';' " " to stay compatible with old versions of the tool, the column number is " optional in the researched pattern let l:pattern = '^%\(Warning\|Error\)[^:]*:\s*\([^:]\+\):\(\d\+\):\(\d\+\)\?:\? \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': str2nr(l:match[3]), \ 'text': l:match[5], \ 'type': l:match[1] is# 'Error' ? 'E' : 'W', \ 'filename': l:match[2], \} if !empty(l:match[4]) let l:item.col = str2nr(l:match[4]) endif call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('verilog', { \ 'name': 'verilator', \ 'output_stream': 'stderr', \ 'executable': 'verilator', \ 'command': function('ale_linters#verilog#verilator#GetCommand'), \ 'callback': 'ale_linters#verilog#verilator#Handle', \ 'read_buffer': 0, \}) ================================================ FILE: ale_linters/verilog/vlog.vim ================================================ " Author: John Gentile " Description: Adds support for Mentor Graphics Questa/ModelSim `vlog` Verilog compiler/checker call ale#Set('verilog_vlog_executable', 'vlog') " See `$ vlog -h` for more options call ale#Set('verilog_vlog_options', '-quiet -lint') function! ale_linters#verilog#vlog#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'verilog_vlog_options')) . ' %t' endfunction function! ale_linters#verilog#vlog#Handle(buffer, lines) abort "Matches patterns like the following: "** Warning: add.v(7): (vlog-2623) Undefined variable: C. "** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: C. let l:pattern = '^**\s\(\w*\): \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[3] + 0, \ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'text': l:match[4], \ 'filename': l:match[2], \}) endfor "Matches patterns like the following: "** Warning: (vlog-2623) add.v(7): Undefined variable: C. "** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C. " let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)' let l:pattern = '^**\s\(\w*\):\s\([^)]*)\) \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)' for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[4] + 0, \ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'text': l:match[2] . ' ' . l:match[5], \ 'filename': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('verilog', { \ 'name': 'vlog', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'verilog_vlog_executable')}, \ 'command': function('ale_linters#verilog#vlog#GetCommand'), \ 'callback': 'ale_linters#verilog#vlog#Handle', \}) ================================================ FILE: ale_linters/verilog/xvlog.vim ================================================ " Author: John Gentile " Description: Adds support for Xilinx Vivado `xvlog` Verilog compiler/checker call ale#Set('verilog_xvlog_executable', 'xvlog') call ale#Set('verilog_xvlog_options', '') function! ale_linters#verilog#xvlog#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'verilog_xvlog_options')) . ' %t' endfunction function! ale_linters#verilog#xvlog#Handle(buffer, lines) abort "Matches patterns like the following: " ERROR: [VRFC 10-1412] syntax error near output [/path/to/file.v:5] let l:pattern = '^ERROR:\s\+\(\[.*\)\[.*:\([0-9]\+\)\]' let l:output = [] " NOTE: `xvlog` only prints 'INFO' and 'ERROR' messages for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'type': 'E', \ 'text': l:match[1], \}) endfor return l:output endfunction call ale#linter#Define('verilog', { \ 'name': 'xvlog', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'verilog_xvlog_executable')}, \ 'command': function('ale_linters#verilog#xvlog#GetCommand'), \ 'callback': 'ale_linters#verilog#xvlog#Handle', \}) ================================================ FILE: ale_linters/verilog/yosys.vim ================================================ " Author: Nathan Sharp " Description: Yosys for Verilog files call ale#Set('verilog_yosys_executable', 'yosys') call ale#Set('verilog_yosys_options', '-Q -T -p ''read_verilog %s''') function! ale_linters#verilog#yosys#GetCommand(buffer) abort return '%e ' . ale#Var(a:buffer, 'verilog_yosys_options') . ' 2>&1' endfunction function! ale_linters#verilog#yosys#Handle(buffer, lines) abort let l:output = [] let l:path = fnamemodify(bufname(a:buffer), ':p') for l:match in ale#util#GetMatches(a:lines, '^\([^:]\+\):\(\d\+\): \(WARNING\|ERROR\): \(.\+\)$') call add(l:output, { \ 'lnum': str2nr(l:match[2]), \ 'text': l:match[4], \ 'type': l:match[3][0], \ 'filename': l:match[1], \}) endfor for l:match in ale#util#GetMatches(a:lines, '^\(Warning\|ERROR\): \(.\+\)$') call add(l:output, { \ 'lnum': 1, \ 'text': l:match[2], \ 'type': l:match[1][0], \}) endfor return l:output endfunction call ale#linter#Define('verilog', { \ 'name': 'yosys', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'verilog_yosys_executable')}, \ 'command': function('ale_linters#verilog#yosys#GetCommand'), \ 'callback': 'ale_linters#verilog#yosys#Handle', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/vhdl/ghdl.vim ================================================ " Author: John Gentile " Description: Adds support for `ghdl` VHDL compiler/checker call ale#Set('vhdl_ghdl_executable', 'ghdl') " Compile w/VHDL-2008 support call ale#Set('vhdl_ghdl_options', '--std=08') function! ale_linters#vhdl#ghdl#GetCommand(buffer) abort return '%e -s ' . ale#Pad(ale#Var(a:buffer, 'vhdl_ghdl_options')) . ' %t' endfunction function! ale_linters#vhdl#ghdl#Handle(buffer, lines) abort " Look for 'error' lines like the following: " dff_en.vhd:41:5:error: 'begin' is expected instead of 'if' " /path/to/file.vhdl:12:8: no declaration for "i0" let l:pattern = '^[a-zA-Z0-9\-\.\_\/ ]\+:\(\d\+\):\(\d\+\):\(.*\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col' : l:match[2] + 0, \ 'text': l:match[3], \ 'type': 'E', \}) endfor return l:output endfunction call ale#linter#Define('vhdl', { \ 'name': 'ghdl', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'vhdl_ghdl_executable')}, \ 'command': function('ale_linters#vhdl#ghdl#GetCommand'), \ 'callback': 'ale_linters#vhdl#ghdl#Handle', \}) ================================================ FILE: ale_linters/vhdl/hdl_checker.vim ================================================ " Author: suoto " Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl " or xvhdl. More info on https://github.com/suoto/hdl_checker call ale#handlers#hdl_checker#DefineLinter('vhdl') ================================================ FILE: ale_linters/vhdl/vcom.vim ================================================ " Author: John Gentile " Description: Adds support for Mentor Graphics Questa/ModelSim `vcom` VHDL compiler/checker call ale#Set('vhdl_vcom_executable', 'vcom') " Use VHDL-2008. See `$ vcom -h` for more options call ale#Set('vhdl_vcom_options', '-2008 -quiet -lint') function! ale_linters#vhdl#vcom#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'vhdl_vcom_options')) . ' %t' endfunction function! ale_linters#vhdl#vcom#Handle(buffer, lines) abort "Matches patterns like the following: "** Warning: ../path/to/file.vhd(218): (vcom-1236) Shared variables must be of a protected type. "** Error: tb_file.vhd(73): (vcom-1136) Unknown identifier "aresetn". "** Error: tb_file.vhd(73): Bad resolution function (STD_LOGIC) for type (error). "** Error: tb_file.vhd(73): near ":": (vcom-1576) expecting ';' or ')'. let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'text': l:match[3], \}) endfor return l:output endfunction call ale#linter#Define('vhdl', { \ 'name': 'vcom', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'vhdl_vcom_executable')}, \ 'command': function('ale_linters#vhdl#vcom#GetCommand'), \ 'callback': 'ale_linters#vhdl#vcom#Handle', \}) ================================================ FILE: ale_linters/vhdl/xvhdl.vim ================================================ " Author: John Gentile " Description: Adds support for Xilinx Vivado `xvhdl` VHDL compiler/checker call ale#Set('vhdl_xvhdl_executable', 'xvhdl') " Use VHDL-2008. See `$ xvhdl -h` for more options call ale#Set('vhdl_xvhdl_options', '--2008') function! ale_linters#vhdl#xvhdl#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'vhdl_xvhdl_options')) . ' %t' endfunction function! ale_linters#vhdl#xvhdl#Handle(buffer, lines) abort "Matches patterns like the following: " ERROR: [VRFC 10-91] aresetn is not declared [/path/to/file.vhd:17] " ERROR: [VRFC 10-91] m_axis_tx_tdata is not declared [/home/user/tx_data.vhd:128] let l:pattern = '^ERROR:\s\+\(\[.*\)\[.*:\([0-9]\+\)\]' let l:output = [] " NOTE: `xvhdl` only prints 'INFO' and 'ERROR' messages for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[2] + 0, \ 'type': 'E', \ 'text': l:match[1], \}) endfor return l:output endfunction call ale#linter#Define('vhdl', { \ 'name': 'xvhdl', \ 'output_stream': 'stdout', \ 'executable': {b -> ale#Var(b, 'vhdl_xvhdl_executable')}, \ 'command': function('ale_linters#vhdl#xvhdl#GetCommand'), \ 'callback': 'ale_linters#vhdl#xvhdl#Handle', \}) ================================================ FILE: ale_linters/vim/ale_custom_linting_rules.vim ================================================ " Author: w0rp " 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#GetCwd(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:temp_dir = ale#command#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 '%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': function('ale_linters#vim#ale_custom_linting_rules#GetExecutable'), \ 'cwd': function('ale_linters#vim#ale_custom_linting_rules#GetCwd'), \ 'command': function('ale_linters#vim#ale_custom_linting_rules#GetCommand'), \ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle', \ 'read_buffer': 0, \}) ================================================ FILE: ale_linters/vim/vimls.vim ================================================ " Author: Jeffrey Lau - https://github.com/zoonfafer " Description: Vim Language Server integration for ALE call ale#Set('vim_vimls_executable', 'vim-language-server') call ale#Set('vim_vimls_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('vim_vimls_config', {}) function! ale_linters#vim#vimls#GetProjectRoot(buffer) abort let l:trigger_file_candidates = [ \ '.vimrc', \ 'init.vim', \] for l:candidate in l:trigger_file_candidates let l:trigger_file = fnamemodify(bufname(a:buffer), ':t') if l:trigger_file is# l:candidate return fnamemodify( \ bufname(a:buffer), \ ':h', \) endif endfor let l:trigger_dir_candidates = [ \ 'autoload', \ 'plugin', \ '.git', \] let l:path_upwards = ale#path#Upwards(fnamemodify(bufname(a:buffer), ':p:h')) for l:path in l:path_upwards for l:candidate in l:trigger_dir_candidates let l:trigger_dir = ale#path#Simplify( \ l:path . '/' . l:candidate, \) if isdirectory(l:trigger_dir) return fnamemodify( \ l:trigger_dir, \ ':p:h:h', \) endif endfor endfor return '' endfunction call ale#linter#Define('vim', { \ 'name': 'vimls', \ 'lsp': 'stdio', \ 'lsp_config': {b -> ale#Var(b, 'vim_vimls_config')}, \ 'executable': {b -> ale#path#FindExecutable(b, 'vim_vimls', [ \ 'node_modules/.bin/vim-language-server', \ ])}, \ 'command': '%e --stdio', \ 'language': 'vim', \ 'project_root': function('ale_linters#vim#vimls#GetProjectRoot'), \}) ================================================ FILE: ale_linters/vim/vint.vim ================================================ " Author: w0rp , KabbAmine " Description: This file adds support for checking Vim code with Vint. " This flag can be used to change enable/disable style issues. call ale#Set('vim_vint_show_style_issues', 1) call ale#Set('vim_vint_executable', 'vint') let s:enable_neovim = has('nvim') ? ' --enable-neovim' : '' let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"' function! ale_linters#vim#vint#GetCommand(buffer, version) abort let l:can_use_no_color_flag = empty(a:version) \ || ale#semver#GTE(a:version, [0, 3, 7]) let l:warning_flag = ale#Var(a:buffer, 'vim_vint_show_style_issues') ? '-s' : '-w' " Use the --stdin-display-name argument if supported, temp file otherwise. let l:stdin_or_temp = ale#semver#GTE(a:version, [0, 4, 0]) \ ? ' --stdin-display-name %s -' \ : ' %t' return '%e' \ . ' ' . l:warning_flag \ . (l:can_use_no_color_flag ? ' --no-color' : '') \ . s:enable_neovim \ . ' ' . s:format \ . l:stdin_or_temp endfunction let s:word_regex_list = [ \ '\v^Undefined variable: ([^ ]+)', \ '\v^Make the scope explicit like ...([^ ]+). ', \ '\v^.*start with a capital or contain a colon: ([^ ]+)', \ '\v.*instead of .(\=[=~]).', \] function! ale_linters#vim#vint#Handle(buffer, lines) abort let l:loclist = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines) for l:item in l:loclist let l:match = [] for l:regex in s:word_regex_list let l:match = matchlist(l:item.text, l:regex) if !empty(l:match) let l:item.end_col = l:item.col + len(l:match[1]) - 1 break endif endfor endfor return l:loclist endfunction call ale#linter#Define('vim', { \ 'name': 'vint', \ 'executable': {buffer -> ale#Var(buffer, 'vim_vint_executable')}, \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'vim_vint_executable'), \ '%e --version', \ function('ale_linters#vim#vint#GetCommand'), \ )}, \ 'callback': 'ale_linters#vim#vint#Handle', \}) ================================================ FILE: ale_linters/vue/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for Vue files. call ale#handlers#cspell#DefineLinter('vue') ================================================ FILE: ale_linters/vue/vls.vim ================================================ " Author: Alexander Olofsson " Description: Vue vls Language Server integration for ALE 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#GetProjectRoot(buffer) abort let l:package_path = ale#path#FindNearestFile(a:buffer, 'package.json') return !empty(l:package_path) ? fnamemodify(l:package_path, ':h') : '' endfunction call ale#linter#Define('vue', { \ 'name': 'vls', \ 'aliases': ['vuels'], \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'vue_vls', [ \ 'node_modules/.bin/vls', \ ])}, \ 'command': '%e --stdio', \ 'language': 'vue', \ 'project_root': function('ale_linters#vue#vls#GetProjectRoot'), \}) ================================================ FILE: ale_linters/vue/volar.vim ================================================ " Author: Arnold Chand " Description: Volar Language Server integration for ALE adopted from " nvim-lspconfig and volar/packages/shared/src/types.ts call ale#Set('vue_volar_executable', 'vue-language-server') call ale#Set('vue_volar_use_global', 1) call ale#Set('vue_volar_init_options', { \ 'typescript': { 'tsdk': '' }, \}) function! ale_linters#vue#volar#GetProjectRoot(buffer) abort let l:project_roots = [ \ 'package.json', \ 'vite.config.js', \ 'vite.config.mjs', \ 'vite.config.cjs', \ 'vite.config.ts', \ '.git', \ bufname(a:buffer) \] for l:project_root in l:project_roots let l:nearest_filepath = ale#path#FindNearestFile(a:buffer, l:project_root) if !empty(l:nearest_filepath) return fnamemodify(l:nearest_filepath, ':h') endif endfor return '' endfunction function! ale_linters#vue#volar#GetInitializationOptions(buffer) abort let l:tsserver_path = ale#path#FindNearestDirectory(a:buffer, 'node_modules/typescript/lib') if l:tsserver_path is# '' " no-custom-checks echohl WarningMsg " no-custom-checks echom '[volar] Must have typescript installed in project, please install via `npm install -D typescript`.' " no-custom-checks echohl None endif let l:init_options = ale#Var(a:buffer, 'vue_volar_init_options') let l:init_options.typescript.tsdk = l:tsserver_path return l:init_options endfunction call ale#linter#Define('vue', { \ 'name': 'volar', \ 'language': 'vue', \ 'lsp': 'stdio', \ 'executable': {b -> ale#path#FindExecutable(b, 'vue_volar', ['node_modules/.bin/vue-language-server'])}, \ 'command': '%e --stdio', \ 'project_root': function('ale_linters#vue#volar#GetProjectRoot'), \ 'initialization_options': function('ale_linters#vue#volar#GetInitializationOptions'), \}) ================================================ FILE: ale_linters/wgsl/naga.vim ================================================ " Author: rhysd " Description: naga-cli linter for WGSL syntax. call ale#Set('wgsl_naga_executable', 'naga') call ale#linter#Define('wgsl', { \ 'name': 'naga', \ 'executable': {b -> ale#Var(b, 'wgsl_naga_executable')}, \ 'output_stream': 'stderr', \ 'command': {b -> '%e --stdin-file-path %s'}, \ 'callback': 'ale#handlers#naga#Handle', \}) ================================================ FILE: ale_linters/xhtml/alex.vim ================================================ " Author: Johannes Wienke " Description: alex for XHTML files call ale#handlers#alex#DefineLinter('xhtml', '--text') ================================================ FILE: ale_linters/xhtml/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: cspell support for XHTML files. call ale#handlers#cspell#DefineLinter('xhtml') ================================================ FILE: ale_linters/xhtml/proselint.vim ================================================ " Author: Daniel M. Capella https://github.com/polyzen " Description: proselint for XHTML files call ale#Set('proselint_executable', 'proselint') call ale#linter#Define('xhtml', { \ 'name': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'), \ 'command': function('ale#proselint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#unix#HandleAsWarning', \}) ================================================ FILE: ale_linters/xhtml/writegood.vim ================================================ " Author: Sumner Evans " Description: write-good for XHTML files call ale#handlers#writegood#DefineLinter('xhtml') ================================================ FILE: ale_linters/xml/xmllint.vim ================================================ " Author: q12321q " Description: This file adds support for checking XML code with xmllint. " CLI options 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#GetCommand(buffer) abort return '%e' \ . ale#Pad(ale#Var(a:buffer, 'xml_xmllint_options')) \ . ' --noout -' endfunction function! ale_linters#xml#xmllint#Handle(buffer, lines) abort " Matches patterns lines like the following: " file/path:123: error level : error message let l:pattern_message = '\v^([^:]+):(\d+):\s*(([^:]+)\s*:\s+.*)$' " parse column token line like that: " file/path:123: parser error : Opening and ending tag mismatch: foo line 1 and bar " " ^ let l:pattern_column_token = '\v^\s*\^$' 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' let l:text = l:match_message[3] call add(l:output, { \ 'lnum': l:line, \ 'text': l:text, \ 'type': l:type, \}) continue endif " 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 endfunction call ale#linter#Define('xml', { \ 'name': 'xmllint', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'xml_xmllint_executable')}, \ 'command': function('ale_linters#xml#xmllint#GetCommand'), \ 'callback': 'ale_linters#xml#xmllint#Handle', \ }) ================================================ FILE: ale_linters/yaml/actionlint.vim ================================================ " Author: Peter Benjamin " Description: Linter for GitHub Workflows call ale#Set('yaml_actionlint_executable', 'actionlint') call ale#Set('yaml_actionlint_options', '') function! ale_linters#yaml#actionlint#GetCommand(buffer) abort " Only execute actionlint on YAML files in /.github/ paths. if expand('#' . a:buffer . ':p') !~# '\v[/\\]\.github[/\\]' return '' endif let l:options = ale#Var(a:buffer, 'yaml_actionlint_options') if l:options !~# '-no-color' let l:options .= ale#Pad('-no-color') endif if l:options !~# '-oneline' let l:options .= ale#Pad('-oneline') endif let l:configfile = ale_linters#yaml#actionlint#GitRepoHasConfig(a:buffer) if !empty(l:configfile) let l:options .= ale#Pad('-config-file ' . l:configfile) endif return '%e' . ale#Pad(l:options) . ' - ' endfunction " If we have a actionlint.yml or actionlint.yaml in our github directory " use that as our config file. function! ale_linters#yaml#actionlint#GitRepoHasConfig(buffer) abort let l:filename = expand('#' . a:buffer . ':p') let l:configfilebase = substitute(l:filename, '\.github/.*', '.github/actionlint.','') for l:ext in ['yml', 'yaml'] let l:configfile = l:configfilebase . l:ext if filereadable(l:configfile) return l:configfile endif endfor return '' endfunction function! ale_linters#yaml#actionlint#Handle(buffer, lines) abort " Matches patterns line the following: ".github/workflows/main.yml:19:0: could not parse as YAML: yaml: line 19: mapping values are not allowed in this context [yaml-syntax] let l:pattern = '\v^.{-}:(\d+):(\d+): (.+) \[(.+)\]$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:code = l:match[4] let l:text = l:match[3] " Handle sub-linter errors like the following: "validate.yml:19:9: shellcheck reported issue in this script: SC2086:info:1:15: Double quote to prevent globbing and word splitting [shellcheck] if l:code is# 'shellcheck' let l:shellcheck_match = matchlist(l:text, '\v^.+: (SC\d{4}):.+:\d+:\d+: (.+)$') let l:text = l:shellcheck_match[2] let l:code = 'shellcheck ' . l:shellcheck_match[1] endif let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:text, \ 'code': l:code, \ 'type': 'E', \} call add(l:output, l:item) endfor return l:output endfunction call ale#linter#Define('yaml', { \ 'name': 'actionlint', \ 'executable': {b -> ale#Var(b, 'yaml_actionlint_executable')}, \ 'command': function('ale_linters#yaml#actionlint#GetCommand'), \ 'callback': 'ale_linters#yaml#actionlint#Handle', \}) ================================================ FILE: ale_linters/yaml/circleci.vim ================================================ function! ale_linters#yaml#circleci#Handle(buffer, lines) abort let l:match_index = -1 let l:output = [] for l:index in range(len(a:lines)) let l:line = a:lines[l:index] if l:line =~? 'Error: ERROR IN CONFIG FILE:' let l:match_index = l:index + 1 break endif endfor if l:match_index > 0 return [{ \ 'type': 'E', \ 'lnum': 1, \ 'text': a:lines[l:match_index], \ 'detail': join(a:lines[l:match_index :], "\n"), \}] endif return [] endfunction " The circleci validate requires network requests, so we'll only run it when " files are saved to prevent the server from being hammered. call ale#linter#Define('yaml', { \ 'name': 'circleci', \ 'executable': {b -> expand('#' . b . ':p') =~? '\.circleci' ? 'circleci' : ''}, \ 'command': 'circleci --skip-update-check config validate - < %s', \ 'callback': 'ale_linters#yaml#circleci#Handle', \ 'output_stream': 'stderr', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/yaml/gitlablint.vim ================================================ call ale#Set('yaml_gitlablint_executable', 'gll') call ale#Set('yaml_gitlablint_options', '') function! ale_linters#yaml#gitlablint#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'yaml_gitlablint_options')) \ . ' -p %t' endfunction function! ale_linters#yaml#gitlablint#Handle(buffer, lines) abort " Matches patterns line the following: " (): mapping values are not allowed in this context at line 68 column 8 " jobs:build:dev config contains unknown keys: ony let l:pattern = '^\(.*\) at line \(\d\+\) column \(\d\+\)$' let l:output = [] for l:line in a:lines let l:match = matchlist(l:line, l:pattern) if !empty(l:match) let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[1], \ 'type': 'E', \} call add(l:output, l:item) else if l:line isnot# 'GitLab CI configuration is invalid' let l:item = { \ 'lnum': 0, \ 'col': 0, \ 'text': l:line, \ 'type': 'E', \} call add(l:output, l:item) endif endif endfor return l:output endfunction call ale#linter#Define('yaml', { \ 'name': 'gitlablint', \ 'executable': {b -> ale#Var(b, 'yaml_gitlablint_executable')}, \ 'command': function('ale_linters#yaml#gitlablint#GetCommand'), \ 'callback': 'ale_linters#yaml#gitlablint#Handle', \ 'output_stream': 'stderr', \}) ================================================ FILE: ale_linters/yaml/ls.vim ================================================ " Author: Jeffrey Lau - https://github.com/zoonfafer " Description: YAML Language Server https://github.com/redhat-developer/yaml-language-server call ale#Set('yaml_ls_executable', 'yaml-language-server') call ale#Set('yaml_ls_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('yaml_ls_config', {}) function! ale_linters#yaml#ls#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'yaml_ls', [ \ 'node_modules/.bin/yaml-language-server', \]) endfunction function! ale_linters#yaml#ls#GetCommand(buffer) abort let l:executable = ale_linters#yaml#ls#GetExecutable(a:buffer) return ale#Escape(l:executable) . ' --stdio' endfunction " Just use the current file function! ale_linters#yaml#ls#FindProjectRoot(buffer) abort let l:project_file = expand('#' . a:buffer . ':p') return fnamemodify(l:project_file, ':h') endfunction call ale#linter#Define('yaml', { \ 'name': 'yaml-language-server', \ 'aliases': ['yamlls'], \ 'lsp': 'stdio', \ 'executable': function('ale_linters#yaml#ls#GetExecutable'), \ 'command': function('ale_linters#yaml#ls#GetCommand'), \ 'project_root': function('ale_linters#yaml#ls#FindProjectRoot'), \ 'lsp_config': {b -> ale#Var(b, 'yaml_ls_config')}, \}) ================================================ FILE: ale_linters/yaml/spectral.vim ================================================ " Author: t2h5 " Description: Integration of Stoplight Spectral CLI with ALE. call ale#Set('yaml_spectral_executable', 'spectral') call ale#Set('yaml_spectral_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define('yaml', { \ 'name': 'spectral', \ 'executable': {b -> ale#path#FindExecutable(b, 'yaml_spectral', [ \ 'node_modules/.bin/spectral', \ ])}, \ 'command': '%e lint --ignore-unknown-format -q -f text %t', \ 'callback': 'ale#handlers#spectral#HandleSpectralOutput' \}) ================================================ FILE: ale_linters/yaml/swaglint.vim ================================================ " Author: Matthew Turland " Description: This file adds support for linting Swagger / OpenAPI documents using swaglint 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#Handle(buffer, lines) abort let l:pattern = ': \([^\s]\+\) @ \(\d\+\):\(\d\+\) - \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:obj = { \ 'type': l:match[1] is# 'error' ? 'E' : 'W', \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \} " Parse the code if it's there. let l:code_match = matchlist(l:obj.text, '\v^(.+) \(([^ (]+)\)$') if !empty(l:code_match) let l:obj.text = l:code_match[1] let l:obj.code = l:code_match[2] endif call add(l:output, l:obj) endfor return l:output endfunction call ale#linter#Define('yaml', { \ 'name': 'swaglint', \ 'executable': {b -> ale#path#FindExecutable(b, 'yaml_swaglint', [ \ 'node_modules/.bin/swaglint', \ ])}, \ 'command': '%e -r compact --stdin', \ 'callback': 'ale_linters#yaml#swaglint#Handle', \}) ================================================ FILE: ale_linters/yaml/yamllint.vim ================================================ " Author: KabbAmine call ale#Set('yaml_yamllint_executable', 'yamllint') call ale#Set('yaml_yamllint_options', '') call ale#linter#Define('yaml', { \ 'name': 'yamllint', \ 'executable': {b -> ale#Var(b, 'yaml_yamllint_executable')}, \ 'command': function('ale#handlers#yamllint#GetCommand'), \ 'callback': 'ale#handlers#yamllint#Handle', \}) ================================================ FILE: ale_linters/yaml/yq.vim ================================================ " Author: axhav call ale#Set('yaml_yq_executable', 'yq') call ale#Set('yaml_yq_options', '') call ale#Set('yaml_yq_filters', '.') " Matches patterns like the following: let s:pattern = '^Error\:.* line \(\d\+\)\: \(.\+\)$' function! ale_linters#yaml#yq#Handle(buffer, lines) abort return ale#util#MapMatches(a:lines, s:pattern, {match -> { \ 'lnum': match[1] + 0, \ 'text': match[2], \}}) endfunction call ale#linter#Define('yaml', { \ 'name': 'yq', \ 'executable': {b -> ale#Var(b, 'yaml_yq_executable')}, \ 'output_stream': 'stderr', \ 'command': '%e', \ 'callback': 'ale_linters#yaml#yq#Handle', \}) ================================================ FILE: ale_linters/yang/yang_lsp.vim ================================================ 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': {b -> ale#Var(b, 'yang_lsp_executable')}, \ 'project_root': function('ale_linters#yang#yang_lsp#GetProjectRoot'), \ 'command': '%e', \}) ================================================ FILE: ale_linters/yara/yls.vim ================================================ " Author: TcM1911 " Description: A language server for Yara. call ale#Set('yara_yls_executable', 'yls') function! ale_linters#yara#yls#FindProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git') return !empty(l:project_root) ? (ale#path#Upwards(l:project_root)[1]) : '' endfunction call ale#linter#Define('yara', { \ 'name': 'yls', \ 'lsp': 'stdio', \ 'executable': {b -> ale#Var(b, 'yara_yls_executable')}, \ 'command': '%e -v', \ 'project_root': function('ale_linters#yara#yls#FindProjectRoot'), \}) ================================================ FILE: ale_linters/zeek/zeek.vim ================================================ " Author: Benjamin Bannier " Description: Support for checking Zeek files. " call ale#Set('zeek_zeek_executable', 'zeek') function! ale_linters#zeek#zeek#HandleErrors(buffer, lines) abort let l:pattern = '\(error\|warning\) in \v.*, line (\d+): (.*)$' return map(ale#util#GetMatches(a:lines, l:pattern), "{ \ 'lnum': str2nr(v:val[2]), \ 'text': v:val[3], \ 'type': (v:val[1] is# 'error') ? 'E': 'W', \}") endfunction call ale#linter#Define('zeek', { \ 'name': 'zeek', \ 'executable': {b -> ale#Var(b, 'zeek_zeek_executable')}, \ 'output_stream': 'stderr', \ 'command': {-> '%e --parse-only %s'}, \ 'callback': 'ale_linters#zeek#zeek#HandleErrors', \ 'lint_file': 1, \}) ================================================ FILE: ale_linters/zig/zlint.vim ================================================ " Author: Don Isaac " Description: A linter for the Zig programming language call ale#Set('zig_zlint_executable', 'zlint') function! ale_linters#zig#zlint#Handle(buffer, lines) abort " GitHub Actions format: ::severity file=file,line=line,col=col,title=code::message let l:pattern = '::\([a-z]\+\) file=\([^,]\+\),line=\(\d\+\),col=\(\d\+\),title=\([^:]\+\)::\(.*\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'filename': l:match[2], \ 'lnum': str2nr(l:match[3]), \ 'col': str2nr(l:match[4]), \ 'text': l:match[6], \ 'type': l:match[1] =~? 'error\|fail' ? 'E' : 'W', \ 'code': l:match[5], \}) endfor return l:output endfunction call ale#linter#Define('zig', { \ 'name': 'zlint', \ 'executable': {b -> ale#Var(b, "zig_zlint_executable")}, \ 'command': '%e %s -f gh', \ 'callback': 'ale_linters#zig#zlint#Handle', \}) ================================================ FILE: ale_linters/zig/zls.vim ================================================ " Author: CherryMan " Description: A language server for Zig call ale#Set('zig_zls_executable', 'zls') call ale#Set('zig_zls_config', {}) function! ale_linters#zig#zls#GetProjectRoot(buffer) abort let l:build_rs = ale#path#FindNearestFile(a:buffer, 'build.zig') return !empty(l:build_rs) ? fnamemodify(l:build_rs, ':h') : '' endfunction call ale#linter#Define('zig', { \ 'name': 'zls', \ 'lsp': 'stdio', \ 'lsp_config': {b -> ale#Var(b, 'zig_zls_config')}, \ 'executable': {b -> ale#Var(b, 'zig_zls_executable')}, \ 'command': '%e', \ 'project_root': function('ale_linters#zig#zls#GetProjectRoot'), \}) ================================================ FILE: autoload/ale/ant.vim ================================================ " Author: Andrew Lee . " Inspired by ale/gradle.vim by Michael Pardo " Description: Functions for working with Ant projects. " Given a buffer number, find an Ant project root function! ale#ant#FindProjectRoot(buffer) abort let l:build_xml_path = ale#path#FindNearestFile(a:buffer, 'build.xml') if !empty(l:build_xml_path) return fnamemodify(l:build_xml_path, ':h') endif return '' endfunction " Given a buffer number, find the path to the `ant` executable. Returns an empty " string if cannot find the executable. function! ale#ant#FindExecutable(buffer) abort if executable('ant') return 'ant' endif return '' endfunction " Given a buffer number, get a working directory and command to print the " classpath of the root project. " " Returns an empty string for the command if Ant is not detected. function! ale#ant#BuildClasspathCommand(buffer) abort let l:executable = ale#ant#FindExecutable(a:buffer) if !empty(l:executable) let l:project_root = ale#ant#FindProjectRoot(a:buffer) if !empty(l:project_root) return [ \ l:project_root, \ ale#Escape(l:executable) .' classpath -S -q' \] endif endif return ['', ''] endfunction ================================================ FILE: autoload/ale/args.vim ================================================ " Author: w0rp " Description: This module implements a function for parsing arguments for " commands. " Given a list of valid arguments like ['foo', 'bar'] and a string to parse, " parse the arguments from the string and return [parsed_args, remainder]. " " Arguments must be prefixed in the string with a single minus (-), and a " double minus (--) denotes the end of arguments. function! ale#args#Parse(arg_list, string) abort let l:parsed = {} let l:end_of_args = 0 let l:word_list = split(a:string, ' ') let l:index = 0 while l:index < len(l:word_list) let l:word = l:word_list[l:index] if l:word[:0] is# '-' let l:index += 1 if l:word is# '--' break endif let l:arg = l:word[1:] if index(a:arg_list, l:arg) >= 0 let l:parsed[l:arg] = '' else throw 'Invalid argument: ' . l:word endif elseif l:word is# '' let l:index += 1 else break endif endwhile let l:new_string = join(l:word_list[l:index :], ' ') return [l:parsed, l:new_string] endfunction ================================================ FILE: autoload/ale/assert.vim ================================================ let s:command_output = [] function! ale#assert#GivenCommandOutput(...) abort let s:command_output = a:000 endfunction function! s:GetLinter() abort let l:linters = ale#linter#GetLintersLoaded() let l:filetype_linters = get(values(l:linters), 0, []) if len(l:linters) is 0 || len(l:filetype_linters) is 0 throw 'No linters were loaded' endif if len(l:linters) > 1 || len(l:filetype_linters) > 1 throw 'More than one linter was loaded' endif return l:filetype_linters[0] endfunction function! s:FormatExe(command, executable) abort return substitute(a:command, '%e', '\=ale#Escape(a:executable)', 'g') endfunction function! s:ProcessDeferredCommands(initial_result) abort let l:result = a:initial_result let l:command_index = 0 let l:command = [] while ale#command#IsDeferred(l:result) call add(l:command, s:FormatExe(l:result.command, l:result.executable)) if get(g:, 'ale_run_synchronously_emulate_commands') " Don't run commands, but simulate the results. let l:Callback = g:ale_run_synchronously_callbacks[0] let l:output = get(s:command_output, l:command_index, []) call l:Callback(0, l:output) unlet g:ale_run_synchronously_callbacks let l:command_index += 1 else " Run the commands in the shell, synchronously. call ale#test#FlushJobs() endif let l:result = l:result.value endwhile call add(l:command, l:result) return l:command endfunction function! s:ProcessDeferredCwds(initial_command, initial_cwd) abort let l:result = a:initial_command let l:last_cwd = v:null let l:command_index = 0 let l:cwd_list = [] while ale#command#IsDeferred(l:result) call add(l:cwd_list, l:result.cwd) if get(g:, 'ale_run_synchronously_emulate_commands') " Don't run commands, but simulate the results. let l:Callback = g:ale_run_synchronously_callbacks[0] let l:output = get(s:command_output, l:command_index, []) call l:Callback(0, l:output) unlet g:ale_run_synchronously_callbacks let l:command_index += 1 else " Run the commands in the shell, synchronously. call ale#test#FlushJobs() endif let l:result = l:result.value endwhile call add(l:cwd_list, a:initial_cwd is v:null ? l:last_cwd : a:initial_cwd) return l:cwd_list endfunction " Load the currently loaded linter for a test case, and check that the command " matches the given string. function! ale#assert#Linter(expected_executable, expected_command) abort let l:buffer = bufnr('') let l:linter = s:GetLinter() let l:executable = ale#linter#GetExecutable(l:buffer, l:linter) while ale#command#IsDeferred(l:executable) call ale#test#FlushJobs() let l:executable = l:executable.value endwhile let l:command = s:ProcessDeferredCommands( \ ale#linter#GetCommand(l:buffer, l:linter), \) if type(a:expected_command) isnot v:t_list let l:command = l:command[-1] 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 = s:FormatExe(l:command, l:executable) elseif type(l:command) is v:t_list call map(l:command, 's:FormatExe(v:val, l:executable)') endif AssertEqual \ [a:expected_executable, a:expected_command], \ [l:executable, l:command] endfunction function! ale#assert#LinterCwd(expected_cwd) abort let l:buffer = bufnr('') let l:linter = s:GetLinter() let l:initial_cwd = ale#linter#GetCwd(l:buffer, l:linter) call ale#command#SetCwd(l:buffer, l:initial_cwd) let l:cwd = s:ProcessDeferredCwds( \ ale#linter#GetCommand(l:buffer, l:linter), \ l:initial_cwd, \) call ale#command#ResetCwd(l:buffer) if type(a:expected_cwd) isnot v:t_list let l:cwd = l:cwd[-1] endif AssertEqual a:expected_cwd, l:cwd endfunction function! ale#assert#FixerCwd(expected_cwd) abort let l:buffer = bufnr('') let l:cwd = s:ProcessDeferredCwds(s:FixerFunction(l:buffer), v:null) if type(a:expected_cwd) isnot v:t_list let l:cwd = l:cwd[-1] endif AssertEqual a:expected_cwd, l:cwd endfunction function! ale#assert#Fixer(expected_result) abort let l:buffer = bufnr('') let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer)) if type(a:expected_result) isnot v:t_list let l:result = l:result[-1] endif AssertEqual a:expected_result, l:result endfunction function! ale#assert#FixerNotExecuted() abort let l:buffer = bufnr('') let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))[-1] Assert empty(l:result), "The fixer will be executed when it shouldn't be" endfunction function! ale#assert#LinterNotExecuted() abort let l:buffer = bufnr('') let l:linter = s:GetLinter() let l:executable = ale#linter#GetExecutable(l:buffer, l:linter) let l:executed = 1 if !empty(l:executable) let l:command = ale#linter#GetCommand(l:buffer, l:linter) if type(l:command) is v:t_list let l:command = l:command[-1] endif let l:executed = !empty(l:command) else let l:executed = 0 endif Assert !l:executed, "The linter will be executed when it shouldn't be" endfunction function! ale#assert#LSPOptions(expected_options) abort let l:buffer = bufnr('') let l:linter = s:GetLinter() let l:initialization_options = ale#lsp_linter#GetOptions(l:buffer, l:linter) 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() let l:Language = l:linter.language let l:language = type(l:Language) is v:t_func \ ? l:Language(l:buffer) \ : l:Language AssertEqual a:expected_language, l:language endfunction function! ale#assert#LSPProject(expected_root) abort let l:buffer = bufnr('') let l:linter = s:GetLinter() let l:root = ale#lsp_linter#FindProjectRoot(l:buffer, l:linter) AssertEqual a:expected_root, l:root endfunction function! ale#assert#LSPAddress(expected_address) abort let l:buffer = bufnr('') let l:linter = s:GetLinter() let l:address = ale#linter#GetAddress(l:buffer, l:linter) AssertEqual a:expected_address, l:address endfunction function! ale#assert#SetUpLinterTestCommands() abort command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput() command! -nargs=+ AssertLinterCwd :call ale#assert#LinterCwd() command! -nargs=+ AssertLinter :call ale#assert#Linter() command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted() command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions() command! -nargs=+ AssertLSPConfig :call ale#assert#LSPConfig() command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage() command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject() command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress() endfunction function! ale#assert#SetUpFixerTestCommands() abort command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput() command! -nargs=+ AssertFixerCwd :call ale#assert#FixerCwd() command! -nargs=+ AssertFixer :call ale#assert#Fixer() command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted() endfunction function! ale#assert#ResetVariables(filetype, name, ...) abort " If the suffix of the option names format is different, an additional " argument can be used for that instead. if a:0 > 1 throw 'Too many arguments' endif let l:option_suffix = get(a:000, 0, a:name) let l:prefix = 'ale_' . a:filetype . '_' \ . substitute(l:option_suffix, '-', '_', 'g') let l:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix' " Save and clear linter variables. " We'll load the runtime file to reset them to defaults. for l:key in filter(keys(g:), l:filter_expr) execute 'Save g:' . l:key unlet g:[l:key] endfor for l:key in filter(keys(b:), l:filter_expr) unlet b:[l:key] endfor 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. let g:ale_create_dummy_temporary_file = 1 " Remove current linters. call ale#linter#Reset() call ale#linter#PreventLoading(a:filetype) Save g:ale_root let g:ale_root = {} Save b:ale_root unlet! b:ale_root call ale#assert#ResetVariables(a:filetype, a:name) Save g:ale_c_build_dir unlet! g:ale_c_build_dir unlet! b:ale_c_build_dir execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim' if !exists('g:dir') call ale#test#SetDirectory('/testplugin/test/linter') endif call ale#assert#SetUpLinterTestCommands() let g:ale_run_synchronously = 1 let g:ale_run_synchronously_emulate_commands = 1 endfunction function! ale#assert#TearDownLinterTest() abort unlet! g:ale_create_dummy_temporary_file unlet! g:ale_run_synchronously unlet! g:ale_run_synchronously_callbacks unlet! g:ale_run_synchronously_emulate_commands unlet! g:ale_run_synchronously_command_results let s:command_output = [] if exists(':GivenCommandOutput') delcommand GivenCommandOutput endif if exists(':AssertLinterCwd') delcommand AssertLinterCwd 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 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 call ale#linter#Reset() if exists('*ale#semver#ResetVersionCache') call ale#semver#ResetVersionCache() endif endfunction function! ale#assert#SetUpFixerTest(filetype, name, ...) abort " If the suffix of the option names format is different, an additional " argument can be used for that instead. if a:0 > 1 throw 'Too many arguments' endif " Set up a marker so ALE doesn't create real random temporary filenames. let g:ale_create_dummy_temporary_file = 1 let l:function_name = ale#fix#registry#GetFunc(a:name) let s:FixerFunction = function(l:function_name) let l:option_suffix = get(a:000, 0, a:name) call ale#assert#ResetVariables(a:filetype, a:name, l:option_suffix) execute 'runtime autoload/ale/fixers/' . substitute(a:name, '-', '_', 'g') . '.vim' if !exists('g:dir') call ale#test#SetDirectory('/testplugin/test/fixers') endif call ale#assert#SetUpFixerTestCommands() let g:ale_run_synchronously = 1 let g:ale_run_synchronously_emulate_commands = 1 endfunction function! ale#assert#TearDownFixerTest() abort unlet! g:ale_create_dummy_temporary_file unlet! g:ale_run_synchronously unlet! g:ale_run_synchronously_callbacks unlet! g:ale_run_synchronously_emulate_commands unlet! g:ale_run_synchronously_command_results let s:command_output = [] unlet! s:FixerFunction if exists('g:dir') call ale#test#RestoreDirectory() endif Restore if exists('*ale#semver#ResetVersionCache') call ale#semver#ResetVersionCache() endif if exists(':GivenCommandOutput') delcommand GivenCommandOutput endif if exists(':AssertFixerCwd') delcommand AssertFixerCwd endif if exists(':AssertFixer') delcommand AssertFixer endif if exists(':AssertFixerNotExecuted') delcommand AssertFixerNotExecuted endif endfunction ================================================ FILE: autoload/ale/balloon.vim ================================================ " Author: w0rp " Description: balloonexpr support for ALE. function! ale#balloon#MessageForPos(bufnr, lnum, col) abort let l:set_balloons = ale#Var(a:bufnr, 'set_balloons') let l:show_problems = 0 let l:show_hover = 0 if l:set_balloons is 1 let l:show_problems = 1 let l:show_hover = 1 elseif l:set_balloons is# 'hover' let l:show_hover = 1 endif " Don't show balloons if they are disabled, or linting is disabled. if !(l:show_problems || l:show_hover) \|| !g:ale_enabled \|| !getbufvar(a:bufnr, 'ale_enabled', 1) return '' endif if l:show_problems let l:loclist = get(g:ale_buffer_info, a:bufnr, {'loclist': []}).loclist let l:index = ale#util#BinarySearch(l:loclist, a:bufnr, a:lnum, a:col) endif " Show the diagnostics message if found, 'Hover' output otherwise if l:show_problems && l:index >= 0 return l:loclist[l:index].text elseif l:show_hover && ( \ exists('*balloon_show') \ || getbufvar( \ a:bufnr, \ 'ale_set_balloons_legacy_echo', \ get(g:, 'ale_set_balloons_legacy_echo', 0) \ ) \) " Request LSP/tsserver hover information, but only if this version of " Vim supports the balloon_show function, or if we turned a legacy " setting on. call ale#hover#Show(a:bufnr, a:lnum, a:col, {'called_from_balloonexpr': 1}) endif return '' endfunction function! ale#balloon#Expr() abort return ale#balloon#MessageForPos(v:beval_bufnr, v:beval_lnum, v:beval_col) endfunction function! ale#balloon#Disable() abort if has('balloon_eval') set noballooneval set balloonexpr= endif if has('balloon_eval_term') set noballoonevalterm set balloonexpr= endif endfunction function! ale#balloon#Enable() abort if has('balloon_eval') set ballooneval set balloonexpr=ale#balloon#Expr() endif if has('balloon_eval_term') set balloonevalterm set balloonexpr=ale#balloon#Expr() endif endfunction ================================================ FILE: autoload/ale/c.vim ================================================ " Author: gagbo , w0rp , roel0 " Description: Functions for integrating with C-family linters. call ale#Set('c_parse_makefile', 0) call ale#Set('c_always_make', has('unix') && !has('macunix')) call ale#Set('c_parse_compile_commands', 1) let s:sep = has('win32') ? '\' : '/' " Set just so tests can override it. let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt'] let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [ \ 'build', \ 'build/Debug', \ 'build/Release', \ 'bin', \]) function! s:CanParseMakefile(buffer) abort " Something somewhere seems to delete this setting in tests, so ensure we " always have a default value. call ale#Set('c_parse_makefile', 0) return ale#Var(a:buffer, 'c_parse_makefile') endfunction function! ale#c#GetBuildDirectory(buffer) abort 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 let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) return ale#path#Dirname(l:json_file) endfunction function! ale#c#ShellSplit(line) abort let l:stack = [] let l:args = [''] let l:prev = '' for l:char in split(a:line, '\zs') if l:char is# '''' if len(l:stack) > 0 && get(l:stack, -1) is# '''' call remove(l:stack, -1) elseif (len(l:stack) == 0 || get(l:stack, -1) isnot# '"') && l:prev isnot# '\' call add(l:stack, l:char) endif elseif (l:char is# '"' || l:char is# '`') && l:prev isnot# '\' if len(l:stack) > 0 && get(l:stack, -1) is# l:char call remove(l:stack, -1) elseif len(l:stack) == 0 || get(l:stack, -1) isnot# '''' call add(l:stack, l:char) endif elseif (l:char is# '(' || l:char is# '[' || l:char is# '{') && l:prev isnot# '\' if len(l:stack) == 0 || get(l:stack, -1) isnot# '''' call add(l:stack, l:char) endif elseif (l:char is# ')' || l:char is# ']' || l:char is# '}') && l:prev isnot# '\' if len(l:stack) > 0 && get(l:stack, -1) is# {')': '(', ']': '[', '}': '{'}[l:char] call remove(l:stack, -1) endif elseif l:char is# ' ' && len(l:stack) == 0 if len(get(l:args, -1)) > 0 call add(l:args, '') endif continue endif let l:args[-1] = get(l:args, -1) . l:char endfor return l:args endfunction " Takes the path prefix and a list of cflags and expands @file arguments to " the contents of the file. " " @file arguments are command line arguments recognised by gcc and clang. For " instance, if @./path/to/file was given to gcc, it would load .path/to/file " and use the contents of that file as arguments. function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort let l:out_lines = [] for l:option in a:raw_split_lines if stridx(l:option, '@') == 0 " This is an argument specifying a location of a file containing other arguments let l:path = join(split(l:option, '\zs')[1:], '') " Make path absolute if !ale#path#IsAbsolute(l:path) let l:rel_path = substitute(l:path, '"', '', 'g') let l:rel_path = substitute(l:rel_path, '''', '', 'g') let l:path = ale#path#GetAbsPath(a:path_prefix, l:rel_path) endif " Read the file and add all the arguments try let l:additional_args = readfile(l:path) catch continue " All we can really do is skip this argument endtry let l:file_lines = [] for l:line in l:additional_args let l:file_lines += ale#c#ShellSplit(l:line) endfor " @file arguments can include other @file arguments, so we must " recurse. let l:out_lines += ale#c#ExpandAtArgs(a:path_prefix, l:file_lines) else " This is not an @file argument, so don't touch it. let l:out_lines += [l:option] endif endfor return l:out_lines endfunction " Quote C/C++ a compiler argument, if needed. " " Quoting arguments might cause issues with some systems/compilers, so we only " quote them if we need to. function! ale#c#QuoteArg(arg) abort if a:arg !~# '\v[#$&*()\\|[\]{};''"<>/?! ^%]' return a:arg endif return ale#Escape(a:arg) endfunction function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort " Expand @file arguments now before parsing let l:arguments = ale#c#ExpandAtArgs(a:path_prefix, a:raw_arguments) " A list of [already_quoted, argument] let l:items = [] let l:option_index = 0 while l:option_index < len(l:arguments) let l:option = l:arguments[l:option_index] let l:option_index = l:option_index + 1 " Include options, that may need relative path fix if stridx(l:option, '-I') == 0 \ || stridx(l:option, '-iquote') == 0 \ || stridx(l:option, '-isystem') == 0 \ || stridx(l:option, '-idirafter') == 0 \ || stridx(l:option, '-iframework') == 0 if stridx(l:option, '-I') == 0 && l:option isnot# '-I' let l:arg = join(split(l:option, '\zs')[2:], '') let l:option = '-I' else let l:arg = l:arguments[l:option_index] let l:option_index = l:option_index + 1 endif " Fix relative paths if needed if !ale#path#IsAbsolute(l:arg) let l:rel_path = substitute(l:arg, '"', '', 'g') let l:rel_path = substitute(l:rel_path, '''', '', 'g') let l:arg = ale#path#GetAbsPath(a:path_prefix, l:rel_path) endif call add(l:items, [1, l:option]) call add(l:items, [1, ale#Escape(l:arg)]) " Options with arg that can be grouped with the option or separate elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0 if l:option is# '-D' || l:option is# '-B' call add(l:items, [1, l:option]) call add(l:items, [0, l:arguments[l:option_index]]) let l:option_index = l:option_index + 1 else call add(l:items, [0, l:option]) endif " Options that have an argument (always separate) elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0 \ || l:option is# '-isysroot' || l:option is# '-imultilib' \ || l:option is# '-include' || l:option is# '-imacros' call add(l:items, [0, l:option]) call add(l:items, [0, l:arguments[l:option_index]]) let l:option_index = l:option_index + 1 " Options without argument elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0) \ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0 \ || l:option is# '-ansi' || stridx(l:option, '-std=') == 0 \ || stridx(l:option, '-f') == 0 && l:option !~# '\v^-f(dump|diagnostics|no-show-column|stack-usage)' \ || stridx(l:option, '-O') == 0 \ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs' \ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0 \ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix' \ || stridx(l:option, '-m') == 0 call add(l:items, [0, l:option]) endif endwhile if a:should_quote " Quote C arguments that haven't already been quoted above. " If and only if we've been asked to quote them. call map(l:items, 'v:val[0] ? v:val[1] : ale#c#QuoteArg(v:val[1])') else call map(l:items, 'v:val[1]') endif return join(l:items, ' ') endfunction function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort if !s:CanParseMakefile(a:buffer) return v:null endif let l:buffer_filename = expand('#' . a:buffer . ':t') 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') let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h') return ale#c#ParseCFlags(l:makefile_dir, 0, ale#c#ShellSplit(l:cflag_line)) endfunction " Given a buffer number, find the project directory containing " compile_commands.json, and the path to the compile_commands.json file. " " If compile_commands.json cannot be found, two empty strings will be " returned. 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 [fnamemodify(l:json_file, ':h'), 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:path, l:json_file] endif endfor endfor return ['', ''] endfunction " Find the project root for C/C++ projects. " " The location of compile_commands.json will be used to find project roots. " " If compile_commands.json cannot be found, other common configuration files " will be used to detect the project root. function! ale#c#FindProjectRoot(buffer) abort let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer) " Fall back on detecting the project root based on other filenames. if empty(l:root) for l:project_filename in g:__ale_c_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, ':h') " Correct .git path detection. if fnamemodify(l:path, ':t') is# '.git' let l:path = fnamemodify(l:path, ':h') endif return l:path endif endfor endif return l:root 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! ale#c#ResetCompileCommandsCache() abort let s:compile_commands_cache = {} endfunction function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort let l:empty = [{}, {}] if empty(a:compile_commands_file) return l:empty endif let l:time = getftime(a:compile_commands_file) if l:time < 0 return l:empty 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:raw_data = [] silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), '')) if type(l:raw_data) isnot v:t_list let l:raw_data = [] endif let l:file_lookup = {} let l:dir_lookup = {} for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : []) let l:filename = ale#path#GetAbsPath(l:entry.directory, l:entry.file) " Store a key for lookups by the absolute path to the filename. let l:file_lookup[l:filename] = get(l:file_lookup, l:filename, []) + [l:entry] " Store a key for fuzzy lookups by the absolute path to the directory. let l:dirname = fnamemodify(l:filename, ':h') let l:dir_lookup[l:dirname] = get(l:dir_lookup, l:dirname, []) + [l:entry] " Store a key for fuzzy lookups by just the basename of the file. let l:basename = tolower(fnamemodify(l:entry.file, ':t')) let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] " Store a key for fuzzy lookups by just the basename of the directory. let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t')) let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry] endfor if !empty(l:file_lookup) && !empty(l:dir_lookup) let l:result = [l:file_lookup, l:dir_lookup] let s:compile_commands_cache[l:key] = l:result return l:result endif return l:empty endfunction " Get [should_quote, arguments] from either 'command' or 'arguments' " 'arguments' should be quoted later, the split 'command' strings should not. function! s:GetArguments(json_item) abort if has_key(a:json_item, 'arguments') return [1, a:json_item.arguments] elseif has_key(a:json_item, 'command') return [0, ale#c#ShellSplit(a:json_item.command)] endif return [0, []] endfunction function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort let l:buffer_filename = ale#path#Simplify(expand('#' . a:buffer . ':p')) let l:basename = tolower(fnamemodify(l:buffer_filename, ':t')) " Look for any file in the same directory if we can't find an exact match. let l:dir = fnamemodify(l:buffer_filename, ':h') " Search for an exact file match first. let l:file_list = get(a:file_lookup, l:buffer_filename, []) " We may have to look for /foo/bar instead of C:\foo\bar if empty(l:file_list) && has('win32') let l:file_list = get( \ a:file_lookup, \ ale#path#RemoveDriveLetter(l:buffer_filename), \ [] \) endif " Try the absolute path to the directory second. let l:dir_list = get(a:dir_lookup, l:dir, []) if empty(l:dir_list) && has('win32') let l:dir_list = get( \ a:dir_lookup, \ ale#path#RemoveDriveLetter(l:dir), \ [] \) endif if empty(l:file_list) && empty(l:dir_list) " If we can't find matches with the path to the file, try a " case-insensitive match for any similarly-named file. let l:file_list = get(a:file_lookup, l:basename, []) " If we can't find matches with the path to the directory, try a " case-insensitive match for anything in similarly-named directory. let l:dir_list = get(a:dir_lookup, tolower(fnamemodify(l:dir, ':t')), []) endif " A source file matching the header filename. let l:source_file = '' if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$' for l:suffix in ['.c', '.cpp'] " Try to find a source file by an absolute path first. let l:key = fnamemodify(l:buffer_filename, ':r') . l:suffix let l:file_list = get(a:file_lookup, l:key, []) if empty(l:file_list) && has('win32') let l:file_list = get( \ a:file_lookup, \ ale#path#RemoveDriveLetter(l:key), \ [] \) endif if empty(l:file_list) " Look fuzzy matches on the basename second. let l:key = fnamemodify(l:basename, ':r') . l:suffix let l:file_list = get(a:file_lookup, l:key, []) endif if !empty(l:file_list) let l:source_file = l:key break endif endfor endif for l:item in l:file_list let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file) " Load the flags for this file, or for a source file matching the " header file. if ( \ bufnr(l:filename) is a:buffer \ || ( \ !empty(l:source_file) \ && l:filename[-len(l:source_file):] is? l:source_file \ ) \) let [l:should_quote, l:args] = s:GetArguments(l:item) return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args) endif endfor for l:item in l:dir_list let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file) if ale#path#RemoveDriveLetter(fnamemodify(l:filename, ':h')) \ is? ale#path#RemoveDriveLetter(l:dir) let [l:should_quote, l:args] = s:GetArguments(l:item) return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args) endif endfor return '' endfunction function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort let l:lookups = s:GetLookupFromCompileCommandsFile(a:compile_commands_file) let l:file_lookup = l:lookups[0] let l:dir_lookup = l:lookups[1] return ale#c#ParseCompileCommandsFlags(a:buffer, l:file_lookup, l:dir_lookup) endfunction function! ale#c#GetCFlags(buffer, output) abort let l:cflags = v:null if ale#Var(a:buffer, 'c_parse_compile_commands') let [l:root, 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 empty(l:cflags) && s:CanParseMakefile(a:buffer) && !empty(a:output) let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output) endif if l:cflags is v:null let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)) endif return l:cflags isnot v:null ? l:cflags : '' endfunction function! ale#c#GetMakeCommand(buffer) abort if s:CanParseMakefile(a:buffer) let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile') if empty(l:path) let l:path = ale#path#FindNearestFile(a:buffer, 'GNUmakefile') endif if !empty(l:path) let l:always_make = ale#Var(a:buffer, 'c_always_make') return [ \ fnamemodify(l:path, ':h'), \ 'make -n' . (l:always_make ? ' --always-make' : ''), \] endif endif return ['', ''] endfunction function! ale#c#RunMakeCommand(buffer, Callback) abort let [l:cwd, l:command] = ale#c#GetMakeCommand(a:buffer) if empty(l:command) return a:Callback(a:buffer, []) endif return ale#command#Run( \ a:buffer, \ l:command, \ {b, output -> a:Callback(a:buffer, output)}, \ {'cwd': l:cwd}, \) endfunction " Given a buffer number, search for a project root, and output a List " of directories to include based on some heuristics. " " For projects with headers in the project root, the project root will " be returned. " " For projects with an 'include' directory, that directory will be returned. function! ale#c#FindLocalHeaderPaths(buffer) abort let l:project_root = ale#c#FindProjectRoot(a:buffer) if empty(l:project_root) return [] endif " See if we can find .h files directory in the project root. " If we can, that's our include directory. if !empty(globpath(l:project_root, '*.h', 0)) return [l:project_root] endif " Look for .hpp files too. if !empty(globpath(l:project_root, '*.hpp', 0)) return [l:project_root] endif " If we find an 'include' directory in the project root, then use that. if isdirectory(l:project_root . '/include') return [ale#path#Simplify(l:project_root . s:sep . 'include')] endif return [] endfunction " Given a List of include paths, create a string containing the -I include " options for those paths, with the paths escaped for use in the shell. function! ale#c#IncludeOptions(include_paths) abort let l:option_list = [] for l:path in a:include_paths call add(l:option_list, '-I' . ale#Escape(l:path)) endfor if empty(l:option_list) return '' endif return join(l:option_list) endfunction " Get the language flag depending on on the executable, options and " file extension function! ale#c#GetLanguageFlag( \ buffer, \ executable, \ use_header_lang_flag, \ header_exts, \ linter_lang_flag \) abort " Use only '-header' if the executable is 'clang' by default if a:use_header_lang_flag == -1 let l:use_header_lang_flag = a:executable =~# 'clang' else let l:use_header_lang_flag = a:use_header_lang_flag endif " If we don't use the header language flag, return the default linter " language flag if !l:use_header_lang_flag return a:linter_lang_flag endif " Get the buffer file extension let l:buf_ext = expand('#' . a:buffer . ':e') " If the buffer file is an header according to its extension, use " the linter language flag + '-header', ex: 'c-header' if index(a:header_exts, l:buf_ext) >= 0 return a:linter_lang_flag . '-header' endif " Else, use the default linter language flag return a:linter_lang_flag endfunction ================================================ FILE: autoload/ale/code_action.vim ================================================ " Author: Jerko Steiner " Description: Code action support for LSP / tsserver function! ale#code_action#ReloadBuffer() abort let l:buffer = bufnr('') execute 'augroup ALECodeActionReloadGroup' . l:buffer autocmd! augroup END silent! execute 'augroup! ALECodeActionReloadGroup' . l:buffer call ale#util#Execute(':e!') endfunction function! ale#code_action#HandleCodeAction(code_action, options) abort let l:current_buffer = bufnr('') let l:changes = a:code_action.changes for l:file_code_edit in l:changes call ale#code_action#ApplyChanges( \ l:file_code_edit.fileName, \ l:file_code_edit.textChanges, \ a:options, \) endfor endfunction function! s:ChangeCmp(left, right) abort if a:left.start.line < a:right.start.line return -1 endif if a:left.start.line > a:right.start.line return 1 endif if a:left.start.offset < a:right.start.offset return -1 endif if a:left.start.offset > a:right.start.offset return 1 endif if a:left.end.line < a:right.end.line return -1 endif if a:left.end.line > a:right.end.line return 1 endif if a:left.end.offset < a:right.end.offset return -1 endif if a:left.end.offset > a:right.end.offset return 1 endif return 0 endfunction function! ale#code_action#ApplyChanges(filename, changes, options) abort let l:should_save = get(a:options, 'should_save') let l:conn_id = get(a:options, 'conn_id') let l:orig_buffer = bufnr('') " The buffer is used to determine the fileformat, if available. let l:buffer = bufnr(a:filename) if l:buffer != l:orig_buffer call ale#util#Execute('silent edit ' . a:filename) let l:buffer = bufnr('') endif let l:lines = getbufline(l:buffer, 1, '$') " Add empty line if there's trailing newline, like readfile() does. if getbufvar(l:buffer, '&eol') let l:lines += [''] endif let l:pos = getpos('.')[1:2] " Changes have to be sorted so we apply them from bottom-to-top for l:code_edit in reverse(sort(copy(a:changes), function('s:ChangeCmp'))) let l:line = l:code_edit.start.line let l:column = l:code_edit.start.offset let l:end_line = l:code_edit.end.line let l:end_column = l:code_edit.end.offset let l:text = l:code_edit.newText let l:insertions = split(l:text, '\n', 1) " Fix invalid columns let l:column = l:column > 0 ? l:column : 1 let l:end_column = l:end_column > 0 ? l:end_column : 1 " Clamp start to BOF if l:line < 1 let [l:line, l:column] = [1, 1] endif " Clamp start to EOF if l:line > len(l:lines) || l:line == len(l:lines) && l:column > len(l:lines[-1]) + 1 let [l:line, l:column] = [len(l:lines), len(l:lines[-1]) + 1] " Special case when start is after EOL elseif l:line < len(l:lines) && l:column > len(l:lines[l:line - 1]) + 1 let [l:line, l:column] = [l:line + 1, 1] endif " Adjust end: clamp if invalid and/or adjust if we moved start if l:end_line < l:line || l:end_line == l:line && l:end_column < l:column let [l:end_line, l:end_column] = [l:line, l:column] endif " Clamp end to EOF if l:end_line > len(l:lines) || l:end_line == len(l:lines) && l:end_column > len(l:lines[-1]) + 1 let [l:end_line, l:end_column] = [len(l:lines), len(l:lines[-1]) + 1] " Special case when end is after EOL elseif l:end_line < len(l:lines) && l:end_column > len(l:lines[l:end_line - 1]) + 1 let [l:end_line, l:end_column] = [l:end_line + 1, 1] endif " Careful, [:-1] is not an empty list let l:start = l:line is 1 ? [] : l:lines[: l:line - 2] let l:middle = l:column is 1 ? [''] : [l:lines[l:line - 1][: l:column - 2]] let l:middle[-1] .= l:insertions[0] let l:middle += l:insertions[1:] let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :] let l:end_line_len = len(l:lines[l:end_line - 1]) let l:lines_before_change = len(l:lines) let l:lines = l:start + l:middle + l:lines[l:end_line :] let l:current_line_offset = len(l:lines) - l:lines_before_change let l:column_offset = len(l:middle[-1]) - l:end_line_len " Keep cursor where it was (if outside of changes) or move it after " the changed text (if inside), but don't touch it when the change " spans the entire buffer, in which case we have no clue and it's " better to not do anything. if l:line isnot 1 || l:column isnot 1 \|| l:end_line < l:lines_before_change \|| l:end_line == l:lines_before_change && l:end_column <= l:end_line_len let l:pos = s:UpdateCursor(l:pos, \ [l:line, l:column], \ [l:end_line, l:end_column], \ [l:current_line_offset, l:column_offset]) endif endfor " Make sure to add a trailing newline if and only if it should be added. if l:lines[-1] is# '' && getbufvar(l:buffer, '&eol') call remove(l:lines, -1) else call setbufvar(l:buffer, '&eol', 0) endif call ale#util#SetBufferContents(l:buffer, l:lines) call ale#lsp#NotifyForChanges(l:conn_id, l:buffer) if l:should_save call ale#util#Execute('silent w!') endif call setpos('.', [0, l:pos[0], l:pos[1], 0]) if l:orig_buffer != l:buffer && bufexists(l:orig_buffer) call ale#util#Execute('silent buf ' . string(l:orig_buffer)) endif endfunction function! s:UpdateCursor(cursor, start, end, offset) abort let l:cur_line = a:cursor[0] let l:cur_column = a:cursor[1] let l:line = a:start[0] let l:column = a:start[1] let l:end_line = a:end[0] let l:end_column = a:end[1] let l:line_offset = a:offset[0] let l:column_offset = a:offset[1] if l:end_line < l:cur_line " both start and end lines are before the cursor. only line offset " needs to be updated let l:cur_line += l:line_offset elseif l:end_line == l:cur_line " end line is at the same location as cursor, which means " l:line <= l:cur_line if l:line < l:cur_line || l:column <= l:cur_column " updates are happening either before or around the cursor if l:end_column < l:cur_column " updates are happening before the cursor, update the " column offset for cursor let l:cur_line += l:line_offset let l:cur_column += l:column_offset else " updates are happening around the cursor, move the cursor " to the end of the changes let l:cur_line += l:line_offset let l:cur_column = l:end_column + l:column_offset endif " else is not necessary, it means modifications are happening " after the cursor so no cursor updates need to be done endif else " end line is after the cursor if l:line < l:cur_line || l:line == l:cur_line && l:column <= l:cur_column " changes are happening around the cursor, move the cursor " to the end of the changes let l:cur_line = l:end_line + l:line_offset let l:cur_column = l:end_column + l:column_offset " else is not necessary, it means modifications are happening " after the cursor so no cursor updates need to be done endif endif return [l:cur_line, l:cur_column] endfunction function! ale#code_action#GetChanges(workspace_edit) abort if a:workspace_edit is v:null return {} endif let l:changes = {} if has_key(a:workspace_edit, 'changes') && !empty(a:workspace_edit.changes) return a:workspace_edit.changes elseif has_key(a:workspace_edit, 'documentChanges') let l:document_changes = [] if type(a:workspace_edit.documentChanges) is v:t_dict \ && has_key(a:workspace_edit.documentChanges, 'edits') call add(l:document_changes, a:workspace_edit.documentChanges) elseif type(a:workspace_edit.documentChanges) is v:t_list let l:document_changes = a:workspace_edit.documentChanges endif for l:text_document_edit in l:document_changes let l:filename = l:text_document_edit.textDocument.uri let l:edits = l:text_document_edit.edits let l:changes[l:filename] = l:edits endfor endif return l:changes endfunction function! ale#code_action#BuildChangesList(changes_map) abort let l:changes = [] for l:file_name in keys(a:changes_map) let l:text_edits = a:changes_map[l:file_name] let l:text_changes = [] for l:edit in l:text_edits let l:range = l:edit.range let l:new_text = l:edit.newText call add(l:text_changes, { \ 'start': { \ 'line': l:range.start.line + 1, \ 'offset': l:range.start.character + 1, \ }, \ 'end': { \ 'line': l:range.end.line + 1, \ 'offset': l:range.end.character + 1, \ }, \ 'newText': l:new_text, \}) endfor call add(l:changes, { \ 'fileName': ale#util#ToResource(l:file_name), \ 'textChanges': l:text_changes, \}) endfor return l:changes endfunction function! s:EscapeMenuName(text) abort return substitute(a:text, '\\\| \|\.\|&', '\\\0', 'g') endfunction function! s:UpdateMenu(data, menu_items) abort silent! aunmenu PopUp.Refactor\.\.\. if empty(a:data) return endif for [l:type, l:item] in a:menu_items let l:name = l:type is# 'tsserver' ? l:item.name : l:item.title let l:func_name = l:type is# 'tsserver' \ ? 'ale#codefix#ApplyTSServerCodeAction' \ : 'ale#codefix#ApplyLSPCodeAction' execute printf( \ 'anoremenu PopUp.&Refactor\.\.\..%s' \ . ' :call %s(%s, %s)', \ s:EscapeMenuName(l:name), \ l:func_name, \ string(a:data), \ string(l:item), \) endfor if empty(a:menu_items) silent! anoremenu PopUp.Refactor\.\.\..(None) :silent endif endfunction function! s:GetCodeActions(linter, options) abort let l:buffer = bufnr('') let [l:line, l:column] = getpos('.')[1:2] let l:column = min([l:column, len(getline(l:line))]) let l:location = { \ 'buffer': l:buffer, \ 'line': l:line, \ 'column': l:column, \ 'end_line': l:line, \ 'end_column': l:column, \} let l:Callback = function('s:OnReady', [l:location, a:options]) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction function! ale#code_action#GetCodeActions(options) abort silent! aunmenu PopUp.Rename silent! aunmenu PopUp.Refactor\.\.\. " Only display the menu items if there's an LSP server. if len(ale#lsp_linter#GetEnabled(bufnr(''))) > 0 if !empty(expand('')) silent! anoremenu PopUp.Rename :ALERename endif silent! anoremenu PopUp.Refactor\.\.\..(None) :silent call ale#codefix#Execute( \ mode() is# 'v' || mode() is# "\", \ function('s:UpdateMenu') \) endif endfunction function! s:Setup(enabled) abort augroup ALECodeActionsGroup autocmd! if a:enabled autocmd MenuPopup * :call ale#code_action#GetCodeActions({}) endif augroup END if !a:enabled silent! augroup! ALECodeActionsGroup silent! aunmenu PopUp.Rename silent! aunmenu PopUp.Refactor\.\.\. endif endfunction function! ale#code_action#EnablePopUpMenu() abort call s:Setup(1) endfunction function! ale#code_action#DisablePopUpMenu() abort call s:Setup(0) endfunction ================================================ FILE: autoload/ale/codefix.vim ================================================ " Author: Dalius Dobravolskas " Description: Code Fix support for tsserver and LSP servers let s:codefix_map = {} " Used to get the codefix map in tests. function! ale#codefix#GetMap() abort return deepcopy(s:codefix_map) endfunction " Used to set the codefix map in tests. function! ale#codefix#SetMap(map) abort let s:codefix_map = a:map endfunction function! ale#codefix#ClearLSPData() abort let s:codefix_map = {} endfunction function! s:message(message) abort call ale#util#Execute('echom ' . string(a:message)) endfunction function! ale#codefix#ApplyTSServerCodeAction(data, item) abort if has_key(a:item, 'changes') let l:changes = a:item.changes call ale#code_action#HandleCodeAction( \ { \ 'description': 'codefix', \ 'changes': l:changes, \ }, \ {}, \) else let l:message = ale#lsp#tsserver_message#GetEditsForRefactor( \ a:data.buffer, \ a:data.line, \ a:data.column, \ a:data.end_line, \ a:data.end_column, \ a:item.id[0], \ a:item.id[1], \) let l:request_id = ale#lsp#Send(a:data.connection_id, l:message) let s:codefix_map[l:request_id] = a:data endif endfunction function! ale#codefix#HandleTSServerResponse(conn_id, response) abort if !has_key(a:response, 'request_seq') \ || !has_key(s:codefix_map, a:response.request_seq) return endif let l:data = remove(s:codefix_map, a:response.request_seq) let l:MenuCallback = get(l:data, 'menu_callback', v:null) if get(a:response, 'command', '') is# 'getCodeFixes' if get(a:response, 'success', v:false) is v:false \&& l:MenuCallback is v:null let l:message = get(a:response, 'message', 'unknown') call s:message('Error while getting code fixes. Reason: ' . l:message) return endif let l:result = get(a:response, 'body', []) call filter(l:result, 'has_key(v:val, ''changes'')') if l:MenuCallback isnot v:null call l:MenuCallback( \ l:data, \ map(copy(l:result), '[''tsserver'', v:val]') \) return endif if len(l:result) == 0 call s:message('No code fixes available.') return endif let l:code_fix_to_apply = 0 if len(l:result) == 1 let l:code_fix_to_apply = 1 else let l:codefix_no = 1 let l:codefixstring = "Code Fixes:\n" for l:codefix in l:result let l:codefixstring .= l:codefix_no . ') ' \ . l:codefix.description . "\n" let l:codefix_no += 1 endfor let l:codefixstring .= 'Type number and (empty cancels): ' let l:code_fix_to_apply = ale#util#Input(l:codefixstring, '') let l:code_fix_to_apply = str2nr(l:code_fix_to_apply) if l:code_fix_to_apply == 0 return endif endif call ale#codefix#ApplyTSServerCodeAction( \ l:data, \ l:result[l:code_fix_to_apply - 1], \) elseif get(a:response, 'command', '') is# 'getApplicableRefactors' if get(a:response, 'success', v:false) is v:false \&& l:MenuCallback is v:null let l:message = get(a:response, 'message', 'unknown') call s:message('Error while getting applicable refactors. Reason: ' . l:message) return endif let l:result = get(a:response, 'body', []) if len(l:result) == 0 call s:message('No applicable refactors available.') return endif let l:refactors = [] for l:item in l:result for l:action in l:item.actions call add(l:refactors, { \ 'name': l:action.description, \ 'id': [l:item.name, l:action.name], \}) endfor endfor if l:MenuCallback isnot v:null call l:MenuCallback( \ l:data, \ map(copy(l:refactors), '[''tsserver'', v:val]') \) return endif let l:refactor_no = 1 let l:refactorstring = "Applicable refactors:\n" for l:refactor in l:refactors let l:refactorstring .= l:refactor_no . ') ' \ . l:refactor.name . "\n" let l:refactor_no += 1 endfor let l:refactorstring .= 'Type number and (empty cancels): ' let l:refactor_to_apply = ale#util#Input(l:refactorstring, '') let l:refactor_to_apply = str2nr(l:refactor_to_apply) if l:refactor_to_apply == 0 return endif let l:id = l:refactors[l:refactor_to_apply - 1].id call ale#codefix#ApplyTSServerCodeAction( \ l:data, \ l:refactors[l:refactor_to_apply - 1], \) elseif get(a:response, 'command', '') is# 'getEditsForRefactor' if get(a:response, 'success', v:false) is v:false let l:message = get(a:response, 'message', 'unknown') call s:message('Error while getting edits for refactor. Reason: ' . l:message) return endif call ale#code_action#HandleCodeAction( \ { \ 'description': 'editsForRefactor', \ 'changes': a:response.body.edits, \ }, \ {}, \) endif endfunction function! ale#codefix#ApplyLSPCodeAction(data, item) abort if has_key(a:item, 'command') \&& type(a:item.command) == v:t_dict let l:command = a:item.command let l:message = ale#lsp#message#ExecuteCommand( \ l:command.command, \ l:command.arguments, \) let l:request_id = ale#lsp#Send(a:data.connection_id, l:message) elseif has_key(a:item, 'command') && has_key(a:item, 'arguments') \&& type(a:item.command) == v:t_string let l:message = ale#lsp#message#ExecuteCommand( \ a:item.command, \ a:item.arguments, \) let l:request_id = ale#lsp#Send(a:data.connection_id, l:message) elseif has_key(a:item, 'edit') || has_key(a:item, 'arguments') if has_key(a:item, 'edit') let l:topass = a:item.edit else let l:topass = a:item.arguments[0] endif let l:changes_map = ale#code_action#GetChanges(l:topass) if empty(l:changes_map) return endif let l:changes = ale#code_action#BuildChangesList(l:changes_map) call ale#code_action#HandleCodeAction( \ { \ 'description': 'codeaction', \ 'changes': l:changes, \ }, \ {}, \) endif endfunction function! ale#codefix#HandleLSPResponse(conn_id, response) abort if has_key(a:response, 'method') \ && a:response.method is# 'workspace/applyEdit' \ && has_key(a:response, 'params') let l:params = a:response.params let l:changes_map = ale#code_action#GetChanges(l:params.edit) if empty(l:changes_map) return endif let l:changes = ale#code_action#BuildChangesList(l:changes_map) call ale#code_action#HandleCodeAction( \ { \ 'description': 'applyEdit', \ 'changes': l:changes, \ }, \ {} \) elseif has_key(a:response, 'id') \&& has_key(s:codefix_map, a:response.id) let l:data = remove(s:codefix_map, a:response.id) let l:MenuCallback = get(l:data, 'menu_callback', v:null) let l:result = get(a:response, 'result') if type(l:result) != v:t_list let l:result = [] endif " Send the results to the menu callback, if set. if l:MenuCallback isnot v:null call l:MenuCallback( \ l:data, \ map(copy(l:result), '[''lsp'', v:val]') \) return endif if len(l:result) == 0 call s:message('No code actions received from server') return endif let l:codeaction_no = 1 let l:codeactionstring = "Code Fixes:\n" for l:codeaction in l:result let l:codeactionstring .= l:codeaction_no . ') ' \ . l:codeaction.title . "\n" let l:codeaction_no += 1 endfor let l:codeactionstring .= 'Type number and (empty cancels): ' let l:codeaction_to_apply = ale#util#Input(l:codeactionstring, '') let l:codeaction_to_apply = str2nr(l:codeaction_to_apply) if l:codeaction_to_apply == 0 return endif let l:item = l:result[l:codeaction_to_apply - 1] call ale#codefix#ApplyLSPCodeAction(l:data, l:item) endif endfunction function! s:FindError(buffer, line, column, end_line, end_column, linter_name) abort let l:nearest_error = v:null if a:line == a:end_line \&& a:column == a:end_column \&& has_key(g:ale_buffer_info, a:buffer) let l:nearest_error_diff = -1 for l:error in get(g:ale_buffer_info[a:buffer], 'loclist', []) if has_key(l:error, 'code') \ && (a:linter_name is v:null || l:error.linter_name is# a:linter_name) \ && l:error.lnum == a:line let l:diff = abs(l:error.col - a:column) if l:nearest_error_diff == -1 || l:diff < l:nearest_error_diff let l:nearest_error_diff = l:diff let l:nearest_error = l:error endif endif endfor endif return l:nearest_error endfunction function! s:OnReady( \ line, \ column, \ end_line, \ end_column, \ MenuCallback, \ linter, \ lsp_details, \) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'code_actions') return endif let l:buffer = a:lsp_details.buffer if a:linter.lsp is# 'tsserver' let l:nearest_error = \ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column, a:linter.lsp) if l:nearest_error isnot v:null let l:message = ale#lsp#tsserver_message#GetCodeFixes( \ l:buffer, \ a:line, \ a:column, \ a:line, \ a:column, \ [l:nearest_error.code], \) else let l:message = ale#lsp#tsserver_message#GetApplicableRefactors( \ l:buffer, \ a:line, \ a:column, \ a:end_line, \ a:end_column, \) endif 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) let l:diagnostics = [] let l:nearest_error = \ s:FindError(l:buffer, a:line, a:column, a:end_line, a:end_column, v:null) if l:nearest_error isnot v:null let l:diagnostics = [ \ { \ 'code': l:nearest_error.code, \ 'message': l:nearest_error.text, \ 'range': { \ 'start': { \ 'line': l:nearest_error.lnum - 1, \ 'character': l:nearest_error.col - 1, \ }, \ 'end': { \ 'line': get(l:nearest_error, 'end_lnum', 1) - 1, \ 'character': get(l:nearest_error, 'end_col', 0) \ }, \ }, \ }, \] endif let l:message = ale#lsp#message#CodeAction( \ l:buffer, \ a:line, \ a:column, \ a:end_line, \ a:end_column, \ l:diagnostics, \) endif let l:Callback = a:linter.lsp is# 'tsserver' \ ? function('ale#codefix#HandleTSServerResponse') \ : function('ale#codefix#HandleLSPResponse') call ale#lsp#RegisterCallback(l:id, l:Callback) let l:request_id = ale#lsp#Send(l:id, l:message) let s:codefix_map[l:request_id] = { \ 'connection_id': l:id, \ 'buffer': l:buffer, \ 'line': a:line, \ 'column': a:column, \ 'end_line': a:end_line, \ 'end_column': a:end_column, \ 'menu_callback': a:MenuCallback, \} endfunction function! s:ExecuteGetCodeFix(linter, range, MenuCallback) abort let l:buffer = bufnr('') if a:range == 0 let [l:line, l:column] = getpos('.')[1:2] let l:end_line = l:line let l:end_column = l:column " Expand the range to cover the current word, if there is one. let l:cword = expand('') if !empty(l:cword) let l:search_pos = searchpos('\V' . l:cword, 'bn', l:line) if l:search_pos != [0, 0] let l:column = l:search_pos[1] let l:end_column = l:column + len(l:cword) - 1 endif endif elseif mode() is# 'v' || mode() is# "\" " You need to get the start and end in a different way when you're in " visual mode. let [l:line, l:column] = getpos('v')[1:2] let [l:end_line, l:end_column] = getpos('.')[1:2] else let [l:line, l:column] = getpos("'<")[1:2] let [l:end_line, l:end_column] = getpos("'>")[1:2] endif let l:column = max([min([l:column, len(getline(l:line))]), 1]) let l:end_column = min([l:end_column, len(getline(l:end_line))]) let l:Callback = function( \ 's:OnReady', [l:line, l:column, l:end_line, l:end_column, a:MenuCallback] \) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction function! ale#codefix#Execute(range, ...) abort if a:0 > 1 throw 'Too many arguments' endif let l:MenuCallback = get(a:000, 0, v:null) let l:linters = ale#lsp_linter#GetEnabled(bufnr('')) if empty(l:linters) if l:MenuCallback is v:null call s:message('No active LSPs') else call l:MenuCallback({}, []) endif return endif for l:linter in l:linters call s:ExecuteGetCodeFix(l:linter, a:range, l:MenuCallback) endfor endfunction ================================================ FILE: autoload/ale/command.vim ================================================ " Author: w0rp " Description: Functions for formatting command strings, running commands, and " managing files during linting and fixing cycles. " This dictionary holds lists of files and directories to remove later. if !exists('s:buffer_data') let s:buffer_data = {} endif " The regular expression used for formatting filenames with modifiers. let s:path_format_regex = '\v\%s(%(:h|:t|:r|:e)*)' " Used to get the data in tests. function! ale#command#GetData() abort return deepcopy(s:buffer_data) endfunction function! ale#command#ClearData() abort let s:buffer_data = {} endfunction function! ale#command#InitData(buffer) abort if !has_key(s:buffer_data, a:buffer) let s:buffer_data[a:buffer] = { \ 'jobs': {}, \ 'file_list': [], \ 'directory_list': [], \} endif endfunction " Set the cwd for commands that are about to run. " Used internally. function! ale#command#SetCwd(buffer, cwd) abort call ale#command#InitData(a:buffer) let s:buffer_data[a:buffer].cwd = a:cwd endfunction function! ale#command#ResetCwd(buffer) abort if has_key(s:buffer_data, a:buffer) let s:buffer_data[a:buffer].cwd = v:null endif endfunction function! ale#command#ManageFile(buffer, file) abort call ale#command#InitData(a:buffer) call add(s:buffer_data[a:buffer].file_list, a:file) endfunction function! ale#command#ManageDirectory(buffer, directory) abort call ale#command#InitData(a:buffer) call add(s:buffer_data[a:buffer].directory_list, a:directory) endfunction function! ale#command#CreateFile(buffer) abort " This variable can be set to 1 in tests to stub this out. if get(g:, 'ale_create_dummy_temporary_file') return 'TEMP' endif let l:temporary_file = ale#util#Tempname() call ale#command#ManageFile(a:buffer, l:temporary_file) return l:temporary_file endfunction " Create a new temporary directory and manage it in one go. function! ale#command#CreateDirectory(buffer) abort " This variable can be set to 1 in tests to stub this out. if get(g:, 'ale_create_dummy_temporary_file') return 'TEMP_DIR' endif let l:temporary_directory = ale#util#Tempname() " Create the temporary directory for the file, unreadable by 'other' " users. call mkdir(l:temporary_directory, '', 0750) call ale#command#ManageDirectory(a:buffer, l:temporary_directory) return l:temporary_directory endfunction function! ale#command#RemoveManagedFiles(buffer) abort let l:info = get(s:buffer_data, a:buffer, {}) if !empty(l:info) && empty(l:info.jobs) " We can't delete anything in a sandbox, so wait until we escape from " it to delete temporary files and directories. if ale#util#InSandbox() return endif " Delete files with a call akin to a plan `rm` command. for l:filename in l:info.file_list call delete(l:filename) endfor " Delete directories like `rm -rf`. " Directories are handled differently from files, so paths that are " intended to be single files can be set up for automatic deletion " without accidentally deleting entire directories. for l:directory in l:info.directory_list call delete(l:directory, 'rf') endfor call remove(s:buffer_data, a:buffer) endif endfunction function! ale#command#CreateTempFile(buffer, temporary_file, input) abort if empty(a:temporary_file) " There is no file, so we didn't create anything. return 0 endif " Use an existing list of lines of input if we have it, or get the lines " from the file. let l:lines = a:input isnot v:null ? a:input : getbufline(a:buffer, 1, '$') let l:temporary_directory = fnamemodify(a:temporary_file, ':h') " Create the temporary directory for the file, unreadable by 'other' " users. call mkdir(l:temporary_directory, '', 0750) " Automatically delete the directory later. call ale#command#ManageDirectory(a:buffer, l:temporary_directory) " Write the buffer out to a file. call ale#util#Writefile(a:buffer, l:lines, a:temporary_file) return 1 endfunction function! s:TemporaryFilename(buffer) abort let l:filename = fnamemodify(bufname(a:buffer), ':t') if empty(l:filename) " If the buffer's filename is empty, create a dummy filename. let l:ft = getbufvar(a:buffer, '&filetype') let l:filename = 'file' . ale#filetypes#GuessExtension(l:ft) endif " Create a temporary filename, / " The file itself will not be created by this function. return ale#util#Tempname() . (has('win32') ? '\' : '/') . l:filename endfunction " Given part of a command, replace any % with %%, so that no characters in " the string will be replaced with filenames, etc. function! ale#command#EscapeCommandPart(command_part) abort return substitute(a:command_part, '%', '%%', 'g') endfunction " Format a filename, converting it with filename mappings, if non-empty, " and escaping it for putting into a command string. " " The filename can be modified. function! s:FormatFilename(filename, mappings, modifiers) abort let l:filename = a:filename if !empty(a:mappings) let l:filename = ale#filename_mapping#Map(l:filename, a:mappings) endif if !empty(a:modifiers) let l:filename = fnamemodify(l:filename, a:modifiers) endif return ale#Escape(l:filename) endfunction " Produce a command prefix to check to a particular directory for a command. " %s format markers with filename-modifiers can be used as the directory, and " will be returned verbatim for formatting in paths relative to files. function! ale#command#CdString(directory) abort let l:match = matchstrpos(a:directory, s:path_format_regex) " Do not escape the directory here if it's a valid format string. " This allows us to use sequences like %s:h, %s:h:h, etc. let l:directory = l:match[1:] == [0, len(a:directory)] \ ? a:directory \ : ale#Escape(a:directory) if has('win32') return 'cd /d ' . l:directory . ' && ' endif return 'cd ' . l:directory . ' && ' endfunction " Given a command string, replace every... " %s -> with the current filename " %t -> with the name of an unused file in a temporary directory " %% -> with a literal % function! ale#command#FormatCommand( \ buffer, \ executable, \ command, \ pipe_file_if_needed, \ input, \ cwd, \ mappings, \) abort let l:temporary_file = '' let l:command = a:command if !empty(a:cwd) let l:command = ale#command#CdString(a:cwd) . l:command endif " First replace all uses of %%, used for literal percent characters, " with an ugly string. let l:command = substitute(l:command, '%%', '<>', 'g') " Replace %e with the escaped executable, if available. if !empty(a:executable) && l:command =~# '%e' let l:command = substitute(l:command, '%e', '\=ale#Escape(a:executable)', 'g') endif " Replace all %s occurrences in the string with the name of the current " file. if l:command =~# '%s' let l:filename = fnamemodify(bufname(a:buffer), ':p') let l:command = substitute( \ l:command, \ s:path_format_regex, \ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))', \ 'g' \) endif if a:input isnot v:false && l:command =~# '%t' " Create a temporary filename, / " The file itself will not be created by this function. let l:temporary_file = s:TemporaryFilename(a:buffer) let l:command = substitute( \ l:command, \ '\v\%t(%(:h|:t|:r|:e)*)', \ '\=s:FormatFilename(l:temporary_file, a:mappings, submatch(1))', \ 'g' \) endif " Finish formatting so %% becomes %. let l:command = substitute(l:command, '<>', '%', 'g') if a:pipe_file_if_needed && empty(l:temporary_file) " If we are to send the Vim buffer to a command, we'll do it " in the shell. We'll write out the file to a temporary file, " and then read it back in, in the shell. let l:temporary_file = s:TemporaryFilename(a:buffer) let l:command = l:command . ' < ' . ale#Escape(l:temporary_file) endif let l:file_created = ale#command#CreateTempFile( \ a:buffer, \ l:temporary_file, \ a:input, \) return [l:temporary_file, l:command, l:file_created] endfunction function! ale#command#StopJobs(buffer, job_type) abort let l:info = get(s:buffer_data, a:buffer, {}) if !empty(l:info) let l:new_map = {} for [l:job_id, l:job_type] in items(l:info.jobs) let l:job_id = str2nr(l:job_id) if a:job_type is# 'all' || a:job_type is# l:job_type call ale#job#Stop(l:job_id) else let l:new_map[l:job_id] = l:job_type endif endfor let l:info.jobs = l:new_map endif endfunction function! s:GatherOutput(line_list, job_id, line) abort call add(a:line_list, a:line) endfunction function! s:ExitCallback(buffer, line_list, Callback, data) abort if !has_key(s:buffer_data, a:buffer) return endif let l:jobs = s:buffer_data[a:buffer].jobs if !has_key(l:jobs, a:data.job_id) return endif let l:job_type = remove(l:jobs, a:data.job_id) if g:ale_history_enabled call ale#history#SetExitCode(a:buffer, a:data.job_id, a:data.exit_code) " Log the output of the command for ALEInfo if we should. if g:ale_history_log_output && a:data.log_output is 1 call ale#history#RememberOutput( \ a:buffer, \ a:data.job_id, \ a:line_list[:] \) endif endif " If the callback starts any new jobs, use the same job type for them. call setbufvar(a:buffer, 'ale_job_type', l:job_type) let l:value = a:Callback(a:buffer, a:line_list, { \ 'exit_code': a:data.exit_code, \ 'temporary_file': a:data.temporary_file, \}) let l:result = a:data.result let l:result.value = l:value " Set the default cwd for this buffer in this call stack. call ale#command#SetCwd(a:buffer, l:result.cwd) try if get(l:result, 'result_callback', v:null) isnot v:null call call(l:result.result_callback, [l:value]) endif finally call ale#command#ResetCwd(a:buffer) endtry endfunction function! ale#command#Run(buffer, command, Callback, ...) abort let l:options = get(a:000, 0, {}) if len(a:000) > 1 throw 'Too many arguments!' endif let l:output_stream = get(l:options, 'output_stream', 'stdout') let l:line_list = [] let l:cwd = get(l:options, 'cwd', v:null) if l:cwd is v:null " Default the working directory to whatever it was for the last " command run in the chain. let l:cwd = get(get(s:buffer_data, a:buffer, {}), 'cwd', v:null) endif let [l:temporary_file, l:command, l:file_created] = ale#command#FormatCommand( \ a:buffer, \ get(l:options, 'executable', ''), \ a:command, \ get(l:options, 'read_buffer', 0), \ get(l:options, 'input', v:null), \ l:cwd, \ get(l:options, 'filename_mappings', []), \) let l:command = ale#job#PrepareCommand(a:buffer, l:command) let l:job_options = { \ 'exit_cb': {job_id, exit_code -> s:ExitCallback( \ a:buffer, \ l:line_list, \ a:Callback, \ { \ 'job_id': job_id, \ 'exit_code': exit_code, \ 'temporary_file': l:temporary_file, \ 'log_output': get(l:options, 'log_output', 1), \ 'result': l:result, \ } \ )}, \ 'mode': 'nl', \} if l:output_stream is# 'stdout' let l:job_options.out_cb = function('s:GatherOutput', [l:line_list]) elseif l:output_stream is# 'stderr' let l:job_options.err_cb = function('s:GatherOutput', [l:line_list]) elseif l:output_stream is# 'both' let l:job_options.out_cb = function('s:GatherOutput', [l:line_list]) let l:job_options.err_cb = function('s:GatherOutput', [l:line_list]) endif let l:status = 'failed' if get(g:, 'ale_run_synchronously') == 1 if get(g:, 'ale_emulate_job_failure') == 1 let l:job_id = 0 else " Generate a fake job ID for tests. let s:fake_job_id = get(s:, 'fake_job_id', 0) + 1 let l:job_id = s:fake_job_id endif elseif has('win32') let l:job_id = ale#job#StartWithCmd(l:command, l:job_options) else let l:job_id = ale#job#Start(l:command, l:job_options) endif if l:job_id let l:status = 'started' let l:job_type = getbufvar(a:buffer, 'ale_job_type', 'all') call ale#command#InitData(a:buffer) let s:buffer_data[a:buffer].jobs[l:job_id] = l:job_type endif if g:ale_history_enabled call ale#history#Add(a:buffer, l:status, l:job_id, l:command) endif if !l:job_id return 0 endif " We'll return this Dictionary. A `result_callback` can be assigned to it " later for capturing the result of a:Callback. " " The `_deferred_job_id` is used for both checking the type of object, and " for checking the job ID and status. " " The cwd is kept and used as the default value for the next command in " the chain. " " The original command here is used in tests. let l:result = { \ '_deferred_job_id': l:job_id, \ 'executable': get(l:options, 'executable', ''), \ 'cwd': l:cwd, \ 'command': a:command, \} if get(g:, 'ale_run_synchronously') == 1 && l:job_id if !exists('g:ale_run_synchronously_callbacks') let g:ale_run_synchronously_callbacks = [] endif if get(g:, 'ale_run_synchronously_emulate_commands', 0) call add( \ g:ale_run_synchronously_callbacks, \ {exit_code, output -> [ \ extend(l:line_list, output), \ l:job_options.exit_cb(l:job_id, exit_code), \ ]} \) else " Run a command synchronously if this test option is set. call extend(l:line_list, systemlist( \ type(l:command) is v:t_list \ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2]) \ : l:command \)) " Don't capture output when the callbacks aren't set. if !has_key(l:job_options, 'out_cb') \&& !has_key(l:job_options, 'err_cb') let l:line_list = [] endif call add( \ g:ale_run_synchronously_callbacks, \ {-> l:job_options.exit_cb(l:job_id, v:shell_error)} \) endif endif return l:result endfunction function! ale#command#IsDeferred(value) abort return type(a:value) is v:t_dict && has_key(a:value, '_deferred_job_id') endfunction ================================================ FILE: autoload/ale/completion/python.vim ================================================ function! ale#completion#python#CompletionItemFilter(buffer, item) abort return a:item.label !~# '\v^__[a-z_]+__' endfunction ================================================ FILE: autoload/ale/completion.vim ================================================ " Author: w0rp " Description: Completion support for LSP linters scriptencoding utf-8 " The omnicompletion menu is shown through a special Plug mapping which is " only valid in Insert mode. This way, feedkeys() won't send these keys if you " quit Insert mode quickly enough. inoremap (ale_show_completion_menu) " If we hit the key sequence in normal mode, then we won't show the menu, so " we should restore the old settings right away. nnoremap (ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions() cnoremap (ale_show_completion_menu) vnoremap (ale_show_completion_menu) onoremap (ale_show_completion_menu) let g:ale_completion_delay = get(g:, 'ale_completion_delay', 100) let g:ale_completion_excluded_words = get(g:, 'ale_completion_excluded_words', []) let g:ale_completion_max_suggestions = get(g:, 'ale_completion_max_suggestions', 50) let g:ale_completion_autoimport = get(g:, 'ale_completion_autoimport', v:true) let g:ale_completion_tsserver_remove_warnings = get(g:, 'ale_completion_tsserver_remove_warnings', 0) let s:timer_id = -1 let s:last_done_pos = [] " CompletionItemKind values from the LSP protocol. let g:ale_lsp_types = { \ 1: 'text', \ 2: 'method', \ 3: 'function', \ 4: 'constructor', \ 5: 'field', \ 6: 'variable', \ 7: 'class', \ 8: 'interface', \ 9: 'module', \ 10: 'property', \ 11: 'unit', \ 12: 'value', \ 13: 'enum', \ 14: 'keyword', \ 15: 'snippet', \ 16: 'color', \ 17: 'file', \ 18: 'reference', \ 19: 'folder', \ 20: 'enum_member', \ 21: 'constant', \ 22: 'struct', \ 23: 'event', \ 24: 'operator', \ 25: 'type_parameter', \ } " from https://github.com/microsoft/TypeScript/blob/29becf05012bfa7ba20d50b0d16813971e46b8a6/lib/protocol.d.ts#L2472 let g:ale_tsserver_types = { \ 'warning': 'text', \ 'keyword': 'keyword', \ 'script': 'file', \ 'module': 'module', \ 'class': 'class', \ 'local class': 'class', \ 'interface': 'interface', \ 'type': 'class', \ 'enum': 'enum', \ 'enum member': 'enum_member', \ 'var': 'variable', \ 'local var': 'variable', \ 'function': 'function', \ 'local function': 'function', \ 'method': 'method', \ 'getter': 'property', \ 'setter': 'method', \ 'property': 'property', \ 'constructor': 'constructor', \ 'call': 'method', \ 'index': 'index', \ 'construct': 'constructor', \ 'parameter': 'parameter', \ 'type parameter': 'type_parameter', \ 'primitive type': 'unit', \ 'label': 'text', \ 'alias': 'class', \ 'const': 'constant', \ 'let': 'variable', \ 'directory': 'folder', \ 'external module name': 'text', \ 'JSX attribute': 'parameter', \ 'string': 'text' \ } " For compatibility reasons, we only use built in VIM completion kinds " See :help complete-items for Vim completion kinds let g:ale_completion_symbols = get(g:, 'ale_completion_symbols', { \ 'text': 'v', \ 'method': 'f', \ 'function': 'f', \ 'constructor': 'f', \ 'field': 'm', \ 'variable': 'v', \ 'class': 't', \ 'interface': 't', \ 'module': 'd', \ 'property': 'm', \ 'unit': 'v', \ 'value': 'v', \ 'enum': 't', \ 'keyword': 'v', \ 'snippet': 'v', \ 'color': 'v', \ 'file': 'v', \ 'reference': 'v', \ 'folder': 'v', \ 'enum_member': 'm', \ 'constant': 'm', \ 'struct': 't', \ 'event': 'v', \ 'operator': 'f', \ 'type_parameter': 'p', \ '': 'v' \ }) let s:LSP_INSERT_TEXT_FORMAT_PLAIN = 1 let s:LSP_INSERT_TEXT_FORMAT_SNIPPET = 2 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 = { \ '': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$', \ 'clojure': s:lisp_regex, \ 'lisp': s:lisp_regex, \ 'racket': '\k\+$', \ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$', \ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$', \ 'cpp': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$|-\>$', \ 'c': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|-\>$', \} " Regular expressions for finding the start column to replace with completion. let s:omni_start_map = { \ '': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$', \ 'racket': '\k\+$', \} " A map of exact characters for triggering LSP completions. Do not forget to " update self.input_patterns in ale.py in updating entries in this map. let s:trigger_character_map = { \ '': ['.'], \ 'typescript': ['.', '''', '"'], \ 'rust': ['.', '::'], \ 'cpp': ['.', '::', '->'], \ 'c': ['.', '->'], \} function! s:GetFiletypeValue(map, filetype) abort for l:part in reverse(split(a:filetype, '\.')) let l:regex = get(a:map, l:part, []) if !empty(l:regex) return l:regex endif endfor " Use the default regex for other files. return a:map[''] 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 " ^ " So we need check the text in the column before that position. return matchstr(getline(a:line)[: a:column - 2], l:regex) endfunction function! ale#completion#GetTriggerCharacter(filetype, prefix) abort if empty(a:prefix) return '' endif let l:char_list = s:GetFiletypeValue(s:trigger_character_map, a:filetype) if index(l:char_list, a:prefix) >= 0 return a:prefix endif return '' endfunction function! ale#completion#Filter( \ buffer, \ filetype, \ suggestions, \ prefix, \ exact_prefix_match, \) abort let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words') if empty(a:prefix) let l:filtered_suggestions = a:suggestions else let l:triggers = s:GetFiletypeValue(s:trigger_character_map, a:filetype) " For completing... " foo. " ^ " We need to include all of the given suggestions. if index(l:triggers, a:prefix) >= 0 || empty(a:prefix) let l:filtered_suggestions = a:suggestions else let l:filtered_suggestions = [] " Filter suggestions down to those starting with the prefix we " used for finding suggestions in the first place. " " Some completion tools will include suggestions which don't even " start with the characters we have already typed. 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) is v:t_string ? l:item : l:item.word if a:exact_prefix_match " Add suggestions if the word is an exact match. if l:word is# a:prefix call add(l:filtered_suggestions, l:item) endif else " Add suggestions if the suggestion starts with a " case-insensitive match for the prefix. if l:word[: len(a:prefix) - 1] is? a:prefix call add(l:filtered_suggestions, l:item) endif endif endfor endif endif if !empty(l:excluded_words) " Copy the List if needed. We don't want to modify the argument. " We shouldn't make a copy if we don't need to. if l:filtered_suggestions is a:suggestions let l:filtered_suggestions = copy(a:suggestions) endif " Remove suggestions with words in the exclusion List. call filter( \ l:filtered_suggestions, \ 'index(l:excluded_words, type(v:val) is v:t_string ? v:val : v:val.word) < 0', \) endif return l:filtered_suggestions endfunction function! s:ReplaceCompletionOptions(source) abort " Remember the old omnifunc value, if there is one. " If we don't store an old one, we'll just never reset the option. " This will stop some random exceptions from appearing. if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc) let b:ale_old_omnifunc = &l:omnifunc endif let &l:omnifunc = 'ale#completion#AutomaticOmniFunc' if a:source is# 'ale-automatic' if !exists('b:ale_old_completeopt') let b:ale_old_completeopt = &l:completeopt endif let l:opt_list = split(&l:completeopt, ',') " The menu and noinsert options must be set, or automatic completion " will be annoying. let l:new_opt_list = ['menu', 'menuone', 'noinsert'] " Permit some other completion options, provided users have set them. for l:opt in ['preview', 'popup', 'noselect'] if index(l:opt_list, l:opt) >= 0 call add(l:new_opt_list, l:opt) endif endfor let &l:completeopt = join(l:new_opt_list, ',') endif endfunction function! ale#completion#RestoreCompletionOptions() abort " Reset settings when completion is done. if exists('b:ale_old_omnifunc') if b:ale_old_omnifunc isnot# 'pythoncomplete#Complete' let &l:omnifunc = b:ale_old_omnifunc endif unlet b:ale_old_omnifunc endif if exists('b:ale_old_completeopt') let &l:completeopt = b:ale_old_completeopt unlet b:ale_old_completeopt endif endfunction function! ale#completion#GetCompletionPosition() abort if !exists('b:ale_completion_info') return 0 endif let l:line = b:ale_completion_info.line let l:column = b:ale_completion_info.column let l:regex = s:GetFiletypeValue(s:omni_start_map, &filetype) let l:up_to_column = getline(l:line)[: l:column - 2] let l:match = matchstr(l:up_to_column, l:regex) return l:column - len(l:match) - 1 endfunction function! ale#completion#GetCompletionPositionForDeoplete(input) abort return match(a:input, '\k*$') endfunction function! ale#completion#GetCompletionResult() abort if exists('b:ale_completion_result') return b:ale_completion_result endif return v:null endfunction function! ale#completion#AutomaticOmniFunc(findstart, base) abort if a:findstart return ale#completion#GetCompletionPosition() else let l:result = ale#completion#GetCompletionResult() let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') if l:source is# 'ale-automatic' || l:source is# 'ale-manual' call s:ReplaceCompletionOptions(l:source) endif return l:result isnot v:null ? l:result : [] endif endfunction function! s:OpenCompletionMenu(...) abort if !&l:paste call ale#util#FeedKeys("\(ale_show_completion_menu)") endif endfunction function! ale#completion#Show(result) abort let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') if ale#util#Mode() isnot# 'i' && l:source isnot# 'ale-import' return endif " Set the list in the buffer. let b:ale_completion_result = a:result " Don't try to open the completion menu if there's nothing to show. if empty(b:ale_completion_result) if l:source is# 'ale-import' " If we ran completion from :ALEImport, " tell the user that nothing is going to happen. call s:message('No possible imports found.') endif return endif " Replace completion options shortly before opening the menu. if l:source is# 'ale-automatic' || l:source is# 'ale-manual' call s:ReplaceCompletionOptions(l:source) call timer_start(0, function('s:OpenCompletionMenu')) endif if l:source is# 'ale-callback' call b:CompleteCallback(b:ale_completion_result) endif if l:source is# 'ale-import' call ale#completion#HandleUserData(b:ale_completion_result[0]) let l:text_changed = '' . g:ale_lint_on_text_changed " Check the buffer again right away, if linting is enabled. if g:ale_enabled \&& ( \ l:text_changed is# '1' \ || g:ale_lint_on_text_changed is v:true \ || l:text_changed is# 'always' \ || l:text_changed is# 'normal' \ || l:text_changed is# 'insert' \) call ale#Queue(0, '') endif endif endfunction function! ale#completion#GetAllTriggers() abort return deepcopy(s:trigger_character_map) endfunction function! ale#completion#GetCompletionKind(kind) abort let l:lsp_symbol = get(g:ale_lsp_types, a:kind, '') if !empty(l:lsp_symbol) return l:lsp_symbol endif return get(g:ale_tsserver_types, a:kind, '') endfunction function! ale#completion#GetCompletionSymbols(kind) abort let l:kind = ale#completion#GetCompletionKind(a:kind) let l:symbol = get(g:ale_completion_symbols, l:kind, '') if !empty(l:symbol) return l:symbol endif return get(g:ale_completion_symbols, '', 'v') endfunction function! s:CompletionStillValid(request_id) abort let [l:line, l:column] = getpos('.')[1:2] return has_key(b:, 'ale_completion_info') \&& ( \ ale#util#Mode() is# 'i' \ || b:ale_completion_info.source is# 'ale-import' \) \&& b:ale_completion_info.request_id == a:request_id \&& b:ale_completion_info.line == l:line \&& ( \ b:ale_completion_info.column == l:column \ || b:ale_completion_info.source is# 'ale-omnifunc' \ || b:ale_completion_info.source is# 'ale-callback' \ || b:ale_completion_info.source is# 'ale-import' \) endfunction function! ale#completion#ParseTSServerCompletions(response) abort let l:names = [] for l:suggestion in a:response.body let l:kind = get(l:suggestion, 'kind', '') if g:ale_completion_tsserver_remove_warnings == 0 || l:kind isnot# 'warning' call add(l:names, { \ 'word': l:suggestion.name, \ 'source': get(l:suggestion, 'source', ''), \}) endif endfor return l:names endfunction function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort let l:buffer = bufnr('') let l:results = [] let l:names_with_details = [] let l:info = get(b:, 'ale_completion_info', {}) for l:suggestion in a:response.body let l:displayParts = [] let l:local_name = v:null for l:action in get(l:suggestion, 'codeActions', []) call add(l:displayParts, l:action.description . ' ') endfor for l:part in l:suggestion.displayParts " Stop on stop on line breaks for the menu. if get(l:part, 'kind') is# 'lineBreak' break endif if get(l:part, 'kind') is# 'localName' let l:local_name = l:part.text endif call add(l:displayParts, l:part.text) endfor " Each one of these parts has 'kind' properties let l:documentationParts = [] for l:part in get(l:suggestion, 'documentation', []) call add(l:documentationParts, l:part.text) endfor " See :help complete-items let l:result = { \ 'word': ( \ l:suggestion.name is# 'default' \ && l:suggestion.kind is# 'alias' \ && !empty(l:local_name) \ ? l:local_name \ : l:suggestion.name \ ), \ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind), \ 'icase': 1, \ 'menu': join(l:displayParts, ''), \ 'dup': get(l:info, 'additional_edits_only', 0) \ || (g:ale_completion_autoimport + 0), \ 'info': join(l:documentationParts, ''), \} " This flag is used to tell if this completion came from ALE or not. let l:user_data = {'_ale_completion_item': 1} if has_key(l:suggestion, 'codeActions') let l:user_data.code_actions = l:suggestion.codeActions endif let l:result.user_data = json_encode(l:user_data) " Include this item if we'll accept any items, " or if we only want items with additional edits, and this has them. if !get(l:info, 'additional_edits_only', 0) \|| has_key(l:user_data, 'code_actions') call add(l:results, l:result) endif endfor let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', []) if !empty(l:names) && len(l:names) != len(l:results) let l:names_with_details = map(copy(l:results), 'v:val.word') let l:missing_names = filter( \ copy(l:names), \ 'index(l:names_with_details, v:val.word) < 0', \) for l:name in l:missing_names call add(l:results, { \ 'word': l:name.word, \ 'kind': 'v', \ 'icase': 1, \ 'menu': '', \ 'info': '', \ 'user_data': json_encode({'_ale_completion_item': 1}), \}) endfor endif return l:results endfunction function! ale#completion#NullFilter(buffer, item) abort return 1 endfunction function! ale#completion#ParseLSPCompletions(response) abort let l:buffer = bufnr('') let l:info = get(b:, 'ale_completion_info', {}) let l:Filter = get(l:info, 'completion_filter', v:null) if l:Filter is v:null let l:Filter = function('ale#completion#NullFilter') else let l:Filter = ale#util#GetFunction(l:Filter) endif let l:item_list = [] if type(get(a:response, 'result')) is v:t_list let l:item_list = a:response.result 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 let l:results = [] for l:item in l:item_list if !call(l:Filter, [l:buffer, l:item]) continue endif if get(l:item, 'insertTextFormat', s:LSP_INSERT_TEXT_FORMAT_PLAIN) is s:LSP_INSERT_TEXT_FORMAT_PLAIN \&& type(get(l:item, 'textEdit')) is v:t_dict let l:text = l:item.textEdit.newText elseif type(get(l:item, 'insertText')) is v:t_string let l:text = l:item.insertText else let l:text = l:item.label endif let l:word = matchstr(l:text, '\v^[^(]+') if empty(l:word) continue endif " Don't use LSP items with additional text edits when autoimport for " completions is turned off. if !empty(get(l:item, 'additionalTextEdits')) \&& !( \ get(l:info, 'additional_edits_only', 0) \ || g:ale_completion_autoimport \) continue 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 " Collapse whitespaces and line breaks into a single space. let l:detail = substitute(get(l:item, 'detail', ''), '\_s\+', ' ', 'g') let l:result = { \ 'word': l:word, \ 'kind': ale#completion#GetCompletionSymbols(get(l:item, 'kind', '')), \ 'icase': 1, \ 'menu': l:detail, \ 'dup': get(l:info, 'additional_edits_only', 0) \ || (g:ale_completion_autoimport + 0), \ 'info': (type(l:doc) is v:t_string ? l:doc : ''), \} " This flag is used to tell if this completion came from ALE or not. let l:user_data = {'_ale_completion_item': 1} if has_key(l:item, 'additionalTextEdits') \ && l:item.additionalTextEdits isnot v:null let l:text_changes = [] for l:edit in l:item.additionalTextEdits call add(l:text_changes, { \ 'start': { \ 'line': l:edit.range.start.line + 1, \ 'offset': l:edit.range.start.character + 1, \ }, \ 'end': { \ 'line': l:edit.range.end.line + 1, \ 'offset': l:edit.range.end.character + 1, \ }, \ 'newText': l:edit.newText, \}) endfor if !empty(l:text_changes) let l:user_data.code_actions = [{ \ 'description': 'completion', \ 'changes': [ \ { \ 'fileName': expand('#' . l:buffer . ':p'), \ 'textChanges': l:text_changes, \ }, \ ], \}] endif endif let l:result.user_data = json_encode(l:user_data) " Include this item if we'll accept any items, " or if we only want items with additional edits, and this has them. if !get(l:info, 'additional_edits_only', 0) \|| has_key(l:user_data, 'code_actions') call add(l:results, l:result) endif endfor if has_key(l:info, 'prefix') let l:results = ale#completion#Filter( \ l:buffer, \ &filetype, \ l:results, \ l:info.prefix, \ get(l:info, 'additional_edits_only', 0), \) endif return l:results[: g:ale_completion_max_suggestions - 1] endfunction function! ale#completion#HandleTSServerResponse(conn_id, response) abort if !s:CompletionStillValid(get(a:response, 'request_seq')) return endif if !has_key(a:response, 'body') return endif let l:buffer = bufnr('') let l:command = get(a:response, 'command', '') if l:command is# 'completions' let l:names = ale#completion#Filter( \ l:buffer, \ &filetype, \ ale#completion#ParseTSServerCompletions(a:response), \ b:ale_completion_info.prefix, \ get(b:ale_completion_info, 'additional_edits_only', 0), \)[: g:ale_completion_max_suggestions - 1] " We need to remember some names for tsserver, as it doesn't send " details back for everything we send. call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names) if empty(l:names) " Response with no results now and skip making a redundant request " for nothing. call ale#completion#Show([]) else let l:identifiers = [] for l:name in l:names let l:identifier = { \ 'name': l:name.word, \} let l:source = get(l:name, 'source', '') " Empty source results in no details for the completed item if !empty(l:source) call extend(l:identifier, { 'source': l:source }) endif call add(l:identifiers, l:identifier) endfor let b:ale_completion_info.request_id = ale#lsp#Send( \ b:ale_completion_info.conn_id, \ ale#lsp#tsserver_message#CompletionEntryDetails( \ l:buffer, \ b:ale_completion_info.line, \ b:ale_completion_info.column, \ l:identifiers, \ ), \) endif elseif l:command is# 'completionEntryDetails' call ale#completion#Show( \ ale#completion#ParseTSServerCompletionEntryDetails(a:response), \) endif endfunction function! ale#completion#HandleLSPResponse(conn_id, response) abort if !s:CompletionStillValid(get(a:response, 'id')) return endif call ale#completion#Show( \ ale#completion#ParseLSPCompletions(a:response), \) endfunction function! s:OnReady(linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'completion') return endif let l:buffer = a:lsp_details.buffer " 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, \ ( \ get(b:ale_completion_info, 'additional_edits_only', 0) \ || g:ale_completion_autoimport \ ) ? v:true : v:false, \) 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, \ 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 " This function can be called to check if ALE can provide completion data for " the current buffer. 1 will be returned if there's a potential source of " completion data ALE can use, and 0 will be returned otherwise. function! ale#completion#CanProvideCompletions() abort " NOTE: We can report that ALE can provide completions to Deoplete from " here, and we might ignore linters still below. for l:linter in ale#linter#Get(&filetype) if !empty(l:linter.lsp) return 1 endif endfor return 0 endfunction " This function can be used to manually trigger autocomplete, even when " g:ale_completion_enabled is set to false function! ale#completion#GetCompletions(...) abort let l:source = get(a:000, 0, '') let l:options = get(a:000, 1, {}) if len(a:000) > 2 throw 'Too many arguments!' endif let l:CompleteCallback = get(l:options, 'callback', v:null) if l:CompleteCallback isnot v:null let b:CompleteCallback = l:CompleteCallback endif if has_key(l:options, 'line') && has_key(l:options, 'column') " Use a provided line and column, if given. let l:line = l:options.line let l:column = l:options.column else let [l:line, l:column] = getpos('.')[1:2] endif if has_key(l:options, 'prefix') let l:prefix = l:options.prefix else let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) endif if l:source is# 'ale-automatic' && empty(l:prefix) return 0 endif let l:line_length = len(getline('.')) let b:ale_completion_info = { \ 'line': l:line, \ 'line_length': l:line_length, \ 'column': l:column, \ 'prefix': l:prefix, \ 'conn_id': 0, \ 'request_id': 0, \ 'source': l:source, \} unlet! b:ale_completion_result if has_key(l:options, 'additional_edits_only') let b:ale_completion_info.additional_edits_only = \ l:options.additional_edits_only endif let l:buffer = bufnr('') let l:Callback = function('s:OnReady') let l:started = 0 for l:linter in ale#lsp_linter#GetEnabled(l:buffer) if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) let l:started = 1 endif endfor return l:started endfunction function! s:message(message) abort call ale#util#Execute('echom ' . string(a:message)) endfunction " This function implements the :ALEImport command. function! ale#completion#Import() abort let l:word = expand('') if empty(l:word) call s:message('Nothing to complete at cursor!') return endif let [l:line, l:column] = getpos('.')[1:2] let l:column = searchpos('\V' . escape(l:word, '/\'), 'bnc', l:line)[1] let l:column = l:column + len(l:word) - 1 if l:column isnot 0 let l:started = ale#completion#GetCompletions('ale-import', { \ 'line': l:line, \ 'column': l:column, \ 'prefix': l:word, \ 'additional_edits_only': 1, \}) if !l:started call s:message('No completion providers are available.') endif endif endfunction function! ale#completion#OmniFunc(findstart, base) abort if a:findstart let l:started = ale#completion#GetCompletions('ale-omnifunc') if !l:started " This is the special value for cancelling completions silently. " See :help complete-functions return -3 endif return ale#completion#GetCompletionPosition() else let l:result = ale#completion#GetCompletionResult() while l:result is v:null && !complete_check() sleep 2ms let l:result = ale#completion#GetCompletionResult() endwhile return l:result isnot v:null ? l:result : [] endif endfunction function! s:TimerHandler(...) abort if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled) return endif let s:timer_id = -1 let [l:line, l:column] = getpos('.')[1:2] " When running the timer callback, we have to be sure that the cursor " hasn't moved from where it was when we requested completions by typing. if s:timer_pos == [l:line, l:column] && ale#util#Mode() is# 'i' call ale#completion#GetCompletions('ale-automatic') endif endfunction " Stop any completion timer that is queued. This is useful for tests. function! ale#completion#StopTimer() abort if s:timer_id != -1 call timer_stop(s:timer_id) endif let s:timer_id = -1 endfunction function! ale#completion#Queue() abort if !get(b:, 'ale_completion_enabled', g:ale_completion_enabled) return endif let s:timer_pos = getpos('.')[1:2] if s:timer_pos == s:last_done_pos " Do not ask for completions if the cursor rests on the position we " last completed on. return endif " If we changed the text again while we're still waiting for a response, " then invalidate the requests before the timer ticks again. if exists('b:ale_completion_info') let b:ale_completion_info.request_id = 0 endif call ale#completion#StopTimer() let s:timer_id = timer_start(g:ale_completion_delay, function('s:TimerHandler')) endfunction function! ale#completion#HandleUserData(completed_item) abort let l:user_data_json = get(a:completed_item, 'user_data', '') let l:user_data = type(l:user_data_json) is v:t_dict \ ? l:user_data_json \ : ale#util#FuzzyJSONDecode(l:user_data_json, {}) if !has_key(l:user_data, '_ale_completion_item') return endif let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') if l:source is# 'ale-automatic' \|| l:source is# 'ale-manual' \|| l:source is# 'ale-callback' \|| l:source is# 'ale-import' \|| l:source is# 'ale-omnifunc' for l:code_action in get(l:user_data, 'code_actions', []) call ale#code_action#HandleCodeAction(l:code_action, {}) endfor endif silent doautocmd User ALECompletePost endfunction function! ale#completion#Done() abort silent! pclose call ale#completion#RestoreCompletionOptions() let s:last_done_pos = getpos('.')[1:2] endfunction augroup ALECompletionActions autocmd! autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item) augroup END function! s:Setup(enabled) abort augroup ALECompletionGroup autocmd! if a:enabled autocmd TextChangedI * call ale#completion#Queue() autocmd CompleteDone * call ale#completion#Done() endif augroup END if !a:enabled augroup! ALECompletionGroup endif endfunction function! ale#completion#Enable() abort let g:ale_completion_enabled = 1 call s:Setup(1) endfunction function! ale#completion#Disable() abort let g:ale_completion_enabled = 0 call s:Setup(0) endfunction ================================================ FILE: autoload/ale/cursor.vim ================================================ scriptencoding utf-8 " Author: w0rp " Author: João Paulo S. de Souza " Description: Echoes lint message for the current line, if any " Controls the milliseconds delay before echoing a message. let g:ale_echo_delay = get(g:, 'ale_echo_delay', 10) " A string format for the echoed message. let g:ale_echo_msg_format = get(g:, 'ale_echo_msg_format', '%code: %%s') let s:cursor_timer = -1 " A wrapper for echon so we can test messages we echo in Vader tests. function! ale#cursor#Echom(message) abort if mode() is# 'n' " no-custom-checks exec "norm! :echom a:message\n" endif endfunction function! ale#cursor#TruncatedEcho(original_message) abort let l:message = a:original_message " Change tabs to spaces. let l:message = substitute(l:message, "\t", ' ', 'g') " Remove any newlines in the message. let l:message = substitute(l:message, "\n", ' ', 'g') " Convert indentation groups into single spaces for better legibility when " put on a single line let l:message = substitute(l:message, ' \+', ' ', 'g') " We need to remember the setting for shortmess and reset it again. let l:shortmess_options = &l:shortmess try let l:cursor_position = getpos('.') " The message is truncated and saved to the history. silent! setlocal shortmess+=T try call ale#cursor#Echom(l:message) 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' catch /E481/ " Do nothing if running from a visual selection. 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 " line. if l:cursor_position != getpos('.') call setpos('.', l:cursor_position) endif finally let &l:shortmess = l:shortmess_options endtry 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#cursor#EchoCursorWarning(...) abort 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(1) isnot# 'n' return endif if ale#ShouldDoNothing(l:buffer) return endif 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. " " no-custom-checks echo let l:info.echoed = 0 endif endif 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 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(1) isnot# 'n' return endif call s:StopCursorTimer() let l:pos = getpos('.')[0:2] if !exists('w:last_pos') let w:last_pos = [0, 0, 0] endif " Check the current buffer, line, and column number against the last " recorded position. If the position has actually changed, *then* " we should echo something. Otherwise we can end up doing processing " the echo message far too frequently. if l:pos != w:last_pos let l:delay = ale#Var(l:buffer, 'echo_delay') let w:last_pos = l:pos let s:cursor_timer = timer_start( \ l:delay, \ function('ale#cursor#EchoCursorWarning') \) 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") if g:ale_floating_preview || g:ale_detail_to_floating_preview call ale#floating_preview#Show(l:lines) else call ale#preview#Show(l:lines, {'stay_here': l:stay_here}) " Clear the echo message if we manually displayed details. if !l:stay_here " no-custom-checks echo endif 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(l:buffer) return endif call s:StopCursorTimer() let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer) if !empty(l:loc) call s:ShowCursorDetailForItem(l:loc, {'stay_here': 0}) endif endfunction ================================================ FILE: autoload/ale/d.vim ================================================ " Author: Auri " 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 ================================================ FILE: autoload/ale/debugging.vim ================================================ " Author: w0rp " Description: This file implements debugging information for ALE let g:ale_info_default_mode = get(g:, 'ale_info_default_mode', 'preview') let s:global_variable_list = [ \ 'ale_cache_executable_check_failures', \ 'ale_change_sign_column_color', \ 'ale_command_wrapper', \ 'ale_completion_delay', \ 'ale_completion_enabled', \ 'ale_completion_max_suggestions', \ 'ale_disable_lsp', \ 'ale_echo_cursor', \ 'ale_echo_msg_error_str', \ 'ale_echo_msg_format', \ 'ale_echo_msg_info_str', \ 'ale_echo_msg_warning_str', \ 'ale_enabled', \ 'ale_fix_on_save', \ 'ale_fixers', \ 'ale_history_enabled', \ 'ale_info_default_mode', \ 'ale_history_log_output', \ 'ale_keep_list_window_open', \ '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_linter_aliases', \ 'ale_linters', \ 'ale_linters_explicit', \ 'ale_linters_ignore', \ 'ale_list_vertical', \ 'ale_list_window_size', \ 'ale_loclist_msg_format', \ 'ale_max_buffer_history_size', \ 'ale_max_signs', \ 'ale_maximum_file_size', \ 'ale_open_list', \ 'ale_pattern_options', \ 'ale_pattern_options_enabled', \ 'ale_root', \ 'ale_set_balloons', \ 'ale_set_highlights', \ 'ale_set_loclist', \ 'ale_set_quickfix', \ 'ale_set_signs', \ 'ale_sign_column_always', \ 'ale_sign_error', \ 'ale_sign_info', \ 'ale_sign_offset', \ 'ale_sign_style_error', \ 'ale_sign_style_warning', \ 'ale_sign_warning', \ 'ale_sign_highlight_linenrs', \ 'ale_type_map', \ 'ale_use_neovim_diagnostics_api', \ 'ale_use_global_executables', \ 'ale_virtualtext_cursor', \ 'ale_warn_about_trailing_blank_lines', \ 'ale_warn_about_trailing_whitespace', \] function! s:Echo(message) abort " no-custom-checks echo a:message endfunction function! s:GetLinterVariables(filetype, exclude_linter_names) abort let l:variable_list = [] let l:filetype_parts = split(a:filetype, '\.') for l:key in keys(g:) " Extract variable names like: 'ale_python_flake8_executable' let l:match = matchlist(l:key, '\v^ale_([^_]+)_([^_]+)_.+$') " Include matching variables. if !empty(l:match) \&& index(l:filetype_parts, l:match[1]) >= 0 \&& index(a:exclude_linter_names, l:match[2]) == -1 call add(l:variable_list, l:key) endif endfor call sort(l:variable_list) return l:variable_list endfunction function! s:EchoLinterVariables(variable_list) abort for l:key in a:variable_list call s:Echo('let g:' . l:key . ' = ' . string(g:[l:key])) if has_key(b:, l:key) call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key])) endif endfor endfunction function! s:EchoGlobalVariables() abort for l:key in s:global_variable_list call s:Echo('let g:' . l:key . ' = ' . string(get(g:, l:key, v:null))) if has_key(b:, l:key) call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key])) endif endfor endfunction " Echo a command that was run. function! s:EchoCommand(item) abort let l:status_message = a:item.status " Include the exit code in output if we have it. if a:item.status is# 'finished' let l:status_message .= ' - exit code ' . a:item.exit_code endif call s:Echo('(' . l:status_message . ') ' . string(a:item.command)) if g:ale_history_log_output && has_key(a:item, 'output') if empty(a:item.output) call s:Echo('') call s:Echo('<<>>') call s:Echo('') else call s:Echo('') call s:Echo('<<>>') for l:line in a:item.output call s:Echo(l:line) endfor call s:Echo('<<>>') call s:Echo('') endif endif endfunction " Echo the results of an executable check. function! s:EchoExecutable(item) abort call s:Echo(printf( \ '(executable check - %s) %s', \ a:item.status ? 'success' : 'failure', \ a:item.command, \)) endfunction function! s:EchoCommandHistory() abort let l:buffer = bufnr('%') for l:item in ale#history#Get(l:buffer) if l:item.job_id is# 'executable' call s:EchoExecutable(l:item) else call s:EchoCommand(l:item) endif endfor endfunction function! s:EchoLinterAliases(all_linters) abort let l:first = 1 for l:linter in a:all_linters if !empty(l:linter.aliases) if l:first call s:Echo(' Linter Aliases:') endif let l:first = 0 call s:Echo(string(l:linter.name) . ' -> ' . string(l:linter.aliases)) endif endfor endfunction function! s:EchoLSPErrorMessages(all_linter_names) abort let l:lsp_error_messages = get(g:, 'ale_lsp_error_messages', {}) let l:header_echoed = 0 for l:linter_name in a:all_linter_names let l:error_list = get(l:lsp_error_messages, l:linter_name, []) if !empty(l:error_list) if !l:header_echoed call s:Echo(' LSP Error Messages:') call s:Echo('') endif call s:Echo('(Errors for ' . l:linter_name . ')') for l:message in l:error_list for l:line in split(l:message, "\n") call s:Echo(l:line) endfor endfor endif endfor endfunction function! s:GetIgnoredLinters(buffer, enabled_linters) abort let l:filetype = &filetype let l:ignore_config = ale#Var(a:buffer, 'linters_ignore') let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp') if ( \ !empty(l:ignore_config) \ || l:disable_lsp is 1 \ || l:disable_lsp is v:true \ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0)) \) let l:non_ignored = ale#engine#ignore#Exclude( \ l:filetype, \ a:enabled_linters, \ l:ignore_config, \ l:disable_lsp, \) else let l:non_ignored = copy(a:enabled_linters) endif call map(l:non_ignored, 'v:val.name') return filter( \ copy(a:enabled_linters), \ 'index(l:non_ignored, v:val.name) < 0' \) endfunction function! ale#debugging#Info(...) abort let l:options = (a:0 > 0) ? a:1 : {} let l:show_preview_info = get(l:options, 'preview') let l:buffer = bufnr('') let l:filetype = &filetype let l:enabled_linters = deepcopy(ale#linter#Get(l:filetype)) " But have to build the list of available linters ourselves. let l:all_linters = [] let l:linter_variable_list = [] for l:part in split(l:filetype, '\.') let l:aliased_filetype = ale#linter#ResolveFiletype(l:part) call extend(l:all_linters, ale#linter#GetAll(l:aliased_filetype)) endfor let l:all_names = map(copy(l:all_linters), 'v:val[''name'']') let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']') let l:exclude_names = filter(copy(l:all_names), 'index(l:enabled_names, v:val) == -1') " Load linter variables to display " This must be done after linters are loaded. let l:variable_list = s:GetLinterVariables(l:filetype, l:exclude_names) let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype) let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1])) let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '') " Get the names of ignored linters. let l:ignored_names = map( \ s:GetIgnoredLinters(l:buffer, l:enabled_linters), \ 'v:val.name' \) call s:Echo(' Current Filetype: ' . l:filetype) call s:Echo('Available Linters: ' . string(l:all_names)) call s:EchoLinterAliases(l:all_linters) call s:Echo(' Enabled Linters: ' . string(l:enabled_names)) call s:Echo(' Ignored Linters: ' . string(l:ignored_names)) call s:Echo(' Suggested Fixers:' . l:fixers_string) " We use this line with only a space to know where to end highlights. call s:Echo(' ') " Only show Linter Variables directive if there are any. if !empty(l:variable_list) call s:Echo(' Linter Variables:') if l:show_preview_info call s:Echo('" Press Space to read :help for a setting') endif call s:EchoLinterVariables(l:variable_list) " We use this line with only a space to know where to end highlights. call s:Echo(' ') endif call s:Echo(' Global Variables:') if l:show_preview_info call s:Echo('" Press Space to read :help for a setting') endif call s:EchoGlobalVariables() call s:Echo(' ') call s:EchoLSPErrorMessages(l:all_names) call s:Echo(' Command History:') call s:Echo('') call s:EchoCommandHistory() endfunction function! ale#debugging#InfoToClipboard() abort if !has('clipboard') call s:Echo('clipboard not available. Try :ALEInfoToFile instead.') return endif let l:output = execute('call ale#debugging#Info()') let @+ = l:output call s:Echo('ALEInfo copied to your clipboard') endfunction function! ale#debugging#InfoToFile(filename) abort let l:expanded_filename = expand(a:filename) let l:output = execute('call ale#debugging#Info()') call writefile(split(l:output, "\n"), l:expanded_filename) call s:Echo('ALEInfo written to ' . l:expanded_filename) endfunction function! ale#debugging#InfoToPreview() abort let l:output = execute('call ale#debugging#Info({''preview'': 1})') call ale#preview#Show(split(l:output, "\n"), { \ 'filetype': 'ale-info', \}) endfunction function! ale#debugging#InfoCommand(...) abort if len(a:000) > 1 " no-custom-checks echom 'Invalid ALEInfo arguments!' return endif " Do not show info for the info window itself. if &filetype is# 'ale-info' return endif " Get 'echo' from '-echo', if there's an argument. let l:mode = get(a:000, '')[1:] if empty(l:mode) let l:mode = ale#Var(bufnr(''), 'info_default_mode') endif if l:mode is# 'echo' call ale#debugging#Info() elseif l:mode is# 'clip' || l:mode is# 'clipboard' call ale#debugging#InfoToClipboard() else call ale#debugging#InfoToPreview() endif endfunction function! ale#debugging#InfoToClipboardDeprecatedCommand() abort " no-custom-checks echom 'ALEInfoToClipboard is deprecated. Use ALEInfo -clipboard instead.' call ale#debugging#InfoToClipboard() endfunction ================================================ FILE: autoload/ale/definition.vim ================================================ " Author: w0rp " Description: Go to definition support for LSP linters. let s:go_to_definition_map = {} " Enable automatic updates of the tagstack let g:ale_update_tagstack = get(g:, 'ale_update_tagstack', v:true) let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer') " Used to get the definition map in tests. function! ale#definition#GetMap() abort return deepcopy(s:go_to_definition_map) endfunction " Used to set the definition map in tests. function! ale#definition#SetMap(map) abort let s:go_to_definition_map = a:map endfunction function! ale#definition#ClearLSPData() abort let s:go_to_definition_map = {} endfunction function! ale#definition#UpdateTagStack() abort let l:should_update_tagstack = exists('*gettagstack') && exists('*settagstack') && g:ale_update_tagstack if l:should_update_tagstack " Grab the old location (to jump back to) and the word under the " cursor (as a label for the tagstack) let l:old_location = [bufnr('%'), line('.'), col('.'), 0] let l:tagname = expand('') let l:winid = win_getid() call settagstack(l:winid, {'items': [{'from': l:old_location, 'tagname': l:tagname}]}, 'a') call settagstack(l:winid, {'curidx': len(gettagstack(l:winid)['items']) + 1}) endif endfunction function! ale#definition#FormatTSServerResponse(response_item, options) abort if get(a:options, 'open_in') is# 'quickfix' return { \ 'filename': a:response_item.file, \ 'lnum': a:response_item.start.line, \ 'col': a:response_item.start.offset, \} else return { \ 'filename': a:response_item.file, \ 'line': a:response_item.start.line, \ 'column': a:response_item.start.offset, \} endif endfunction function! ale#definition#HandleTSServerResponse(conn_id, response) abort if has_key(a:response, 'request_seq') \&& has_key(s:go_to_definition_map, a:response.request_seq) let l:options = remove(s:go_to_definition_map, a:response.request_seq) if get(a:response, 'success', v:false) is v:true && !empty(a:response.body) let l:item_list = [] for l:response_item in a:response.body call add( \ l:item_list, \ ale#definition#FormatTSServerResponse(l:response_item, l:options) \) endfor if empty(l:item_list) call ale#util#Execute('echom ''No definitions found''') elseif len(l:item_list) == 1 let l:filename = l:item_list[0].filename if get(l:options, 'open_in') is# 'quickfix' let l:line = l:item_list[0].lnum let l:column = l:item_list[0].col else let l:line = l:item_list[0].line let l:column = l:item_list[0].column endif call ale#definition#UpdateTagStack() call ale#util#Open(l:filename, l:line, l:column, l:options) else if get(l:options, 'open_in') is# 'quickfix' call setqflist([], 'r') call setqflist(l:item_list, 'a') call ale#util#Execute('cc 1') else call ale#definition#UpdateTagStack() call ale#preview#ShowSelection(l:item_list, l:options) endif endif endif endif endfunction function! ale#definition#FormatLSPResponse(response_item, options) abort if has_key(a:response_item, 'targetUri') " LocationLink items use targetUri let l:uri = a:response_item.targetUri let l:line = a:response_item.targetRange.start.line + 1 let l:column = a:response_item.targetRange.start.character + 1 else " LocationLink items use uri let l:uri = a:response_item.uri let l:line = a:response_item.range.start.line + 1 let l:column = a:response_item.range.start.character + 1 endif if get(a:options, 'open_in') is# 'quickfix' return { \ 'filename': ale#util#ToResource(l:uri), \ 'lnum': l:line, \ 'col': l:column, \} else return { \ 'filename': ale#util#ToResource(l:uri), \ 'line': l:line, \ 'column': l:column, \} endif endfunction function! ale#definition#HandleLSPResponse(conn_id, response) abort if has_key(a:response, 'id') \&& has_key(s:go_to_definition_map, a:response.id) let l:options = remove(s:go_to_definition_map, a:response.id) " 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 v:t_dict let l:result = [l:result] elseif type(l:result) isnot v:t_list let l:result = [] endif let l:item_list = [] for l:response_item in l:result call add(l:item_list, \ ale#definition#FormatLSPResponse(l:response_item, l:options) \) endfor if empty(l:item_list) call ale#util#Execute('echom ''No definitions found''') elseif len(l:item_list) == 1 call ale#definition#UpdateTagStack() let l:uri = ale#util#ToURI(l:item_list[0].filename) if get(l:options, 'open_in') is# 'quickfix' let l:line = l:item_list[0].lnum let l:column = l:item_list[0].col else let l:line = l:item_list[0].line let l:column = l:item_list[0].column endif let l:uri_handler = ale#uri#GetURIHandler(l:uri) if l:uri_handler is# v:null let l:filename = ale#path#FromFileURI(l:uri) call ale#util#Open(l:filename, l:line, l:column, l:options) else call l:uri_handler.OpenURILink(l:uri, l:line, l:column, l:options, a:conn_id) endif else if get(l:options, 'open_in') is# 'quickfix' call setqflist([], 'r') call setqflist(l:item_list, 'a') call ale#util#Execute('cc 1') else call ale#definition#UpdateTagStack() call ale#preview#ShowSelection(l:item_list, l:options) endif endif endif endfunction function! s:OnReady(line, column, options, capability, linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, a:capability) return endif let l:buffer = a:lsp_details.buffer 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' if a:capability is# 'definition' let l:message = ale#lsp#tsserver_message#Definition( \ l:buffer, \ a:line, \ a:column \) elseif a:capability is# 'typeDefinition' let l:message = ale#lsp#tsserver_message#TypeDefinition( \ l:buffer, \ a:line, \ a:column \) elseif a:capability is# 'implementation' let l:message = ale#lsp#tsserver_message#Implementation( \ l:buffer, \ a:line, \ a:column \) endif 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. if a:capability is# 'definition' let l:message = ale#lsp#message#Definition(l:buffer, a:line, a:column) elseif a:capability is# 'typeDefinition' let l:message = ale#lsp#message#TypeDefinition(l:buffer, a:line, a:column) elseif a:capability is# 'implementation' let l:message = ale#lsp#message#Implementation(l:buffer, a:line, a:column) else " XXX: log here? return endif endif let l:request_id = ale#lsp#Send(l:id, l:message) let s:go_to_definition_map[l:request_id] = { \ 'open_in': get(a:options, 'open_in', 'current-buffer'), \} endfunction function! s:GoToLSPDefinition(linter, options, capability) abort let l:buffer = bufnr('') let [l:line, l:column] = getpos('.')[1:2] let l:column = min([l:column, len(getline(l:line))]) let l:Callback = function( \ 's:OnReady', \ [l:line, l:column, a:options, a:capability] \) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction function! ale#definition#GoTo(options) abort for l:linter in ale#lsp_linter#GetEnabled(bufnr('')) call s:GoToLSPDefinition(l:linter, a:options, 'definition') endfor endfunction function! ale#definition#GoToType(options) abort for l:linter in ale#lsp_linter#GetEnabled(bufnr('')) call s:GoToLSPDefinition(l:linter, a:options, 'typeDefinition') endfor endfunction function! ale#definition#GoToImpl(options) abort for l:linter in ale#lsp_linter#GetEnabled(bufnr('')) call s:GoToLSPDefinition(l:linter, a:options, 'implementation') endfor endfunction function! ale#definition#GoToCommandHandler(command, ...) abort let l:options = {} if len(a:000) > 0 for l:option in a:000 if l:option is? '-tab' let l:options.open_in = 'tab' elseif l:option is? '-split' let l:options.open_in = 'split' elseif l:option is? '-vsplit' let l:options.open_in = 'vsplit' endif endfor endif if !has_key(l:options, 'open_in') let l:default_navigation = ale#Var(bufnr(''), 'default_navigation') if index(['tab', 'split', 'vsplit'], l:default_navigation) >= 0 let l:options.open_in = l:default_navigation endif endif if a:command is# 'type' call ale#definition#GoToType(l:options) elseif a:command is# 'implementation' call ale#definition#GoToImpl(l:options) else call ale#definition#GoTo(l:options) endif endfunction ================================================ FILE: autoload/ale/dhall.vim ================================================ " Author: Pat Brisbin , toastal " Description: Functions for working with Dhall’s executable call ale#Set('dhall_executable', 'dhall') call ale#Set('dhall_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('dhall_options', '') function! ale#dhall#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'dhall_executable') " Dhall is written in Haskell and commonly installed with Stack return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'dhall') endfunction function! ale#dhall#GetExecutableWithOptions(buffer) abort let l:executable = ale#dhall#GetExecutable(a:buffer) return l:executable \ . ale#Pad(ale#Var(a:buffer, 'dhall_options')) endfunction function! ale#dhall#GetCommand(buffer) abort return '%e ' . ale#Pad(ale#Var(a:buffer, 'dhall_options')) endfunction ================================================ FILE: autoload/ale/engine/ignore.vim ================================================ " Author: w0rp " Description: Code for ignoring linters. Only loaded and if configured. " A map for remapping lspconfig server names to linter names or aliases in " ALE. We should change the names where they will conflict with names in ALE. " " Notes on names from nvim-lspconfig not included here. " " * 'rubocop' is run in a language server mode " * 'eslint' is run via 'vscode-eslint-language-server' let s:lspconfig_map = { \ 'als': 'adals', \ 'ansiblels': 'ansible-language-server', \ 'bicep': 'bicep_language_server', \ 'cmake': 'cmake_language_server', \ 'denols': 'deno', \ 'erlangls': 'erlang_ls', \ 'html': 'vscodehtml', \ 'ocamlls': 'ocaml-language-server', \ 'ols': 'odin-lsp', \ 'puppet': 'puppet_languageserver', \} " 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 v:t_list return a:config endif if type(a:config) is v:t_dict let l:names_to_remove = [] for l:part in split(a:filetype , '\.') call extend(l:names_to_remove, get(a:config, l:part, [])) endfor return l:names_to_remove endif return [] endfunction " This function can be mocked in tests. function! ale#engine#ignore#GetLSPConfigNames() abort return luaeval('require ''ale.util''.configured_lspconfig_servers()') endfunction function! s:GetMappedLSPConfigNames() abort " Check the lspconfig flag before calling luaeval. if !get(g:, 'lspconfig', 0) return [] endif let l:lspconfig_servers = ale#engine#ignore#GetLSPConfigNames() return map( \ !empty(l:lspconfig_servers) ? l:lspconfig_servers : [], \ {_, val -> get(s:lspconfig_map, val, val) } \) endfunction " Given a List of linter descriptions, exclude the linters to be ignored. function! ale#engine#ignore#Exclude(filetype, all_linters, config, disable_lsp) abort let l:names_to_remove = ale#engine#ignore#GetList(a:filetype, a:config) " If configured to automatically ignore otherwise configured LSP linter " names, add them to the names to remove. This could ignore linters " with matching names that are not marked as LSP linters. if a:disable_lsp is# 'auto' call extend(l:names_to_remove, s:GetMappedLSPConfigNames()) endif let l:ignore_all_lsps = a:disable_lsp is 1 || a:disable_lsp is v:true let l:filtered_linters = [] for l:linter in a:all_linters let l:should_include = index(l:names_to_remove, l:linter.name) == -1 let l:i = 0 while l:should_include && l:i < len(l:linter.aliases) let l:name = l:linter.aliases[l:i] let l:should_include = index(l:names_to_remove, l:name) == -1 let l:i += 1 endwhile if l:should_include && l:ignore_all_lsps let l:should_include = empty(get(l:linter, 'lsp')) endif if l:should_include call add(l:filtered_linters, l:linter) endif endfor return l:filtered_linters endfunction ================================================ FILE: autoload/ale/engine.vim ================================================ " Author: w0rp " Description: Backend execution and job management " Executes linters in the background, using NeoVim or Vim 8 jobs " Remapping of linter problems. let g:ale_type_map = get(g:, 'ale_type_map', {}) let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {}) 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#MarkLinterActive(info, linter) abort let l:found = 0 for l:other_linter in a:info.active_linter_list if l:other_linter.name is# a:linter.name let l:found = 1 break endif endfor if !l:found call add(a:info.active_linter_list, a:linter) endif endfunction function! ale#engine#MarkLinterInactive(info, linter_name) abort call filter(a:info.active_linter_list, 'v:val.name isnot# a:linter_name') endfunction function! ale#engine#ResetExecutableCache() abort let s:executable_cache_map = {} endfunction " Check if files are executable, and if they are, remember that they are " for subsequent calls. We'll keep checking until programs can be executed. function! ale#engine#IsExecutable(buffer, executable) abort if empty(a:executable) " Don't log the executable check if the executable string is empty. return 0 endif " Check for a cached executable() check. let l:result = get(s:executable_cache_map, a:executable, v:null) if l:result isnot v:null return l:result endif " Check if the file is executable, and convert -1 to 1. let l:result = executable(a:executable) isnot 0 " Cache the executable check if we found it, or if the option to cache " failing checks is on. if l:result || get(g:, 'ale_cache_executable_check_failures') let s:executable_cache_map[a:executable] = l:result endif if g:ale_history_enabled call ale#history#Add(a:buffer, l:result, 'executable', a:executable) endif return l:result endfunction function! ale#engine#InitBufferInfo(buffer) abort if !has_key(g:ale_buffer_info, a:buffer) " active_linter_list will hold the list of active linter names " loclist holds the loclist items after all jobs have completed. let g:ale_buffer_info[a:buffer] = { \ 'active_linter_list': [], \ 'active_other_sources_list': [], \ 'loclist': [], \} return 1 endif return 0 endfunction " This function is documented and part of the public API. " " Return 1 if ALE is busy checking a given buffer 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 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 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.name 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:from_other_source, \ a:loclist, \) " Remove previous items for this linter. call filter(l:info.loclist, 'v:val.linter_name isnot# a:linter_name') " We don't need to add items or sort the list when this list is empty. if !empty(l:linter_loclist) " Add the new items. call extend(l:info.loclist, l:linter_loclist) " Sort the loclist again. " We need a sorted list so we can run a binary search against it " for efficient lookup of the messages in the cursor handler. call sort(l:info.loclist, 'ale#util#LocItemCompare') endif if ale#ShouldDoNothing(a:buffer) return endif call ale#engine#SetResults(a:buffer, l:info.loclist) endfunction function! s:HandleExit(job_info, buffer, output, data) abort let l:buffer_info = get(g:ale_buffer_info, a:buffer) if empty(l:buffer_info) return endif let l:linter = a:job_info.linter let l:executable = a:job_info.executable " Remove this job from the list. call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name) " Stop here if we land in the handle for a job completing if we're in " a sandbox. if ale#util#InSandbox() return endif if has('nvim') && !empty(a:output) && empty(a:output[-1]) call remove(a:output, -1) endif try let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output) " Handle the function being unknown, or being deleted. catch /E700/ let l:loclist = [] endtry if type(l:loclist) isnot# v:t_list " we only expect the list type; don't pass anything else down to " `ale#engine#HandleLoclist` since it won't understand it let l:loclist = [] endif call ale#engine#HandleLoclist(l:linter.name, a:buffer, l:loclist, 0) endfunction function! ale#engine#SetResults(buffer, loclist) abort let l:linting_is_done = !ale#engine#IsCheckingBuffer(a:buffer) if g:ale_use_neovim_diagnostics_api call ale#engine#SendResultsToNeovimDiagnostics(a:buffer, a:loclist) endif " Set signs first. This could potentially fix some line numbers. " The List could be sorted again here by SetSigns. if !g:ale_use_neovim_diagnostics_api && g:ale_set_signs call ale#sign#SetSigns(a:buffer, a:loclist) endif if g:ale_set_quickfix || g:ale_set_loclist call ale#list#SetLists(a:buffer, a:loclist) endif if exists('*ale#statusline#Update') " Don't load/run if not already loaded. call ale#statusline#Update(a:buffer, a:loclist) endif if !g:ale_use_neovim_diagnostics_api && g:ale_set_highlights call ale#highlight#SetHighlights(a:buffer, a:loclist) endif if !g:ale_use_neovim_diagnostics_api \&& (g:ale_virtualtext_cursor is# 'all' || g:ale_virtualtext_cursor == 2) call ale#virtualtext#SetTexts(a:buffer, a:loclist) endif if l:linting_is_done if g:ale_echo_cursor " Try and echo the warning now. " This will only do something meaningful if we're in normal mode. call ale#cursor#EchoCursorWarning() endif if !g:ale_use_neovim_diagnostics_api \&& (g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor == 1) " 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. call setbufvar( \ a:buffer, \ 'ale_linted', \ getbufvar(a:buffer, 'ale_linted', 0) + 1 \) " Automatically remove all managed temporary files and directories " now that all jobs have completed. call ale#command#RemoveManagedFiles(a:buffer) " Call user autocommands. This allows users to hook into ALE's lint cycle. silent doautocmd User ALELintPost endif endfunction function! ale#engine#SendResultsToNeovimDiagnostics(buffer, loclist) abort if !has('nvim-0.6') " We will warn the user on startup as well if they try to set " g:ale_use_neovim_diagnostics_api outside of a Neovim context. return endif " Keep the Lua surface area really small in the VimL part of ALE, " and just require the diagnostics.lua module on demand. let l:SendDiagnostics = luaeval('require("ale.diagnostics").send') call l:SendDiagnostics(a:buffer, a:loclist) endfunction function! s:RemapItemTypes(type_map, loclist) abort for l:item in a:loclist let l:key = l:item.type \ . (get(l:item, 'sub_type', '') is# 'style' ? 'S' : '') let l:new_key = get(a:type_map, l:key, '') if l:new_key is# 'E' \|| l:new_key is# 'ES' \|| l:new_key is# 'W' \|| l:new_key is# 'WS' \|| l:new_key is# 'I' let l:item.type = l:new_key[0] if l:new_key is# 'ES' || l:new_key is# 'WS' let l:item.sub_type = 'style' elseif has_key(l:item, 'sub_type') call remove(l:item, 'sub_type') endif endif endfor endfunction function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort let l:mappings = ale#GetFilenameMappings(a:buffer, a:linter_name) if !empty(l:mappings) " We need to apply reverse filename mapping here. let l:mappings = ale#filename_mapping#Invert(l:mappings) endif let l:bufnr_map = {} let l:new_loclist = [] " Some errors have line numbers beyond the end of the file, " so we need to adjust them so they set the error at the last line " of the file instead. let l:last_line_number = ale#util#GetLineCount(a:buffer) for l:old_item in a:loclist " Copy the loclist item with some default values and corrections. " " line and column numbers will be converted to numbers. " The buffer will default to the buffer being checked. " The vcol setting will default to 0, a byte index. " The error type will default to 'E' for errors. " The error number will default to -1. " " The line number and text are the only required keys. " " The linter_name will be set on the errors so it can be used in " output, filtering, etc.. let l:item = { \ 'bufnr': a:buffer, \ 'text': l:old_item.text, \ 'lnum': str2nr(l:old_item.lnum), \ 'col': str2nr(get(l:old_item, 'col', 0)), \ 'vcol': 0, \ 'type': get(l:old_item, 'type', 'E'), \ 'nr': get(l:old_item, 'nr', -1), \ '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 let l:old_name = get(l:old_item, 'filename', '') " Map parsed from output to local filesystem files. if !empty(l:old_name) && !empty(l:mappings) let l:old_name = ale#filename_mapping#Map(l:old_name, l:mappings) endif if !empty(l:old_name) && !ale#path#IsTempName(l:old_name) " Use the filename given. " Temporary files are assumed to be for this buffer, " and the filename is not included then, because it looks bad " in the loclist window. let l:filename = l:old_name let l:item.filename = l:filename if has_key(l:old_item, 'bufnr') " If a buffer number is also given, include that too. " If Vim detects that he buffer number is valid, it will " be used instead of the filename. let l:item.bufnr = l:old_item.bufnr elseif has_key(l:bufnr_map, l:filename) " Get the buffer number from the map, which can be faster. let l:item.bufnr = l:bufnr_map[l:filename] else " Look up the buffer number. let l:item.bufnr = bufnr(l:filename) let l:bufnr_map[l:filename] = l:item.bufnr endif elseif has_key(l:old_item, 'bufnr') let l:item.bufnr = l:old_item.bufnr endif if has_key(l:old_item, 'detail') let l:item.detail = l:old_item.detail endif " Pass on a end_col key if set, used for highlights. if has_key(l:old_item, 'end_col') let l:item.end_col = str2nr(l:old_item.end_col) endif if has_key(l:old_item, 'end_lnum') let l:item.end_lnum = str2nr(l:old_item.end_lnum) " When the error ends after the end of the file, put it at the " end. This is only done for the current buffer. if l:item.bufnr == a:buffer && l:item.end_lnum > l:last_line_number let l:item.end_lnum = l:last_line_number endif endif if has_key(l:old_item, 'sub_type') let l:item.sub_type = l:old_item.sub_type endif if l:item.lnum < 1 " When errors appear before line 1, put them at line 1. let l:item.lnum = 1 elseif l:item.bufnr == a:buffer && l:item.lnum > l:last_line_number " When errors go beyond the end of the file, put them at the end. " This is only done for the current buffer. let l:item.lnum = l:last_line_number elseif get(l:old_item, 'vcol', 0) " Convert virtual column positions to byte positions. " The positions will be off if the buffer has changed recently. let l:line = getbufline(a:buffer, l:item.lnum)[0] let l:item.col = ale#util#Col(l:line, l:item.col) if has_key(l:item, 'end_col') let l:end_line = get(l:item, 'end_lnum', l:line) != l:line \ ? getbufline(a:buffer, l:item.end_lnum)[0] \ : l:line let l:item.end_col = ale#util#Col(l:end_line, l:item.end_col) endif endif call add(l:new_loclist, l:item) endfor let l:type_map = get(ale#Var(a:buffer, 'type_map'), a:linter_name, {}) if !empty(l:type_map) call s:RemapItemTypes(l:type_map, l:new_loclist) endif return l:new_loclist endfunction " Given part of a command, replace any % with %%, so that no characters in " the string will be replaced with filenames, etc. function! ale#engine#EscapeCommandPart(command_part) abort " TODO: Emit deprecation warning here later. return ale#command#EscapeCommandPart(a:command_part) endfunction " Run a job. " " Returns 1 when a job was started successfully. function! s:RunJob(command, options) abort if ale#command#IsDeferred(a:command) let a:command.result_callback = { \ command -> s:RunJob(command, a:options) \} return 1 endif let l:command = a:command if empty(l:command) return 0 endif let l:cwd = a:options.cwd let l:executable = a:options.executable let l:buffer = a:options.buffer let l:linter = a:options.linter let l:output_stream = a:options.output_stream let l:read_buffer = a:options.read_buffer && !a:options.lint_file let l:info = g:ale_buffer_info[l:buffer] let l:Callback = function('s:HandleExit', [{ \ 'linter': l:linter, \ 'executable': l:executable, \}]) let l:result = ale#command#Run(l:buffer, l:command, l:Callback, { \ 'cwd': l:cwd, \ 'output_stream': l:output_stream, \ 'executable': l:executable, \ 'read_buffer': l:read_buffer, \ 'log_output': 1, \ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name), \}) " Only proceed if the job is being run. if empty(l:result) return 0 endif call ale#engine#MarkLinterActive(l:info, l:linter) silent doautocmd User ALEJobStarted return 1 endfunction function! s:StopCurrentJobs(buffer, clear_lint_file_jobs, linter_slots) abort let l:info = get(g:ale_buffer_info, a:buffer, {}) call ale#command#StopJobs(a:buffer, 'linter') " Update the active linter list, clearing out anything not running. if a:clear_lint_file_jobs call ale#command#StopJobs(a:buffer, 'file_linter') let l:info.active_linter_list = [] else let l:lint_file_map = {} " Use a previously computed map of `lint_file` values to find " linters that are used for linting files. for [l:lint_file, l:linter] in a:linter_slots if l:lint_file is 1 let l:lint_file_map[l:linter.name] = 1 endif endfor " Keep jobs for linting files when we're only linting buffers. call filter(l:info.active_linter_list, 'get(l:lint_file_map, v:val.name)') endif endfunction function! ale#engine#Stop(buffer) abort call s:StopCurrentJobs(a:buffer, 1, []) 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 let l:name_map[l:linter.name] = 1 endfor call filter( \ get(g:ale_buffer_info[a:buffer], 'loclist', []), \ 'get(v:val, ''from_other_source'') || get(l:name_map, get(v:val, ''linter_name''))', \) endfunction function! s:AddProblemsFromOtherBuffers(buffer, linters) abort let l:filename = expand('#' . a:buffer . ':p') let l:loclist = [] let l:name_map = {} " Build a map of the active linters. for l:linter in a:linters let l:name_map[l:linter.name] = 1 endfor " Find the items from other buffers, for the linters that are enabled. for l:info in values(g:ale_buffer_info) for l:item in l:info.loclist if has_key(l:item, 'filename') \&& l:item.filename is# l:filename \&& has_key(l:name_map, l:item.linter_name) " Copy the items and set the buffer numbers to this one. let l:new_item = copy(l:item) let l:new_item.bufnr = a:buffer call add(l:loclist, l:new_item) endif endfor endfor if !empty(l:loclist) call sort(l:loclist, function('ale#util#LocItemCompareWithText')) call uniq(l:loclist, function('ale#util#LocItemCompareWithText')) " Set the loclist variable, used by some parts of ALE. let g:ale_buffer_info[a:buffer].loclist = l:loclist call ale#engine#SetResults(a:buffer, l:loclist) endif endfunction function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort if ale#command#IsDeferred(a:executable) let a:executable.result_callback = { \ executable -> s:RunIfExecutable( \ a:buffer, \ a:linter, \ a:lint_file, \ executable \ ) \} return 1 endif if ale#engine#IsExecutable(a:buffer, a:executable) " Use different job types for file or linter jobs. let l:job_type = a:lint_file ? 'file_linter' : 'linter' call setbufvar(a:buffer, 'ale_job_type', l:job_type) " Get the cwd for the linter and set it before we call GetCommand. " This will ensure that ale#command#Run uses it by default. let l:cwd = ale#linter#GetCwd(a:buffer, a:linter) if l:cwd isnot v:null call ale#command#SetCwd(a:buffer, l:cwd) endif let l:command = ale#linter#GetCommand(a:buffer, a:linter) if l:cwd isnot v:null call ale#command#ResetCwd(a:buffer) endif let l:options = { \ 'cwd': l:cwd, \ 'executable': a:executable, \ 'buffer': a:buffer, \ 'linter': a:linter, \ 'output_stream': get(a:linter, 'output_stream', 'stdout'), \ 'read_buffer': a:linter.read_buffer, \ 'lint_file': a:lint_file, \} return s:RunJob(l:command, l:options) endif return 0 endfunction " Run a linter for a buffer. " " Returns 1 if the linter was successfully run. function! s:RunLinter(buffer, linter, lint_file) abort if !empty(a:linter.lsp) return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter) else let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) return s:RunIfExecutable(a:buffer, a:linter, a:lint_file, l:executable) endif return 0 endfunction function! s:GetLintFileSlots(buffer, linters) abort let l:linter_slots = [] for l:linter in a:linters let l:LintFile = l:linter.lint_file if type(l:LintFile) is v:t_func let l:LintFile = l:LintFile(a:buffer) endif call add(l:linter_slots, [l:LintFile, l:linter]) endfor return l:linter_slots endfunction function! s:GetLintFileValues(slots, Callback) abort let l:deferred_list = [] let l:new_slots = [] for [l:lint_file, l:linter] in a:slots while ale#command#IsDeferred(l:lint_file) && has_key(l:lint_file, 'value') " If we've already computed the return value, use it. let l:lint_file = l:lint_file.value endwhile if ale#command#IsDeferred(l:lint_file) " If we are going to return the result later, wait for it. call add(l:deferred_list, l:lint_file) else " If we have the value now, coerce it to 0 or 1. let l:lint_file = l:lint_file is 1 endif call add(l:new_slots, [l:lint_file, l:linter]) endfor if !empty(l:deferred_list) for l:deferred in l:deferred_list let l:deferred.result_callback = \ {-> s:GetLintFileValues(l:new_slots, a:Callback)} endfor else call a:Callback(l:new_slots) endif endfunction function! s:RunLinters( \ buffer, \ linters, \ slots, \ should_lint_file, \ new_buffer, \) abort call s:StopCurrentJobs(a:buffer, a:should_lint_file, a:slots) call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters) " We can only clear the results if we aren't checking the buffer. let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer) silent doautocmd User ALELintPre for [l:lint_file, l:linter] in a:slots " Only run lint_file linters if we should. if !l:lint_file || a:should_lint_file if s:RunLinter(a:buffer, l:linter, l:lint_file) " If a single linter ran, we shouldn't clear everything. let l:can_clear_results = 0 endif else " If we skipped running a lint_file linter still in the list, " we shouldn't clear everything. let l:can_clear_results = 0 endif endfor " Clear the results if we can. This needs to be done when linters are " disabled, or ALE itself is disabled. if l:can_clear_results call ale#engine#SetResults(a:buffer, []) elseif a:new_buffer call s:AddProblemsFromOtherBuffers( \ a:buffer, \ map(copy(a:slots), 'v:val[1]') \) endif endfunction function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort " Initialise the buffer information if needed. let l:new_buffer = ale#engine#InitBufferInfo(a:buffer) call s:GetLintFileValues( \ s:GetLintFileSlots(a:buffer, a:linters), \ { \ slots -> s:RunLinters( \ a:buffer, \ a:linters, \ slots, \ a:should_lint_file, \ l:new_buffer, \ ) \ } \) endfunction " Clean up a buffer. " " This function will stop all current jobs for the buffer, " clear the state of everything, and remove the Dictionary for managing " the buffer. function! ale#engine#Cleanup(buffer) abort " Don't bother with cleanup code when newer NeoVim versions are exiting. if get(v:, 'exiting', v:null) isnot v:null return endif if exists('*ale#lsp#CloseDocument') call ale#lsp#CloseDocument(a:buffer) endif if !has_key(g:ale_buffer_info, a:buffer) return endif call ale#engine#RunLinters(a:buffer, [], 1) call remove(g:ale_buffer_info, a:buffer) endfunction " Given a buffer number, return the warnings and errors for a given buffer. function! ale#engine#GetLoclist(buffer) abort if !has_key(g:ale_buffer_info, a:buffer) return [] endif return g:ale_buffer_info[a:buffer].loclist endfunction ================================================ FILE: autoload/ale/events.vim ================================================ " Author: w0rp " Description: ALE functions for autocmd events. " Get the number of milliseconds since some vague, but consistent, point in " the past. " " This function can be used for timing execution, etc. " " The time will be returned as a Number. function! ale#events#ClockMilliseconds() abort return float2nr(reltimefloat(reltime()) * 1000) endfunction function! ale#events#QuitEvent(buffer) abort " Remember when ALE is quitting for BufWrite, etc. call setbufvar(a:buffer, 'ale_quitting', ale#events#ClockMilliseconds()) endfunction function! ale#events#QuitRecently(buffer) abort let l:time = getbufvar(a:buffer, 'ale_quitting', 0) return l:time && ale#events#ClockMilliseconds() - l:time < 1000 endfunction function! ale#events#SaveEvent(buffer) abort let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save if l:should_lint call setbufvar(a:buffer, 'ale_save_event_fired', 1) endif 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 if l:should_lint && !ale#events#QuitRecently(a:buffer) call ale#Queue(0, 'lint_file', a:buffer) endif endfunction function! ale#events#LintOnEnter(buffer) abort " Unmark a file as being changed outside of Vim after we try to check it. call setbufvar(a:buffer, 'ale_file_changed', 0) if ale#Var(a:buffer, 'enabled') && g:ale_lint_on_enter call ale#Queue(0, 'lint_file', a:buffer) endif endfunction function! ale#events#ReadOrEnterEvent(buffer) abort " Apply pattern options if the variable is set. if get(g:, 'ale_pattern_options_enabled', 1) \&& !empty(get(g:, 'ale_pattern_options')) call ale#pattern_options#SetOptions(a:buffer) endif " When entering a buffer, we are no longer quitting it. call setbufvar(a:buffer, 'ale_quitting', 0) let l:filetype = getbufvar(a:buffer, '&filetype') call setbufvar(a:buffer, 'ale_original_filetype', l:filetype) " If the file changed outside of Vim, check it on BufEnter,BufRead if getbufvar(a:buffer, 'ale_file_changed') call ale#events#LintOnEnter(a:buffer) endif endfunction function! ale#events#FileTypeEvent(buffer, new_filetype) abort " The old filetype will be set to an empty string by the BuFEnter event, " and not linting when the old filetype hasn't been set yet prevents " buffers being checked when you enter them when linting on enter is off. let l:old_filetype = getbufvar(a:buffer, 'ale_original_filetype', v:null) if l:old_filetype isnot v:null \&& !empty(a:new_filetype) \&& a:new_filetype isnot# l:old_filetype " Remember what the new filetype is. call setbufvar(a:buffer, 'ale_original_filetype', a:new_filetype) if g:ale_lint_on_filetype_changed call ale#Queue(300, 'lint_file', a:buffer) endif endif endfunction function! ale#events#FileChangedEvent(buffer) abort call setbufvar(a:buffer, 'ale_file_changed', 1) if bufnr('') == a:buffer call ale#events#LintOnEnter(a:buffer) endif endfunction " A timer for emulating InsertLeave. " " We only need a single timer, and we'll lint the last buffer we entered " insert mode on. if !exists('s:insert_leave_timer') let s:insert_leave_timer = -1 endif " True if the ModeChanged event exists. " In this case, ModeChanged will be used instead of InsertLeave emulation. let s:mode_changed_exists = exists('##ModeChanged') function! ale#events#EmulateInsertLeave(buffer) abort if mode() is# 'n' call timer_stop(s:insert_leave_timer) call ale#Queue(0, '', a:buffer) endif endfunction function! ale#events#InsertEnterEvent(buffer) abort if g:ale_close_preview_on_insert && exists('*ale#preview#CloseIfTypeMatches') call ale#preview#CloseIfTypeMatches('ale-preview') endif " Start a repeating timer if the use might not trigger InsertLeave, so we " can emulate its behavior. " If the ModeChanged autocmd exists, it will be used instead of this " timer; as ModeChanged will be sent regardless of how the insert mode is " exited, including , and . if ale#Var(a:buffer, 'lint_on_insert_leave') \&& maparg("\", 'i') isnot# '' \&& !s:mode_changed_exists call timer_stop(s:insert_leave_timer) let s:insert_leave_timer = timer_start( \ 100, \ {-> ale#events#EmulateInsertLeave(a:buffer) }, \ {'repeat': -1} \) endif endfunction function! ale#events#InsertLeaveEvent(buffer) abort " Kill the InsertLeave emulation if the event fired. " If the ModeChanged event is available, it will be used instead of " a timer. if !s:mode_changed_exists call timer_stop(s:insert_leave_timer) endif if ale#Var(a:buffer, 'lint_on_insert_leave') call ale#Queue(0, '', a:buffer) 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. " " We don't echo this message in emulated insert leave mode, as the user " may want less work to happen on pressing versus if exists('*ale#engine#Cleanup') call ale#cursor#EchoCursorWarning() if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1' " Show a virtualtext message if enabled. call ale#virtualtext#ShowCursorWarning() endif endif endfunction function! ale#events#Init() abort " This value used to be a Boolean as a Number, and is now a String. let l:text_changed = '' . g:ale_lint_on_text_changed augroup ALEEvents autocmd! " These events always need to be set up. autocmd BufEnter,BufRead * call ale#events#ReadOrEnterEvent(str2nr(expand(''))) autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand(''))) if g:ale_enabled if l:text_changed is? 'always' \|| l:text_changed is# '1' \|| g:ale_lint_on_text_changed is v:true autocmd TextChanged,TextChangedI * call ale#Queue(ale#Var(str2nr(expand('')), 'lint_delay')) elseif l:text_changed is? 'normal' autocmd TextChanged * call ale#Queue(ale#Var(str2nr(expand('')), 'lint_delay')) elseif l:text_changed is? 'insert' autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('')), 'lint_delay')) endif if g:ale_lint_on_enter autocmd BufWinEnter * call ale#events#LintOnEnter(str2nr(expand(''))) " Track when the file is changed outside of Vim. autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''))) endif if g:ale_lint_on_filetype_changed " Only start linting if the FileType actually changes after " opening a buffer. The FileType will fire when buffers are opened. autocmd FileType * call ale#events#FileTypeEvent( \ str2nr(expand('')), \ expand('') \) endif " Add an InsertEnter event if we need to close the preview window " on entering insert mode, or if we want to run ALE on leaving " insert mode and is not the same as . " " We will emulate leaving insert mode for users that might not " trigger InsertLeave. " " If the ModeChanged event is available, this timer will not " be used. if g:ale_close_preview_on_insert \|| (g:ale_lint_on_insert_leave && maparg("\", 'i') isnot# '' && !s:mode_changed_exists) autocmd InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''))) endif let l:add_insert_leave_event = g:ale_lint_on_insert_leave if g:ale_echo_cursor || g:ale_cursor_detail " We need to make the message display on InsertLeave let l:add_insert_leave_event = 1 autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif endif if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1' " We need to make the message display on InsertLeave let l:add_insert_leave_event = 1 autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarningWithDelay() | endif endif if l:add_insert_leave_event if s:mode_changed_exists " If the ModeChanged event is available, handle any " transition from the Insert mode to any other mode. autocmd ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand(''))) else " If ModeChanged is not available, handle InsertLeave events. autocmd InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''))) endif endif if g:ale_hover_cursor autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif endif endif augroup END augroup AleURISchemes autocmd! autocmd BufNewFile,BufReadPre jdt://** call ale#uri#jdt#ReadJDTLink(expand('')) augroup END endfunction ================================================ FILE: autoload/ale/filename_mapping.vim ================================================ " Author: w0rp " Description: Logic for handling mappings between files " Invert filesystem mappings so they can be mapped in reverse. function! ale#filename_mapping#Invert(filename_mappings) abort return map(copy(a:filename_mappings), '[v:val[1], v:val[0]]') endfunction " Given a filename and some filename_mappings, map a filename. function! ale#filename_mapping#Map(filename, filename_mappings) abort let l:simplified_filename = ale#path#Simplify(a:filename) for [l:mapping_from, l:mapping_to] in a:filename_mappings let l:mapping_from = ale#path#Simplify(l:mapping_from) if l:simplified_filename[:len(l:mapping_from) - 1] is# l:mapping_from return l:mapping_to . l:simplified_filename[len(l:mapping_from):] endif endfor return a:filename endfunction ================================================ FILE: autoload/ale/filerename.vim ================================================ " Author: Dalius Dobravolskas " Description: Rename file support for tsserver let s:filerename_map = {} " Used to get the rename map in tests. function! ale#filerename#GetMap() abort return deepcopy(s:filerename_map) endfunction " Used to set the rename map in tests. function! ale#filerename#SetMap(map) abort let s:filerename_map = a:map endfunction function! ale#filerename#ClearLSPData() abort let s:filerename_map = {} endfunction function! s:message(message) abort call ale#util#Execute('echom ' . string(a:message)) endfunction function! ale#filerename#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') isnot# 'getEditsForFileRename' return endif if !has_key(s:filerename_map, a:response.request_seq) return endif let l:options = remove(s:filerename_map, a:response.request_seq) let l:old_name = l:options.old_name let l:new_name = l:options.new_name if get(a:response, 'success', v:false) is v:false let l:message = get(a:response, 'message', 'unknown') call s:message('Error renaming file "' . l:old_name . '" to "' . l:new_name \ . '". Reason: ' . l:message) return endif let l:changes = a:response.body if empty(l:changes) call s:message('No changes while renaming "' . l:old_name . '" to "' . l:new_name . '"') else call ale#code_action#HandleCodeAction( \ { \ 'description': 'filerename', \ 'changes': l:changes, \ }, \ { \ 'should_save': 1, \ }, \) endif silent! noautocmd execute 'saveas ' . l:new_name call delete(l:old_name) endfunction function! s:OnReady(options, linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'filerename') return endif let l:buffer = a:lsp_details.buffer let l:Callback = function('ale#filerename#HandleTSServerResponse') call ale#lsp#RegisterCallback(l:id, l:Callback) let l:message = ale#lsp#tsserver_message#GetEditsForFileRename( \ a:options.old_name, \ a:options.new_name, \) let l:request_id = ale#lsp#Send(l:id, l:message) let s:filerename_map[l:request_id] = a:options endfunction function! s:ExecuteFileRename(linter, options) abort let l:buffer = bufnr('') let l:Callback = function('s:OnReady', [a:options]) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction function! ale#filerename#Execute() abort let l:buffer = bufnr('') let l:lsp_linters = [] for l:linter in ale#lsp_linter#GetEnabled(l:buffer) if l:linter.lsp is# 'tsserver' call add(l:lsp_linters, l:linter) endif endfor if empty(l:lsp_linters) call s:message('No active tsserver LSPs') return endif let l:old_name = expand('#' . l:buffer . ':p') let l:new_name = ale#util#Input('New file name: ', l:old_name, 'file') if l:old_name is# l:new_name call s:message('New file name matches old file name') return endif if empty(l:new_name) call s:message('New name cannot be empty!') return endif for l:lsp_linter in l:lsp_linters call s:ExecuteFileRename(l:lsp_linter, { \ 'old_name': l:old_name, \ 'new_name': l:new_name, \}) endfor endfunction ================================================ FILE: autoload/ale/filetypes.vim ================================================ " Author: w0rp " Description: This file handles guessing file extensions for filetypes, etc. function! ale#filetypes#LoadExtensionMap() abort " Output includes: " '*.erl setf erlang' let l:output = execute('exec "autocmd"') let l:map = {} for l:line in split(l:output, "\n") " Parse filetypes, like so: " " *.erl setf erlang " *.md set filetype=markdown " *.snippet setlocal filetype=snippets let l:match = matchlist(l:line, '\v^ *\*(\.[^ ]+).*set(f *| *filetype=|local *filetype=)([^ ]+)') if !empty(l:match) let l:map[substitute(l:match[3], '^=', '', '')] = l:match[1] endif endfor return l:map endfunction let s:cached_map = {} function! s:GetCachedExtensionMap() abort if empty(s:cached_map) let s:cached_map = ale#filetypes#LoadExtensionMap() endif return s:cached_map endfunction function! ale#filetypes#GuessExtension(filetype) abort let l:map = s:GetCachedExtensionMap() let l:ext = get(l:map, a:filetype, '') " If we have an exact match, like something for javascript.jsx, use that. if !empty(l:ext) return l:ext endif " If we don't have an exact match, use the first filetype in the compound " filetype. for l:part in split(a:filetype, '\.') let l:ext = get(l:map, l:part, '') if !empty(l:ext) return l:ext endif endfor " Return an empty string if we don't find anything. return '' endfunction ================================================ FILE: autoload/ale/fix/registry.vim ================================================ " Author: w0rp " Description: A registry of functions for fixing things. let s:default_registry = { \ 'add_blank_lines_for_python_control_statements': { \ 'function': 'ale#fixers#generic_python#AddLinesBeforeControlStatements', \ 'suggested_filetypes': ['python'], \ 'description': 'Add blank lines before control statements.', \ }, \ 'alejandra': { \ 'function': 'ale#fixers#alejandra#Fix', \ 'suggested_filetypes': ['nix'], \ 'description': 'The Uncompromising Nix Code Formatter', \ }, \ 'align_help_tags': { \ 'function': 'ale#fixers#help#AlignTags', \ 'suggested_filetypes': ['help'], \ 'description': 'Align help tags to the right margin', \ }, \ 'apkbuild-fixer': { \ 'function': 'ale#fixers#apkbuild_fixer#Fix', \ 'suggested_filetypes': ['apkbuild'], \ 'description': 'Fix policy violations found by apkbuild-lint in APKBUILDs', \ }, \ 'autoimport': { \ 'function': 'ale#fixers#autoimport#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix import issues with autoimport.', \ }, \ 'autoflake': { \ 'function': 'ale#fixers#autoflake#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix flake issues with autoflake.', \ }, \ 'autopep8': { \ 'function': 'ale#fixers#autopep8#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix PEP8 issues with autopep8.', \ }, \ 'bibclean': { \ 'function': 'ale#fixers#bibclean#Fix', \ 'suggested_filetypes': ['bib'], \ 'description': 'Format bib files using bibclean.', \ }, \ 'biome': { \ 'function': 'ale#fixers#biome#Fix', \ 'suggested_filetypes': ['javascript', 'typescript', 'json', 'jsonc', 'css', 'graphql'], \ 'description': 'Fix JavaScript and TypeScript using biome.', \ }, \ 'black': { \ 'function': 'ale#fixers#black#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix PEP8 issues with black.', \ }, \ 'buf-format': { \ 'function': 'ale#fixers#buf_format#Fix', \ 'suggested_filetypes': ['proto'], \ 'description': 'Fix .proto files with buf format.', \ }, \ 'buildifier': { \ 'function': 'ale#fixers#buildifier#Fix', \ 'suggested_filetypes': ['bzl'], \ 'description': 'Format BUILD and .bzl files with buildifier.', \ }, \ 'css-beautify': { \ 'function': 'ale#fixers#css_beautify#Fix', \ 'suggested_filetypes': ['css'], \ 'description': 'Format CSS using css-beautify from js-beautify.', \ }, \ 'deno': { \ 'function': 'ale#fixers#deno#Fix', \ 'suggested_filetypes': ['typescript'], \ 'description': 'Fix TypeScript using deno fmt.', \ }, \ 'dfmt': { \ 'function': 'ale#fixers#dfmt#Fix', \ 'suggested_filetypes': ['d'], \ 'description': 'Fix D files with dfmt.', \ }, \ 'dhall': { \ 'function': 'ale#fixers#dhall#Fix', \ 'suggested_filetypes': ['dhall'], \ 'description': 'Fix Dhall files with dhall-format.', \ }, \ 'dhall-format': { \ 'function': 'ale#fixers#dhall_format#Fix', \ 'suggested_filetypes': ['dhall'], \ 'description': 'Standard code formatter for the Dhall language', \ 'aliases': ['dhall'], \ }, \ 'dhall-freeze': { \ 'function': 'ale#fixers#dhall_freeze#Freeze', \ 'suggested_filetypes': ['dhall'], \ 'description': 'Add integrity checks to remote import statements of an expression for the Dhall language', \ }, \ 'dhall-lint': { \ 'function': 'ale#fixers#dhall_lint#Fix', \ 'suggested_filetypes': ['dhall'], \ 'description': 'Standard code formatter for the Dhall language and removing dead code', \ }, \ 'djlint': { \ 'function': 'ale#fixers#djlint#Fix', \ 'suggested_filetypes': ['html', 'htmldjango', 'htmlangular', 'jinja', 'handlebars', 'nunjucks', 'gohtmltmpl'], \ 'description': 'Fix HTML templates with `djlint --reformat`.', \ }, \ 'dune': { \ 'function': 'ale#fixers#dune#Fix', \ 'suggested_filetypes': ['dune'], \ 'description': 'Fix dune files with dune format', \ }, \ 'erlang_mode': { \ 'function': 'ale#fixers#erlang_mode#Fix', \ 'suggested_filetypes': ['erlang'], \ 'description': 'Indent with the Erlang mode for Emacs', \ 'aliases': ['erlang-mode'], \ }, \ 'erlfmt': { \ 'function': 'ale#fixers#erlfmt#Fix', \ 'suggested_filetypes': ['erlang'], \ 'description': 'Format Erlang code with erlfmt', \ }, \ 'fecs': { \ 'function': 'ale#fixers#fecs#Fix', \ 'suggested_filetypes': ['javascript', 'css', 'html'], \ 'description': 'Apply fecs format to a file.', \ }, \ 'hurlfmt': { \ 'function': 'ale#fixers#hurlfmt#Fix', \ 'suggested_filetypes': ['hurl'], \ 'description': 'Fix hurl files with hurlfmt.', \ }, \ 'kulala_fmt': { \ 'function': 'ale#fixers#kulala_fmt#Fix', \ 'suggested_filetypes': ['http', 'rest'], \ 'description': 'Fix http and rest files with kulala_fmt.', \ }, \ 'tidy': { \ 'function': 'ale#fixers#tidy#Fix', \ 'suggested_filetypes': ['html'], \ 'description': 'Fix HTML files with tidy.', \ }, \ 'prettier_standard': { \ 'function': 'ale#fixers#prettier_standard#Fix', \ 'suggested_filetypes': ['javascript'], \ 'description': 'Apply prettier-standard to a file.', \ 'aliases': ['prettier-standard'], \ }, \ 'elm-format': { \ 'function': 'ale#fixers#elm_format#Fix', \ 'suggested_filetypes': ['elm'], \ 'description': 'Apply elm-format to a file.', \ 'aliases': ['format'], \ }, \ 'nimpretty': { \ 'function': 'ale#fixers#nimpretty#Fix', \ 'suggested_filetypes': ['nim'], \ 'description': 'Apply nimpretty to a file.', \ }, \ 'erblint': { \ 'function': 'ale#fixers#erblint#Fix', \ 'suggested_filetypes': ['eruby'], \ 'description': 'Apply erblint --autocorrect to a file.', \ }, \ 'eslint': { \ 'function': 'ale#fixers#eslint#Fix', \ 'suggested_filetypes': ['javascript', 'typescript', 'astro'], \ 'description': 'Apply eslint --fix to a file.', \ }, \ 'mix_format': { \ 'function': 'ale#fixers#mix_format#Fix', \ 'suggested_filetypes': ['elixir'], \ 'description': 'Apply mix format to a file.', \ }, \ 'isort': { \ 'function': 'ale#fixers#isort#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Sort Python imports with isort.', \ }, \ 'prettier': { \ 'function': 'ale#fixers#prettier#Fix', \ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue', 'svelte', 'html', 'yaml', 'openapi', 'ruby', 'astro'], \ 'description': 'Apply prettier to a file.', \ }, \ 'prettier_eslint': { \ 'function': 'ale#fixers#prettier_eslint#Fix', \ 'suggested_filetypes': ['javascript'], \ 'description': 'Apply prettier-eslint to a file.', \ 'aliases': ['prettier-eslint'], \ }, \ 'pyflyby': { \ 'function': 'ale#fixers#pyflyby#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Tidy Python imports with pyflyby.', \ }, \ 'unimport': { \ 'function': 'ale#fixers#unimport#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'unimport fixer', \ }, \ 'importjs': { \ 'function': 'ale#fixers#importjs#Fix', \ 'suggested_filetypes': ['javascript'], \ 'description': 'automatic imports for javascript', \ }, \ 'puppetlint': { \ 'function': 'ale#fixers#puppetlint#Fix', \ 'suggested_filetypes': ['puppet'], \ 'description': 'Run puppet-lint -f on a file.', \ }, \ 'remove_trailing_lines': { \ 'function': 'ale#fixers#generic#RemoveTrailingBlankLines', \ 'suggested_filetypes': [], \ 'description': 'Remove all blank lines at the end of a file.', \ }, \ 'trim_whitespace': { \ 'function': 'ale#fixers#generic#TrimWhitespace', \ 'suggested_filetypes': [], \ 'description': 'Remove all trailing whitespace characters at the end of every line.', \ }, \ 'yamlfix': { \ 'function': 'ale#fixers#yamlfix#Fix', \ 'suggested_filetypes': ['yaml'], \ 'description': 'Fix YAML files with yamlfix.', \ }, \ 'yamlfmt': { \ 'function': 'ale#fixers#yamlfmt#Fix', \ 'suggested_filetypes': ['yaml'], \ 'description': 'Format YAML files with yamlfmt.', \ }, \ 'yapf': { \ 'function': 'ale#fixers#yapf#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix Python files with yapf.', \ }, \ 'yq': { \ 'function': 'ale#fixers#yq#Fix', \ 'suggested_filetypes': ['yaml'], \ 'description': 'Fix YAML files with yq.', \ }, \ 'rubocop': { \ 'function': 'ale#fixers#rubocop#Fix', \ 'suggested_filetypes': ['ruby'], \ 'description': 'Fix ruby files with rubocop --auto-correct.', \ }, \ 'rufo': { \ 'function': 'ale#fixers#rufo#Fix', \ 'suggested_filetypes': ['ruby'], \ 'description': 'Fix ruby files with rufo', \ }, \ 'scalafmt': { \ 'function': 'ale#fixers#scalafmt#Fix', \ 'suggested_filetypes': ['sbt', 'scala'], \ 'description': 'Fix Scala files using scalafmt', \ }, \ 'sorbet': { \ 'function': 'ale#fixers#sorbet#Fix', \ 'suggested_filetypes': ['ruby'], \ 'description': 'Fix ruby files with srb tc --autocorrect.', \ }, \ 'standard': { \ 'function': 'ale#fixers#standard#Fix', \ 'suggested_filetypes': ['javascript'], \ 'description': 'Fix JavaScript files using standard --fix', \ }, \ 'standardrb': { \ 'function': 'ale#fixers#standardrb#Fix', \ 'suggested_filetypes': ['ruby'], \ 'description': 'Fix ruby files with standardrb --fix', \ }, \ 'statix': { \ 'function': 'ale#fixers#statix#Fix', \ 'suggested_filetypes': ['nix'], \ 'description': 'Fix common Nix antipatterns with statix fix', \ }, \ 'stylelint': { \ 'function': 'ale#fixers#stylelint#Fix', \ 'suggested_filetypes': ['css', 'sass', 'scss', 'sugarss', 'stylus'], \ 'description': 'Fix stylesheet files using stylelint --fix.', \ }, \ 'swiftformat': { \ 'function': 'ale#fixers#swiftformat#Fix', \ 'suggested_filetypes': ['swift'], \ 'description': 'Apply SwiftFormat to a file.', \ }, \ 'syntax_tree': { \ 'function': 'ale#fixers#syntax_tree#Fix', \ 'suggested_filetypes': ['ruby'], \ 'description': 'Fix ruby files with stree write', \ }, \ 'apple-swift-format': { \ 'function': 'ale#fixers#appleswiftformat#Fix', \ 'suggested_filetypes': ['swift'], \ 'description': 'Apply apple/swift-format to a file.', \ }, \ 'phpcbf': { \ 'function': 'ale#fixers#phpcbf#Fix', \ 'suggested_filetypes': ['php'], \ 'description': 'Fix PHP files with phpcbf.', \ }, \ 'php_cs_fixer': { \ 'function': 'ale#fixers#php_cs_fixer#Fix', \ 'suggested_filetypes': ['php'], \ 'description': 'Fix PHP files with php-cs-fixer.', \ }, \ 'pint': { \ 'function': 'ale#fixers#pint#Fix', \ 'suggested_filetypes': ['php'], \ 'description': 'Fix PHP files with Laravel Pint.', \ }, \ 'astyle': { \ 'function': 'ale#fixers#astyle#Fix', \ 'suggested_filetypes': ['c', 'cpp'], \ 'description': 'Fix C/C++ with astyle.', \ }, \ 'clangtidy': { \ 'function': 'ale#fixers#clangtidy#Fix', \ 'suggested_filetypes': ['c', 'cpp', 'objc'], \ 'description': 'Fix C/C++ and ObjectiveC files with clang-tidy.', \ }, \ 'clang-format': { \ 'function': 'ale#fixers#clangformat#Fix', \ 'suggested_filetypes': ['c', 'cpp', 'cs', 'cuda', 'java', 'javascript', 'json', 'objc', 'proto'], \ 'description': 'Fix C, C++, C#, CUDA, Java, JavaScript, JSON, ObjectiveC and Protobuf files with clang-format.', \ }, \ 'cmakeformat': { \ 'function': 'ale#fixers#cmakeformat#Fix', \ 'suggested_filetypes': ['cmake'], \ 'description': 'Fix CMake files with cmake-format.', \ }, \ 'fish_indent': { \ 'function': 'ale#fixers#fish_indent#Fix', \ 'suggested_filetypes': ['fish'], \ 'description': 'Format fish scripts using fish_indent.', \ }, \ 'forge': { \ 'function': 'ale#fixers#forge#Fix', \ 'suggested_filetypes': ['solidity'], \ 'description': 'Fix Solidity files with forge fmt.', \ }, \ 'gleam_format': { \ 'function': 'ale#fixers#gleam_format#Fix', \ 'suggested_filetypes': ['gleam'], \ 'description': 'Fix Gleam files with gleam format.', \ }, \ 'gofmt': { \ 'function': 'ale#fixers#gofmt#Fix', \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go files with go fmt.', \ }, \ 'gofumpt': { \ 'function': 'ale#fixers#gofumpt#Fix', \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go files with gofumpt, a stricter go fmt.', \ }, \ 'goimports': { \ 'function': 'ale#fixers#goimports#Fix', \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go files imports with goimports.', \ }, \ 'golangci_lint': { \ 'function': 'ale#fixers#golangci_lint#Fix', \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go files with golangci-lint.', \ }, \ 'golines': { \ 'function': 'ale#fixers#golines#Fix', \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go file long lines with golines', \ }, \ 'gomod': { \ 'function': 'ale#fixers#gomod#Fix', \ 'suggested_filetypes': ['gomod'], \ 'description': 'Fix Go module files with go mod edit -fmt.', \ }, \ 'gopls': { \ 'function': 'ale#fixers#gopls#Fix', \ 'suggested_filetypes': ['go'], \ 'description': 'Fix Go files with gopls.', \ }, \ 'tslint': { \ 'function': 'ale#fixers#tslint#Fix', \ 'suggested_filetypes': ['typescript'], \ 'description': 'Fix typescript files with tslint --fix.', \ }, \ 'rustfmt': { \ 'function': 'ale#fixers#rustfmt#Fix', \ 'suggested_filetypes': ['rust'], \ 'description': 'Fix Rust files with Rustfmt.', \ }, \ 'textlint': { \ 'function': 'ale#fixers#textlint#Fix', \ 'suggested_filetypes': ['text','markdown','asciidoc','tex'], \ 'description': 'Fix text files with textlint --fix', \ }, \ 'hackfmt': { \ 'function': 'ale#fixers#hackfmt#Fix', \ 'suggested_filetypes': ['hack'], \ 'description': 'Fix Hack files with hackfmt.', \ }, \ 'floskell': { \ 'function': 'ale#fixers#floskell#Fix', \ 'suggested_filetypes': ['haskell'], \ 'description': 'Fix Haskell files with floskell.', \ }, \ 'hfmt': { \ 'function': 'ale#fixers#hfmt#Fix', \ 'suggested_filetypes': ['haskell'], \ 'description': 'Fix Haskell files with hfmt.', \ }, \ 'brittany': { \ 'function': 'ale#fixers#brittany#Fix', \ 'suggested_filetypes': ['haskell'], \ 'description': 'Fix Haskell files with brittany.', \ }, \ 'hindent': { \ 'function': 'ale#fixers#hindent#Fix', \ 'suggested_filetypes': ['haskell'], \ 'description': 'Fix Haskell files with hindent.', \ }, \ '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.', \ }, \ 'purs-tidy': { \ 'function': 'ale#fixers#purs_tidy#Fix', \ 'suggested_filetypes': ['purescript'], \ 'description': 'Format PureScript files with purs-tidy.', \ }, \ 'purty': { \ 'function': 'ale#fixers#purty#Fix', \ 'suggested_filetypes': ['purescript'], \ 'description': 'Format PureScript files with purty.', \ }, \ 'ocamlformat': { \ 'function': 'ale#fixers#ocamlformat#Fix', \ 'suggested_filetypes': ['ocaml', 'ocamlinterface'], \ 'description': 'Fix OCaml files with ocamlformat.', \ }, \ 'ocp-indent': { \ 'function': 'ale#fixers#ocp_indent#Fix', \ 'suggested_filetypes': ['ocaml', 'ocamlinterface'], \ 'description': 'Fix OCaml files with ocp-indent.', \ }, \ 'refmt': { \ 'function': 'ale#fixers#refmt#Fix', \ 'suggested_filetypes': ['reason'], \ 'description': 'Fix ReasonML files with refmt.', \ }, \ 'pandoc': { \ 'function': 'ale#fixers#pandoc#Fix', \ 'suggested_filetypes': ['markdown'], \ 'description': 'Fix markdown files with pandoc.', \ }, \ 'pymarkdown': { \ 'function': 'ale#fixers#pymarkdown#Fix', \ 'suggested_filetypes': ['markdown'], \ 'description': 'Fix markdown files with pymarkdown.', \ }, \ 'shfmt': { \ 'function': 'ale#fixers#shfmt#Fix', \ 'suggested_filetypes': ['sh'], \ 'description': 'Fix sh files with shfmt.', \ }, \ 'sqlfluff': { \ 'function': 'ale#fixers#sqlfluff#Fix', \ 'suggested_filetypes': ['sql'], \ 'description': 'Fix SQL files with sqlfluff.', \ }, \ 'sqlfmt': { \ 'function': 'ale#fixers#sqlfmt#Fix', \ 'suggested_filetypes': ['sql'], \ 'description': 'Fix SQL files with sqlfmt.', \ }, \ 'sqlformat': { \ 'function': 'ale#fixers#sqlformat#Fix', \ 'suggested_filetypes': ['sql'], \ 'description': 'Fix SQL files with sqlformat.', \ }, \ 'google_java_format': { \ 'function': 'ale#fixers#google_java_format#Fix', \ 'suggested_filetypes': ['java'], \ 'description': 'Fix Java files with google-java-format.', \ }, \ 'fixjson': { \ 'function': 'ale#fixers#fixjson#Fix', \ 'suggested_filetypes': ['json'], \ 'description': 'Fix JSON files with fixjson.', \ }, \ 'jq': { \ 'function': 'ale#fixers#jq#Fix', \ 'suggested_filetypes': ['json'], \ 'description': 'Fix JSON files with jq.', \ }, \ 'json_pytool': { \ 'function': 'ale#fixers#json_pytool#Fix', \ 'suggested_filetypes': ['json'], \ 'description': "Fix JSON files with python's built-in json.tool module.", \ }, \ 'protolint': { \ 'function': 'ale#fixers#protolint#Fix', \ 'suggested_filetypes': ['proto'], \ 'description': 'Fix Protocol Buffer files with protolint.', \ }, \ 'perltidy': { \ 'function': 'ale#fixers#perltidy#Fix', \ 'suggested_filetypes': ['perl'], \ 'description': 'Fix Perl files with perltidy.', \ }, \ 'xo': { \ 'function': 'ale#fixers#xo#Fix', \ 'suggested_filetypes': ['javascript', 'typescript'], \ 'description': 'Fix JavaScript/TypeScript files using xo --fix.', \ }, \ 'qmlfmt': { \ 'function': 'ale#fixers#qmlfmt#Fix', \ 'suggested_filetypes': ['qml'], \ 'description': 'Fix QML files with qmlfmt.', \ }, \ 'dartfmt': { \ 'function': 'ale#fixers#dartfmt#Fix', \ 'suggested_filetypes': ['dart'], \ 'description': 'Fix Dart files with dartfmt.', \ }, \ 'dart-format': { \ 'function': 'ale#fixers#dart_format#Fix', \ 'suggested_filetypes': ['dart'], \ 'description': 'Fix Dart files with dart format.', \ }, \ 'dotnet-format': { \ 'function': 'ale#fixers#dotnet_format#Fix', \ 'suggested_filetypes': ['cs'], \ 'description': 'Fix C# files with dotnet format.', \ }, \ '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.', \ }, \ 'packer': { \ 'function': 'ale#fixers#packer#Fix', \ 'suggested_filetypes': ['hcl', 'packer'], \ 'description': 'Fix Packer HCL files with packer fmt.', \ }, \ 'crystal': { \ 'function': 'ale#fixers#crystal#Fix', \ 'suggested_filetypes': ['cr'], \ 'description': 'Fix cr (crystal).', \ }, \ 'ktlint': { \ 'function': 'ale#fixers#ktlint#Fix', \ 'suggested_filetypes': ['kt', 'kotlin'], \ 'description': 'Fix Kotlin files with ktlint.', \ }, \ 'styler': { \ 'function': 'ale#fixers#styler#Fix', \ 'suggested_filetypes': ['r', 'rmarkdown', 'rmd'], \ 'description': 'Fix R files with styler.', \ }, \ 'latexindent': { \ 'function': 'ale#fixers#latexindent#Fix', \ 'suggested_filetypes': ['tex'], \ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.', \ }, \ 'pgformatter': { \ 'function': 'ale#fixers#pgformatter#Fix', \ 'suggested_filetypes': ['sql'], \ 'description': 'A PostgreSQL SQL syntax beautifier', \ }, \ 'reorder-python-imports': { \ 'function': 'ale#fixers#reorder_python_imports#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Sort Python imports with reorder-python-imports.', \ }, \ 'gnatpp': { \ 'function': 'ale#fixers#gnatpp#Fix', \ 'suggested_filetypes': ['ada'], \ 'description': 'Format Ada files with gnatpp.', \ }, \ 'nixfmt': { \ 'function': 'ale#fixers#nixfmt#Fix', \ 'suggested_filetypes': ['nix'], \ 'description': 'A nix formatter written in Haskell.', \ }, \ 'nixpkgs-fmt': { \ 'function': 'ale#fixers#nixpkgsfmt#Fix', \ 'suggested_filetypes': ['nix'], \ 'description': 'A formatter for Nix code', \ }, \ 'remark-lint': { \ 'function': 'ale#fixers#remark_lint#Fix', \ 'suggested_filetypes': ['markdown'], \ 'description': 'Fix markdown files with remark-lint', \ }, \ 'html-beautify': { \ 'function': 'ale#fixers#html_beautify#Fix', \ 'suggested_filetypes': ['html', 'htmldjango'], \ 'description': 'Fix HTML files with html-beautify from js-beautify.', \ }, \ 'htmlbeautifier': { \ 'function': 'ale#fixers#htmlbeautifier#Fix', \ 'suggested_filetypes': ['eruby'], \ 'description': 'Fix ERB files with htmlbeautifier gem.', \ }, \ 'lua-format': { \ 'function': 'ale#fixers#lua_format#Fix', \ 'suggested_filetypes': ['lua'], \ 'description': 'Fix Lua files with lua-format.', \ }, \ 'luafmt': { \ 'function': 'ale#fixers#luafmt#Fix', \ 'suggested_filetypes': ['lua'], \ 'description': 'Fix Lua files with luafmt.', \ }, \ 'dprint': { \ 'function': 'ale#fixers#dprint#Fix', \ 'suggested_filetypes': ['dockerfile', 'javascript', 'json', 'markdown', 'toml', 'typescript'], \ 'description': 'Pluggable and configurable code formatting platform', \ }, \ 'stylua': { \ 'function': 'ale#fixers#stylua#Fix', \ 'suggested_filetypes': ['lua'], \ 'description': 'Fix Lua files with stylua.', \ }, \ 'ormolu': { \ 'function': 'ale#fixers#ormolu#Fix', \ 'suggested_filetypes': ['haskell'], \ 'description': 'A formatter for Haskell source code.', \ }, \ 'fourmolu': { \ 'function': 'ale#fixers#fourmolu#Fix', \ 'suggested_filetypes': ['haskell'], \ 'description': 'A formatter for Haskell source code.', \ }, \ 'jsonnetfmt': { \ 'function': 'ale#fixers#jsonnetfmt#Fix', \ 'suggested_filetypes': ['jsonnet'], \ 'description': 'Fix jsonnet files with jsonnetfmt', \ }, \ 'ptop': { \ 'function': 'ale#fixers#ptop#Fix', \ 'suggested_filetypes': ['pascal'], \ 'description': 'Fix Pascal files with ptop.', \ }, \ 'opafmt': { \ 'function': 'ale#fixers#opafmt#Fix', \ 'suggested_filetypes': ['rego'], \ 'description': 'Fix rego files with opa fmt.', \ }, \ 'vfmt': { \ 'function': 'ale#fixers#vfmt#Fix', \ 'suggested_filetypes': ['v'], \ 'description': 'A formatter for V source code.', \ }, \ 'zigfmt': { \ 'function': 'ale#fixers#zigfmt#Fix', \ 'suggested_filetypes': ['zig'], \ 'description': 'Official formatter for Zig', \ }, \ 'raco_fmt': { \ 'function': 'ale#fixers#raco_fmt#Fix', \ 'suggested_filetypes': ['racket'], \ 'description': 'Fix Racket files with raco fmt.', \ }, \ 'rescript_format': { \ 'function': 'ale#fixers#rescript_format#Fix', \ 'suggested_filetypes': ['rescript'], \ 'description': 'Official formatter for ReScript.', \ }, \ 'ruff': { \ 'function': 'ale#fixers#ruff#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix python files with ruff.', \ }, \ 'ruff_format': { \ 'function': 'ale#fixers#ruff_format#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'Fix python files with the ruff formatter.', \ }, \ 'pycln': { \ 'function': 'ale#fixers#pycln#Fix', \ 'suggested_filetypes': ['python'], \ 'description': 'remove unused python import statements', \ }, \ 'rustywind': { \ 'function': 'ale#fixers#rustywind#Fix', \ 'suggested_filetypes': ['html'], \ 'description': 'Sort Tailwind CSS classes', \ }, \ 'npm-groovy-lint': { \ 'function': 'ale#fixers#npmgroovylint#Fix', \ 'suggested_filetypes': ['groovy'], \ 'description': 'Fix Groovy files with npm-groovy-fix.', \ }, \ 'erb-formatter': { \ 'function': 'ale#fixers#erbformatter#Fix', \ 'suggested_filetypes': ['eruby'], \ 'description': 'Apply erb-formatter -w to eruby/erb files.', \ }, \ 'nickel_format': { \ 'function': 'ale#fixers#nickel_format#Fix', \ 'suggested_filetypes': ['nickel'], \ 'description': 'Fix nickel files with nickel format', \ }, \ 'rubyfmt': { \ 'function': 'ale#fixers#rubyfmt#Fix', \ 'suggested_filetypes': ['ruby'], \ 'description': 'A formatter for Ruby source code', \ }, \ 'scadformat': { \ 'function': 'ale#fixers#scadformat#Fix', \ 'suggested_filetypes': ['openscad'], \ 'description': 'Formatter for scad files', \ }, \ 'cljfmt': { \ 'function': 'ale#fixers#cljfmt#Fix', \ 'suggested_filetypes': ['clojure'], \ 'description': 'formatter and linter for clojure files', \ }, \ 'typstyle': { \ 'function': 'ale#fixers#typstyle#Fix', \ 'suggested_filetypes': ['typst'], \ 'description': 'A formatter for Typst files', \ }, \ 'roc_format': { \ 'function': 'ale#fixers#roc_format#Fix', \ 'suggested_filetypes': ['roc'], \ 'description': 'Formats Roc files.', \ }, \ 'roc_annotate': { \ 'function': 'ale#fixers#roc_annotate#Fix', \ 'suggested_filetypes': ['roc'], \ 'description': 'Annotates all top-level definitions in Roc files.', \ }, \ 'tombi_format': { \ 'function': 'ale#fixers#tombi_format#Fix', \ 'suggested_filetypes': ['toml'], \ 'description': 'Formats TOML files', \ }, \ 'tombi_lint': { \ 'function': 'ale#fixers#tombi_lint#Fix', \ 'suggested_filetypes': ['toml'], \ 'description': 'Lints TOML files', \ }, \ 'verible_format': { \ 'function': 'ale#fixers#verible_format#Fix', \ 'suggested_filetypes': ['verilog'], \ 'description': 'Formats verilog files using verible.', \ }, \ 'markdownlint': { \ 'function': 'ale#fixers#markdownlint#Fix', \ 'suggested_filetypes': ['markdown'], \ 'description': 'Fix markdown files with markdownlint.', \ }, \} " Reset the function registry to the default entries. function! ale#fix#registry#ResetToDefaults() abort let s:entries = deepcopy(s:default_registry) let s:aliases = {} " Set up aliases for fixers too. for [l:key, l:entry] in items(s:entries) for l:alias in get(l:entry, 'aliases', []) let s:aliases[l:alias] = l:key endfor endfor endfunction " Set up entries now. call ale#fix#registry#ResetToDefaults() " Remove everything from the registry, useful for tests. function! ale#fix#registry#Clear() abort let s:entries = {} let s:aliases = {} endfunction " Add a function for fixing problems to the registry. " (name, func, filetypes, desc, aliases) function! ale#fix#registry#Add(name, func, filetypes, desc, ...) abort " This command will throw from the sandbox. let &l:equalprg=&l:equalprg if type(a:name) isnot v:t_string throw '''name'' must be a String' endif if type(a:func) isnot v:t_string throw '''func'' must be a String' endif 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) isnot v:t_string throw 'Each entry of ''filetypes'' must be a String' endif endfor 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) 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 let s:entries[a:name] = { \ 'function': a:func, \ 'suggested_filetypes': a:filetypes, \ 'description': a:desc, \} " Set up aliases for the fixer. if !empty(l:aliases) let s:entries[a:name].aliases = l:aliases for l:alias in l:aliases let s:aliases[l:alias] = a:name endfor endif endfunction " Get a function from the registry by its short name. function! ale#fix#registry#GetFunc(name) abort " Use the exact name, or an alias. let l:resolved_name = !has_key(s:entries, a:name) \ ? get(s:aliases, a:name, a:name) \ : a:name return get(s:entries, l:resolved_name, {'function': ''}).function endfunction function! s:ShouldSuggestForType(suggested_filetypes, type_list) abort for l:type in a:type_list if index(a:suggested_filetypes, l:type) >= 0 return 1 endif endfor return 0 endfunction function! s:IsGenericFixer(suggested_filetypes) abort if empty(a:suggested_filetypes) return 1 endif return 0 endfunction function! s:FormatEntry(key, entry) abort let l:aliases_str = '' " Show aliases in :ALEFixSuggest if they are there. if !empty(get(a:entry, 'aliases', [])) let l:aliases_str = ', ' . join( \ map(copy(a:entry.aliases), 'string(v:val)'), \ ',' \) endif return printf( \ '%s%s - %s', \ string(a:key), \ l:aliases_str, \ a:entry.description, \) endfunction " Get list of applicable fixers for filetype, including generic fixers function! ale#fix#registry#GetApplicableFixers(filetype) abort let l:type_list = split(a:filetype, '\.') let l:fixer_name_list = [] for l:key in sort(keys(s:entries)) let l:suggested_filetypes = s:entries[l:key].suggested_filetypes if s:IsGenericFixer(l:suggested_filetypes) || s:ShouldSuggestForType(l:suggested_filetypes, l:type_list) call add(l:fixer_name_list, l:key) endif endfor return l:fixer_name_list endfunction " Function that returns autocomplete candidates for ALEFix command function! ale#fix#registry#CompleteFixers(ArgLead, CmdLine, CursorPos) abort return filter(ale#fix#registry#GetApplicableFixers(&filetype), 'v:val =~? a:ArgLead') endfunction function! ale#fix#registry#SuggestedFixers(filetype) abort let l:type_list = split(a:filetype, '\.') let l:filetype_fixer_list = [] for l:key in sort(keys(s:entries)) let l:suggested_filetypes = s:entries[l:key].suggested_filetypes if s:ShouldSuggestForType(l:suggested_filetypes, l:type_list) call add( \ l:filetype_fixer_list, \ s:FormatEntry(l:key, s:entries[l:key]), \) endif endfor let l:generic_fixer_list = [] for l:key in sort(keys(s:entries)) if s:IsGenericFixer(s:entries[l:key].suggested_filetypes) call add( \ l:generic_fixer_list, \ s:FormatEntry(l:key, s:entries[l:key]), \) endif endfor return [l:filetype_fixer_list, l:generic_fixer_list] endfunction " Suggest functions to use from the registry. function! ale#fix#registry#Suggest(filetype) abort let l:suggested = ale#fix#registry#SuggestedFixers(a:filetype) let l:filetype_fixer_list = l:suggested[0] let l:generic_fixer_list = l:suggested[1] let l:filetype_fixer_header = !empty(l:filetype_fixer_list) \ ? ['Try the following fixers appropriate for the filetype:', ''] \ : [] let l:generic_fixer_header = !empty(l:generic_fixer_list) \ ? ['Try the following generic fixers:', ''] \ : [] let l:has_both_lists = !empty(l:filetype_fixer_list) && !empty(l:generic_fixer_list) let l:lines = \ l:filetype_fixer_header \ + l:filetype_fixer_list \ + (l:has_both_lists ? [''] : []) \ + l:generic_fixer_header \ + l:generic_fixer_list if empty(l:lines) let l:lines = ['There is nothing in the registry to suggest.'] else let l:lines += ['', 'See :help ale-fix-configuration'] endif let l:lines += ['', 'Press q to close this window'] new +set\ filetype=ale-fix-suggest call setline(1, l:lines) setlocal nomodified setlocal nomodifiable endfunction ================================================ FILE: autoload/ale/fix.vim ================================================ " Author: w0rp " Description: Functions for fixing code with programs, or other means. let g:ale_fix_on_save_ignore = get(g:, 'ale_fix_on_save_ignore', {}) let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {}) " Apply fixes queued up for buffers which may be hidden. " Vim doesn't let you modify hidden buffers. function! ale#fix#ApplyQueuedFixes(buffer) abort let l:data = get(g:ale_fix_buffer_data, a:buffer, {'done': 0}) if !l:data.done || (!ale#util#HasBuflineApi() && a:buffer isnot bufnr('')) return endif call remove(g:ale_fix_buffer_data, a:buffer) try if l:data.changes_made let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output) if l:data.should_save if a:buffer is bufnr('') if empty(&buftype) noautocmd :w! else set nomodified endif else call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks call setbufvar(a:buffer, '&modified', 0) endif endif endif catch /E21\|E5555/ " If we cannot modify the buffer now, try again later. let g:ale_fix_buffer_data[a:buffer] = l:data return endtry if l:data.should_save let l:should_lint = ale#Var(a:buffer, 'fix_on_save') \ && ale#Var(a:buffer, 'lint_on_save') else let l:should_lint = l:data.changes_made endif silent doautocmd User ALEFixPost " If ALE linting is enabled, check for problems with the file again after " fixing problems. if g:ale_enabled \&& l:should_lint \&& !ale#events#QuitRecently(a:buffer) call ale#Queue(0, l:data.should_save ? 'lint_file' : '') endif endfunction function! ale#fix#ApplyFixes(buffer, output) abort let l:data = g:ale_fix_buffer_data[a:buffer] let l:data.output = a:output let l:data.changes_made = l:data.lines_before !=# l:data.output " no-custom-checks let l:data.done = 1 call ale#command#RemoveManagedFiles(a:buffer) if !bufexists(a:buffer) " Remove the buffer data when it doesn't exist. call remove(g:ale_fix_buffer_data, a:buffer) endif if l:data.changes_made && bufexists(a:buffer) let l:lines = getbufline(a:buffer, 1, '$') if l:data.lines_before != l:lines call remove(g:ale_fix_buffer_data, a:buffer) if !l:data.ignore_file_changed_errors " no-custom-checks echom 'The file was changed before fixing finished' endif return endif endif " We can only change the lines of a buffer which is currently open, " so try and apply the fixes to the current buffer. call ale#fix#ApplyQueuedFixes(a:buffer) endfunction function! s:HandleExit(job_info, buffer, job_output, data) abort let l:buffer_info = get(g:ale_fix_buffer_data, a:buffer, {}) if empty(l:buffer_info) return endif if a:job_info.read_temporary_file let l:output = !empty(a:data.temporary_file) \ ? readfile(a:data.temporary_file) \ : [] else let l:output = a:job_output endif let l:ProcessWith = get(a:job_info, 'process_with', v:null) " Post-process the output with a function if we have one. if l:ProcessWith isnot v:null let l:output = call(l:ProcessWith, [a:buffer, l:output]) endif " Use the output of the job for changing the file if it isn't empty, " otherwise skip this job and use the input from before. " " We'll use the input from before for chained commands. if !empty(split(join(l:output))) let l:input = l:output else let l:input = a:job_info.input endif call s:RunFixer({ \ 'buffer': a:buffer, \ 'input': l:input, \ 'callback_list': a:job_info.callback_list, \ 'callback_index': a:job_info.callback_index + 1, \}) endfunction function! s:RunJob(result, options) abort if ale#command#IsDeferred(a:result) let a:result.result_callback = {x -> s:RunJob(x, a:options)} return endif let l:buffer = a:options.buffer let l:input = a:options.input let l:fixer_name = a:options.fixer_name if a:result is 0 || type(a:result) is v:t_list if type(a:result) is v:t_list let l:input = a:result endif call s:RunFixer({ \ 'buffer': l:buffer, \ 'input': l:input, \ 'callback_index': a:options.callback_index + 1, \ 'callback_list': a:options.callback_list, \}) return endif let l:command = get(a:result, 'command', '') if empty(l:command) " If the command is empty, skip to the next item. call s:RunFixer({ \ 'buffer': l:buffer, \ 'input': l:input, \ 'callback_index': a:options.callback_index, \ 'callback_list': a:options.callback_list, \}) return endif let l:read_temporary_file = get(a:result, 'read_temporary_file', 0) let l:read_buffer = get(a:result, 'read_buffer', 1) let l:output_stream = get(a:result, 'output_stream', 'stdout') let l:cwd = get(a:result, 'cwd', v:null) if l:read_temporary_file let l:output_stream = 'none' endif let l:Callback = function('s:HandleExit', [{ \ 'input': l:input, \ 'callback_index': a:options.callback_index, \ 'callback_list': a:options.callback_list, \ 'process_with': get(a:result, 'process_with', v:null), \ 'read_temporary_file': l:read_temporary_file, \}]) let l:run_result = ale#command#Run(l:buffer, l:command, l:Callback, { \ 'output_stream': l:output_stream, \ 'executable': '', \ 'read_buffer': l:read_buffer, \ 'input': l:input, \ 'log_output': 0, \ 'cwd': l:cwd, \ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name), \}) if empty(l:run_result) call s:RunFixer({ \ 'buffer': l:buffer, \ 'input': l:input, \ 'callback_index': a:options.callback_index + 1, \ 'callback_list': a:options.callback_list, \}) endif endfunction function! s:RunFixer(options) abort let l:buffer = a:options.buffer let l:input = a:options.input let l:index = a:options.callback_index if len(a:options.callback_list) <= l:index call ale#fix#ApplyFixes(l:buffer, l:input) return endif let [l:fixer_name, l:Function] = a:options.callback_list[l:index] " Record new jobs started as fixer jobs. call setbufvar(l:buffer, 'ale_job_type', 'fixer') " Regular fixer commands accept (buffer, [input]) let l:result = ale#util#FunctionArgCount(l:Function) == 1 \ ? call(l:Function, [l:buffer]) \ : call(l:Function, [l:buffer, copy(l:input)]) call s:RunJob(l:result, { \ 'buffer': l:buffer, \ 'input': l:input, \ 'callback_list': a:options.callback_list, \ 'callback_index': l:index, \ 'fixer_name': l:fixer_name, \}) endfunction function! s:AddSubCallbacks(full_list, callbacks) abort if type(a:callbacks) is v:t_string call add(a:full_list, a:callbacks) elseif type(a:callbacks) is v:t_list call extend(a:full_list, a:callbacks) else return 0 endif return 1 endfunction function! s:IgnoreFixers(callback_list, filetype, config) abort if type(a:config) is v:t_list let l:ignore_list = a:config else let l:ignore_list = [] for l:part in split(a:filetype , '\.') call extend(l:ignore_list, get(a:config, l:part, [])) endfor endif call filter(a:callback_list, 'index(l:ignore_list, v:val) < 0') endfunction function! s:GetCallbacks(buffer, fixing_flag, fixers) abort if len(a:fixers) let l:callback_list = a:fixers 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 " buffer and global options can use dictionaries mapping filetypes to " callbacks to run. let l:fixers = ale#Var(a:buffer, 'fixers') let l:callback_list = [] let l:matched = 0 for l:sub_type in split(&filetype, '\.') if s:AddSubCallbacks(l:callback_list, get(l:fixers, l:sub_type)) let l:matched = 1 endif endfor " If we couldn't find fixers for a filetype, default to '*' fixers. if !l:matched call s:AddSubCallbacks(l:callback_list, get(l:fixers, '*')) endif endif if a:fixing_flag is# 'save_file' let l:config = ale#Var(a:buffer, 'fix_on_save_ignore') if !empty(l:config) call s:IgnoreFixers(l:callback_list, &filetype, l:config) endif endif let l:corrected_list = [] " Variables with capital characters are needed, or Vim will complain about " funcref variables. for l:Item in l:callback_list " Try to capture the names of registered fixer names, so we can use " them for filename mapping or other purposes later. let l:fixer_name = v:null if type(l:Item) is v:t_string let l:Func = ale#fix#registry#GetFunc(l:Item) if !empty(l:Func) let l:fixer_name = l:Item let l:Item = l:Func endif endif try call add(l:corrected_list, [ \ l:fixer_name, \ ale#util#GetFunction(l:Item) \]) catch /E475/ " Rethrow exceptions for failing to get a function so we can print " a friendly message about it. throw 'BADNAME ' . v:exception endtry endfor return l:corrected_list endfunction function! ale#fix#InitBufferData(buffer, fixing_flag) abort " The 'done' flag tells the function for applying changes when fixing " is complete. let g:ale_fix_buffer_data[a:buffer] = { \ 'lines_before': getbufline(a:buffer, 1, '$'), \ 'done': 0, \ 'should_save': a:fixing_flag is# 'save_file', \ 'ignore_file_changed_errors': a:fixing_flag is# '!', \ 'temporary_directory_list': [], \} endfunction " Accepts an optional argument for what to do when fixing. " " Returns 0 if no fixes can be applied, and 1 if fixing can be done. function! ale#fix#Fix(buffer, fixing_flag, ...) abort if a:fixing_flag isnot# '' \&& a:fixing_flag isnot# '!' \&& a:fixing_flag isnot# 'save_file' throw "fixing_flag must be '', '!', or 'save_file'" endif try let l:callback_list = s:GetCallbacks(a:buffer, a:fixing_flag, a:000) catch /E700\|BADNAME/ if a:fixing_flag isnot# '!' let l:function_name = join(split(split(v:exception, ':')[3])) let l:echo_message = printf( \ 'There is no fixer named `%s`. Check :ALEFixSuggest', \ l:function_name, \) " no-custom-checks echom l:echo_message endif return 0 endtry if empty(l:callback_list) if a:fixing_flag is# '' " no-custom-checks echom 'No fixers have been defined. Try :ALEFixSuggest' endif return 0 endif call ale#command#StopJobs(a:buffer, 'fixer') " Clean up any files we might have left behind from a previous run. call ale#command#RemoveManagedFiles(a:buffer) call ale#fix#InitBufferData(a:buffer, a:fixing_flag) silent doautocmd User ALEFixPre call s:RunFixer({ \ 'buffer': a:buffer, \ 'input': g:ale_fix_buffer_data[a:buffer].lines_before, \ 'callback_index': 0, \ 'callback_list': l:callback_list, \}) return 1 endfunction " Set up an autocmd command to try and apply buffer fixes when available. augroup ALEBufferFixGroup autocmd! autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand(''))) augroup END ================================================ FILE: autoload/ale/fixers/alejandra.vim ================================================ call ale#Set('nix_alejandra_executable', 'alejandra') call ale#Set('nix_alejandra_options', '') function! ale#fixers#alejandra#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'nix_alejandra_executable') let l:options = ale#Var(a:buffer, 'nix_alejandra_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' -- -' \} endfunction ================================================ FILE: autoload/ale/fixers/apkbuild_fixer.vim ================================================ " Author: Leo " Description: Fix policy violations found by apkbuild-lint call ale#Set('apkbuild_apkbuild_fixer_executable', 'apkbuild-fixer') call ale#Set('apkbuild_apkbuild_fixer_lint_executable', get(g:, 'ale_apkbuild_apkbuild_lint_executable')) call ale#Set('apkbuild_apkbuild_fixer_options', '') function! ale#fixers#apkbuild_fixer#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'apkbuild_apkbuild_fixer_executable') let l:options = ale#Var(a:buffer, 'apkbuild_apkbuild_fixer_options') return { \ 'command': ale#Escape(l:executable) \ . ' -p ' . ale#Var(a:buffer, 'apkbuild_apkbuild_fixer_lint_executable') \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/appleswiftformat.vim ================================================ " Author: (bosr) " Description: Integration of apple/swift-format formatter with ALE. function! ale#fixers#appleswiftformat#Fix(buffer) abort let l:command_args = ale#swift#GetAppleSwiftFormatCommand(a:buffer) . ' format --in-place %t' let l:config_args = ale#swift#GetAppleSwiftFormatConfigArgs(a:buffer) if l:config_args isnot# '' let l:command_args = l:command_args . ' ' . l:config_args endif return { \ 'read_temporary_file': 1, \ 'command': l:command_args, \} endfunction ================================================ FILE: autoload/ale/fixers/astyle.vim ================================================ " Author: James Kim " Description: Fix C/C++ files with astyle. function! s:set_variables() abort for l:ft in ['c', 'cpp'] call ale#Set(l:ft . '_astyle_executable', 'astyle') call ale#Set(l:ft . '_astyle_project_options', '') endfor endfunction call s:set_variables() function! ale#fixers#astyle#Var(buffer, name) abort let l:ft = getbufvar(str2nr(a:buffer), '&filetype') let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c' return ale#Var(a:buffer, l:ft . '_astyle_' . a:name) endfunction " Try to find a project options file. function! ale#fixers#astyle#FindProjectOptions(buffer) abort let l:proj_options = ale#fixers#astyle#Var(a:buffer, 'project_options') " If user has set project options variable then use it and skip any searching. " This would allow users to use project files named differently than .astylerc. if !empty(l:proj_options) return l:proj_options endif " Try to find nearest .astylerc file. let l:proj_options = fnamemodify(ale#path#FindNearestFile(a:buffer, '.astylerc'), ':t') if !empty(l:proj_options) return l:proj_options endif " Try to find nearest _astylerc file. let l:proj_options = fnamemodify(ale#path#FindNearestFile(a:buffer, '_astylerc'), ':t') if !empty(l:proj_options) return l:proj_options endif " If no project options file is found return an empty string. return '' endfunction function! ale#fixers#astyle#Fix(buffer) abort let l:executable = ale#fixers#astyle#Var(a:buffer, 'executable') let l:proj_options = ale#fixers#astyle#FindProjectOptions(a:buffer) let l:command = ' --stdin=' . ale#Escape(expand('#' . a:buffer)) return { \ 'command': ale#Escape(l:executable) \ . (empty(l:proj_options) ? '' : ' --project=' . l:proj_options) \ . l:command \} endfunction ================================================ FILE: autoload/ale/fixers/autoflake.vim ================================================ " Author: circld " Description: Fixing files with autoflake. call ale#Set('python_autoflake_executable', 'autoflake') call ale#Set('python_autoflake_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_autoflake_options', '') call ale#Set('python_autoflake_auto_pipenv', 0) call ale#Set('python_autoflake_auto_poetry', 0) call ale#Set('python_autoflake_auto_uv', 0) function! ale#fixers#autoflake#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_autoflake_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_autoflake_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_autoflake_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_autoflake', ['autoflake']) endfunction function! ale#fixers#autoflake#Fix(buffer) abort let l:executable = ale#fixers#autoflake#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run autoflake' \ : '' let l:options = ale#Var(a:buffer, 'python_autoflake_options') return { \ 'command': ale#Escape(l:executable) . l:exec_args \ . ale#Pad(l:options) \ . ' --in-place ' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/autoimport.vim ================================================ " Author: lyz-code " Description: Fixing Python imports with autoimport. call ale#Set('python_autoimport_executable', 'autoimport') call ale#Set('python_autoimport_options', '') call ale#Set('python_autoimport_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_autoimport_auto_pipenv', 0) call ale#Set('python_autoimport_auto_poetry', 0) call ale#Set('python_autoimport_auto_uv', 0) function! ale#fixers#autoimport#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_autoimport_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_autoimport_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_autoimport_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_autoimport', ['autoimport']) endfunction function! ale#fixers#autoimport#Fix(buffer) abort let l:executable = ale#fixers#autoimport#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run autoimport' \ : '' let l:options = ale#Var(a:buffer, 'python_autoimport_options') return { \ 'cwd': '%s:h', \ 'command': ale#Escape(l:executable) . l:exec_args \ . ale#Pad(l:options) \ . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/autopep8.vim ================================================ " Author: w0rp " Description: Fixing files with autopep8. call ale#Set('python_autopep8_executable', 'autopep8') call ale#Set('python_autopep8_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_autopep8_options', '') call ale#Set('python_autopep8_auto_pipenv', 0) call ale#Set('python_autopep8_auto_poetry', 0) call ale#Set('python_autopep8_auto_uv', 0) function! ale#fixers#autopep8#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_autopep8_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_autopep8_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_autopep8_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_autopep8', ['autopep8']) endfunction function! ale#fixers#autopep8#Fix(buffer) abort let l:executable = ale#fixers#autopep8#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run autopep8' \ : '' let l:options = ale#Var(a:buffer, 'python_autopep8_options') return { \ 'command': ale#Escape(l:executable) . l:exec_args \ . ale#Pad(l:options) \ . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/bibclean.vim ================================================ " Author: Horacio Sanson - https://github.com/hsanson " Description: Support for bibclean fixer for BibTeX files. call ale#Set('bib_bibclean_executable', 'bibclean') call ale#Set('bib_bibclean_options', '-align-equals') function! ale#fixers#bibclean#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'bib_bibclean_options') let l:executable = ale#Var(a:buffer, 'bib_bibclean_executable') return { \ 'command': ale#Escape(l:executable) \ . ' ' . (empty(l:options) ? '' : l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/biome.vim ================================================ function! ale#fixers#biome#Fix(buffer) abort let l:executable = ale#handlers#biome#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'biome_options') let l:unsafe = ale#Var(a:buffer, 'biome_fixer_apply_unsafe') ? ' --unsafe' : '' return { \ 'command': ale#Escape(l:executable) . ' check ' \ . '--write --stdin-file-path %s' . l:unsafe \ . ale#Pad(l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/black.vim ================================================ " Author: w0rp " Description: Fixing Python files with black. " call ale#Set('python_black_executable', 'black') call ale#Set('python_black_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_black_options', '') call ale#Set('python_black_auto_pipenv', 0) call ale#Set('python_black_auto_poetry', 0) call ale#Set('python_black_auto_uv', 0) call ale#Set('python_black_change_directory', 1) function! ale#fixers#black#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_black_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_black_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_black_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_black', ['black']) endfunction function! ale#fixers#black#Fix(buffer) abort let l:executable = ale#fixers#black#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'black']) endif let l:options = ale#Var(a:buffer, 'python_black_options') if !empty(l:options) call add(l:cmd, l:options) endif let l:fname = expand('#' . a:buffer . '...') call add(l:cmd, '--stdin-filename '.ale#Escape(ale#path#Simplify(l:fname))) if expand('#' . a:buffer . ':e') is? 'pyi' call add(l:cmd, '--pyi') endif call add(l:cmd, '-') let l:result = {'command': join(l:cmd, ' ')} if ale#Var(a:buffer, 'python_black_change_directory') let l:result.cwd = '%s:h' endif return l:result endfunction ================================================ FILE: autoload/ale/fixers/brittany.vim ================================================ " Author: eborden , ifyouseewendy , aspidiets " Description: Integration of brittany with ALE. call ale#Set('haskell_brittany_executable', 'brittany') 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': l:executable \ . ' --write-mode inplace' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/buf_format.vim ================================================ " Author: Alex McKinney " Description: Run buf format. call ale#Set('proto_buf_format_executable', 'buf') function! ale#fixers#buf_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'proto_buf_format_executable') return { \ 'command': ale#Escape(l:executable) . ' format %t', \} endfunction ================================================ FILE: autoload/ale/fixers/buildifier.vim ================================================ " Author: Jon Parise " Description: Format Bazel BUILD and .bzl files with buildifier. " call ale#Set('bazel_buildifier_executable', 'buildifier') call ale#Set('bazel_buildifier_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('bazel_buildifier_options', '') function! ale#fixers#buildifier#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'bazel_buildifier', [ \ 'buildifier', \]) endfunction function! ale#fixers#buildifier#Fix(buffer) abort let l:executable = ale#Escape(ale#fixers#buildifier#GetExecutable(a:buffer)) let l:options = ale#Var(a:buffer, 'bazel_buildifier_options') let l:filename = ale#Escape(bufname(a:buffer)) let l:command = l:executable . ' -mode fix -lint fix -path ' . l:filename if l:options isnot# '' let l:command .= ' ' . l:options endif return {'command': l:command . ' -'} endfunction ================================================ FILE: autoload/ale/fixers/clangformat.vim ================================================ scriptencoding utf-8 " Author: Peter Renström " Description: Fixing C/C++ files with clang-format. call ale#Set('c_clangformat_executable', 'clang-format') call ale#Set('c_clangformat_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('c_clangformat_options', '') call ale#Set('c_clangformat_style_option', '') call ale#Set('c_clangformat_use_local_file', 0) function! ale#fixers#clangformat#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'c_clangformat', [ \ 'clang-format', \]) endfunction function! ale#fixers#clangformat#Fix(buffer) abort let l:executable = ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer)) let l:filename = ale#Escape(bufname(a:buffer)) let l:options = ale#Var(a:buffer, 'c_clangformat_options') let l:style_option = ale#Var(a:buffer, 'c_clangformat_style_option') let l:use_local_file = ale#Var(a:buffer, 'c_clangformat_use_local_file') if l:style_option isnot# '' let l:style_option = '-style=' . ale#Escape(l:style_option) endif if l:use_local_file let l:config = ale#path#FindNearestFile(a:buffer, '.clang-format') if !empty(l:config) let l:style_option = '-style=file' endif endif if l:style_option isnot# '' let l:options .= ' ' . l:style_option endif let l:command = l:executable . ' --assume-filename=' . l:filename if l:options isnot# '' let l:command .= ' ' . l:options endif return {'command': l:command} endfunction ================================================ FILE: autoload/ale/fixers/clangtidy.vim ================================================ scriptencoding utf-8 " Author: ObserverOfTime " Description: Fixing C/C++ files with clang-tidy. function! s:set_variables() abort let l:use_global = get(g:, 'ale_use_global_executables', 0) for l:ft in ['c', 'cpp'] call ale#Set(l:ft . '_clangtidy_executable', 'clang-tidy') call ale#Set(l:ft . '_clangtidy_use_global', l:use_global) call ale#Set(l:ft . '_clangtidy_checks', []) call ale#Set(l:ft . '_clangtidy_options', '') call ale#Set(l:ft . '_clangtidy_extra_options', '') call ale#Set(l:ft . '_clangtidy_fix_errors', 1) endfor call ale#Set('c_build_dir', '') endfunction call s:set_variables() function! ale#fixers#clangtidy#Var(buffer, name) abort let l:ft = getbufvar(str2nr(a:buffer), '&filetype') let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c' return ale#Var(a:buffer, l:ft . '_clangtidy_' . a:name) endfunction function! ale#fixers#clangtidy#GetCommand(buffer) abort let l:checks = join(ale#fixers#clangtidy#Var(a:buffer, 'checks'), ',') let l:extra_options = ale#fixers#clangtidy#Var(a:buffer, 'extra_options') let l:build_dir = ale#c#GetBuildDirectory(a:buffer) let l:options = empty(l:build_dir) \ ? ale#fixers#clangtidy#Var(a:buffer, 'options') : '' let l:fix_errors = ale#fixers#clangtidy#Var(a:buffer, 'fix_errors') return ' -fix' . (l:fix_errors ? ' -fix-errors' : '') \ . (empty(l:checks) ? '' : ' -checks=' . ale#Escape(l:checks)) \ . (empty(l:extra_options) ? '' : ' ' . l:extra_options) \ . (empty(l:build_dir) ? '' : ' -p ' . ale#Escape(l:build_dir)) \ . ' %t' . (empty(l:options) ? '' : ' -- ' . l:options) endfunction function! ale#fixers#clangtidy#Fix(buffer) abort let l:executable = ale#fixers#clangtidy#Var(a:buffer, 'executable') let l:command = ale#fixers#clangtidy#GetCommand(a:buffer) return { \ 'command': ale#Escape(l:executable) . l:command, \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/cljfmt.vim ================================================ " Author: rudolf ordoyne " Description: Support for cljfmt https://github.com/weavejester/cljfmt call ale#Set('clojure_cljfmt_executable', 'cljfmt') function! ale#fixers#cljfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'clojure_cljfmt_executable') return { \ 'command': ale#Escape(l:executable) . ' fix %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/cmakeformat.vim ================================================ " Author: Attila Maczak " Description: Integration of cmakeformat with ALE. call ale#Set('cmake_cmakeformat_executable', 'cmake-format') call ale#Set('cmake_cmakeformat_options', '') function! ale#fixers#cmakeformat#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'cmake_cmakeformat_executable') let l:options = ale#Var(a:buffer, 'cmake_cmakeformat_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' -' \} endfunction ================================================ FILE: autoload/ale/fixers/crystal.vim ================================================ call ale#Set('crystal_format_executable', 'crystal') call ale#Set('crystal_format_options', '') function! ale#fixers#crystal#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'crystal_format_executable') let l:options = ale#Var(a:buffer, 'crystal_format_options') return { \ 'command': ale#Escape(l:executable) \ . ' tool format' \ . ale#Pad(l:options) \ . ' -' \} endfunction ================================================ FILE: autoload/ale/fixers/css_beautify.vim ================================================ " Author: https://github.com/Spixmaster " Description: Format CSS using css-beautify from js-beautify. call ale#Set('css_css_beautify_executable', 'css-beautify') call ale#Set('css_css_beautify_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('css_css_beautify_options', '') function! ale#fixers#css_beautify#Fix(buffer) abort let l:executable = ale#python#FindExecutable( \ a:buffer, \ 'css_css_beautify', \ ['css-beautify'] \) let l:options = ale#Var(a:buffer, 'css_css_beautify_options') return { \ 'command': ale#Escape(l:executable) . ' ' . l:options . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/dart_format.vim ================================================ " Author: ghsang " Description: Integration of dart format with ALE. call ale#Set('dart_format_executable', 'dart') call ale#Set('dart_format_options', '') function! ale#fixers#dart_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'dart_format_executable') let l:options = ale#Var(a:buffer, 'dart_format_options') return { \ 'command': ale#Escape(l:executable) \ . ' format' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/dartfmt.vim ================================================ " Author: reisub0 " Description: Integration of dartfmt with ALE. call ale#Set('dart_dartfmt_executable', 'dartfmt') call ale#Set('dart_dartfmt_options', '') function! ale#fixers#dartfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'dart_dartfmt_executable') let l:options = ale#Var(a:buffer, 'dart_dartfmt_options') return { \ 'command': ale#Escape(l:executable) \ . ' -w' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/deno.vim ================================================ function! ale#fixers#deno#Fix(buffer) abort let l:executable = ale#handlers#deno#GetExecutable(a:buffer) if !executable(l:executable) return 0 endif let l:options = ' fmt -' if ale#Var(a:buffer, 'deno_unstable') let l:options = l:options . ' --unstable' endif return { \ 'command': ale#Escape(l:executable) . l:options \} endfunction ================================================ FILE: autoload/ale/fixers/dfmt.vim ================================================ " Author: theoldmoon0602 " Description: Integration of dfmt with ALE. call ale#Set('d_dfmt_executable', 'dfmt') call ale#Set('d_dfmt_options', '') function! ale#fixers#dfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'd_dfmt_executable') let l:options = ale#Var(a:buffer, 'd_dfmt_options') return { \ 'command': ale#Escape(l:executable) \ . ' -i' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/dhall_format.vim ================================================ " Author: toastal " Description: Dhall’s built-in formatter " function! ale#fixers#dhall_format#Fix(buffer) abort let l:executable = ale#dhall#GetExecutableWithOptions(a:buffer) return { \ 'command': l:executable \ . ' format' \} endfunction ================================================ FILE: autoload/ale/fixers/dhall_freeze.vim ================================================ " Author: toastal " Description: Dhall’s package freezing call ale#Set('dhall_freeze_options', '') function! ale#fixers#dhall_freeze#Freeze(buffer) abort let l:executable = ale#dhall#GetExecutableWithOptions(a:buffer) return { \ 'command': l:executable \ . ' freeze' \ . ale#Pad(ale#Var(a:buffer, 'dhall_freeze_options')) \} endfunction ================================================ FILE: autoload/ale/fixers/dhall_lint.vim ================================================ " Author: toastal " Description: Dhall’s built-in linter/formatter function! ale#fixers#dhall_lint#Fix(buffer) abort let l:executable = ale#dhall#GetExecutableWithOptions(a:buffer) return { \ 'command': l:executable \ . ' lint' \} endfunction ================================================ FILE: autoload/ale/fixers/djlint.vim ================================================ " Author: Adrian Vollmer (computerfluesterer@protonmail.com) " Description: HTML template formatter using `djlint --reformat` call ale#Set('html_djlint_executable', 'djlint') call ale#Set('html_djlint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('html_djlint_options', '') function! ale#fixers#djlint#Fix(buffer) abort let l:executable = ale#python#FindExecutable( \ a:buffer, \ 'html_djlint', \ ['djlint'] \) let l:options = ale#Var(a:buffer, 'html_djlint_options') let l:profile = '' let l:filetypes = split(getbufvar(a:buffer, '&filetype'), '\.') " Append the --profile flag depending on the current filetype (unless it's " already set in g:html_djlint_options). if match(l:options, '--profile') == -1 let l:djlint_profiles = { \ 'html': 'html', \ 'htmldjango': 'django', \ 'jinja': 'jinja', \ 'nunjucks': 'nunjucks', \ 'handlebars': 'handlebars', \ 'gohtmltmpl': 'golang', \ 'htmlangular': 'angular', \} for l:filetype in l:filetypes if has_key(l:djlint_profiles, l:filetype) let l:profile = l:djlint_profiles[l:filetype] break endif endfor endif if !empty(l:profile) let l:options = (!empty(l:options) ? l:options . ' ' : '') . '--profile ' . l:profile endif return { \ 'command': ale#Escape(l:executable) . ' --reformat ' . l:options . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/dotnet_format.vim ================================================ " Author: ghsang " Description: Integration of dotnet format with ALE. call ale#Set('cs_dotnet_format_executable', 'dotnet') call ale#Set('cs_dotnet_format_options', '') function! ale#fixers#dotnet_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'cs_dotnet_format_executable') let l:options = ale#Var(a:buffer, 'cs_dotnet_format_options') return { \ 'command': ale#Escape(l:executable) \ . ' format' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' --folder --include %t "$(dirname %t)"', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/dprint.vim ================================================ call ale#Set('dprint_executable', 'dprint') call ale#Set('dprint_executable_override', 0) call ale#Set('dprint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('dprint_options', '') call ale#Set('dprint_config', 'dprint.json') function! ale#fixers#dprint#Fix(buffer) abort let l:executable = ale#path#FindExecutable(a:buffer, 'dprint', ['dprint']) let l:executable_override = ale#Var(a:buffer, 'dprint_executable_override') if !executable(l:executable) && !l:executable_override return 0 endif let l:options = ale#Var(a:buffer, 'dprint_options') let l:config = ale#path#FindNearestFile(a:buffer, ale#Var(a:buffer, 'dprint_config')) if !empty(l:config) let l:options = l:options . ' -c ' . ale#Escape(l:config) endif let l:options = l:options . ' --stdin %s' return { \ 'command': ale#Escape(l:executable) \ . ' fmt ' \ . l:options \} endfunction ================================================ FILE: autoload/ale/fixers/dune.vim ================================================ " Author: Albert Peschar " Description: Fix files with dune format. call ale#Set('ocaml_dune_executable', 'dune') call ale#Set('ocaml_dune_options', '') function! ale#fixers#dune#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'ocaml_dune_executable') let l:options = ale#Var(a:buffer, 'ocaml_dune_options') return { \ 'command': ale#Escape(l:executable) \ . ' format' \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/elm_format.vim ================================================ " Author: soywod " Description: Integration of elm-format with ALE. call ale#Set('elm_format_executable', 'elm-format') call ale#Set('elm_format_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('elm_format_options', '--yes') function! ale#fixers#elm_format#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'elm_format', [ \ 'node_modules/.bin/elm-format', \]) endfunction function! ale#fixers#elm_format#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'elm_format_options') return { \ 'command': ale#Escape(ale#fixers#elm_format#GetExecutable(a:buffer)) \ . ' %t' \ . (empty(l:options) ? '' : ' ' . l:options), \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/erbformatter.vim ================================================ " Author: Arash Mousavi " Description: Support for ERB::Formetter https://github.com/nebulab/erb-formatter call ale#Set('eruby_erbformatter_executable', 'erb-formatter') function! ale#fixers#erbformatter#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'eruby_erbformatter_executable') return { \ 'command': ale#Escape(l:executable) . ' -w %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/erblint.vim ================================================ " Author: Roeland Moors - https://github.com/roelandmoors " Description: ERB Lint, support for https://github.com/Shopify/erb-lint call ale#Set('eruby_erblint_executable', 'erblint') call ale#Set('eruby_erblint_options', '') " Erblint fixer outputs diagnostics first and then the fixed " output. These are delimited by something like this: " ================ /path/to/demo.html.erb ================== " We only need the output after this function! ale#fixers#erblint#PostProcess(buffer, output) abort let l:line = 0 for l:output in a:output let l:line = l:line + 1 if l:output =~# "^=\\+.*=\\+$" break endif endfor return a:output[l:line :] endfunction function! ale#fixers#erblint#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'eruby_erblint_executable') let l:options = ale#Var(a:buffer, 'eruby_erblint_options') return ale#ruby#EscapeExecutable(l:executable, 'erblint') \ . ale#Pad(l:options) \ . ' --autocorrect --stdin %s' endfunction function! ale#fixers#erblint#Fix(buffer) abort return { \ 'command': ale#fixers#erblint#GetCommand(a:buffer), \ 'process_with': 'ale#fixers#erblint#PostProcess' \} endfunction ================================================ FILE: autoload/ale/fixers/erlang_mode.vim ================================================ " Author: Dmitri Vereshchagin " Description: Indent with the Erlang mode for Emacs call ale#Set('erlang_erlang_mode_emacs_executable', 'emacs') call ale#Set('erlang_erlang_mode_indent_level', 4) call ale#Set('erlang_erlang_mode_icr_indent', 'nil') call ale#Set('erlang_erlang_mode_indent_guard', 2) call ale#Set('erlang_erlang_mode_argument_indent', 2) call ale#Set('erlang_erlang_mode_indent_tabs_mode', 'nil') let s:variables = { \ 'erlang-indent-level': 'erlang_erlang_mode_indent_level', \ 'erlang-icr-indent': 'erlang_erlang_mode_icr_indent', \ 'erlang-indent-guard': 'erlang_erlang_mode_indent_guard', \ 'erlang-argument-indent': 'erlang_erlang_mode_argument_indent', \ 'indent-tabs-mode': 'erlang_erlang_mode_indent_tabs_mode', \} function! ale#fixers#erlang_mode#Fix(buffer) abort let l:emacs_executable = \ ale#Var(a:buffer, 'erlang_erlang_mode_emacs_executable') let l:exprs = [ \ '(setq enable-local-variables :safe)', \ s:SetqDefault(a:buffer, s:variables), \ '(erlang-mode)', \ '(font-lock-fontify-region (point-min) (point-max))', \ '(indent-region (point-min) (point-max))', \ '(funcall (if indent-tabs-mode ''tabify ''untabify)' \ . ' (point-min) (point-max))', \ '(save-buffer 0)', \] let l:command = ale#Escape(l:emacs_executable) \ . ' --batch' \ . ' --find-file=%t' \ . join(map(l:exprs, '" --eval=" . ale#Escape(v:val)'), '') return {'command': l:command, 'read_temporary_file': 1} endfunction function! s:SetqDefault(buffer, variables) abort let l:args = [] for [l:emacs_name, l:ale_name] in items(a:variables) let l:args += [l:emacs_name, ale#Var(a:buffer, l:ale_name)] endfor return '(setq-default ' . join(l:args) . ')' endfunction ================================================ FILE: autoload/ale/fixers/erlfmt.vim ================================================ " Author: AntoineGagne - https://github.com/AntoineGagne " Description: Integration of erlfmt with ALE. call ale#Set('erlang_erlfmt_executable', 'erlfmt') call ale#Set('erlang_erlfmt_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('erlang_erlfmt_options', '') function! ale#fixers#erlfmt#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'erlang_erlfmt', ['erlfmt']) endfunction function! ale#fixers#erlfmt#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'erlang_erlfmt_options') let l:executable = ale#fixers#erlfmt#GetExecutable(a:buffer) let l:command = ale#Escape(l:executable) . ale#Pad(l:options) . ' -' return {'command': l:command} endfunction ================================================ FILE: autoload/ale/fixers/eslint.vim ================================================ " Author: w0rp " Description: Fixing files with eslint. function! ale#fixers#eslint#Fix(buffer) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) let l:command = ale#node#Executable(a:buffer, l:executable) \ . ' --version' return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale#fixers#eslint#ApplyFixForVersion'), \) endfunction function! ale#fixers#eslint#ProcessFixDryRunOutput(buffer, output) abort for l:item in ale#util#FuzzyJSONDecode(a:output, []) return split(get(l:item, 'output', ''), "\n") endfor return [] 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 =~# '\v^Error:|^Could not connect' return [] endif endfor return a:output endfunction function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_eslint_options') " Use the configuration file from the options, if configured. if l:options =~# '\v(^| )-c|(^| )--config' let l:config = '' let l:has_config = 1 else let l:config = ale#handlers#eslint#FindConfig(a:buffer) let l:has_config = !empty(l:config) endif if !l:has_config return 0 endif " Use --fix-to-stdout with eslint_d if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0]) return { \ 'cwd': ale#handlers#eslint#GetCwd(a:buffer), \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' --stdin-filename %s --stdin --fix-to-stdout', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \} endif " 4.9.0 is the first version with --fix-dry-run if ale#semver#GTE(a:version, [4, 9, 0]) return { \ 'cwd': ale#handlers#eslint#GetCwd(a:buffer), \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \} endif return { \ 'cwd': ale#handlers#eslint#GetCwd(a:buffer), \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '') \ . ' --fix %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/fecs.vim ================================================ " Author: harttle " Description: Apply fecs format to a file. function! ale#fixers#fecs#Fix(buffer) abort let l:executable = ale#handlers#fecs#GetExecutable(a:buffer) if !executable(l:executable) return 0 endif let l:config_options = ' format --replace=true %t' return { \ 'command': ale#Escape(l:executable) . l:config_options, \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/fish_indent.vim ================================================ " Author: Chen YuanYuan " Description: Integration of fish_indent with ALE. call ale#Set('fish_fish_indent_executable', 'fish_indent') call ale#Set('fish_fish_indent_options', '') function! ale#fixers#fish_indent#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'fish_fish_indent_executable') let l:options = ale#Var(a:buffer, 'fish_fish_indent_options') let l:filename = ale#Escape(bufname(a:buffer)) return { \ 'command': ale#Escape(l:executable) \ . ' -w ' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/fixjson.vim ================================================ " Author: rhysd " Description: Integration of fixjson with ALE. call ale#Set('json_fixjson_executable', 'fixjson') call ale#Set('json_fixjson_options', '') call ale#Set('json_fixjson_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#fixers#fixjson#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'json_fixjson', [ \ 'node_modules/.bin/fixjson', \]) endfunction function! ale#fixers#fixjson#Fix(buffer) abort let l:executable = ale#Escape(ale#fixers#fixjson#GetExecutable(a:buffer)) let l:filename = ale#Escape(bufname(a:buffer)) 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 return { \ 'command': l:command \} endfunction ================================================ FILE: autoload/ale/fixers/floskell.vim ================================================ " Author: robertjlooby " Description: Integration of floskell with ALE. call ale#Set('haskell_floskell_executable', 'floskell') function! ale#fixers#floskell#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'haskell_floskell_executable') return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'floskell') endfunction function! ale#fixers#floskell#Fix(buffer) abort let l:executable = ale#fixers#floskell#GetExecutable(a:buffer) return { \ 'command': l:executable \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/forge.vim ================================================ call ale#Set('solidity_forge_executable', 'forge') function! ale#fixers#forge#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'solidity_forge_executable') return { \ 'command': ale#Escape(l:executable) \ . ' fmt %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/fourmolu.vim ================================================ call ale#Set('haskell_fourmolu_executable', 'fourmolu') call ale#Set('haskell_fourmolu_options', '') function! ale#fixers#fourmolu#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'haskell_fourmolu_executable') return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'fourmolu') endfunction function! ale#fixers#fourmolu#Fix(buffer) abort let l:executable = ale#fixers#fourmolu#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'haskell_fourmolu_options') return { \ 'command': l:executable \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' --stdin-input-file ' \ . ale#Escape(@%), \} endfunction ================================================ FILE: autoload/ale/fixers/generic.vim ================================================ " Author: w0rp " Description: Generic functions for fixing files with. function! ale#fixers#generic#RemoveTrailingBlankLines(buffer, lines) abort let l:end_index = len(a:lines) - 1 while l:end_index > 0 && empty(a:lines[l:end_index]) let l:end_index -= 1 endwhile return a:lines[:l:end_index] endfunction " Remove all whitespaces at the end of lines function! ale#fixers#generic#TrimWhitespace(buffer, lines) abort let l:index = 0 let l:lines_new = range(len(a:lines)) for l:line in a:lines let l:lines_new[l:index] = substitute(l:line, '\s\+$', '', 'g') let l:index = l:index + 1 endfor return l:lines_new endfunction ================================================ FILE: autoload/ale/fixers/generic_python.vim ================================================ " Author: w0rp " Description: Generic fixer functions for Python. " Add blank lines before control statements. function! ale#fixers#generic_python#AddLinesBeforeControlStatements(buffer, lines) abort let l:new_lines = [] let l:last_indent_size = 0 let l:last_line_is_blank = 0 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 call add(l:new_lines, '') endif call add(l:new_lines, l:line) let l:last_indent_size = l:indent_size let l:last_line_is_blank = empty(split(l:line)) endfor return l:new_lines endfunction " This function breaks up long lines so that autopep8 or other tools can " fix the badly-indented code which is produced as a result. function! ale#fixers#generic_python#BreakUpLongLines(buffer, lines) abort " Default to a maximum line length of 79 let l:max_line_length = 79 let l:conf = ale#path#FindNearestFile(a:buffer, 'setup.cfg') " Read the maximum line length from setup.cfg if !empty(l:conf) for l:match in ale#util#GetMatches( \ readfile(l:conf), \ '\v^ *max-line-length *\= *(\d+)', \) let l:max_line_length = str2nr(l:match[1]) endfor endif let l:new_list = [] for l:line in a:lines if len(l:line) > l:max_line_length && l:line !~# '# *noqa' let l:line = substitute(l:line, '\v([(,])([^)])', '\1\n\2', 'g') let l:line = substitute(l:line, '\v([^(])([)])', '\1,\n\2', 'g') for l:split_line in split(l:line, "\n") call add(l:new_list, l:split_line) endfor else call add(l:new_list, l:line) endif endfor return l:new_list endfunction ================================================ FILE: autoload/ale/fixers/gleam_format.vim ================================================ " Author: Jonathan Palardt https://github.com/jpalardy " Description: Integration of 'gleam format' with ALE. call ale#Set('gleam_format_executable', 'gleam') function! ale#fixers#gleam_format#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'gleam_format_executable') return ale#Escape(l:executable) endfunction function! ale#fixers#gleam_format#Fix(buffer) abort let l:executable = ale#fixers#gleam_format#GetExecutable(a:buffer) return { \ 'command': l:executable . ' format %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/gnatpp.vim ================================================ " Author: tim " Description: Fix files with gnatpp. call ale#Set('ada_gnatpp_executable', 'gnatpp') call ale#Set('ada_gnatpp_options', '') function! ale#fixers#gnatpp#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'ada_gnatpp_executable') let l:options = ale#Var(a:buffer, 'ada_gnatpp_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/gofmt.vim ================================================ " Author: aliou " Description: Integration of gofmt with ALE. call ale#Set('go_gofmt_executable', 'gofmt') call ale#Set('go_gofmt_options', '') function! ale#fixers#gofmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_gofmt_executable') let l:options = ale#Var(a:buffer, 'go_gofmt_options') let l:env = ale#go#EnvString(a:buffer) return { \ 'command': l:env . ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/gofumpt.vim ================================================ " Author: David Houston " Description: A stricter gofmt implementation. call ale#Set('go_gofumpt_executable', 'gofumpt') call ale#Set('go_gofumpt_options', '') function! ale#fixers#gofumpt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_gofumpt_executable') let l:options = ale#Var(a:buffer, 'go_gofumpt_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' -w -- %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/goimports.vim ================================================ " Author: Jeff Willette " Description: Integration of goimports with ALE. call ale#Set('go_goimports_executable', 'goimports') call ale#Set('go_goimports_options', '') function! ale#fixers#goimports#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_goimports_executable') let l:options = ale#Var(a:buffer, 'go_goimports_options') let l:env = ale#go#EnvString(a:buffer) if !executable(l:executable) return 0 endif return { \ 'command': l:env . ale#Escape(l:executable) \ . ' -l -w -srcdir %s' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/golangci_lint.vim ================================================ " Author: Ian Stapleton Cordasco " Description: Run golangci-lint with the --fix flag to autofix some issues call ale#Set('go_golangci_formatter_options', '') call ale#Set('go_golangci_formatter_executable', 'golangci-lint') function! ale#fixers#golangci_lint#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'go_golangci_formatter_executable') return l:executable endfunction function! ale#fixers#golangci_lint#GetCommand(buffer, version) abort let l:filename = expand('#' . a:buffer . ':t') let l:executable = ale#fixers#golangci_lint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'go_golangci_formatter_options') let l:env = ale#go#EnvString(a:buffer) if ale#semver#GTE(a:version, [2, 0, 0]) return l:env . ale#Escape(l:executable) \ . ' fmt --stdin ' \ . l:options else return l:env . ale#Escape(l:executable) \ . ' run --fix ' \ . l:options \ . ' ' \ . ale#Escape(l:filename) endif endfunction function! ale#fixers#golangci_lint#GetCommandForVersion(buffer, version) abort return { \ 'command': ale#fixers#golangci_lint#GetCommand(a:buffer, a:version) \} endfunction function! ale#fixers#golangci_lint#Fix(buffer) abort let l:executable = ale#fixers#golangci_lint#GetExecutable(a:buffer) let l:command = ale#fixers#golangci_lint#GetExecutable(a:buffer) . ale#Pad('--version') return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale#fixers#golangci_lint#GetCommandForVersion'), \) endfunction ================================================ FILE: autoload/ale/fixers/golines.vim ================================================ " Author Pig Frown " Description: Fix Go files long lines with golines" call ale#Set('go_golines_executable', 'golines') call ale#Set('go_golines_options', '') function! ale#fixers#golines#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_golines_executable') let l:options = ale#Var(a:buffer, 'go_golines_options') let l:env = ale#go#EnvString(a:buffer) if !executable(l:executable) return 0 endif return { \ 'command': l:env . ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/gomod.vim ================================================ call ale#Set('go_go_executable', 'go') function! ale#fixers#gomod#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_go_executable') let l:env = ale#go#EnvString(a:buffer) return { \ 'command': l:env . ale#Escape(l:executable) . ' mod edit -fmt %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/google_java_format.vim ================================================ " Author: butlerx " Description: Integration of Google-java-format with ALE. 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, 'java_google_java_format_options') let l:executable = ale#Var(a:buffer, 'java_google_java_format_executable') if !executable(l:executable) return 0 endif return { \ 'command': ale#Escape(l:executable) \ . ' ' . (empty(l:options) ? '' : ' ' . l:options) \ . ' --replace' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/gopls.vim ================================================ " Author: Sean Enck " Description: Integration of gopls format with ALE. call ale#Set('go_gopls_fix_executable', 'gopls') call ale#Set('go_gopls_fix_options', '') function! ale#fixers#gopls#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'go_gopls_fix_executable') let l:options = ale#Var(a:buffer, 'go_gopls_fix_options') let l:env = ale#go#EnvString(a:buffer) if !executable(l:executable) return 0 endif return { \ 'command': l:env . ale#Escape(l:executable) \ . ' format' \ . ale#Pad(l:options) \ . ' -l -w %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/hackfmt.vim ================================================ " Author: Sam Howie " Description: Integration of hackfmt with ALE. 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, 'hack_hackfmt_executable') let l:options = ale#Var(a:buffer, 'hack_hackfmt_options') return { \ 'command': ale#Escape(l:executable) \ . ' -i' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/help.vim ================================================ " Author: w0rp " Description: Generic fixer functions for Vim help documents. function! ale#fixers#help#AlignTags(buffer, lines) abort let l:new_lines = [] for l:line in a:lines if len(l:line) != 79 let l:match = matchlist(l:line, '\v +(\*[^*]+\*)$') if !empty(l:match) let l:start = l:line[:-len(l:match[0]) - 1] let l:tag = l:match[1] let l:spaces = repeat(' ', 79 - len(l:start) - len(l:tag)) let l:line = l:start . l:spaces . l:tag endif endif call add(l:new_lines, l:line) endfor return l:new_lines endfunction ================================================ FILE: autoload/ale/fixers/hfmt.vim ================================================ " Author: zack " Description: Integration of hfmt with ALE. call ale#Set('haskell_hfmt_executable', 'hfmt') function! ale#fixers#hfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'haskell_hfmt_executable') return { \ 'command': ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hfmt') \ . ' -w' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/hindent.vim ================================================ " Author: AlexeiDrake " Description: Integration of hindent formatting with ALE. " call ale#Set('haskell_hindent_executable', 'hindent') function! ale#fixers#hindent#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'haskell_hindent_executable') return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hindent') endfunction function! ale#fixers#hindent#Fix(buffer) abort let l:executable = ale#fixers#hindent#GetExecutable(a:buffer) return { \ 'command': l:executable \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/hlint.vim ================================================ " Author: eborden " 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 ================================================ FILE: autoload/ale/fixers/html_beautify.vim ================================================ " Author: WhyNotHugo " Description: Format HTML files with html-beautify. call ale#Set('html_beautify_executable', 'html-beautify') call ale#Set('html_beautify_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('html_beautify_options', '') function! ale#fixers#html_beautify#Fix(buffer) abort let l:executable = ale#python#FindExecutable( \ a:buffer, \ 'html_beautify', \ ['html-beautify'] \) let l:options = ale#Var(a:buffer, 'html_beautify_options') return { \ 'command': ale#Escape(l:executable) . ' ' . l:options . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/htmlbeautifier.vim ================================================ " Author: Arash Mousavi " Description: Support for HTML Beautifier https://github.com/threedaymonk/htmlbeautifier call ale#Set('eruby_htmlbeautifier_executable', 'htmlbeautifier') function! ale#fixers#htmlbeautifier#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'eruby_htmlbeautifier_executable') return { \ 'command': ale#Escape(l:executable) . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/hurlfmt.vim ================================================ call ale#Set('hurl_hurlfmt_executable', 'hurlfmt') function! ale#fixers#hurlfmt#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'hurl_hurlfmt_executable') return ale#Escape(l:executable) \ . ' --out hurl' endfunction function! ale#fixers#hurlfmt#Fix(buffer) abort return { \ 'command': ale#fixers#hurlfmt#GetCommand(a:buffer) \} endfunction ================================================ FILE: autoload/ale/fixers/importjs.vim ================================================ " Author: Jeff Willette " Description: Integration of importjs with ALE. 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, 'javascript_importjs_executable') if !executable(l:executable) return 0 endif return { \ 'command': ale#Escape(l:executable) \ . ' fix' \ . ' %s', \ 'process_with': 'ale#fixers#importjs#ProcessOutput', \} endfunction ================================================ FILE: autoload/ale/fixers/isort.vim ================================================ " Author: w0rp " Description: Fixing Python imports with isort. call ale#Set('python_isort_executable', 'isort') call ale#Set('python_isort_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_isort_options', '') call ale#Set('python_isort_auto_pipenv', 0) call ale#Set('python_isort_auto_poetry', 0) call ale#Set('python_isort_auto_uv', 0) function! ale#fixers#isort#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_isort_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_isort_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_isort_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_isort', ['isort']) endfunction function! ale#fixers#isort#GetCmd(buffer) abort let l:executable = ale#fixers#isort#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'isort']) endif return join(l:cmd, ' ') endfunction function! ale#fixers#isort#FixForVersion(buffer, version) abort let l:executable = ale#fixers#isort#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'isort']) endif if ale#semver#GTE(a:version, [5, 7, 0]) call add(l:cmd, '--filename %s') endif let l:options = ale#Var(a:buffer, 'python_isort_options') if !empty(l:options) call add(l:cmd, l:options) endif call add(l:cmd, '-') return { \ 'cwd': '%s:h', \ 'command': join(l:cmd, ' '), \} endfunction function! ale#fixers#isort#Fix(buffer) abort let l:executable = ale#fixers#isort#GetExecutable(a:buffer) let l:command = ale#fixers#isort#GetCmd(a:buffer) . ale#Pad('--version') return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale#fixers#isort#FixForVersion'), \) endfunction ================================================ FILE: autoload/ale/fixers/jq.vim ================================================ 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') 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:filters . ' ' \ . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/json_pytool.vim ================================================ " Author: idbrii " Description: json formatter as ALE fixer using python's json.tool call ale#Set('json_pytool_executable', 'python') call ale#Set('json_pytool_options', '') call ale#Set('json_pytool_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#fixers#json_pytool#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'json_pytool', ['python']) endfunction function! ale#fixers#json_pytool#Fix(buffer) abort let l:executable = ale#Escape(ale#fixers#json_pytool#GetExecutable(a:buffer)) let l:opts = ale#Var(a:buffer, 'json_pytool_options') let l:command = printf('%s -m json.tool %s -', l:executable, l:opts) return { \ 'command': l:command \ } endfunction ================================================ FILE: autoload/ale/fixers/jsonnetfmt.vim ================================================ " Authors: Trevor Whitney and Takuya Kosugiyama " Description: Integration of jsonnetfmt with ALE. call ale#Set('jsonnet_jsonnetfmt_executable', 'jsonnetfmt') call ale#Set('jsonnet_jsonnetfmt_options', '') function! ale#fixers#jsonnetfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'jsonnet_jsonnetfmt_executable') let l:options = ale#Var(a:buffer, 'jsonnet_jsonnetfmt_options') return { \ 'command': ale#Escape(l:executable) \ . ' -i' \ . ale#Pad(l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/ktlint.vim ================================================ " Author: Michael Phillips " Description: Fix Kotlin files with ktlint. function! ale#fixers#ktlint#Fix(buffer) abort return { \ 'command': ale#handlers#ktlint#GetCommand(a:buffer) . ' --format' \} endfunction ================================================ FILE: autoload/ale/fixers/kulala_fmt.vim ================================================ " Author: hsanson " Description: kulala_fmt fixer for http and rest files. call ale#Set('http_kulala_fmt_executable', 'kulala-fmt') function! ale#fixers#kulala_fmt#Fix(buffer) abort return { \ 'command': ale#Escape(ale#Var(a:buffer, 'http_kulala_fmt_executable')) . ' format %t > /dev/null', \ 'read_temporary_file': 1 \ } endfunction ================================================ FILE: autoload/ale/fixers/latexindent.vim ================================================ " Author: riley-martine " Description: Integration of latexindent with ALE. call ale#Set('tex_latexindent_executable', 'latexindent') call ale#Set('tex_latexindent_options', '') function! ale#fixers#latexindent#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'tex_latexindent_executable') let l:options = ale#Var(a:buffer, 'tex_latexindent_options') return { \ 'command': ale#Escape(l:executable) \ . ' -l' \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/lua_format.vim ================================================ " Author: Mathias Jean Johansen " Description: Integration of LuaFormatter with ALE. call ale#Set('lua_lua_format_executable', 'lua-format') call ale#Set('lua_lua_format_options', '') function! ale#fixers#lua_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'lua_lua_format_executable') let l:options = ale#Var(a:buffer, 'lua_lua_format_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' -i', \} endfunction ================================================ FILE: autoload/ale/fixers/luafmt.vim ================================================ call ale#Set('lua_luafmt_executable', 'luafmt') call ale#Set('lua_luafmt_options', '') function! ale#fixers#luafmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'lua_luafmt_executable') let l:options = ale#Var(a:buffer, 'lua_luafmt_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' --stdin', \} endfunction ================================================ FILE: autoload/ale/fixers/markdownlint.vim ================================================ :scriptencoding utf-8 call ale#Set('markdownlint_executable', 'markdownlint') call ale#Set('markdownlint_options', '--fix') function! ale#fixers#markdownlint#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'markdownlint_executable') let l:options = ale#Var(a:buffer, 'markdownlint_options') return { \ 'command': ale#Escape(l:executable) \ . ' ' . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/mix_format.vim ================================================ " Author: carakan , Fernando Mendes " Description: Fixing files with elixir formatter 'mix format'. call ale#Set('elixir_mix_executable', 'mix') call ale#Set('elixir_mix_format_options', '') function! ale#fixers#mix_format#GetExecutable(buffer) abort return ale#Var(a:buffer, 'elixir_mix_executable') endfunction function! ale#fixers#mix_format#GetCommand(buffer) abort let l:executable = ale#Escape(ale#fixers#mix_format#GetExecutable(a:buffer)) let l:options = ale#Var(a:buffer, 'elixir_mix_format_options') return l:executable . ' format' \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale#fixers#mix_format#Fix(buffer) abort return { \ 'command': ale#fixers#mix_format#GetCommand(a:buffer), \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/nickel_format.vim ================================================ " Author: Yining " Description: nickel format as ALE fixer for Nickel files call ale#Set('nickel_nickel_format_executable', 'nickel') call ale#Set('nickel_nickel_format_options', '') function! ale#fixers#nickel_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'nickel_nickel_format_executable') let l:options = ale#Var(a:buffer, 'nickel_nickel_format_options') return { \ 'command': ale#Escape(l:executable) . ' format' \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/nimpretty.vim ================================================ " Author: Nhan " Description: Integration of nimpretty with ALE. call ale#Set('nim_nimpretty_executable', 'nimpretty') call ale#Set('nim_nimpretty_options', '--maxLineLen:80') function! ale#fixers#nimpretty#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'nim_nimpretty_executable') let l:options = ale#Var(a:buffer, 'nim_nimpretty_options') return { \ 'command': ale#Escape(l:executable) . ' %t' . ale#Pad(l:options), \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/nixfmt.vim ================================================ scriptencoding utf-8 " Author: houstdav000 " Description: Fix files with nixfmt call ale#Set('nix_nixfmt_executable', 'nixfmt') call ale#Set('nix_nixfmt_options', '') function! ale#fixers#nixfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'nix_nixfmt_executable') let l:options = ale#Var(a:buffer, 'nix_nixfmt_options') return { \ 'command': ale#Escape(l:executable) . ale#Pad(l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/nixpkgsfmt.vim ================================================ call ale#Set('nix_nixpkgsfmt_executable', 'nixpkgs-fmt') call ale#Set('nix_nixpkgsfmt_options', '') function! ale#fixers#nixpkgsfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'nix_nixpkgsfmt_executable') let l:options = ale#Var(a:buffer, 'nix_nixpkgsfmt_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/npmgroovylint.vim ================================================ " Author: lucas-str " Description: Integration of npm-groovy-lint for Groovy files. call ale#Set('groovy_npmgroovylint_fix_options', '--fix') function! ale#fixers#npmgroovylint#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'groovy_npmgroovylint_executable') let l:options = ale#Var(a:buffer, 'groovy_npmgroovylint_fix_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/ocamlformat.vim ================================================ " 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: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=%s' \ . ' -' \} endfunction ================================================ FILE: autoload/ale/fixers/ocp_indent.vim ================================================ " Author: Kanenobu Mitsuru " Description: Integration of ocp-indent with ALE. call ale#Set('ocaml_ocp_indent_executable', 'ocp-indent') call ale#Set('ocaml_ocp_indent_options', '') call ale#Set('ocaml_ocp_indent_config', '') function! ale#fixers#ocp_indent#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'ocaml_ocp_indent_executable') let l:config = ale#Var(a:buffer, 'ocaml_ocp_indent_config') let l:options = ale#Var(a:buffer, 'ocaml_ocp_indent_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:config) ? '' : ' --config=' . ale#Escape(l:config)) \ . (empty(l:options) ? '': ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/opafmt.vim ================================================ " Description: Fixer for rego files call ale#Set('opa_fmt_executable', 'opa') call ale#Set('opa_fmt_options', '') function! ale#fixers#opafmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'opa_fmt_executable') let l:options = ale#Var(a:buffer, 'opa_fmt_options') return { \ 'command': ale#Escape(l:executable) \ . ' fmt' \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/ormolu.vim ================================================ call ale#Set('haskell_ormolu_executable', 'ormolu') call ale#Set('haskell_ormolu_options', '') function! ale#fixers#ormolu#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'haskell_ormolu_executable') let l:options = ale#Var(a:buffer, 'haskell_ormolu_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/packer.vim ================================================ " Author: Zhuoyun Wei " Description: Fixer for Packer HCL files call ale#Set('packer_fmt_executable', 'packer') call ale#Set('packer_fmt_options', '') function! ale#fixers#packer#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'packer_fmt_executable') let l:options = ale#Var(a:buffer, 'packer_fmt_options') return { \ 'command': ale#Escape(l:executable) \ . ' fmt' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' -' \} endfunction ================================================ FILE: autoload/ale/fixers/pandoc.vim ================================================ scriptencoding utf-8 " Author: Jesse Hathaway " Description: Fix markdown files with pandoc. call ale#Set('markdown_pandoc_executable', 'pandoc') call ale#Set('markdown_pandoc_options', '-f gfm -t gfm -s -') function! ale#fixers#pandoc#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'markdown_pandoc_executable') let l:options = ale#Var(a:buffer, 'markdown_pandoc_options') return { \ 'command': ale#Escape(l:executable) \ . ' ' . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/perltidy.vim ================================================ " Author: kfly8 " Description: Integration of perltidy with ALE. call ale#Set('perl_perltidy_executable', 'perltidy') call ale#Set('perl_perltidy_options', '') function! ale#fixers#perltidy#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'perl_perltidy_executable') let l:options = ale#Var(a:buffer, 'perl_perltidy_options') return { \ 'command': ale#Escape(l:executable) \ . ' -b' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/pgformatter.vim ================================================ call ale#Set('sql_pgformatter_executable', 'pg_format') call ale#Set('sql_pgformatter_options', '') function! ale#fixers#pgformatter#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'sql_pgformatter_executable') let l:options = ale#Var(a:buffer, 'sql_pgformatter_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/php_cs_fixer.vim ================================================ " Author: Julien Deniau " Description: Fixing files with php-cs-fixer. call ale#Set('php_cs_fixer_executable', 'php-cs-fixer') call ale#Set('php_cs_fixer_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('php_cs_fixer_options', '') call ale#Set('php_cs_fixer_fix_options', '') function! ale#fixers#php_cs_fixer#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'php_cs_fixer', [ \ 'vendor/bin/php-cs-fixer', \ 'php-cs-fixer' \]) 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') \ . ' fix ' . ale#Var(a:buffer, 'php_cs_fixer_fix_options') \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/phpcbf.vim ================================================ " Author: notomo " Description: Fixing files with phpcbf. call ale#Set('php_phpcbf_standard', '') call ale#Set('php_phpcbf_options', '') call ale#Set('php_phpcbf_executable', 'phpcbf') call ale#Set('php_phpcbf_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#fixers#phpcbf#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'php_phpcbf', [ \ 'vendor/bin/phpcbf', \ 'phpcbf' \]) endfunction function! ale#fixers#phpcbf#Fix(buffer) abort let l:executable = ale#fixers#phpcbf#GetExecutable(a:buffer) let l:standard = ale#Var(a:buffer, 'php_phpcbf_standard') let l:standard_option = !empty(l:standard) \ ? '--standard=' . l:standard \ : '' return { \ 'command': ale#Escape(l:executable) . ' --stdin-path=%s ' . l:standard_option . ale#Pad(ale#Var(a:buffer, 'php_phpcbf_options')) . ' -' \} endfunction ================================================ FILE: autoload/ale/fixers/pint.vim ================================================ " Author: Michael Dyrynda " Description: Fixing files with Laravel Pint. call ale#Set('php_pint_executable', 'pint') call ale#Set('php_pint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('php_pint_options', '') function! ale#fixers#pint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'php_pint', [ \ 'vendor/bin/pint', \ 'pint' \]) endfunction function! ale#fixers#pint#Fix(buffer) abort let l:executable = ale#fixers#pint#GetExecutable(a:buffer) return { \ 'command': ale#Escape(l:executable) \ . ' ' . ale#Var(a:buffer, 'php_pint_options') \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/prettier.vim ================================================ " Author: tunnckoCore (Charlike Mike Reagent) , " w0rp , morhetz (Pavel Pertsev) " Description: Integration of Prettier with ALE. call ale#Set('javascript_prettier_executable', 'prettier') call ale#Set('javascript_prettier_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_prettier_options', '') function! ale#fixers#prettier#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_prettier', [ \ 'node_modules/.bin/prettier_d', \ 'node_modules/prettier-cli/index.js', \ 'node_modules/.bin/prettier', \]) endfunction function! ale#fixers#prettier#Fix(buffer) abort return ale#semver#RunWithVersionCheck( \ a:buffer, \ ale#fixers#prettier#GetExecutable(a:buffer), \ '%e --version', \ function('ale#fixers#prettier#ApplyFixForVersion'), \) 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#GetCwd(buffer) abort let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore') " Fall back to the directory of the buffer return !empty(l:config) ? fnamemodify(l:config, ':h') : '%s:h' endfunction function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_prettier_options') let l:parser = '' let l:filetypes = split(getbufvar(a:buffer, '&filetype'), '\.') if index(l:filetypes, 'handlebars') > -1 let l:parser = 'glimmer' endif " 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')) && l:parser is# '' && match(l:options, '--parser') == -1 " Mimic Prettier's defaults. In cases without a file extension or " filetype (scratch buffer), Prettier needs `parser` set to know how " to process the buffer. if ale#semver#GTE(a:version, [1, 16, 0]) let l:parser = 'babel' else let l:parser = 'babylon' endif let l:prettier_parsers = { \ 'typescript': 'typescript', \ 'css': 'css', \ 'less': 'less', \ 'scss': 'scss', \ 'json': 'json', \ 'json5': 'json5', \ 'graphql': 'graphql', \ 'markdown': 'markdown', \ 'vue': 'vue', \ 'svelte': 'svelte', \ 'yaml': 'yaml', \ 'openapi': 'yaml', \ 'html': 'html', \ 'ruby': 'ruby', \ 'astro': 'astro', \} for l:filetype in l:filetypes if has_key(l:prettier_parsers, l:filetype) let l:parser = l:prettier_parsers[l:filetype] break endif endfor endif if !empty(l:parser) 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 { \ 'cwd': '%s:h', \ 'command':ale#Escape(l:executable) \ . ale#Pad(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(a:version, [1, 4, 0]) return { \ 'cwd': ale#fixers#prettier#GetCwd(a:buffer), \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' --stdin-filepath %s --stdin', \} endif return { \ 'command': ale#Escape(l:executable) \ . ' %t' \ . ale#Pad(l:options) \ . ' --write', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/prettier_eslint.vim ================================================ " Author: tunnckoCore (Charlike Mike Reagent) , " w0rp , morhetz (Pavel Pertsev) " Description: Integration between Prettier and ESLint. call ale#Set('javascript_prettier_eslint_executable', 'prettier-eslint') call ale#Set('javascript_prettier_eslint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_prettier_eslint_options', '') function! ale#fixers#prettier_eslint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_prettier_eslint', [ \ 'node_modules/prettier-eslint-cli/dist/index.js', \ 'node_modules/.bin/prettier-eslint', \]) endfunction function! ale#fixers#prettier_eslint#Fix(buffer) abort return ale#semver#RunWithVersionCheck( \ a:buffer, \ ale#fixers#prettier_eslint#GetExecutable(a:buffer), \ '%e --version', \ function('ale#fixers#prettier_eslint#ApplyFixForVersion'), \) endfunction function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort let l:options = ale#Var(a:buffer, 'javascript_prettier_eslint_options') let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer) " 4.2.0 is the first version with --eslint-config-path let l:config = ale#semver#GTE(a:version, [4, 2, 0]) \ ? ale#handlers#eslint#FindConfig(a:buffer) \ : '' let l:eslint_config_option = !empty(l:config) \ ? ' --eslint-config-path ' . ale#Escape(l:config) \ : '' " 4.4.0 is the first version with --stdin-filepath if ale#semver#GTE(a:version, [4, 4, 0]) return { \ 'cwd': '%s:h', \ 'command': ale#Escape(l:executable) \ . l:eslint_config_option \ . ale#Pad(l:options) \ . ' --stdin-filepath %s --stdin', \} endif return { \ 'command': ale#Escape(l:executable) \ . ' %t' \ . l:eslint_config_option \ . ale#Pad(l:options) \ . ' --write', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/prettier_standard.vim ================================================ " Author: sheerun (Adam Stankiewicz) " Description: Integration of Prettier Standard with ALE. call ale#Set('javascript_prettier_standard_executable', 'prettier-standard') call ale#Set('javascript_prettier_standard_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_prettier_standard_options', '') function! ale#fixers#prettier_standard#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_prettier_standard', [ \ 'node_modules/prettier-standard/lib/index.js', \ 'node_modules/.bin/prettier-standard', \]) endfunction function! ale#fixers#prettier_standard#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'javascript_prettier_standard_options') return { \ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer)) \ . ' --stdin' \ . ' --stdin-filepath=%s' \ . ' ' . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/protolint.vim ================================================ " Author: Yohei Yoshimuta " Description: Integration of protolint with ALE. call ale#Set('proto_protolint_executable', 'protolint') call ale#Set('proto_protolint_config', '') function! ale#fixers#protolint#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'proto_protolint_executable') return ale#Escape(l:executable) endfunction function! ale#fixers#protolint#Fix(buffer) abort let l:executable = ale#fixers#protolint#GetExecutable(a:buffer) let l:config = ale#Var(a:buffer, 'proto_protolint_config') return { \ 'command': l:executable \ . (!empty(l:config) ? ' -config_path=' . ale#Escape(l:config) : '') \ . ' -fix' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/ptop.vim ================================================ " Author: BarrOff https://github.com/BarrOff " Description: Integration of ptop with ALE. call ale#Set('pascal_ptop_executable', 'ptop') call ale#Set('pascal_ptop_options', '') function! ale#fixers#ptop#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'pascal_ptop_executable') let l:options = ale#Var(a:buffer, 'pascal_ptop_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %s %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/puppetlint.vim ================================================ " Author: Alexander Olofsson " Description: puppet-lint fixer 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 function! ale#fixers#puppetlint#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'puppet_puppetlint_executable') return { \ 'command': ale#Escape(l:executable) \ . ' ' . ale#Var(a:buffer, 'puppet_puppetlint_options') \ . ' --fix' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/purs_tidy.vim ================================================ " Author: toastal " Description: Integration of purs-tidy with ALE. call ale#Set('purescript_tidy_executable', 'purs-tidy') call ale#Set('purescript_tidy_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('purescript_tidy_options', '') function! ale#fixers#purs_tidy#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'purescript_tidy', [ \ 'node_modules/purescript-tidy/bin/index.js', \ 'node_modules/.bin/purs-tidy', \]) endfunction function! ale#fixers#purs_tidy#Fix(buffer) abort let l:executable = ale#fixers#purs_tidy#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'purescript_tidy_options') return { \ 'command': ale#Escape(l:executable) \ . ' format' \ . ale#Pad(l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/purty.vim ================================================ " Author: iclanzan " Description: Integration of purty with ALE. call ale#Set('purescript_purty_executable', 'purty') function! ale#fixers#purty#GetExecutable(buffer) abort let l:executable = ale#Var(a:buffer, 'purescript_purty_executable') return ale#Escape(l:executable) endfunction function! ale#fixers#purty#Fix(buffer) abort let l:executable = ale#fixers#purty#GetExecutable(a:buffer) return { \ 'command': l:executable \ . ' --write' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/pycln.vim ================================================ " Author: Yining " Description: pycln as ALE fixer for python files call ale#Set('python_pycln_executable', 'pycln') call ale#Set('python_pycln_options', '') call ale#Set('python_pycln_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pycln_change_directory', 1) call ale#Set('python_pycln_auto_pipenv', 0) call ale#Set('python_pycln_auto_poetry', 0) call ale#Set('python_pycln_auto_uv', 0) call ale#Set('python_pycln_config_file', '') function! ale#fixers#pycln#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_pycln_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '%s:h' endfunction function! ale#fixers#pycln#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pycln_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pycln_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pycln_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pycln', ['pycln']) endfunction function! ale#fixers#pycln#GetCommand(buffer) abort let l:executable = ale#fixers#pycln#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run pycln' \ : '' return ale#Escape(l:executable) . l:exec_args endfunction function! ale#fixers#pycln#FixForVersion(buffer, version) abort let l:executable = ale#fixers#pycln#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'pycln']) endif let l:options = ale#Var(a:buffer, 'python_pycln_options') if !empty(l:options) call add(l:cmd, l:options) endif let l:config_file = ale#Var(a:buffer, 'python_pycln_config_file') let l:config_file = l:options !~# '\v(^| )--config ' && !empty(l:config_file) \ ? ale#Escape(ale#path#Simplify(l:config_file)) \ : '' if !empty(l:config_file) call add(l:cmd, '--config ' . l:config_file) endif call add(l:cmd, '--silence') " NOTE: pycln version `1.3.0` support reading from stdin call add(l:cmd, ale#semver#GTE(a:version, [1, 3, 0]) ? '-' : '%s') return { \ 'cwd': ale#fixers#pycln#GetCwd(a:buffer), \ 'command': join(l:cmd, ' '), \} endfunction function! ale#fixers#pycln#Fix(buffer) abort let l:executable = ale#fixers#pycln#GetExecutable(a:buffer) let l:command = ale#fixers#pycln#GetCommand(a:buffer) . ale#Pad('--version') return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale#fixers#pycln#FixForVersion'), \) endfunction ================================================ FILE: autoload/ale/fixers/pyflyby.vim ================================================ " Author: infokiller " Description: Tidy imports using pyflyby's tidy-import script " https://github.com/deshaw/pyflyby call ale#Set('python_pyflyby_executable', 'tidy-imports') call ale#Set('python_pyflyby_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_pyflyby_options', '') call ale#Set('python_pyflyby_auto_pipenv', 0) call ale#Set('python_pyflyby_auto_poetry', 0) call ale#Set('python_pyflyby_auto_uv', 0) function! ale#fixers#pyflyby#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pyflyby_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pyflyby_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pyflyby_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_pyflyby', ['tidy-imports']) endfunction function! ale#fixers#pyflyby#Fix(buffer) abort " let l:executable = ale#fixers#pyflyby#GetExecutable(a:buffer) let l:executable = ale#fixers#pyflyby#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'tidy-imports']) endif let l:options = ale#Var(a:buffer, 'python_pyflyby_options') if !empty(l:options) call add(l:cmd, l:options) endif return {'command': join(l:cmd, ' ')} endfunction ================================================ FILE: autoload/ale/fixers/pymarkdown.vim ================================================ scriptencoding utf-8 " Author: Adrian Vollmer " Description: Fix markdown files with pymarkdown. call ale#Set('markdown_pymarkdown_executable', 'pymarkdown') call ale#Set('markdown_pymarkdown_options', '') call ale#Set('markdown_pymarkdown_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('markdown_pymarkdown_auto_pipenv', 0) call ale#Set('markdown_pymarkdown_auto_poetry', 0) call ale#Set('markdown_pymarkdown_auto_uv', 0) function! ale#fixers#pymarkdown#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'markdown_pymarkdown', ['pymarkdown']) endfunction function! ale#fixers#pymarkdown#Fix(buffer) abort let l:executable = ale#fixers#pymarkdown#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'markdown_pymarkdown_options') let l:exec_args = l:executable =~? 'pipenv\|poetry\|uv$' \ ? ' run pymarkdown' \ : '' return { \ 'command': ale#Escape(l:executable) . l:exec_args \ . ' fix' \ . ale#Pad(l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/qmlfmt.vim ================================================ call ale#Set('qml_qmlfmt_executable', 'qmlfmt') function! ale#fixers#qmlfmt#GetExecutable(buffer) abort return ale#Var(a:buffer, 'qml_qmlfmt_executable') endfunction function! ale#fixers#qmlfmt#Fix(buffer) abort return { \ 'command': ale#Escape(ale#fixers#qmlfmt#GetExecutable(a:buffer)), \} endfunction ================================================ FILE: autoload/ale/fixers/raco_fmt.vim ================================================ " Author: Jeremy Cantrell " Description: Integration of raco fmt with ALE. call ale#Set('racket_raco_fmt_executable', 'raco') call ale#Set('racket_raco_fmt_options', '') function! ale#fixers#raco_fmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'racket_raco_fmt_executable') let l:options = ale#Var(a:buffer, 'racket_raco_fmt_options') return { \ 'command': ale#Escape(l:executable) . ' fmt' \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/refmt.vim ================================================ " Author: Ahmed El Gabri <@ahmedelgabri> " Description: Integration of refmt with ALE. call ale#Set('reasonml_refmt_executable', 'refmt') call ale#Set('reasonml_refmt_options', '') function! ale#fixers#refmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'reasonml_refmt_executable') let l:options = ale#Var(a:buffer, 'reasonml_refmt_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' --in-place' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/remark_lint.vim ================================================ " Author: blyoa " Description: Fixing files with remark-lint. 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#fixers#remark_lint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'markdown_remark_lint', [ \ 'node_modules/remark-cli/cli.js', \ 'node_modules/.bin/remark', \]) endfunction function! ale#fixers#remark_lint#Fix(buffer) abort let l:executable = ale#fixers#remark_lint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/reorder_python_imports.vim ================================================ " Author: jake " Description: Fixing Python imports with reorder-python-imports. call ale#Set('python_reorder_python_imports_executable', 'reorder-python-imports') call ale#Set('python_reorder_python_imports_options', '') call ale#Set('python_reorder_python_imports_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_reorder_python_imports_auto_pipenv', 0) call ale#Set('python_reorder_python_imports_auto_poetry', 0) call ale#Set('python_reorder_python_imports_auto_uv', 0) function! ale#fixers#reorder_python_imports#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_reorder_python_imports_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_reorder_python_imports_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_reorder_python_imports_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_reorder_python_imports', ['reorder-python-imports']) endfunction function! ale#fixers#reorder_python_imports#Fix(buffer) abort let l:executable = ale#fixers#reorder_python_imports#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run reorder-python-imports' \ : '' let l:options = ale#Var(a:buffer, 'python_reorder_python_imports_options') return { \ 'command': ale#Escape(l:executable) . l:exec_args \ . ale#Pad(l:options) . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/rescript_format.vim ================================================ " Author: John Jackson " Description: Fix ReScript files with the ReScript formatter. call ale#Set('rescript_format_executable', 'rescript') call ale#Set( \ 'rescript_format_use_global', \ get(g:, 'ale_use_global_executables', v:false) \ ) function! s:GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'rescript_format', [ \ 'node_modules/.bin/rescript', \]) endfunction function! s:FixWithVersion(buffer, version) abort let l:exe = ale#Escape(s:GetExecutable(a:buffer)) let l:stdin = ale#semver#GTE(a:version, [12, 0, 0]) ? ' --stdin' : ' -stdin' let l:ext = fnamemodify(bufname(a:buffer), ':e') is? 'resi' \ ? ' .resi' \ : ' .res' return {'command': l:exe . ' format' . l:stdin . l:ext} endfunction function! ale#fixers#rescript_format#Fix(buffer) abort return ale#semver#RunWithVersionCheck( \ a:buffer, \ s:GetExecutable(a:buffer), \ '%e --version', \ function('s:FixWithVersion'), \) endfunction ================================================ FILE: autoload/ale/fixers/roc_annotate.vim ================================================ " Author: Benjamin Block " Description: Official type annotation tool for Roc. call ale#Set('roc_roc_annotate_executable', 'roc') call ale#Set('roc_roc_annotate_options', '') function! ale#fixers#roc_annotate#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'roc_roc_annotate_executable') let l:command = l:executable . ' format annotate' let l:options = ale#Var(a:buffer, 'roc_roc_annotate_options') if l:options isnot# '' let l:command .= ' ' . l:options endif return { \ 'command': l:command . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/roc_format.vim ================================================ " Author: Benjamin Block " Description: Official formatter for Roc. call ale#Set('roc_roc_format_executable', 'roc') call ale#Set('roc_roc_format_options', '') function! ale#fixers#roc_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'roc_roc_format_executable') let l:command = l:executable . ' format' let l:options = ale#Var(a:buffer, 'roc_roc_format_options') if l:options isnot# '' let l:command .= ' ' . l:options endif return { \ 'command': l:command . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/rubocop.vim ================================================ call ale#Set('ruby_rubocop_options', '') call ale#Set('ruby_rubocop_auto_correct_all', 0) call ale#Set('ruby_rubocop_executable', 'rubocop') " Rubocop fixer outputs diagnostics first and then the fixed " output. These are delimited by a "=======" string that we " look for to remove everything before it. function! ale#fixers#rubocop#PostProcess(buffer, output) abort let l:line = 0 for l:output in a:output let l:line = l:line + 1 if l:output =~# "^=\\+$" break endif endfor return a:output[l:line :] endfunction function! ale#fixers#rubocop#GetCommand(buffer, version) abort let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable') let l:options = ale#Var(a:buffer, 'ruby_rubocop_options') let l:auto_correct_all = ale#Var(a:buffer, 'ruby_rubocop_auto_correct_all') let l:editor_mode = ale#semver#GTE(a:version, [1, 61, 0]) return ale#ruby#EscapeExecutable(l:executable, 'rubocop') \ . ale#Pad(l:options) \ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct') \ . (l:editor_mode ? ' --editor-mode' : '') \ . ' --force-exclusion --stdin %s' endfunction function! ale#fixers#rubocop#GetCommandForVersion(buffer, version) abort return { \ 'command': ale#fixers#rubocop#GetCommand(a:buffer, a:version), \ 'process_with': 'ale#fixers#rubocop#PostProcess' \} endfunction function! ale#fixers#rubocop#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_rubocop_executable') let l:command = l:executable . ale#Pad('--version') return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale#fixers#rubocop#GetCommandForVersion'), \) endfunction ================================================ FILE: autoload/ale/fixers/rubyfmt.vim ================================================ " Author: Yining " Description: support rubyfmt as ALE fixer for Ruby files call ale#Set('ruby_rubyfmt_executable', 'rubyfmt') call ale#Set('ruby_rubyfmt_options', '') function! ale#fixers#rubyfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_rubyfmt_executable') let l:options = ale#Var(a:buffer, 'ruby_rubyfmt_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/ruff.vim ================================================ " Author: Yining " Description: ruff as ALE fixer for python files call ale#Set('python_ruff_executable', 'ruff') call ale#Set('python_ruff_options', '') call ale#Set('python_ruff_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_ruff_change_directory', 1) call ale#Set('python_ruff_auto_pipenv', 0) call ale#Set('python_ruff_auto_poetry', 0) call ale#Set('python_ruff_auto_uv', 0) function! ale#fixers#ruff#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_ruff_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '%s:h' endfunction function! ale#fixers#ruff#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_ruff_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_ruff_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_ruff_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_ruff', ['ruff']) endfunction function! ale#fixers#ruff#GetCommand(buffer) abort let l:executable = ale#fixers#ruff#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run ruff' \ : '' return ale#Escape(l:executable) . l:exec_args endfunction function! ale#fixers#ruff#FixForVersion(buffer, version) abort let l:executable = ale#fixers#ruff#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'ruff']) endif " NOTE: ruff 0.5.0 removes `ruff ` in favor of `ruff check ` if ale#semver#GTE(a:version, [0, 5, 0]) call extend(l:cmd, ['check']) endif let l:options = ale#Var(a:buffer, 'python_ruff_options') if !empty(l:options) call add(l:cmd, l:options) endif " when --stdin-filename present, ruff will use it for proj root resolution " https://github.com/charliermarsh/ruff/pull/1281 let l:fname = expand('#' . a:buffer . '...') call add(l:cmd, '--stdin-filename '.ale#Escape(ale#path#Simplify(l:fname))) call add(l:cmd, '--fix') " NOTE: ruff version `0.0.72` implements `--fix` with stdin if ale#semver#GTE(a:version, [0, 0, 72]) call add(l:cmd, '-') else call add(l:cmd, '%s') endif return { \ 'cwd': ale#fixers#ruff#GetCwd(a:buffer), \ 'command': join(l:cmd, ' '), \} endfunction function! ale#fixers#ruff#Fix(buffer) abort let l:executable = ale#fixers#ruff#GetExecutable(a:buffer) let l:command = ale#fixers#ruff#GetCommand(a:buffer) . ale#Pad('--version') return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ l:command, \ function('ale#fixers#ruff#FixForVersion'), \) endfunction ================================================ FILE: autoload/ale/fixers/ruff_format.vim ================================================ " Author: Yining , Joseph Henrich " Description: ruff formatter as ALE fixer for python files call ale#Set('python_ruff_format_executable', 'ruff') call ale#Set('python_ruff_format_options', '') call ale#Set('python_ruff_format_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_ruff_format_change_directory', 1) call ale#Set('python_ruff_format_auto_pipenv', 0) call ale#Set('python_ruff_format_auto_poetry', 0) call ale#Set('python_ruff_format_auto_uv', 0) function! ale#fixers#ruff_format#GetCwd(buffer) abort if ale#Var(a:buffer, 'python_ruff_format_change_directory') " Run from project root if found, else from buffer dir. let l:project_root = ale#python#FindProjectRoot(a:buffer) return !empty(l:project_root) ? l:project_root : '%s:h' endif return '%s:h' endfunction function! ale#fixers#ruff_format#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_ruff_format_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_ruff_format_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_ruff_format_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_ruff_format', ['ruff']) endfunction function! ale#fixers#ruff_format#GetCommand(buffer) abort let l:executable = ale#fixers#ruff_format#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run ruff' \ : '' return ale#Escape(l:executable) . l:exec_args endfunction function! ale#fixers#ruff_format#Fix(buffer) abort let l:executable = ale#fixers#ruff_format#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'ruff']) endif let l:options = ale#Var(a:buffer, 'python_ruff_format_options') " when --stdin-filename present, ruff will use it for proj root resolution " https://github.com/charliermarsh/ruff/pull/1281 let l:fname = expand('#' . a:buffer . '...') call add(l:cmd, 'format') if !empty(l:options) call add(l:cmd, l:options) endif call add(l:cmd, '--stdin-filename '.ale#Escape(ale#path#Simplify(l:fname))) call add(l:cmd, '-') return { \ 'cwd': ale#fixers#ruff_format#GetCwd(a:buffer), \ 'command': join(l:cmd, ' '), \} endfunction ================================================ FILE: autoload/ale/fixers/rufo.vim ================================================ " Author: Fohte (Hayato Kawai) https://github.com/fohte " Description: Integration of Rufo with ALE. call ale#Set('ruby_rufo_executable', 'rufo') function! ale#fixers#rufo#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_rufo_executable') let l:exec_args = l:executable =~? 'bundle$' \ ? ' exec rufo' \ : '' return ale#Escape(l:executable) . l:exec_args . ' %t' endfunction function! ale#fixers#rufo#Fix(buffer) abort return { \ 'command': ale#fixers#rufo#GetCommand(a:buffer), \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/rustfmt.vim ================================================ " Author: Kelly Fox " Description: Integration of rustfmt with ALE. call ale#Set('rust_rustfmt_executable', 'rustfmt') call ale#Set('rust_rustfmt_options', '') function! ale#fixers#rustfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'rust_rustfmt_executable') let l:options = ale#Var(a:buffer, 'rust_rustfmt_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/rustywind.vim ================================================ scriptencoding utf-8 " Author: Guillermo Roig " Description: Sort TailwindCSS classes with rustywind call ale#Set('html_rustywind_executable', 'rustywind') call ale#Set('html_rustywind_options', '') function! ale#fixers#rustywind#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'html_rustywind_executable') let l:options = ale#Var(a:buffer, 'html_rustywind_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' --stdin' \} endfunction ================================================ FILE: autoload/ale/fixers/scadformat.vim ================================================ " Author: tony o'dell " Description: Fix scad files with scadformat call ale#Set('openscad_scadformat_executable', 'scadformat') call ale#Set('openscad_scadformat_options', '') function! ale#fixers#scadformat#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'openscad_scadformat_executable') let l:options = ale#Var(a:buffer, 'openscad_scadformat_options') return { \ 'command': ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/scalafmt.vim ================================================ " Author: Jeffrey Lau https://github.com/zoonfafer " Description: Integration of Scalafmt with ALE. call ale#Set('scala_scalafmt_executable', 'scalafmt') call ale#Set('scala_scalafmt_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('scala_scalafmt_options', '') function! ale#fixers#scalafmt#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'scala_scalafmt_executable') let l:options = ale#Var(a:buffer, 'scala_scalafmt_options') let l:exec_args = l:executable =~? 'ng$' \ ? ' scalafmt' \ : '' return ale#Escape(l:executable) . l:exec_args \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t' endfunction function! ale#fixers#scalafmt#Fix(buffer) abort return { \ 'command': ale#fixers#scalafmt#GetCommand(a:buffer), \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/shfmt.vim ================================================ scriptencoding utf-8 " Author: Simon Bugert " Description: Fix sh files with shfmt. call ale#Set('sh_shfmt_executable', 'shfmt') call ale#Set('sh_shfmt_options', '') 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) \ . ' -filename=%s' \ . (empty(l:options) ? '' : ' ' . l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/sorbet.vim ================================================ call ale#Set('ruby_sorbet_executable', 'srb') call ale#Set('ruby_sorbet_options', '') function! ale#fixers#sorbet#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable') let l:options = ale#Var(a:buffer, 'ruby_sorbet_options') return ale#ruby#EscapeExecutable(l:executable, 'srb') \ . ' tc' \ . ale#Pad(l:options) \ . ' --autocorrect --file %t' endfunction function! ale#fixers#sorbet#Fix(buffer) abort return { \ 'command': ale#fixers#sorbet#GetCommand(a:buffer), \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/sqlfluff.vim ================================================ " Author: Carl Smedstad " Description: Fixing SQL files with sqlfluff call ale#Set('sql_sqlfluff_executable', 'sqlfluff') function! ale#fixers#sqlfluff#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'sql_sqlfluff_executable') let l:cmd = \ ale#Escape(l:executable) \ . ' fix --force' let l:config_file = ale#path#FindNearestFile(a:buffer, '.sqlfluff') if !empty(l:config_file) let l:cmd .= ' --config ' . ale#Escape(l:config_file) else let l:cmd .= ' --dialect ansi' endif return { \ 'command': l:cmd . ' %t > /dev/null', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/sqlfmt.vim ================================================ 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 ================================================ FILE: autoload/ale/fixers/sqlformat.vim ================================================ " Author: Cluas " Description: Fixing files with sqlformat. call ale#Set('sql_sqlformat_executable', 'sqlformat') call ale#Set('sql_sqlformat_options', '') function! ale#fixers#sqlformat#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'sql_sqlformat_executable') let l:options = ale#Var(a:buffer, 'sql_sqlformat_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) \ . ' -' \} endfunction ================================================ FILE: autoload/ale/fixers/standard.vim ================================================ " Author: Sumner Evans " Description: Fixing files with Standard. call ale#Set('javascript_standard_executable', 'standard') call ale#Set('javascript_standard_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_standard_options', '') function! ale#fixers#standard#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_standard', [ \ 'node_modules/standardx/bin/cmd.js', \ 'node_modules/standard/bin/cmd.js', \ 'node_modules/.bin/standard', \]) endfunction function! ale#fixers#standard#Fix(buffer) abort let l:executable = ale#fixers#standard#GetExecutable(a:buffer) let l:filetype = getbufvar(a:buffer, '&filetype') let l:options_type = 'javascript_standard_options' if l:filetype =~# 'typescript' let l:options_type = 'typescript_standard_options' endif let l:options = ale#Var(a:buffer, l:options_type) return { \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' --fix --stdin < %s > %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/standardrb.vim ================================================ " Author: Justin Searls - https://github.com/searls " Description: Fix Ruby files with StandardRB. call ale#Set('ruby_standardrb_options', '') call ale#Set('ruby_standardrb_executable', 'standardrb') function! ale#fixers#standardrb#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_standardrb_executable') let l:config = ale#path#FindNearestFile(a:buffer, '.standard.yml') let l:options = ale#Var(a:buffer, 'ruby_standardrb_options') return ale#ruby#EscapeExecutable(l:executable, 'standardrb') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . ale#Pad(l:options) \ . ' --fix --force-exclusion --stdin %s' endfunction function! ale#fixers#standardrb#Fix(buffer) abort return { \ 'command': ale#fixers#standardrb#GetCommand(a:buffer), \ 'process_with': 'ale#fixers#rubocop#PostProcess' \} endfunction ================================================ FILE: autoload/ale/fixers/statix.vim ================================================ " Author: David Houston " Description: Provide statix fix as a fixer for simple Nix antipatterns. call ale#Set('nix_statix_fix_executable', 'statix') call ale#Set('nix_statix_fix_options', '') function! ale#fixers#statix#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'nix_statix_fix_executable') let l:options = ale#Var(a:buffer, 'nix_statix_fix_options') return { \ 'command': ale#Escape(l:executable) \ . ale#Pad('fix') \ . ale#Pad('--stdin') \ . ale#Pad(l:options), \} endfunction ================================================ FILE: autoload/ale/fixers/stylelint.vim ================================================ " Author: Mahmoud Mostafa " Description: Fixing files with stylelint. call ale#Set('stylelint_executable', 'stylelint') call ale#Set('stylelint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('stylelint_options', '') function! ale#fixers#stylelint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'stylelint', [ \ 'node_modules/stylelint/bin/stylelint.js', \ 'node_modules/.bin/stylelint', \]) endfunction function! ale#fixers#stylelint#Fix(buffer) abort let l:executable = ale#fixers#stylelint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'stylelint_options') return { \ 'cwd': '%s:h', \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' --fix --stdin --no-color --stdin-filename %s', \ 'read_temporary_file': 0, \} endfunction ================================================ FILE: autoload/ale/fixers/styler.vim ================================================ " Author: tvatter " Description: Fixing R files with styler. call ale#Set('r_styler_executable', 'Rscript') call ale#Set('r_styler_options', 'tidyverse_style()') function! ale#fixers#styler#Fix(buffer) abort return { \ 'command': 'Rscript --vanilla -e ' \ . '"suppressPackageStartupMessages(library(styler));' \ . 'style_file(commandArgs(TRUE), transformers = ' \ . ale#Var(a:buffer, 'r_styler_options') . ')"' \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/stylish_haskell.vim ================================================ " Author: eborden " 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 ================================================ FILE: autoload/ale/fixers/stylua.vim ================================================ " Author: Robert Liebowitz " Description: https://github.com/johnnymorganz/stylua call ale#Set('lua_stylua_executable', 'stylua') call ale#Set('lua_stylua_options', '') function! ale#fixers#stylua#GetCwd(buffer) abort for l:possible_configfile in ['stylua.toml', '.stylua.toml'] let l:config = ale#path#FindNearestFile(a:buffer, l:possible_configfile) if !empty(l:config) return fnamemodify(l:config, ':h') endif endfor return '%s:h' endfunction function! ale#fixers#stylua#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'lua_stylua_executable') let l:options = ale#Var(a:buffer, 'lua_stylua_options') return { \ 'cwd': ale#fixers#stylua#GetCwd(a:buffer), \ 'command': ale#Escape(l:executable) . ale#Pad(l:options) . ' --stdin-filepath %s -', \} endfunction ================================================ FILE: autoload/ale/fixers/swiftformat.vim ================================================ " Author: gfontenot (Gordon Fontenot) " Description: Integration of SwiftFormat with ALE. call ale#Set('swift_swiftformat_executable', 'swiftformat') call ale#Set('swift_swiftformat_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('swift_swiftformat_options', '') function! ale#fixers#swiftformat#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'swift_swiftformat', [ \ 'Pods/SwiftFormat/CommandLineTool/swiftformat', \ 'ios/Pods/SwiftFormat/CommandLineTool/swiftformat', \ 'swiftformat', \]) endfunction function! ale#fixers#swiftformat#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'swift_swiftformat_options') return { \ 'read_temporary_file': 1, \ 'command': ale#Escape(ale#fixers#swiftformat#GetExecutable(a:buffer)) \ . ' %t' \ . ' ' . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/syntax_tree.vim ================================================ call ale#Set('ruby_syntax_tree_options', '') call ale#Set('ruby_syntax_tree_executable', 'stree') function! ale#fixers#syntax_tree#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'ruby_syntax_tree_executable') let l:options = ale#Var(a:buffer, 'ruby_syntax_tree_options') return ale#ruby#EscapeExecutable(l:executable, 'stree') \ . ' format' \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale#fixers#syntax_tree#Fix(buffer) abort return { \ 'command': ale#fixers#syntax_tree#GetCommand(a:buffer), \} endfunction ================================================ FILE: autoload/ale/fixers/terraform.vim ================================================ " Author: dsifford " 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 ================================================ FILE: autoload/ale/fixers/textlint.vim ================================================ " Author: TANIGUCHI Masaya " Description: Integration of textlint with ALE. function! ale#fixers#textlint#Fix(buffer) abort let l:executable = ale#handlers#textlint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'textlint_options') return { \ 'command': ale#Escape(l:executable) \ . ' --fix' \ . (empty(l:options) ? '' : ' ' . l:options) \ . ' %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/tidy.vim ================================================ " Author: meain " Description: Fixing HTML files with tidy. call ale#Set('html_tidy_executable', 'tidy') call ale#Set('html_tidy_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#fixers#tidy#Fix(buffer) abort let l:executable = ale#path#FindExecutable( \ a:buffer, \ 'html_tidy', \ ['tidy'], \) if !executable(l:executable) return 0 endif let l:config = ale#path#FindNearestFile(a:buffer, '.tidyrc') let l:config_options = !empty(l:config) \ ? ' -q --tidy-mark no --show-errors 0 --show-warnings 0 -config ' . ale#Escape(l:config) \ : ' -q --tidy-mark no --show-errors 0 --show-warnings 0' return { \ 'command': ale#Escape(l:executable) . l:config_options, \} endfunction ================================================ FILE: autoload/ale/fixers/tombi_format.vim ================================================ " Author: Ben Boeckel " Description: Integration of tombi formatting with ALE. call ale#Set('toml_tombi_executable', 'tombi') call ale#Set('toml_tombi_format_options', '') call ale#Set('toml_tombi_online', 0) function! ale#fixers#tombi_format#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'toml_tombi_executable') let l:offline = '' if !ale#Var(a:buffer, 'toml_tombi_online') let l:offline = '--offline' endif return { \ 'command': ale#Escape(l:executable) \ . ' format' \ . ale#Pad(l:offline) \ . ale#Pad(ale#Var(a:buffer, 'toml_tombi_format_options')), \} endfunction ================================================ FILE: autoload/ale/fixers/tombi_lint.vim ================================================ " Author: Ben Boeckel " Description: Integration of tombi linting with ALE. call ale#Set('toml_tombi_executable', 'tombi') call ale#Set('toml_tombi_lint_options', '') call ale#Set('toml_tombi_online', 0) function! ale#fixers#tombi_lint#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'toml_tombi_executable') let l:offline = '' if !ale#Var(a:buffer, 'toml_tombi_online') let l:offline = '--offline' endif return { \ 'command': ale#Escape(l:executable) \ . ' lint' \ . ale#Pad(l:offline) \ . ale#Pad(ale#Var(a:buffer, 'toml_tombi_lint_options')), \} endfunction ================================================ FILE: autoload/ale/fixers/tslint.vim ================================================ " Author: carakan " Description: Fixing files with tslint. function! ale#fixers#tslint#Fix(buffer) abort let l:executable = ale#handlers#tslint#GetExecutable(a:buffer) let l:tslint_config_path = ale#path#ResolveLocalPath( \ a:buffer, \ 'tslint.json', \ ale#Var(a:buffer, 'typescript_tslint_config_path') \) let l:tslint_config_option = !empty(l:tslint_config_path) \ ? ' -c ' . ale#Escape(l:tslint_config_path) \ : '' return { \ 'command': ale#node#Executable(a:buffer, l:executable) \ . l:tslint_config_option \ . ' --outputAbsolutePaths --fix %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/typstyle.vim ================================================ " Author: Adrian Vollmer (computerfluesterer@protonmail.com) " Description: Typst formatter using typstyle call ale#Set('typst_typstyle_executable', 'typstyle') call ale#Set('typst_typstyle_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('typst_typstyle_options', '') function! ale#fixers#typstyle#Fix(buffer) abort let l:executable = ale#path#FindExecutable( \ a:buffer, \ 'typst_typstyle', \ ['typstyle'] \) let l:options = ale#Var(a:buffer, 'typst_typstyle_options') return { \ 'command': ale#Escape(l:executable) . ' ' . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/uncrustify.vim ================================================ " Author: Derek P Sifford " 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', '') let s:languages = { \ 'c': 'C', \ 'cpp': 'CPP', \ 'cs': 'CS', \ 'objc': 'OC', \ 'objcpp': 'OC+', \ 'd': 'D', \ 'java': 'JAVA', \ 'vala': 'VALA', \ 'p': 'PAWN', \} function! ale#fixers#uncrustify#Language(buffer) abort return get(s:languages, &filetype, 'C') endfunction 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 ' \ . '-l' . ale#Pad(ale#fixers#uncrustify#Language(a:buffer)) \ . ale#Pad(l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/unimport.vim ================================================ call ale#Set('python_unimport_executable', 'unimport') call ale#Set('python_unimport_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_unimport_options', '') call ale#Set('python_unimport_auto_pipenv', 0) call ale#Set('python_unimport_auto_poetry', 0) call ale#Set('python_unimport_auto_uv', 0) function! ale#fixers#unimport#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_unimport_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_unimport_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_unimport_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_unimport', ['unimport']) endfunction function! ale#fixers#unimport#Fix(buffer) abort let l:executable = ale#fixers#unimport#GetExecutable(a:buffer) let l:cmd = [ale#Escape(l:executable)] if l:executable =~? '\(pipenv\|poetry\|uv\)$' call extend(l:cmd, ['run', 'unimport']) endif let l:options = ale#Var(a:buffer, 'python_unimport_options') if !empty(l:options) call add(l:cmd, l:options) endif return {'command': join(l:cmd, ' ')} endfunction ================================================ FILE: autoload/ale/fixers/verible_format.vim ================================================ " Author: Nicolas Derumigny " Description: verible formatter for verilog. call ale#Set('verilog_verible_format_executable', 'verible-verilog-format') call ale#Set('verilog_verible_format_options', '') function! ale#fixers#verible_format#Fix(buffer) abort let l:executable = ale#Escape(ale#Var(a:buffer, 'verilog_verible_format_executable')) let l:command = l:executable let l:options = ale#Var(a:buffer, 'verilog_verible_format_options') if l:options isnot# '' let l:command .= ' ' . l:options endif return {'command': l:command . ' -'} endfunction ================================================ FILE: autoload/ale/fixers/vfmt.vim ================================================ " Author: fiatjaf " Description: Integration of `v fmt` with ALE. call ale#Set('v_vfmt_options', '') function! ale#fixers#vfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'v_v_executable') let l:options = ale#Var(a:buffer, 'v_vfmt_options') return { \ 'command': ale#Escape(l:executable) . ' fmt' . ale#Pad(l:options) \} endfunction ================================================ FILE: autoload/ale/fixers/xmllint.vim ================================================ " Author: Cyril Roelandt , jiz4oh " 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:command = l:executable . ' --format' 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 ================================================ FILE: autoload/ale/fixers/xo.vim ================================================ " Author: Albert Marquez - https://github.com/a-marquez " Description: Fixing files with XO. function! ale#fixers#xo#Fix(buffer) abort let l:executable = ale#handlers#xo#GetExecutable(a:buffer) let l:options = ale#handlers#xo#GetOptions(a:buffer) return ale#semver#RunWithVersionCheck( \ a:buffer, \ l:executable, \ '%e --version', \ {b, v -> ale#fixers#xo#ApplyFixForVersion(b, v, l:executable, l:options)} \) endfunction function! ale#fixers#xo#ApplyFixForVersion(buffer, version, executable, options) abort let l:executable = ale#node#Executable(a:buffer, a:executable) let l:options = ale#Pad(a:options) " 0.30.0 is the first version with a working --stdin --fix if ale#semver#GTE(a:version, [0, 30, 0]) return { \ 'command': l:executable \ . ' --stdin --stdin-filename %s' \ . ' --fix' \ . l:options, \} endif return { \ 'command': l:executable \ . ' --fix %t' \ . l:options, \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/fixers/yamlfix.vim ================================================ " Author: lyz-code " Description: Fixing yaml files with yamlfix. call ale#Set('yaml_yamlfix_executable', 'yamlfix') call ale#Set('yaml_yamlfix_options', '') call ale#Set('yaml_yamlfix_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#fixers#yamlfix#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'yaml_yamlfix_options') let l:executable = ale#python#FindExecutable( \ a:buffer, \ 'yaml_yamlfix', \ ['yamlfix'], \) if !executable(l:executable) return 0 endif return { \ 'cwd': '%s:h', \ 'command': ale#Escape(l:executable) \ . ale#Pad(l:options) . ' -', \} endfunction ================================================ FILE: autoload/ale/fixers/yamlfmt.vim ================================================ " Author: https://github.com/Spixmaster " Description: Format YAML files with yamlfmt. call ale#Set('yaml_yamlfmt_executable', 'yamlfmt') call ale#Set('yaml_yamlfmt_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('yaml_yamlfmt_options', '') function! ale#fixers#yamlfmt#Fix(buffer) abort let l:executable = ale#python#FindExecutable( \ a:buffer, \ 'yaml_yamlfmt', \ ['yamlfmt'] \) let l:options = ale#Var(a:buffer, 'yaml_yamlfmt_options') return { \ 'command': ale#Escape(l:executable) . ' ' . l:options . ' -in', \} endfunction ================================================ FILE: autoload/ale/fixers/yapf.vim ================================================ " Author: w0rp " Description: Fixing Python files with yapf. call ale#Set('python_yapf_executable', 'yapf') call ale#Set('python_yapf_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_yapf_auto_pipenv', 0) call ale#Set('python_yapf_auto_poetry', 0) call ale#Set('python_yapf_auto_uv', 0) function! ale#fixers#yapf#GetExecutable(buffer) abort if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_yapf_auto_pipenv')) \ && ale#python#PipenvPresent(a:buffer) return 'pipenv' endif if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_yapf_auto_poetry')) \ && ale#python#PoetryPresent(a:buffer) return 'poetry' endif if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_yapf_auto_uv')) \ && ale#python#UvPresent(a:buffer) return 'uv' endif return ale#python#FindExecutable(a:buffer, 'python_yapf', ['yapf']) endfunction function! ale#fixers#yapf#Fix(buffer) abort let l:executable = ale#fixers#yapf#GetExecutable(a:buffer) let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$' \ ? ' run yapf' \ : '' let l:config = ale#path#FindNearestFile(a:buffer, '.style.yapf') let l:config_options = !empty(l:config) \ ? ' --no-local-style --style ' . ale#Escape(l:config) \ : '' return { \ 'command': ale#Escape(l:executable) . l:exec_args . l:config_options, \} endfunction ================================================ FILE: autoload/ale/fixers/yq.vim ================================================ call ale#Set('yaml_yq_executable', 'yq') call ale#Set('yaml_yq_options', '') call ale#Set('yaml_yq_filters', '.') function! ale#fixers#yq#GetExecutable(buffer) abort return ale#Var(a:buffer, 'yaml_yq_executable') endfunction function! ale#fixers#yq#Fix(buffer) abort let l:options = ale#Var(a:buffer, 'yaml_yq_options') let l:filters = ale#Var(a:buffer, 'yaml_yq_filters') if empty(l:filters) return 0 endif return { \ 'command': ale#Escape(ale#fixers#yq#GetExecutable(a:buffer)) \ . ' ' . l:filters . ' ' \ . l:options, \} endfunction ================================================ FILE: autoload/ale/fixers/zigfmt.vim ================================================ scriptencoding utf-8 " Author: Arash Mousavi " Description: Official formatter for Zig. call ale#Set('zig_zigfmt_executable', 'zig') function! ale#fixers#zigfmt#Fix(buffer) abort let l:executable = ale#Var(a:buffer, 'zig_zigfmt_executable') return { \ 'command': ale#Escape(l:executable) . ' fmt %t', \ 'read_temporary_file': 1, \} endfunction ================================================ FILE: autoload/ale/floating_preview.vim ================================================ " Author: Jan-Grimo Sobez " Author: Kevin Clark " Author: D. Ben Knoble " Author: Shaun Duncan " Description: Floating preview window for showing whatever information in. " Precondition: exists('*nvim_open_win') || has('popupwin') function! ale#floating_preview#Show(lines, ...) abort if !exists('*nvim_open_win') && !has('popupwin') " no-custom-checks echom 'Floating windows not supported in this vim instance.' return endif let l:options = get(a:000, 0, {}) if has('nvim') call s:NvimShow(a:lines, l:options) else call s:VimShow(a:lines, l:options) endif return w:preview.id endfunction function! s:NvimShow(lines, options) abort " Remove the close autocmd so it doesn't happen mid update augroup ale_floating_preview_window autocmd! augroup END " Only create a new window if we need it if !exists('w:preview') || index(nvim_list_wins(), w:preview['id']) is# -1 call s:NvimCreate(a:options) else call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:true) endif " Execute commands in window context if exists('*win_execute') for l:command in get(a:options, 'commands', []) call win_execute(w:preview['id'], l:command) endfor else let l:parent_window = nvim_get_current_win() call nvim_set_current_win(w:preview['id']) for l:command in get(a:options, 'commands', []) call execute(l:command) endfor call nvim_set_current_win(l:parent_window) endif " Return to parent context on move augroup ale_floating_preview_window autocmd! if g:ale_close_preview_on_insert autocmd CursorMoved,TabLeave,WinLeave,BufWinLeave,WinScrolled,InsertEnter ++once call s:NvimClose() else autocmd CursorMoved,TabLeave,WinLeave,BufWinLeave,WinScrolled ++once call s:NvimClose() endif augroup END let [l:lines, l:width, l:height] = s:NvimPrepareWindowContent(a:lines) call nvim_win_set_width(w:preview['id'], l:width) call nvim_win_set_height(w:preview['id'], l:height) call nvim_buf_set_lines(w:preview['buffer'], 0, -1, v:false, l:lines) call nvim_buf_set_option(w:preview['buffer'], 'modified', v:false) call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:false) endfunction function! s:VimShow(lines, options) abort if g:ale_close_preview_on_insert " Remove the close autocmd so it doesn't happen mid update silent! autocmd! ale_floating_preview_window endif " Only create a new window if we need it if !exists('w:preview') || index(popup_list(), w:preview['id']) is# -1 call s:VimCreate(a:options) endif " Execute commands in window context for l:command in get(a:options, 'commands', []) call win_execute(w:preview['id'], l:command) endfor call popup_settext(w:preview['id'], a:lines) if g:ale_close_preview_on_insert augroup ale_floating_preview_window autocmd! autocmd InsertEnter * ++once call s:VimClose() augroup END endif endfunction function! s:NvimPrepareWindowContent(lines) abort let l:max_height = 10 let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)')) let l:height = min([len(a:lines), l:max_height]) return [a:lines[0:l:height-1], l:width, l:height] endfunction function! s:NvimCreate(options) abort let l:left = get(g:ale_floating_window_border, 0, '|') let l:top = get(g:ale_floating_window_border, 1, '-') let l:popup_opts = extend({ \ 'relative': 'cursor', \ 'row': 1, \ 'col': 0, \ 'width': 42, \ 'height': 4, \ 'style': 'minimal', \ 'border': empty(g:ale_floating_window_border) ? 'none' : [ \ get(g:ale_floating_window_border, 2, '+'), \ l:top, \ get(g:ale_floating_window_border, 3, '+'), \ get(g:ale_floating_window_border, 6, l:left), \ get(g:ale_floating_window_border, 4, '+'), \ get(g:ale_floating_window_border, 7, l:top), \ get(g:ale_floating_window_border, 5, '+'), \ l:left, \ ], \ }, s:GetPopupOpts()) let l:buffer = nvim_create_buf(v:false, v:false) let l:winid = nvim_open_win(l:buffer, v:false, l:popup_opts) call nvim_buf_set_option(l:buffer, 'buftype', 'acwrite') call nvim_buf_set_option(l:buffer, 'bufhidden', 'delete') call nvim_buf_set_option(l:buffer, 'swapfile', v:false) call nvim_buf_set_option(l:buffer, 'filetype', get(a:options, 'filetype', 'ale-preview')) let w:preview = {'id': l:winid, 'buffer': l:buffer} endfunction function! s:VimCreate(options) abort " default options let l:popup_opts = extend({ \ 'line': 'cursor+1', \ 'col': 'cursor', \ 'drag': v:true, \ 'resize': v:true, \ 'close': 'button', \ 'padding': [0, 1, 0, 1], \ 'border': [], \ 'borderchars': empty(g:ale_floating_window_border) ? [' '] : [ \ get(g:ale_floating_window_border, 1, '-'), \ get(g:ale_floating_window_border, 6, '|'), \ get(g:ale_floating_window_border, 7, '-'), \ get(g:ale_floating_window_border, 0, '|'), \ get(g:ale_floating_window_border, 2, '+'), \ get(g:ale_floating_window_border, 3, '+'), \ get(g:ale_floating_window_border, 4, '+'), \ get(g:ale_floating_window_border, 5, '+'), \ ], \ 'moved': 'any', \ }, s:GetPopupOpts()) let l:popup_id = popup_create([], l:popup_opts) call setbufvar(winbufnr(l:popup_id), '&filetype', get(a:options, 'filetype', 'ale-preview')) let w:preview = {'id': l:popup_id} endfunction function! s:NvimClose() abort let l:mode = mode() let l:restore_visual = l:mode is# 'v' || l:mode is# 'V' || l:mode is# "\" if !exists('w:preview') return endif call setbufvar(w:preview['buffer'], '&modified', 0) if win_id2win(w:preview['id']) > 0 execute win_id2win(w:preview['id']).'wincmd c' endif unlet w:preview if l:restore_visual normal! gv endif endfunction function! s:VimClose() abort if !exists('w:preview') return endif call popup_close(w:preview['id']) unlet w:preview endfunction " get either the results of a function callback or dictionary for popup overrides function! s:GetPopupOpts() abort if exists('g:ale_floating_preview_popup_opts') let l:ref = g:ale_floating_preview_popup_opts if type(l:ref) is# v:t_dict return l:ref elseif type(l:ref) is# v:t_string try return function(l:ref)() catch /E700/ endtry endif endif return {} endfunction ================================================ FILE: autoload/ale/fzf.vim ================================================ " Author: bretello https://github.com/bretello " Description: Functions for integrating with fzf " Handle references found with ALEFindReferences using fzf function! ale#fzf#ShowReferences(item_list, options) abort let l:name = 'LSP References' let l:capname = 'References' let l:items = copy(a:item_list) let l:cwd = getcwd() " no-custom-checks let l:sep = has('win32') ? '\' : '/' function! s:relative_paths(line) closure abort return substitute(a:line, '^' . l:cwd . l:sep, '', '') endfunction if get(a:options, 'use_relative_paths') let l:items = map(filter(l:items, 'len(v:val)'), 's:relative_paths(v:val)') endif let l:start_query = '' let l:fzf_options = { \ 'source': items, \ 'options': ['--prompt', l:name.'> ', '--query', l:start_query, \ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all', \ '--delimiter', ':', '--preview-window', '+{2}/2'] \} call add(l:fzf_options['options'], '--highlight-line') " this only works for more recent fzf versions (TODO: handle version check?) " wrap with #with_preview and #fzfwrap before adding the sinklist, " otherwise --expect options are not added let l:opts_with_preview = fzf#vim#with_preview(l:fzf_options) let l:bang = 0 " TODO: handle bang let l:wrapped = fzf#wrap(l:name, l:opts_with_preview, l:bang) call remove(l:wrapped, 'sink*') " remove the default sinklist to add in our custom sinklist function! l:wrapped.sinklist(lines) closure abort if len(a:lines) <2 return endif let l:cmd = a:lines[0] function! s:references_to_qf(line) closure abort " mimics ag_to_qf in junegunn/fzf.vim let l:parts = matchlist(a:line, '\(.\{-}\)\s*:\s*\(\d\+\)\%(\s*:\s*\(\d\+\)\)\?\%(\s*:\(.*\)\)\?') let l:filename = &autochdir ? fnamemodify(l:parts[1], ':p') : l:parts[1] return {'filename': l:filename, 'lnum': l:parts[2], 'col': l:parts[3], 'text': l:parts[4]} endfunction let l:references = map(filter(a:lines[1:], 'len(v:val)'), 's:references_to_qf(v:val)') if empty(l:references) return endif if get(a:options, 'open_in') is# 'quickfix' call setqflist([], 'r') call setqflist(l:references, 'a') call ale#util#Execute('cc 1') endif function! s:action(key, file) abort " copied from fzf.vim let l:default_action = { \ 'ctrl-t': 'tab split', \ 'ctrl-x': 'split', \ 'ctrl-v': 'vsplit' } let fzf_actions = get(g:, 'fzf_action', l:default_action) let l:Cmd = get(fzf_actions, a:key, 'edit') let l:cursor_cmd = escape('call cursor(' . a:file['lnum'] . ',' . a:file['col'] . ')', ' ') let l:fullcmd = l:Cmd . ' +' . l:cursor_cmd . ' ' . fnameescape(a:file['filename']) silent keepjumps keepalt execute fullcmd endfunction return map(l:references, 's:action(cmd, v:val)') endfunction call fzf#run(l:wrapped) endfunction ================================================ FILE: autoload/ale/go.vim ================================================ " 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 call ale#Set('go_go111module', '') " Return a string setting Go-specific environment variables function! ale#go#EnvString(buffer) abort let l:env = '' " GO111MODULE - turn go modules behavior on/off let l:go111module = ale#Var(a:buffer, 'go_go111module') if !empty(l:go111module) let l:env = ale#Env('GO111MODULE', l:go111module) . l:env endif return l:env endfunction function! ale#go#GetGoPathExecutable(suffix) abort let l:prefix = $GOPATH if !empty($GOPATH) let l:prefix = $GOPATH elseif has('win32') let l:prefix = $USERPROFILE . '/go' else let l:prefix = $HOME . '/go' endif return ale#path#Simplify(l:prefix . '/' . a:suffix) endfunction ================================================ FILE: autoload/ale/gradle/init.gradle ================================================ class ClasspathPlugin implements Plugin { void apply(Project project) { project.task('printClasspath') { doLast { project .rootProject .allprojects .configurations .flatten() .findAll { it.name.endsWith('Classpath') } .collect { it.resolve() } .flatten() .unique() .findAll { it.exists() } .each { println it } } } } } rootProject { apply plugin: ClasspathPlugin } ================================================ FILE: autoload/ale/gradle.vim ================================================ " Author: Michael Pardo " Description: Functions for working with Gradle projects. let s:script_path = fnamemodify(resolve(expand(':p')), ':h') let s:init_path = has('win32') \ ? s:script_path . '\gradle\init.gradle' \ : s:script_path . '/gradle/init.gradle' function! ale#gradle#GetInitPath() abort return s:init_path endfunction " Given a buffer number, find a Gradle project root. function! ale#gradle#FindProjectRoot(buffer) abort let l:gradlew_path = ale#path#FindNearestFile(a:buffer, 'gradlew') if !empty(l:gradlew_path) return fnamemodify(l:gradlew_path, ':h') endif let l:settings_path = ale#path#FindNearestFile(a:buffer, 'settings.gradle') if !empty(l:settings_path) return fnamemodify(l:settings_path, ':h') endif let l:build_path = ale#path#FindNearestFile(a:buffer, 'build.gradle') if !empty(l:build_path) return fnamemodify(l:build_path, ':h') endif return '' endfunction " Given a buffer number, find the path to the executable. " First search on the path for 'gradlew', if nothing is found, try the global " command. Returns an empty string if cannot find the executable. function! ale#gradle#FindExecutable(buffer) abort let l:gradlew_path = ale#path#FindNearestFile(a:buffer, 'gradlew') if !empty(l:gradlew_path) return l:gradlew_path endif if executable('gradle') return 'gradle' endif return '' endfunction " Given a buffer number, get a working directory and command to print the " classpath of the root project. " " Returns an empty string for the command if Gradle is not detected. function! ale#gradle#BuildClasspathCommand(buffer) abort let l:executable = ale#gradle#FindExecutable(a:buffer) if !empty(l:executable) let l:project_root = ale#gradle#FindProjectRoot(a:buffer) if !empty(l:project_root) return [ \ l:project_root, \ ale#Escape(l:executable) \ . ' -I ' . ale#Escape(s:init_path) \ . ' -q printClasspath' \] endif endif return ['', ''] endfunction ================================================ FILE: autoload/ale/handlers/alex.vim ================================================ scriptencoding utf-8 " Author: Johannes Wienke " Description: Error handling for errors in alex output format function! ale#handlers#alex#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'alex', [ \ 'node_modules/.bin/alex', \ 'node_modules/alex/cli.js', \]) endfunction function! ale#handlers#alex#CreateCommandCallback(flags) abort return {b -> ale#node#Executable(b, ale#handlers#alex#GetExecutable(b)) \ . ' --stdin ' \ . a:flags \} endfunction function! ale#handlers#alex#Handle(buffer, lines) abort " Example output: " 6:256-6:262 warning Be careful with “killed”, it’s profane in some cases killed retext-profanities let l:pattern = '\v^ *(\d+):(\d+)-(\d+):(\d+) +warning +(.{-}) +(.{-}) +(.{-})$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'end_lnum': l:match[3] + 0, \ 'end_col': l:match[4] - 1, \ 'text': l:match[5] . ' (' . (l:match[7]) . ')', \ 'type': 'W', \}) endfor return l:output endfunction " Define a linter for a specific filetype. Accept flags to adapt to the filetype. " no flags treat input as markdown " --html treat input as HTML " --mdx treat input as MDX " --text treat input as plaintext function! ale#handlers#alex#DefineLinter(filetype, flags) abort call ale#Set('alex_executable', 'alex') call ale#Set('alex_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define(a:filetype, { \ 'name': 'alex', \ 'executable': function('ale#handlers#alex#GetExecutable'), \ 'command': ale#handlers#alex#CreateCommandCallback(a:flags), \ 'output_stream': 'stderr', \ 'callback': 'ale#handlers#alex#Handle', \}) endfunction ================================================ FILE: autoload/ale/handlers/atools.vim ================================================ " Author: Leo " Description: Handlers for output expected from atools function! ale#handlers#atools#Handle(buffer, lines) abort " Format: SEVERITY:[TAG]:PATH:LINENUM:MSG " Example: MC:[AL5]:./APKBUILD:12:variable set to empty string: install= let l:pattern = '\([^:]\+\):\([^:]\+\):\([^:]\+\):\(\d\+\):\(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) " We are expected to receive 2 characters, the first character " can be 'S', 'I', 'M' 'T', which are respectively: " Serious (Error) " Important (Error) " Minor (Warning) " Style (Warning) " " The second character can be either 'C' or 'P', which are respectively: " Certain (Error) " Possible (Warning) let l:severity = matchstr(l:match[1], '^.') let l:certainty = matchstr(l:match[1], '.$') let l:type = 'E' " If the tag returns 'Minor' or 'Style' or is 'Possible' " then return a warning if l:severity is# 'M' || l:severity is# 'T' || l:certainty is# 'P' let l:type = 'W' endif call add(l:output, { \ 'lnum': l:match[4] + 0, \ 'text': l:match[5], \ 'type': l:type, \ 'code': matchstr(l:match[2], 'AL[0-9]*'), \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/biome.vim ================================================ " Author: Filip Gospodinov " Description: Functions for working with biome, for checking or fixing files. call ale#Set('biome_executable', 'biome') call ale#Set('biome_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('biome_options', '') call ale#Set('biome_fixer_apply_unsafe', 0) call ale#Set('biome_lsp_project_root', '') function! ale#handlers#biome#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'biome', [ \ 'node_modules/@biomejs/cli-linux-x64/biome', \ 'node_modules/@biomejs/cli-linux-arm64/biome', \ 'node_modules/@biomejs/cli-win32-x64/biome.exe', \ 'node_modules/@biomejs/cli-win32-arm64/biome.exe', \ 'node_modules/@biomejs/cli-darwin-x64/biome', \ 'node_modules/@biomejs/cli-darwin-arm64/biome', \ 'node_modules/.bin/biome', \]) endfunction function! ale#handlers#biome#GetLanguage(buffer) abort return getbufvar(a:buffer, '&filetype') endfunction function! ale#handlers#biome#GetProjectRoot(buffer) abort let l:project_root = ale#Var(a:buffer, 'biome_lsp_project_root') if !empty(l:project_root) return l:project_root endif let l:possible_project_roots = [ \ 'biome.json', \ 'biome.jsonc', \ 'package.json', \ '.git', \ bufname(a:buffer), \] for l:possible_root in l:possible_project_roots let l:project_root = ale#path#FindNearestFile(a:buffer, l:possible_root) if empty(l:project_root) let l:project_root = ale#path#FindNearestDirectory(a:buffer, l:possible_root) endif if !empty(l:project_root) " dir:p expands to /full/path/to/dir/ whereas " file:p expands to /full/path/to/file (no trailing slash) " Appending '/' ensures that :h:h removes the path's last segment " regardless of whether it is a directory or not. return fnamemodify(l:project_root . '/', ':p:h:h') endif endfor return '' endfunction ================================================ FILE: autoload/ale/handlers/c3lsp.vim ================================================ scriptencoding utf-8 " Author: Koni Marti " Description: Utilities for c3lsp function! ale#handlers#c3lsp#GetProjectRoot(buffer) abort let l:config = ale#path#FindNearestFile(a:buffer, 'project.json') if !empty(l:config) return fnamemodify(l:config, ':h') endif return expand('#' . a:buffer . ':p:h') endfunction function! ale#handlers#c3lsp#GetInitOpts(buffer, init_options_var) abort let l:init_options = {} return extend(l:init_options, ale#Var(a:buffer, a:init_options_var)) endfunction ================================================ FILE: autoload/ale/handlers/cairo.vim ================================================ " Author: 0xhyoga <0xhyoga@gmx.com>, " Description: This file implements handlers specific to Cairo " function! ale#handlers#cairo#HandleCairoErrors(buffer, lines) abort " Matches patterns like the following: " Error: Expected ';' but got '(' " --> /path/to/file/file.cairo:1:10:) let l:pattern = '\v(error|warning): (.*)$' let l:line_and_column_pattern = '\v\.cairo:(\d+):(\d+)' let l:exclude_pattern = '\vcould not compile.*' let l:output = [] 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:line_and_column_pattern) if len(l:match) > 0 let l:index = len(l:output) - 1 let l:output[l:index]['lnum'] = l:match[1] + 0 let l:output[l:index]['col'] = l:match[2] + 0 endif else let l:text = l:match[2] if l:text !~# l:exclude_pattern let l:isError = l:match[1] is? 'Error' call add(l:output, { \ 'lnum': 0, \ 'col': 0, \ 'text': l:text, \ 'type': l:isError ? 'E' : 'W', \}) endif endif endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/ccls.vim ================================================ scriptencoding utf-8 " Author: Ye Jingchen " Description: Utilities for ccls function! ale#handlers#ccls#GetProjectRoot(buffer) abort " Try to find ccls configuration files first. let l:config = ale#path#FindNearestFile(a:buffer, '.ccls-root') if empty(l:config) let l:config = ale#path#FindNearestFile(a:buffer, '.ccls') endif if !empty(l:config) return fnamemodify(l:config, ':h') endif " Fall back on default project root detection. return ale#c#FindProjectRoot(a:buffer) endfunction function! ale#handlers#ccls#GetInitOpts(buffer, init_options_var) abort let l:build_dir = ale#c#GetBuildDirectory(a:buffer) let l:init_options = empty(l:build_dir) ? {} : {'compilationDatabaseDirectory': l:build_dir} return extend(l:init_options, ale#Var(a:buffer, a:init_options_var)) endfunction ================================================ FILE: autoload/ale/handlers/cppcheck.vim ================================================ " Description: Handle errors for cppcheck. function! ale#handlers#cppcheck#GetCwd(buffer) abort let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer) return !empty(l:dir) ? l:dir : '' endfunction function! ale#handlers#cppcheck#GetBufferPathIncludeOptions(buffer) abort let l:buffer_path_include = '' " Get path to this buffer so we can include it into cppcheck with -I " This could be expanded to get more -I directives from the compile " command in compile_commands.json, if it's found. let l:buffer_path = fnamemodify(bufname(a:buffer), ':p:h') let l:buffer_path_include = ' -I' . ale#Escape(l:buffer_path) return l:buffer_path_include endfunction function! ale#handlers#cppcheck#GetCompileCommandsOptions(buffer) abort " The compile_commands.json doesn't apply to headers and cppheck will " bail out if it cannot find a file matching the filter, below. Skip out " now, for headers. Also, suppress FPs; cppcheck is not meant to " process lone header files. let b:buffer_name = bufname(a:buffer) let b:file_extension = fnamemodify(b:buffer_name, ':e') if b:file_extension is# 'h' || b:file_extension is# 'hpp' return ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ . ' --suppress=unusedStructMember' endif " If the current buffer is modified, using compile_commands.json does no " good, so include the file's directory instead. It's not quite as good as " using --project, but is at least equivalent to running cppcheck on this " file manually from the file's directory. let l:modified = getbufvar(a:buffer, '&modified') if l:modified return '' endif " Search upwards from the file for compile_commands.json. " " If we find it, we'll `cd` to where the compile_commands.json file is, " then use the file to set up import paths, etc. let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer) " By default, cppcheck processes every config in compile_commands.json. " Use --file-filter to limit to just the buffer file. return !empty(l:json_path) \ ? '--project=' . ale#Escape(l:json_path[len(l:dir) + 1: ]) . ' --file-filter=' . ale#Escape(bufname(a:buffer)) \ : '' endfunction function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort " Look for lines like the following. " "test.cpp:974:6: error:inconclusive Array 'n[3]' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\ " n[3]=3; " ^ "" OR if cppcheck doesn't support {column} or {inconclusive:text}: "test.cpp:974:{column}: error:{inconclusive:inconclusive} Array 'n[3]' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\ " n[3]=3; " ^ " "" OR if using the misra addon: "test.c:1:16: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.7]\' "void test( int parm ) {} " ^ let l:pattern = '\v(\f+):(\d+):(\d+|\{column\}): (\w+):(\{inconclusive:inconclusive\})? ?(.*) \[(%(\w[-.]?)+)\]\\?' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if ale#path#IsBufferPath(a:buffer, l:match[1]) let l:text = substitute(l:match[6], '\\$', '', '') call add(l:output, { \ 'lnum': str2nr(l:match[2]), \ 'col': match(l:match[3],'{column}') >= 0 ? 1 : str2nr(l:match[3]), \ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'sub_type': l:match[4] is# 'style' ? 'style' : '', \ 'text': l:match[6], \ 'code': l:match[7] \}) endif endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/cpplint.vim ================================================ " Author: Dawid Kurek https://github.com/dawikur " Description: Handle errors for cpplint. function! ale#handlers#cpplint#HandleCppLintFormat(buffer, lines) abort " Look for lines like the following. " test.cpp:5: Estra space after ( in function call [whitespace/parents] [4] 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, \ 'col': 0, \ 'text': join(split(l:match[2])), \ 'code': l:match[3], \ 'type': 'W', \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/cspell.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: Define a handler function for cspell's output function! ale#handlers#cspell#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, \ 'cspell', [ \ 'node_modules/.bin/cspell', \ 'node_modules/cspell/bin.js', \ ] \) endfunction function! ale#handlers#cspell#GetLanguageId(buffer) abort let l:filetype = getbufvar(a:buffer, '&filetype') if l:filetype is# 'tex' " Vim's tex corresponds to latex language-id in cspell return 'latex' elseif l:filetype is# 'plaintex' " Vim's plaintex corresponds to tex language-id in cspell return 'tex' else " Fallback to filetype for everything else. return l:filetype endif endfunction function! ale#handlers#cspell#GetCommand(buffer) abort let l:executable = ale#handlers#cspell#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'cspell_options') let l:language_id = ale#handlers#cspell#GetLanguageId(a:buffer) let l:language_id_option = empty(l:language_id) ? '' : '--language-id="' . l:language_id . '"' return ale#node#Executable(a:buffer, l:executable) \ . ' lint --no-color --no-progress --no-summary' \ . ale#Pad(l:language_id_option) \ . ale#Pad(l:options) \ . ' -- stdin' endfunction function! ale#handlers#cspell#Handle(buffer, lines) abort " Look for lines like the following: " " /home/user/repos/ale/README.md:3:128 - Unknown word (Neovim) " match1: 3 " match2: 128 " match3: Unknown word (Neovim) " match4: Neovim let l:pattern = '\v^.*:(\d+):(\d+) - ([^\(]+\(([^\)]+)\).*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'end_col': l:match[2] + len(l:match[4]) - 1, \ 'text': l:match[3], \ 'type': 'W', \}) endfor return l:output endfunction function! ale#handlers#cspell#DefineLinter(filetype) abort call ale#Set('cspell_executable', 'cspell') call ale#Set('cspell_options', '') call ale#Set('cspell_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define(a:filetype, { \ 'name': 'cspell', \ 'executable': function('ale#handlers#cspell#GetExecutable'), \ 'command': function('ale#handlers#cspell#GetCommand'), \ 'callback': 'ale#handlers#cspell#Handle', \}) endfunction ================================================ FILE: autoload/ale/handlers/css.vim ================================================ scriptencoding utf-8 " Author: w0rp " Description: Error handling for CSS linters. function! ale#handlers#css#HandleCSSLintFormat(buffer, lines) abort " Matches patterns line the following: " " something.css: line 2, col 1, Error - Expected RBRACE at line 2, col 1. (errors) " something.css: line 2, col 5, Warning - Expected (inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | run-in | ruby | ruby-base | ruby-text | ruby-base-container | ruby-text-container | contents | none | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex) but found 'wat'. (known-properties) " " These errors can be very massive, so the type will be moved to the front " so you can actually read the error type. let l:pattern = '\v^.*: line (\d+), col (\d+), (Error|Warning) - (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3] is# 'Warning' ? 'W' : 'E', \ 'text': l:match[4], \} let l:code_match = matchlist(l:match[4], '\v(.+) \(([^(]+)\)$') " Split up the error code and the text if we find one. if !empty(l:code_match) let l:item.text = l:code_match[1] let l:item.code = l:code_match[2] endif call add(l:output, l:item) endfor return l:output endfunction function! ale#handlers#css#HandleStyleLintFormat(buffer, lines) abort let l:exception_pattern = '\v^(Syntax)?Error:' for l:line in a:lines[:10] if len(matchlist(l:line, l:exception_pattern)) > 0 return [{ \ 'lnum': 1, \ 'text': 'stylelint exception thrown (type :ALEDetail for more information)', \ 'detail': join(a:lines, "\n"), \}] endif endfor " Matches patterns line the following: " " src/main.css " 108:10 ✖ Unexpected leading zero number-leading-zero " 116:20 ✖ Expected a trailing semicolon declaration-block-trailing-semicolon let l:pattern = '\v^.* (\d+):(\d+) \s+(\S+)\s+ (.*[^ ])\s+([^ ]+)\s*$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3] is# '✖' ? 'E' : 'W', \ 'text': l:match[4], \ 'code': l:match[5], \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/deadnix.vim ================================================ function! ale#handlers#deadnix#Handle(buffer, lines) abort let l:output = [] for l:line in a:lines try let l:file = ale#util#FuzzyJSONDecode(l:line, v:null) catch continue endtry if type(l:file) isnot v:t_dict continue endif for l:error in l:file['results'] try let l:ale_error = { \ 'lnum': l:error['line'], \ 'col': l:error['column'], \ 'end_col': l:error['endColumn'], \ 'text': l:error['message'], \ 'type': 'W', \} catch continue endtry call add(l:output, l:ale_error) endfor endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/deno.vim ================================================ " Author: Mohammed Chelouti - https://github.com/motato1 " Arnold Chand " Description: Handler functions for Deno. call ale#Set('deno_executable', 'deno') call ale#Set('deno_unstable', 0) call ale#Set('deno_import_map', 'import_map.json') call ale#Set('deno_lsp_project_root', '') function! ale#handlers#deno#GetExecutable(buffer) abort return ale#Var(a:buffer, 'deno_executable') endfunction " Find project root for Deno's language server. " " Deno projects do not require a project or configuration file at the project root. " This means the root directory has to be guessed, " unless it is explicitly specified by the user. " " The project root is determined by ... " 1. using a user-specified value from deno_lsp_project_root " 2. looking for common top-level files/dirs " 3. using the buffer's directory function! ale#handlers#deno#GetProjectRoot(buffer) abort let l:project_root = ale#Var(a:buffer, 'deno_lsp_project_root') if !empty(l:project_root) return l:project_root endif let l:possible_project_roots = [ \ 'deno.json', \ 'deno.jsonc', \ 'tsconfig.json', \ '.git', \ bufname(a:buffer), \] for l:possible_root in l:possible_project_roots let l:project_root = ale#path#FindNearestFile(a:buffer, l:possible_root) if empty(l:project_root) let l:project_root = ale#path#FindNearestDirectory(a:buffer, l:possible_root) endif if !empty(l:project_root) " dir:p expands to /full/path/to/dir/ whereas " file:p expands to /full/path/to/file (no trailing slash) " Appending '/' ensures that :h:h removes the path's last segment " regardless of whether it is a directory or not. return fnamemodify(l:project_root . '/', ':p:h:h') endif endfor return '' endfunction " Initialization Options for deno, for javascript and typescript function! ale#handlers#deno#GetInitializationOptions(buffer) abort let l:options = { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': ale#path#FindNearestFile(a:buffer, 'import_map.json'), \ } if ale#Var(a:buffer, 'deno_unstable') let l:options.unstable = v:true endif " Look for a value set using the historical option name. let l:import_map = getbufvar( \ a:buffer, \ 'ale_deno_importMap', \ get(g:, 'ale_deno_importMap', '') \) if empty(l:import_map) let l:import_map = ale#Var(a:buffer, 'deno_import_map') endif if !empty(l:import_map) let l:options.importMap = ale#path#FindNearestFile(a:buffer, l:import_map) endif return l:options endfunction ================================================ FILE: autoload/ale/handlers/djlint.vim ================================================ " Author: Vivian De Smedt , Adrian Vollmer " Description: Adds support for djlint " function! ale#handlers#djlint#GetExecutable(buffer) abort return ale#Var(a:buffer, 'html_djlint_executable') endfunction function! ale#handlers#djlint#GetCommand(buffer) abort let l:executable = ale#handlers#djlint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'html_djlint_options') let l:profile = '' let l:filetypes = split(getbufvar(a:buffer, '&filetype'), '\.') " Append the --profile flag depending on the current filetype (unless it's " already set in g:html_djlint_options). if match(l:options, '--profile') == -1 let l:djlint_profiles = { \ 'html': 'html', \ 'htmldjango': 'django', \ 'jinja': 'jinja', \ 'nunjucks': 'nunjucks', \ 'handlebars': 'handlebars', \ 'gohtmltmpl': 'golang', \ 'htmlangular': 'angular', \} for l:filetype in l:filetypes if has_key(l:djlint_profiles, l:filetype) let l:profile = l:djlint_profiles[l:filetype] break endif endfor endif if !empty(l:profile) let l:options = (!empty(l:options) ? l:options . ' ' : '') . '--profile ' . l:profile endif return ale#Escape(l:executable) \ . ale#Pad(l:options) . ' %s' endfunction function! ale#handlers#djlint#Handle(buffer, lines) abort let l:output = [] let l:pattern = '\v^([A-Z]\d+) (\d+):(\d+) (.*)$' let l:i = 0 for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:i += 1 let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'vcol': 1, \ 'text': l:match[4], \ 'code': l:match[1], \ 'type': 'W', \} call add(l:output, l:item) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/elixir.vim ================================================ " Author: Matteo Centenaro (bugant) - https://github.com/bugant " Author: Jon Parise " 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 ================================================ FILE: autoload/ale/handlers/embertemplatelint.vim ================================================ " Author: Adrian Zalewski " Description: Ember-template-lint for checking Handlebars files function! ale#handlers#embertemplatelint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [ \ 'node_modules/.bin/ember-template-lint', \]) endfunction function! ale#handlers#embertemplatelint#GetCommand(buffer, version) abort if ale#semver#GTE(a:version, [4, 0, 0]) " --json was removed in favor of --format=json in ember-template-lint@4.0.0 return '%e --format=json --filename %s' endif return '%e --json --filename %s' endfunction function! ale#handlers#embertemplatelint#GetCommandWithVersionCheck(buffer) abort return ale#semver#RunWithVersionCheck( \ a:buffer, \ ale#handlers#embertemplatelint#GetExecutable(a:buffer), \ '%e --version', \ function('ale#handlers#embertemplatelint#GetCommand'), \) endfunction function! ale#handlers#embertemplatelint#Handle(buffer, lines) abort let l:output = [] let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) for l:error in get(values(l:json), 0, []) if has_key(l:error, 'fatal') call add(l:output, { \ 'lnum': get(l:error, 'line', 1), \ 'col': get(l:error, 'column', 1), \ 'text': l:error.message, \ 'type': l:error.severity == 1 ? 'W' : 'E', \}) else call add(l:output, { \ 'lnum': l:error.line, \ 'col': l:error.column, \ 'text': l:error.rule . ': ' . l:error.message, \ 'type': l:error.severity == 1 ? 'W' : 'E', \}) endif endfor return l:output endfunction function! ale#handlers#embertemplatelint#DefineLinter(filetype) abort call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint') call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#linter#Define(a:filetype, { \ 'name': 'embertemplatelint', \ 'aliases': ['ember-template-lint'], \ 'executable': function('ale#handlers#embertemplatelint#GetExecutable'), \ 'command': function('ale#handlers#embertemplatelint#GetCommandWithVersionCheck'), \ 'callback': 'ale#handlers#embertemplatelint#Handle', \}) endfunction ================================================ FILE: autoload/ale/handlers/eslint.vim ================================================ " Author: w0rp " Description: Functions for working with eslint, for checking or fixing files. let s:executables = [ \ '.yarn/sdks/eslint/bin/eslint.js', \ 'node_modules/.bin/eslint_d', \ 'node_modules/eslint/bin/eslint.js', \ 'node_modules/.bin/eslint', \] let s:sep = has('win32') ? '\' : '/' call ale#Set('javascript_eslint_options', '') call ale#Set('javascript_eslint_executable', 'eslint') call ale#Set('javascript_eslint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_eslint_suppress_eslintignore', 0) call ale#Set('javascript_eslint_suppress_missing_config', 0) function! ale#handlers#eslint#FindConfig(buffer) abort for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) for l:basename in [ \ 'eslint.config.js', \ 'eslint.config.mjs', \ 'eslint.config.cjs', \ '.eslintrc.js', \ '.eslintrc.cjs', \ '.eslintrc.yaml', \ '.eslintrc.yml', \ '.eslintrc.json', \ '.eslintrc', \] let l:config = ale#path#Simplify(join([l:path, l:basename], s:sep)) if filereadable(l:config) return l:config endif endfor endfor return ale#path#FindNearestFile(a:buffer, 'package.json') endfunction function! ale#handlers#eslint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_eslint', s:executables) endfunction " Given a buffer, return an appropriate working directory for ESLint. function! ale#handlers#eslint#GetCwd(buffer) abort return ale#path#Dirname(ale#handlers#eslint#FindConfig(a:buffer)) endfunction function! ale#handlers#eslint#GetCommand(buffer) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_eslint_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' -f json --stdin --stdin-filename %s' endfunction function! s:AddHintsForTypeScriptParsingErrors(output) abort for l:item in a:output let l:item.text = substitute( \ l:item.text, \ '^\(Parsing error\)', \ '\1 (You may need configure typescript-eslint-parser)', \ '', \) endfor endfunction function! s:CheckForBadConfig(buffer, lines) abort let l:config_error_pattern = '\v^ESLint couldn''t find a configuration file' \ . '|^Cannot read config file' \ . '|^.*Configuration for rule .* is invalid' \ . '|^ImportDeclaration should appear' " Look for a message in the first few lines which indicates that " a configuration file couldn't be found. for l:line in a:lines[:10] let l:match = matchlist(l:line, l:config_error_pattern) if len(l:match) > 0 " Don't show the missing config error if we've disabled it. if ale#Var(a:buffer, 'javascript_eslint_suppress_missing_config') \&& l:match[0] is# 'ESLint couldn''t find a configuration file' return 0 endif return 1 endif endfor return 0 endfunction function! s:parseJSON(buffer, lines) abort let l:parsed = [] for l:line in a:lines try let l:parsed = extend(l:parsed, json_decode(l:line)) catch endtry endfor if type(l:parsed) != v:t_list || empty(l:parsed) return [] endif let l:errors = l:parsed[0]['messages'] if empty(l:errors) return [] endif let l:output = [] for l:error in l:errors let l:obj = ({ \ 'lnum': get(l:error, 'line', 0), \ 'text': get(l:error, 'message', ''), \ 'type': 'E', \}) if get(l:error, 'severity', 0) is# 1 let l:obj.type = 'W' endif if has_key(l:error, 'ruleId') let l:code = l:error['ruleId'] " Sometimes ESLint returns null here if !empty(l:code) let l:obj.code = l:code endif endif if has_key(l:error, 'column') let l:obj.col = l:error['column'] endif if has_key(l:error, 'endColumn') let l:obj.end_col = l:error['endColumn'] - 1 endif if has_key(l:error, 'endLine') let l:obj.end_lnum = l:error['endLine'] endif call add(l:output, l:obj) endfor return l:output endfunction let s:col_end_patterns = [ \ '\vParsing error: Unexpected token (.+) ?', \ '\v''(.+)'' is not defined.', \ '\v%(Unexpected|Redundant use of) [''`](.+)[''`]', \ '\vUnexpected (console) statement', \] function! s:parseLines(buffer, lines) abort " Matches patterns line the following: " " /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle] " /path/to/some-filename.js:56:41: Missing semicolon. [Error/semi] let l:pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$' " This second pattern matches lines like the following: " " /path/to/some-filename.js:13:3: Parsing error: Unexpected token let l:parsing_pattern = '^.*:\(\d\+\):\(\d\+\): \(.\+\)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:parsing_pattern]) let l:text = l:match[3] let l:obj = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:text, \ 'type': 'E', \} " Take the error type from the output if available. let l:split_code = split(l:match[4], '/') if get(l:split_code, 0, '') is# 'Warning' let l:obj.type = 'W' endif " The code can be something like 'Error/foo/bar', or just 'Error' if !empty(get(l:split_code, 1)) let l:obj.code = join(l:split_code[1:], '/') endif for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns) let l:obj.end_col = l:obj.col + len(l:col_match[1]) - 1 endfor call add(l:output, l:obj) endfor return l:output endfunction function! s:FilterResult(buffer, obj) abort if ale#Var(a:buffer, 'javascript_eslint_suppress_eslintignore') if a:obj.text =~# '^File ignored' return 0 endif endif if has_key(a:obj, 'code') && a:obj.code is# 'no-trailing-spaces' \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') return 0 endif return 1 endfunction function! s:HandleESLintOutput(buffer, lines, type) abort if s:CheckForBadConfig(a:buffer, a:lines) return [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(a:lines, "\n"), \}] 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 if a:type is# 'json' let l:output = s:parseJSON(a:buffer, a:lines) else let l:output = s:parseLines(a:buffer, a:lines) endif call filter(l:output, {idx, obj -> s:FilterResult(a:buffer, obj)}) if expand('#' . a:buffer . ':t') =~? '\.tsx\?$' call s:AddHintsForTypeScriptParsingErrors(l:output) endif return l:output endfunction function! ale#handlers#eslint#HandleJSON(buffer, lines) abort return s:HandleESLintOutput(a:buffer, a:lines, 'json') endfunction function! ale#handlers#eslint#Handle(buffer, lines) abort return s:HandleESLintOutput(a:buffer, a:lines, 'lines') endfunction ================================================ FILE: autoload/ale/handlers/fecs.vim ================================================ " Author: harttle " Description: fecs http://fecs.baidu.com/ call ale#Set('javascript_fecs_executable', 'fecs') call ale#Set('javascript_fecs_use_global', get(g:, 'ale_use_global_executables', 0)) function! ale#handlers#fecs#GetCommand(buffer) abort return '%e check --colors=false --rule=true %t' endfunction function! ale#handlers#fecs#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'javascript_fecs', [ \ 'node_modules/.bin/fecs', \ 'node_modules/fecs/bin/fecs', \]) endfunction function! ale#handlers#fecs#Handle(buffer, lines) abort " Matches patterns looking like the following " " fecs WARN → line 20, col 25: Unexpected console statement. (no-console) " fecs ERROR → line 24, col 36: Missing radix parameter. (radix) " let l:pattern = '\v^.*(WARN|ERROR)\s+→\s+line (\d+),\s+col\s+(\d+):\s+(.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:obj = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4] \} let l:code_match = matchlist(l:match[4], '\v^(.{-})\s*\((.+)\)$') if !empty(l:code_match) let l:obj.code = l:code_match[2] let l:obj.text = l:code_match[1] endif if l:match[1] is# 'WARN' let l:obj.type = 'W' elseif l:match[1] is# 'ERROR' let l:obj.type = 'E' endif call add(l:output, l:obj) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/flawfinder.vim ================================================ scriptencoding utf-8 " Author: Christian Gibbons " Description: This file defines a handler function that should work for the " flawfinder format with the -CDQS flags. " Swiped this function from the GCC handler. Not sure if needed, but doesn't " hurt to have it. function! s:RemoveUnicodeQuotes(text) abort let l:text = a:text let l:text = substitute(l:text, '[`´‘’]', '''', 'g') let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g') let l:text = substitute(l:text, '[“”]', '"', 'g') return l:text endfunction function! ale#handlers#flawfinder#HandleFlawfinderFormat(buffer, lines) abort " Look for lines like the following. " " :12:4: [2] (buffer) char:Statically-sized arrays can be improperly restricted, leading to potential overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use functions that limit length, or ensure that the size is larger than the maximum possible length. " :31:4: [1] (buffer) strncpy:Easily used incorrectly; doesn't always \0-terminate or check for invalid pointers [MS-banned] (CWE-120). let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ( \[[0-5]\] [^:]+):(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) " Use severity level to determine if it should be considered a warning " or error. let l:severity = str2nr(matchstr(split(l:match[4])[0], '[0-5]')) let l:item = { \ 'lnum': str2nr(l:match[2]), \ 'col': str2nr(l:match[3]), \ 'type': (l:severity < ale#Var(a:buffer, 'c_flawfinder_error_severity')) \ ? 'W' : 'E', \ 'text': s:RemoveUnicodeQuotes(join(split(l:match[4])[1:]) . ': ' . l:match[5]), \} " If the filename is something like , or -, then " this is an error for the file we checked. if l:match[1] isnot# '-' && l:match[1][0] isnot# '<' let l:item['filename'] = l:match[1] endif call add(l:output, l:item) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/gawk.vim ================================================ " Author: Anthony DeDominic " Description: Handle output from gawk's --lint option function! ale#handlers#gawk#HandleGawkFormat(buffer, lines) abort " Look for lines like the following: " gawk: /tmp/v0fddXz/1/something.awk:1: ^ invalid char ''' in expression let l:pattern = '^.\{-}:\(\d\+\):\s\+\(warning:\|\^\)\s*\(.*\)' let l:output = [] 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, \ 'text': l:match[3], \ 'code': 0, \ 'type': l:ecode, \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/gcc.vim ================================================ scriptencoding utf-8 " Author: w0rp " Description: This file defines a handler function which ought to work for " any program which outputs errors in the format that GCC uses. let s:pragma_error = '#pragma once in main file' " Look for lines like the following. " " :8:5: warning: conversion lacks type at end of format [-Wformat=] " :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+)?:? ([^:]+): (.+)$' let s:inline_pattern = '\v inlined from .* at \:(\d+):(\d+):$' function! s:IsHeaderFile(filename) abort return a:filename =~? '\v\.(h|hpp)$' endfunction function! s:RemoveUnicodeQuotes(text) abort let l:text = a:text let l:text = substitute(l:text, '[`´‘’]', '''', 'g') let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g') let l:text = substitute(l:text, '[“”]', '"', 'g') return l:text endfunction function! s:ParseInlinedFunctionProblems(buffer, lines) abort let l:output = [] let l:pos_match = [] for l:line in a:lines let l:match = matchlist(l:line, s:pattern) if !empty(l:match) && !empty(l:pos_match) call add(l:output, { \ 'lnum': str2nr(l:pos_match[1]), \ 'col': str2nr(l:pos_match[2]), \ 'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W', \ 'text': s:RemoveUnicodeQuotes(l:match[5]), \}) endif let l:pos_match = matchlist(l:line, s:inline_pattern) endfor return l:output 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# '' 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 \:(\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 let l:output = [] 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 continue endif " If the 'error type' is a note, make it detail related to " the previous error parsed in output if l:match[4] is# 'note' if !empty(l:output) if !has_key(l:output[-1], 'detail') let l:output[-1].detail = l:output[-1].text " handle macro expansion errors/notes if l:match[5] =~? '^in expansion of macro ‘\w*\w’$' " if the macro expansion is in the file we're in, add " the lnum and col keys to the previous error if l:match[1] is# '' \ && !has_key(l:output[-1], 'col') let l:output[-1].lnum = str2nr(l:match[2]) let l:output[-1].col = str2nr(l:match[3]) else " the error is not in the current file, and since " macro expansion errors don't show the full path to " the error from the current file, we have to just " give out a generic error message let l:output[-1].text = 'Error found in macro expansion. See :ALEDetail' endif endif endif let l:output[-1].detail = l:output[-1].detail . "\n" \ . s:RemoveUnicodeQuotes(l:match[0]) endif continue endif let l:item = { \ 'lnum': str2nr(l:match[2]), \ 'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W', \ 'text': s:RemoveUnicodeQuotes(l:match[5]), \} if !empty(l:match[3]) let l:item.col = str2nr(l:match[3]) endif " If the filename is something like , or -, then " this is an error for the file we checked. if l:match[1] isnot# '-' && l:match[1][0] isnot# '<' let l:item['filename'] = l:match[1] endif call add(l:output, l:item) endfor return l:output endfunction " 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:ParseInlinedFunctionProblems(a:buffer, a:lines)) call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines)) return l:output endfunction ================================================ FILE: autoload/ale/handlers/go.vim ================================================ " Author: neersighted " Description: go vet for Go files " " Author: John Eikenberry " Description: updated to work with go1.10 " " Author: Ben Paxton " Description: moved to generic Golang file from govet " " Author: mostfunkyduck " Description: updated to work with go 1.14 function! ale#handlers#go#Handler(buffer, lines) abort let l:pattern = '\v^%(vet: )?([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?:? ?(.+)$' let l:output = [] let l:dir = expand('#' . a:buffer . ':p:h') for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:match[4], \ 'type': 'E', \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/haskell.vim ================================================ " Author: w0rp " 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') " Build part of a regular expression for matching ALE temporary filenames. let s:temp_regex_prefix = \ '\M' \ . substitute(s:temp_dir, '\\', '\\\\', 'g') \ . '\.\{-}' function! s:PanicOutput(lines) abort return [{ \ 'lnum': 1, \ 'col': 1, \ 'text': 'ghc panic!', \ 'type': 'E', \ 'detail' : join(a:lines, "\n"), \}] endfunction function! ale#handlers#haskell#HandleGHCFormat(buffer, lines) abort " Look for lines like the following. " "Appoint/Lib.hs:8:1: warning: "Appoint/Lib.hs:8:1: let l:basename = expand('#' . a:buffer . ':t') " Build a complete regular expression for replacing temporary filenames " in Haskell error messages with the basename for this file. let l:temp_filename_regex = s:temp_regex_prefix . l:basename let l:pattern = '\v^\s*([a-zA-Z]?:?[^:]+):(\d+):(\d+):(.*)?$' let l:output = [] let l:corrected_lines = [] " If ghc panic error, put the whole message in details and exit. let l:panic_position = match(a:lines,'ghc: panic!') let l:panic_end = match(a:lines,'Please report this as a GHC bug:') if l:panic_position >= 0 return s:PanicOutput(a:lines[l:panic_position : l:panic_end]) endif " Group the lines into smaller lists. for l:line in a:lines if len(matchlist(l:line, l:pattern)) > 0 call add(l:corrected_lines, [l:line]) elseif l:line is# '' call add(l:corrected_lines, [l:line]) elseif len(l:corrected_lines) > 0 call add(l:corrected_lines[-1], l:line) endif endfor for l:line_list in l:corrected_lines " Join the smaller lists into one large line to parse. let l:line = l:line_list[0] for l:extra_line in l:line_list[1:] let l:line .= substitute(l:extra_line, '\v^\s+', ' ', '') endfor let l:match = matchlist(l:line, l:pattern) if len(l:match) == 0 continue endif if !ale#path#IsBufferPath(a:buffer, l:match[1]) continue endif let l:errors = matchlist(l:match[4], '\v([wW]arning|[eE]rror): ?(.*)') if len(l:errors) > 0 let l:ghc_type = l:errors[1] let l:text = l:errors[2] else let l:ghc_type = '' let l:text = l:match[4][:0] is# ' ' ? l:match[4][1:] : l:match[4] endif if l:ghc_type is? 'Warning' let l:type = 'W' else let l:type = 'E' endif " Replace temporary filenames in problem messages with the basename let l:text = substitute(l:text, l:temp_filename_regex, l:basename, 'g') let l:item = { \ 'lnum': l:match[2] + 0, \ 'col': l:match[3] + 0, \ 'text': l:text, \ 'type': l:type, \} " Include extra lines as details if they are there. if len(l:line_list) > 1 let l:item.detail = join(l:line_list[1:], "\n") endif call add(l:output, l:item) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/haskell_stack.vim ================================================ 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 ================================================ FILE: autoload/ale/handlers/hdl_checker.vim ================================================ " Author: suoto " Description: Adds support for HDL Code Checker, which wraps vcom/vlog, ghdl " or xvhdl. More info on https://github.com/suoto/hdl_checker call ale#Set('hdl_checker_executable', 'hdl_checker') call ale#Set('hdl_checker_config_file', has('unix') ? '.hdl_checker.config' : '_hdl_checker.config') call ale#Set('hdl_checker_options', '') " Use this as a function so we can mock it on testing. Need to do this because " test files are inside /testplugin (which refers to the ale repo), which will " always have a .git folder function! ale#handlers#hdl_checker#IsDotGit(path) abort return ! empty(a:path) && isdirectory(a:path) endfunction " Should return (in order of preference) " 1. Nearest config file " 2. Nearest .git directory " 3. The current path function! ale#handlers#hdl_checker#GetProjectRoot(buffer) abort let l:project_root = ale#path#FindNearestFile( \ a:buffer, \ ale#Var(a:buffer, 'hdl_checker_config_file')) if !empty(l:project_root) return fnamemodify(l:project_root, ':h') endif " Search for .git to use as root let l:project_root = ale#path#FindNearestDirectory(a:buffer, '.git') if ale#handlers#hdl_checker#IsDotGit(l:project_root) return fnamemodify(l:project_root, ':h:h') endif return '' endfunction function! ale#handlers#hdl_checker#GetExecutable(buffer) abort return ale#Var(a:buffer, 'hdl_checker_executable') endfunction function! ale#handlers#hdl_checker#GetCommand(buffer) abort let l:command = ale#Escape(ale#handlers#hdl_checker#GetExecutable(a:buffer)) . ' --lsp' " Add extra parameters only if config has been set let l:options = ale#Var(a:buffer, 'hdl_checker_options') if ! empty(l:options) let l:command = l:command . ' ' . l:options endif return l:command endfunction " To allow testing function! ale#handlers#hdl_checker#GetInitOptions(buffer) abort return {'project_file': ale#Var(a:buffer, 'hdl_checker_config_file')} endfunction " Define the hdl_checker linter for a given filetype. function! ale#handlers#hdl_checker#DefineLinter(filetype) abort call ale#linter#Define(a:filetype, { \ 'name': 'hdl_checker', \ 'aliases': ['hdl-checker'], \ 'lsp': 'stdio', \ 'language': a:filetype, \ 'executable': function('ale#handlers#hdl_checker#GetExecutable'), \ 'command': function('ale#handlers#hdl_checker#GetCommand'), \ 'project_root': function('ale#handlers#hdl_checker#GetProjectRoot'), \ 'initialization_options': function('ale#handlers#hdl_checker#GetInitOptions'), \ }) endfunction ================================================ FILE: autoload/ale/handlers/hlint.vim ================================================ 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 ================================================ FILE: autoload/ale/handlers/inko.vim ================================================ " Author: Yorick Peterse " Description: output handlers for the Inko JSON format function! ale#handlers#inko#GetType(severity) abort if a:severity is? 'warning' return 'W' endif return 'E' endfunction function! ale#handlers#inko#Handle(buffer, lines) abort try let l:errors = json_decode(join(a:lines, '')) catch return [] endtry if empty(l:errors) return [] endif let l:output = [] let l:dir = expand('#' . a:buffer . ':p:h') for l:error in l:errors call add(l:output, { \ 'filename': ale#path#GetAbsPath(l:dir, l:error['file']), \ 'lnum': l:error['line'], \ 'col': l:error['column'], \ 'text': l:error['message'], \ 'type': ale#handlers#inko#GetType(l:error['level']), \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/ktlint.vim ================================================ " Author: Michael Phillips " Description: Handler functions for ktlint. call ale#Set('kotlin_ktlint_executable', 'ktlint') call ale#Set('kotlin_ktlint_rulesets', []) call ale#Set('kotlin_ktlint_options', '') function! ale#handlers#ktlint#GetCommand(buffer) abort let l:executable = ale#Var(a:buffer, 'kotlin_ktlint_executable') let l:options = ale#Var(a:buffer, 'kotlin_ktlint_options') let l:rulesets = ale#handlers#ktlint#GetRulesets(a:buffer) return ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:rulesets) ? '' : ' ' . l:rulesets) \ . ' --stdin' endfunction function! ale#handlers#ktlint#GetRulesets(buffer) abort let l:rulesets = map(ale#Var(a:buffer, 'kotlin_ktlint_rulesets'), '''--ruleset '' . v:val') return join(l:rulesets, ' ') endfunction function! ale#handlers#ktlint#Handle(buffer, lines) abort let l:message_pattern = '^\(.*\):\([0-9]\+\):\([0-9]\+\):\s\+\(.*\)' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:message_pattern) let l:line = l:match[2] + 0 let l:column = l:match[3] + 0 let l:text = l:match[4] let l:type = l:text =~? 'not a valid kotlin file' ? 'E' : 'W' call add(l:output, { \ 'lnum': l:line, \ 'col': l:column, \ 'text': l:text, \ 'type': l:type \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/languagetool.vim ================================================ " Author: Vincent (wahrwolf [at] wolfpit.net) " Description: languagetool for markdown files " call ale#Set('languagetool_executable', 'languagetool') call ale#Set('languagetool_options', '--autoDetect') function! ale#handlers#languagetool#GetExecutable(buffer) abort return ale#Var(a:buffer, 'languagetool_executable') endfunction function! ale#handlers#languagetool#GetCommand(buffer) abort let l:executable = ale#handlers#languagetool#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'languagetool_options') return ale#Escape(l:executable) \ . (empty(l:options) ? '' : ' ' . l:options) . ' %s' endfunction function! ale#handlers#languagetool#HandleOutput(buffer, lines) abort " Match lines like: " 1.) Line 5, column 1, Rule ID: let l:head_pattern = '^\v.+.\) Line (\d+), column (\d+), Rule ID. (.+)$' let l:head_matches = ale#util#GetMatches(a:lines, l:head_pattern) " Match lines like: " Message: Did you forget a comma after a conjunctive/linking adverb? let l:message_pattern = '^\vMessage. (.+)$' let l:message_matches = ale#util#GetMatches(a:lines, l:message_pattern) " Match lines like: " ^^^^^ " let l:markers_pattern = '^\v *(\^+) *$' let l:markers_matches = ale#util#GetMatches(a:lines, l:markers_pattern) let l:output = [] " Okay tbh I was to lazy to figure out a smarter solution here " We just check that the arrays are same sized and merge everything " together let l:i = 0 while l:i < len(l:head_matches) \ && ( \ (len(l:head_matches) == len(l:markers_matches)) \ && (len(l:head_matches) == len(l:message_matches)) \ ) let l:item = { \ 'lnum' : str2nr(l:head_matches[l:i][1]), \ 'col' : str2nr(l:head_matches[l:i][2]), \ 'end_col' : str2nr(l:head_matches[l:i][2]) + len(l:markers_matches[l:i][1])-1, \ 'type' : 'W', \ 'code' : l:head_matches[l:i][3], \ 'text' : l:message_matches[l:i][1] \} call add(l:output, l:item) let l:i+=1 endwhile return l:output endfunction " Define the languagetool linter for a given filetype. " TODO: " - Add language detection settings based on user env (for mothertongue) " - Add fixer " - Add config options for rules function! ale#handlers#languagetool#DefineLinter(filetype) abort call ale#linter#Define(a:filetype, { \ 'name': 'languagetool', \ 'executable': function('ale#handlers#languagetool#GetExecutable'), \ 'command': function('ale#handlers#languagetool#GetCommand'), \ 'output_stream': 'stdout', \ 'callback': 'ale#handlers#languagetool#HandleOutput', \ 'lint_file': 1, \}) endfunction ================================================ FILE: autoload/ale/handlers/markdownlint.vim ================================================ " Author: Ty-Lucas Kelley " Description: Adds support for markdownlint function! ale#handlers#markdownlint#Handle(buffer, lines) abort let l:pattern=': \?\(\d\+\)\(:\(\d\+\)\?\)\? \(error\|warning\)\? \?\(MD\d\{3}/[A-Za-z0-9-/]\+\) \(.*\)$' let l:output=[] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:type = 'W' if l:match[4] is# 'error' let l:type = 'E' endif let l:result = ({ \ 'lnum': l:match[1] + 0, \ 'code': l:match[5], \ 'text': l:match[6], \ 'type': l:type, \}) if len(l:match[3]) > 0 let l:result.col = (l:match[3] + 0) endif call add(l:output, l:result) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/naga.vim ================================================ " Author: rhysd " Description: Handle errors for naga-cli. function! ale#handlers#naga#Handle(buffer, lines) abort let l:errors = [] let l:current_error = v:null for l:line in a:lines if l:line =~# '^error: ' let l:text = l:line[7:] let l:current_error = { 'text': l:text, 'type': 'E' } continue endif if l:current_error isnot v:null let l:matches = matchlist(l:line, '\v:(\d+):(\d+)$') if !empty(l:matches) let l:current_error.lnum = str2nr(l:matches[1]) let l:current_error.col = str2nr(l:matches[2]) call add(l:errors, l:current_error) let l:current_error = v:null continue endif endif endfor return l:errors endfunction ================================================ FILE: autoload/ale/handlers/ocamllsp.vim ================================================ " Author: Risto Stevcev " Description: Handlers for the official OCaml language server let s:language_id_of_filetype = { \ 'menhir': 'ocaml.menhir', \ 'ocaml': 'ocaml', \ 'ocamlinterface': 'ocaml.interface', \ 'ocamllex': 'ocaml.lex' \} function! ale#handlers#ocamllsp#GetExecutable(buffer) abort return 'ocamllsp' endfunction function! ale#handlers#ocamllsp#GetCommand(buffer) abort let l:executable = ale#handlers#ocamllsp#GetExecutable(a:buffer) let l:ocaml_ocamllsp_use_opam = ale#Var(a:buffer, 'ocaml_ocamllsp_use_opam') return l:ocaml_ocamllsp_use_opam ? 'opam config exec -- ' . l:executable : l:executable endfunction function! ale#handlers#ocamllsp#GetLanguage(buffer) abort return s:language_id_of_filetype[getbufvar(a:buffer, '&filetype')] endfunction function! ale#handlers#ocamllsp#GetProjectRoot(buffer) abort let l:dune_project_file = ale#path#FindNearestFile(a:buffer, 'dune-project') return !empty(l:dune_project_file) ? fnamemodify(l:dune_project_file, ':h') : '' endfunction ================================================ FILE: autoload/ale/handlers/ols.vim ================================================ " Author: Michael Jungo " Description: Handlers for the OCaml language server function! ale#handlers#ols#GetExecutable(buffer) abort let l:ols_setting = ale#handlers#ols#GetLanguage(a:buffer) . '_ols' return ale#path#FindExecutable(a:buffer, l:ols_setting, [ \ 'node_modules/.bin/ocaml-language-server', \]) endfunction function! ale#handlers#ols#GetCommand(buffer) abort let l:executable = ale#handlers#ols#GetExecutable(a:buffer) return ale#node#Executable(a:buffer, l:executable) . ' --stdio' endfunction function! ale#handlers#ols#GetLanguage(buffer) abort return getbufvar(a:buffer, '&filetype') endfunction function! ale#handlers#ols#GetProjectRoot(buffer) abort let l:merlin_file = ale#path#FindNearestFile(a:buffer, '.merlin') return !empty(l:merlin_file) ? fnamemodify(l:merlin_file, ':h') : '' endfunction ================================================ FILE: autoload/ale/handlers/openscad.vim ================================================ scriptencoding utf-8LE " Description: This file defines a handler function for linting OpenSCAD files " with SCA2D function! ale#handlers#openscad#SCA2D_callback(buffer, lines) abort " Example output:: " foo.scad:3:1: W2001: Variable `unused` overwritten within scope. " foo.scad:1:1: F0001: Cannot read file due to syntax error: " - No terminal matches '}' in the current parser context, at line 1 col 36 let l:filename_re = '^\([^:]*\):' let l:linenum_re = '\([0-9]*\):' let l:colnum_re = '\([0-9]*\):' let l:err_id = '\([IWEFU][0-9]\+\):' let l:err_msg = '\(.*\)' let l:pattern = filename_re . \ linenum_re . \ colnum_re . \ ' ' . \ err_id . \ ' ' . \ err_msg let l:result = [] let l:idx = 0 for l:line in a:lines let l:matches = matchlist(line, pattern) if len(matches) > 0 " option: Info, Warning, Error, Fatal, Unknown if index(['I', 'W'], matches[4][0]) >= 0 let l:type = 'W' else let l:type = 'E' endif let l:lnum = matches[2] let l:col = matches[3] let l:text = matches[5] " Better locations for some syntax errors if matches[4][0] is# 'F' let l:syntax_error_re = '^\(.*\), at line \([0-9]\+\) col \([0-9]\+\)$' let l:next_line = a:lines[idx+1] let l:syn_err_matches = matchlist(l:next_line, l:syntax_error_re) if len(syn_err_matches) > 0 let l:text = l:text . l:syn_err_matches[1] let l:lnum = l:syn_err_matches[2] let l:col = l:syn_err_matches[3] else let l:text = l:next_line endif endif let l:element = { \ 'lnum': str2nr(l:lnum), \ 'col': str2nr(l:col), \ 'text': l:text, \ 'detail': l:matches[4] . ': ' . l:text, \ 'filename': fnamemodify(matches[1], ':p'), \ 'type': l:type \ } call add(l:result, l:element) endif let l:idx += 1 endfor return result endfun ================================================ FILE: autoload/ale/handlers/pony.vim ================================================ scriptencoding utf-8 " Description: This file defines a handler function which ought to work for " any program which outputs errors in the format that ponyc uses. function! s:RemoveUnicodeQuotes(text) abort let l:text = a:text let l:text = substitute(l:text, '[`´‘’]', '''', 'g') let l:text = substitute(l:text, '\v\\u2018([^\\]+)\\u2019', '''\1''', 'g') let l:text = substitute(l:text, '[“”]', '"', 'g') return l:text 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 = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'filename': l:match[1], \ 'lnum': str2nr(l:match[2]), \ 'col': str2nr(l:match[3]), \ 'type': 'E', \ 'text': s:RemoveUnicodeQuotes(l:match[4]), \} call add(l:output, l:item) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/redpen.vim ================================================ " Author: rhysd https://rhysd.github.io " Description: Redpen, a proofreading tool (http://redpen.cc) call ale#Set('redpen_options', '') function! ale#handlers#redpen#HandleRedpenOutput(buffer, lines) abort " Only one file was passed to redpen. So response array has only one " element. let l:res = get(ale#util#FuzzyJSONDecode(a:lines, []), 0, {}) let l:output = [] for l:err in get(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 endif else " Fallback to a whole sentence region when a region is not " specified by the error. let l:item.lnum = l:err.lineNum let l:item.col = l:err.sentenceStartColumnNum + 1 endif " 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 " Define the redpen linter for a given filetype. function! ale#handlers#redpen#DefineLinter(filetype) abort call ale#linter#Define(a:filetype, { \ 'name': 'redpen', \ 'executable': 'redpen', \ 'command': {b -> 'redpen -f ' . a:filetype . ' -r json' . ale#Pad(ale#Var(b, 'redpen_options')) . ' %t'}, \ 'callback': 'ale#handlers#redpen#HandleRedpenOutput', \}) endfunction ================================================ FILE: autoload/ale/handlers/ruby.vim ================================================ " Author: Brandon Roehl - https://github.com/BrandonRoehl, Matthias Guenther https://wikimatze.de " " Description: This file implements handlers specific to Ruby. function! s:HandleSyntaxError(buffer, lines) abort " Matches patterns line the following: " " test.rb:3: warning: parentheses after method name is interpreted as an argument list, not a decomposed argument " test.rb:8: syntax error, unexpected keyword_end, expecting end-of-input let l:pattern = '\v^.+:(\d+): (warning: )?(.+)$' let l:column = '\v^(\s+)\^$' let l:output = [] 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 else call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': 0, \ 'text': l:match[2] . l:match[3], \ 'type': empty(l:match[2]) ? 'E' : 'W', \}) endif endfor return l:output endfunction function! ale#handlers#ruby#HandleSyntaxErrors(buffer, lines) abort return s:HandleSyntaxError(a:buffer, a:lines) endfunction ================================================ FILE: autoload/ale/handlers/rust.vim ================================================ " Author: Daniel Schemala , " w0rp " " Description: This file implements handlers specific to Rust. 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# '' return a:span endif " Search inside the expansion of an error, as the problem for this buffer " could lie inside a nested object. if !empty(get(a:span, 'expansion', v:null)) return s:FindSpan(a:buffer, a:span.expansion.span) endif return {} endfunction function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort let l:output = [] for l:errorline in a:lines " ignore everything that is not JSON if l:errorline !~# '^{' continue endif let l:error = json_decode(l:errorline) if has_key(l:error, 'message') && type(l:error.message) is v:t_dict let l:error = l:error.message endif if !has_key(l:error, 'code') continue endif if !empty(l:error.code) && index(g:ale_rust_ignore_error_codes, l:error.code.code) > -1 continue endif 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) let l:output_line = { \ 'lnum': l:span.line_start, \ 'end_lnum': l:span.line_end, \ 'col': l:span.column_start, \ 'end_col': l:span.column_end-1, \ 'text': empty(l:span.label) ? l:error.message : printf('%s: %s', l:error.message, l:span.label), \ 'type': toupper(l:error.level[0]), \} if has_key(l:error, 'rendered') && !empty(l:error.rendered) let l:output_line.detail = l:error.rendered endif call add(l:output, l:output_line) endif endfor endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/scala.vim ================================================ " Author: Nils Leuzinger - https://github.com/PawkyPenguin " Description: Scala linting handlers for scalac-like compilers. function! ale#handlers#scala#HandleScalacLintFormat(buffer, lines) abort " Matches patterns line the following: " " /var/folders/5q/20rgxx3x1s34g3m14n5bq0x80000gn/T/vv6pSsy/0:26: error: expected class or object definition let l:pattern = '^.\+:\(\d\+\): \(\w\+\): \(.\+\)' let l:output = [] let l:ln = 0 for l:line in a:lines let l:ln = l:ln + 1 let l:match = matchlist(l:line, l:pattern) if len(l:match) == 0 continue endif let l:text = l:match[3] let l:type = l:match[2] is# 'error' ? 'E' : 'W' let l:col = 0 if l:ln + 1 < len(a:lines) let l:col = stridx(a:lines[l:ln + 1], '^') endif call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:col + 1, \ 'text': l:text, \ 'type': l:type, \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/sh.vim ================================================ " Author: w0rp function! ale#handlers#sh#GetShellType(buffer) abort let l:shebang = get(getbufline(a:buffer, 1), 0, '') let l:command = '' " Take the shell executable from the shebang, if we can. if l:shebang[:1] is# '#!' " Remove options like -e, etc. let l:command = substitute(l:shebang, ' --\?[a-zA-Z0-9]\+', '', 'g') endif " With no shebang line, attempt to use Vim's buffer-local variables. if l:command is# '' if getbufvar(a:buffer, 'is_bash', 0) let l:command = 'bash' elseif getbufvar(a:buffer, 'is_sh', 0) let l:command = 'sh' elseif getbufvar(a:buffer, 'is_kornshell', 0) let l:command = 'ksh' endif endif " If we couldn't find a shebang, try the filetype if l:command is# '' let l:command = &filetype endif for l:possible_shell in ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh'] if l:command =~# l:possible_shell . '\s*$' return l:possible_shell endif endfor return '' endfunction ================================================ FILE: autoload/ale/handlers/shellcheck.vim ================================================ " Author: w0rp " Description: This file adds support for using the shellcheck linter " Shellcheck supports shell directives to define the shell dialect for scripts " that do not have a shebang for some reason. " https://github.com/koalaman/shellcheck/wiki/Directive#shell function! ale#handlers#shellcheck#GetShellcheckDialectDirective(buffer) abort let l:linenr = 0 let l:pattern = '\s\{-}#\s\{-}shellcheck\s\{-}shell=\(.*\)' let l:possible_shell = ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh'] while l:linenr < min([50, line('$')]) let l:linenr += 1 let l:match = matchlist(getline(l:linenr), l:pattern) if len(l:match) > 1 && index(l:possible_shell, l:match[1]) >= 0 return l:match[1] endif endwhile return '' endfunction function! ale#handlers#shellcheck#GetDialectArgument(buffer) abort let l:shell_type = ale#handlers#shellcheck#GetShellcheckDialectDirective(a:buffer) if empty(l:shell_type) let l:shell_type = ale#handlers#sh#GetShellType(a:buffer) endif if !empty(l:shell_type) " Use the dash dialect for /bin/ash, etc. if l:shell_type is# 'ash' return 'dash' endif return l:shell_type endif return '' endfunction function! ale#handlers#shellcheck#GetCwd(buffer) abort return ale#Var(a:buffer, 'sh_shellcheck_change_directory') ? '%s:h' : '' endfunction function! ale#handlers#shellcheck#GetCommand(buffer, version) abort let l:options = ale#Var(a:buffer, 'sh_shellcheck_options') let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions') let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect') let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : '' let l:format = ale#semver#GTE(a:version, [0, 7, 0]) ? 'json1' : 'gcc' if l:dialect is# 'auto' let l:dialect = ale#handlers#shellcheck#GetDialectArgument(a:buffer) endif return '%e' \ . (!empty(l:dialect) ? ' -s ' . l:dialect : '') \ . ale#Pad(l:options) \ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '') \ . l:external_option \ . ' -f ' . l:format . ' -' endfunction function! s:ShouldIgnoreErrorCode(buffer, code) abort " Skip warnings for trailing whitespace if the option is off. return a:code is# 'SC1101' \ && !ale#Var(a:buffer, 'warn_about_trailing_whitespace') endfunction function! s:HandleShellcheckJSON(buffer, lines) abort try let l:errors = json_decode(a:lines[0]) catch return [] endtry if !has_key(l:errors, 'comments') return [] endif let l:output = [] for l:error in l:errors['comments'] if l:error['level'] is# 'error' let l:type = 'E' elseif l:error['level'] is# 'info' let l:type = 'I' elseif l:error['level'] is# 'style' let l:type = 'I' else let l:type = 'W' endif let l:code = 'SC' . l:error['code'] if s:ShouldIgnoreErrorCode(a:buffer, l:code) continue endif let l:item = { \ 'lnum': l:error['line'], \ 'type': l:type, \ 'text': l:error['message'], \ 'code': l:code, \ 'detail': l:error['message'] . "\n\nFor more information:\n https://www.shellcheck.net/wiki/SC" . l:error['code'], \} if has_key(l:error, 'column') let l:item.col = l:error['column'] endif if has_key(l:error, 'endColumn') let l:item.end_col = l:error['endColumn'] - 1 endif if has_key(l:error, 'endLine') let l:item.end_lnum = l:error['endLine'] endif " If the filename is something like , or -, then " this is an error for the file we checked. if has_key(l:error, 'file') if l:error['file'] isnot# '-' && l:error['file'][0] isnot# '<' let l:item['filename'] = l:error['file'] endif endif call add(l:output, l:item) endfor return l:output endfunction function! s:HandleShellcheckGCC(buffer, lines) abort let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+) \[([^\]]+)\]$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) if l:match[4] is# 'error' let l:type = 'E' elseif l:match[4] is# 'note' let l:type = 'I' else let l:type = 'W' endif let l:code = l:match[6] if s:ShouldIgnoreErrorCode(a:buffer, l:code) continue endif let l:item = { \ 'lnum': str2nr(l:match[2]), \ 'type': l:type, \ 'text': l:match[5], \ 'code': l:code, \ 'detail': l:match[5] . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . l:match[6], \} if !empty(l:match[3]) let l:item.col = str2nr(l:match[3]) endif " If the filename is something like , or -, then " this is an error for the file we checked. if l:match[1] isnot# '-' && l:match[1][0] isnot# '<' let l:item['filename'] = l:match[1] endif call add(l:output, l:item) endfor return l:output endfunction function! ale#handlers#shellcheck#Handle(buffer, version, lines) abort return ale#semver#GTE(a:version, [0, 7, 0]) \ ? s:HandleShellcheckJSON(a:buffer, a:lines) \ : s:HandleShellcheckGCC(a:buffer, a:lines) endfunction function! ale#handlers#shellcheck#DefineLinter(filetype) abort " This global variable can be set with a string of comma-separated error " codes to exclude from shellcheck. For example: " let g:ale_sh_shellcheck_exclusions = 'SC2002,SC2004' call ale#Set('sh_shellcheck_exclusions', '') call ale#Set('sh_shellcheck_executable', 'shellcheck') call ale#Set('sh_shellcheck_dialect', 'auto') call ale#Set('sh_shellcheck_options', '') call ale#Set('sh_shellcheck_change_directory', 1) call ale#linter#Define(a:filetype, { \ 'name': 'shellcheck', \ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')}, \ 'cwd': function('ale#handlers#shellcheck#GetCwd'), \ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'sh_shellcheck_executable'), \ '%e --version', \ function('ale#handlers#shellcheck#GetCommand'), \ )}, \ 'callback': {buffer, lines -> ale#semver#RunWithVersionCheck( \ buffer, \ ale#Var(buffer, 'sh_shellcheck_executable'), \ '%e --version', \ {buffer, version -> ale#handlers#shellcheck#Handle( \ buffer, \ l:version, \ lines)}, \ )}, \}) endfunction ================================================ FILE: autoload/ale/handlers/sml.vim ================================================ " Author: Jake Zimmerman " Description: Shared functions for SML linters " The glob to use for finding the .cm file. " " See :help ale-sml-smlnj for more information. call ale#Set('sml_smlnj_cm_file', '*.cm') function! ale#handlers#sml#GetCmFile(buffer) abort let l:pattern = ale#Var(a:buffer, 'sml_smlnj_cm_file') 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. let l:cmfile = l:results[0] endif endfor return l:cmfile endfunction " Only one of smlnj or smlnj-cm can be enabled at a time. function! s:GetExecutable(buffer, source) abort if ale#handlers#sml#GetCmFile(a:buffer) is# '' " No CM file found; only allow single-file mode to be enabled if a:source is# 'smlnj-file' return 'sml' elseif a:source is# 'smlnj-cm' return '' endif else " Found a CM file; only allow cm-file mode to be enabled if a:source is# 'smlnj-file' return '' elseif a:source is# 'smlnj-cm' return 'sml' endif endif 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 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\): .*\)' for l:line in a:lines let l:match2 = matchlist(l:line, l:pattern2) if len(l:match2) != 0 if l:match2[1] =~# 'stdIn$' let l:loc = {'bufnr': a:buffer} else let l:loc = {'filename': l:match2[1]} endif call add(l:out, extend(l:loc, { \ 'lnum': l:match2[2] + 0, \ 'col' : l:match2[3] - 1, \ 'text': l:match2[4], \ 'type': l:match2[4] =~# '^Warning' ? 'W' : 'E', \})) continue endif let l:match = matchlist(l:line, l:pattern) if len(l:match) != 0 if l:match[1] =~# 'stdIn$' let l:loc = {'bufnr': a:buffer} else let l:loc = {'filename': l:match[1]} endif call add(l:out, extend(l:loc, { \ 'lnum': l:match[2] + 0, \ 'text': l:match[3] . ': ' . l:match[4], \ 'type': l:match[3] is# 'error' ? 'E' : 'W', \})) continue endif endfor return l:out endfunction " vim:ts=4:sts=4:sw=4 ================================================ FILE: autoload/ale/handlers/spectral.vim ================================================ " Author: t2h5 " Description: Integration of Stoplight Spectral CLI with ALE. function! ale#handlers#spectral#HandleSpectralOutput(buffer, lines) abort " Matches patterns like the following: " openapi.yml:1:1 error oas3-schema "Object should have required property `info`." " openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array." let l:pattern = '\v^.*:(\d+):(\d+) (error|warning) (.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:obj = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3] is# 'error' ? 'E' : 'W', \ 'text': l:match[4], \} let l:code_match = matchlist(l:obj.text, '\v^(.+) "(.+)"$') if !empty(l:code_match) let l:obj.code = l:code_match[1] let l:obj.text = l:code_match[2] endif call add(l:output, l:obj) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/statix.vim ================================================ scriptencoding utf-8 " Author: David Houston " Description: This file defines a handler function for statix's errorformat " output. function! ale#handlers#statix#Handle(buffer, lines) abort " Look for lines like the following. " " flake.nix>46:13:W:3:This assignment is better written with `inherit` let l:pattern = '\v^.*\>(\d+):(\d+):([A-Z]):(\d+):(.*)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'type': l:match[3], \ 'code': l:match[4], \ 'text': l:match[5], \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/textlint.vim ================================================ " Author: tokida https://rouger.info, Yasuhiro Kiyota " Description: textlint, a proofreading tool (https://textlint.github.io/) call ale#Set('textlint_executable', 'textlint') call ale#Set('textlint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('textlint_options', '') function! ale#handlers#textlint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'textlint', [ \ 'node_modules/.bin/textlint', \ 'node_modules/textlint/bin/textlint.js', \]) endfunction function! ale#handlers#textlint#GetCommand(buffer) abort let l:executable = ale#handlers#textlint#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'textlint_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' -f json --stdin --stdin-filename %s' endfunction function! ale#handlers#textlint#HandleTextlintOutput(buffer, lines) abort let l:res = get(ale#util#FuzzyJSONDecode(a:lines, []), 0, {'messages': []}) let l:output = [] for l:err in l:res.messages call add(l:output, { \ 'text': l:err.message, \ 'type': 'W', \ 'code': l:err.ruleId, \ 'lnum': l:err.line, \ 'col' : l:err.column \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/tslint.vim ================================================ function! ale#handlers#tslint#InitVariables() abort call ale#Set('typescript_tslint_executable', 'tslint') call ale#Set('typescript_tslint_config_path', '') call ale#Set('typescript_tslint_rules_dir', '') call ale#Set('typescript_tslint_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('typescript_tslint_ignore_empty_files', 0) endfunction function! ale#handlers#tslint#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'typescript_tslint', [ \ 'node_modules/.bin/tslint', \]) endfunction ================================================ FILE: autoload/ale/handlers/tsserver.vim ================================================ " Author: Derek Sifford " Description: Handlers for tsserver function! ale#handlers#tsserver#GetProjectRoot(buffer) abort let l:tsconfig_file = ale#path#FindNearestFile(a:buffer, 'tsconfig.json') return !empty(l:tsconfig_file) ? fnamemodify(l:tsconfig_file, ':h') : '' endfunction ================================================ FILE: autoload/ale/handlers/unix.vim ================================================ " Author: w0rp " Description: Error handling for errors in a Unix format. function! s:HandleUnixFormat(buffer, lines, type) abort let l:pattern = '\v^[a-zA-Z]?:?[^:]+:(\d+):?(\d+)?:? ?(.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) call add(l:output, { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[3], \ 'type': a:type, \}) endfor return l:output endfunction function! ale#handlers#unix#HandleAsError(buffer, lines) abort return s:HandleUnixFormat(a:buffer, a:lines, 'E') endfunction function! ale#handlers#unix#HandleAsWarning(buffer, lines) abort return s:HandleUnixFormat(a:buffer, a:lines, 'W') endfunction ================================================ FILE: autoload/ale/handlers/vale.vim ================================================ " Author: Johannes Wienke " Description: output handler for the vale JSON format function! ale#handlers#vale#GetType(severity) abort if a:severity is? 'warning' return 'W' elseif a:severity is? 'suggestion' return 'I' endif return 'E' endfunction function! ale#handlers#vale#Handle(buffer, lines) abort try let l:errors = json_decode(join(a:lines, '')) catch return [] endtry if empty(l:errors) return [] endif let l:output = [] for l:error in l:errors[keys(l:errors)[0]] call add(l:output, { \ 'lnum': l:error['Line'], \ 'col': l:error['Span'][0], \ 'end_col': l:error['Span'][1], \ 'code': l:error['Check'], \ 'text': l:error['Message'], \ 'type': ale#handlers#vale#GetType(l:error['Severity']), \}) endfor return l:output endfunction ================================================ FILE: autoload/ale/handlers/writegood.vim ================================================ " Author: Sumner Evans " Description: Error handling for errors in the write-good format. function! ale#handlers#writegood#ResetOptions() abort call ale#Set('writegood_options', '') call ale#Set('writegood_executable', 'write-good') call ale#Set('writegood_use_global', get(g:, 'ale_use_global_executables', 0)) endfunction " Reset the options so the tests can test how they are set. call ale#handlers#writegood#ResetOptions() function! ale#handlers#writegood#GetExecutable(buffer) abort return ale#path#FindExecutable(a:buffer, 'writegood', [ \ 'node_modules/.bin/write-good', \ 'node_modules/write-good/bin/write-good.js', \]) endfunction function! ale#handlers#writegood#GetCommand(buffer) abort let l:executable = ale#handlers#writegood#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'writegood_options') return ale#node#Executable(a:buffer, l:executable) \ . ale#Pad(l:options) \ . ' %t' endfunction function! ale#handlers#writegood#Handle(buffer, lines) abort " Look for lines like the following. " " "it is" is wordy or unneeded on line 20 at column 53 " "easily" can weaken meaning on line 154 at column 29 let l:marks_pattern = '\v^ *(\^+) *$' let l:pattern = '\v^(".*"\s.*)\son\sline\s(\d+)\sat\scolumn\s(\d+)$' let l:output = [] let l:last_len = 0 for l:match in ale#util#GetMatches(a:lines, [l:marks_pattern, l:pattern]) if empty(l:match[2]) let l:last_len = len(l:match[1]) else let l:col = l:match[3] + 1 " Add the linter error. Note that we need to add 1 to the col because " write-good reports the column corresponding to the space before the " offending word or phrase. call add(l:output, { \ 'text': l:match[1], \ 'lnum': l:match[2] + 0, \ 'col': l:col, \ 'end_col': l:last_len ? (l:col + l:last_len - 1) : l:col, \ 'type': 'W', \}) let l:last_len = 0 endif endfor return l:output endfunction " Define the writegood linter for a given filetype. function! ale#handlers#writegood#DefineLinter(filetype) abort call ale#linter#Define(a:filetype, { \ 'name': 'writegood', \ 'aliases': ['write-good'], \ 'executable': function('ale#handlers#writegood#GetExecutable'), \ 'command': function('ale#handlers#writegood#GetCommand'), \ 'callback': 'ale#handlers#writegood#Handle', \}) endfunction ================================================ FILE: autoload/ale/handlers/xo.vim ================================================ call ale#Set('javascript_xo_executable', 'xo') call ale#Set('javascript_xo_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('javascript_xo_options', '') call ale#Set('typescript_xo_executable', 'xo') call ale#Set('typescript_xo_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('typescript_xo_options', '') function! ale#handlers#xo#GetExecutable(buffer) abort let l:type = ale#handlers#xo#GetType(a:buffer) return ale#path#FindExecutable(a:buffer, l:type . '_xo', [ \ 'node_modules/xo/cli.js', \ 'node_modules/.bin/xo', \]) endfunction function! ale#handlers#xo#GetLintCommand(buffer) abort return ale#Escape(ale#handlers#xo#GetExecutable(a:buffer)) \ . ale#Pad(ale#handlers#xo#GetOptions(a:buffer)) \ . ' --reporter json --stdin --stdin-filename %s' endfunction function! ale#handlers#xo#GetOptions(buffer) abort let l:type = ale#handlers#xo#GetType(a:buffer) return ale#Var(a:buffer, l:type . '_xo_options') endfunction " xo uses eslint and the output format is the same function! ale#handlers#xo#HandleJSON(buffer, lines) abort return ale#handlers#eslint#HandleJSON(a:buffer, a:lines) endfunction function! ale#handlers#xo#GetType(buffer) abort let l:filetype = getbufvar(a:buffer, '&filetype') let l:type = 'javascript' if l:filetype =~# 'typescript' let l:type = 'typescript' endif return l:type endfunction ================================================ FILE: autoload/ale/handlers/yamllint.vim ================================================ function! ale#handlers#yamllint#GetCommand(buffer) abort return '%e' . ale#Pad(ale#Var(a:buffer, 'yaml_yamllint_options')) \ . ' -f parsable %t' endfunction function! ale#handlers#yamllint#Handle(buffer, lines) abort " Matches patterns line the following: " something.yaml:1:1: [warning] missing document start "---" (document-start) " something.yml:2:1: [error] syntax error: expected the node content, but found '' let l:pattern = '\v^.*:(\d+):(\d+): \[(error|warning)\] (.+)$' let l:output = [] for l:match in ale#util#GetMatches(a:lines, l:pattern) let l:item = { \ 'lnum': l:match[1] + 0, \ 'col': l:match[2] + 0, \ 'text': l:match[4], \ 'type': l:match[3] is# 'error' ? 'E' : 'W', \} let l:code_match = matchlist(l:item.text, '\v^(.+) \(([^)]+)\)$') if !empty(l:code_match) if l:code_match[2] is# 'trailing-spaces' \&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace') " Skip warnings for trailing whitespace if the option is off. continue endif let l:item.text = l:code_match[1] let l:item.code = l:code_match[2] endif call add(l:output, l:item) endfor return l:output endfunction ================================================ FILE: autoload/ale/highlight.vim ================================================ scriptencoding utf8 " Author: w0rp " Description: This module implements error/warning highlighting. if !hlexists('ALEError') highlight link ALEError SpellBad endif if !hlexists('ALEStyleError') highlight link ALEStyleError ALEError endif if !hlexists('ALEWarning') highlight link ALEWarning SpellCap endif if !hlexists('ALEStyleWarning') highlight link ALEStyleWarning ALEWarning endif if !hlexists('ALEInfo') highlight link ALEInfo ALEWarning endif " The maximum number of items for the second argument of matchaddpos() let s:MAX_POS_VALUES = 8 let s:MAX_COL_SIZE = 1073741824 " pow(2, 30) let s:has_nvim_highlight = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace') if s:has_nvim_highlight let s:ns_id = nvim_create_namespace('ale_highlight') endif " Wrappers are necessary to test this functionality by faking the calls in tests. function! ale#highlight#nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end) abort " Ignore all errors for adding highlights. try call nvim_buf_add_highlight(a:buffer, a:ns_id, a:hl_group, a:line, a:col_start, a:col_end) catch endtry endfunction function! ale#highlight#nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end) abort call nvim_buf_clear_namespace(a:buffer, a:ns_id, a:line_start, a:line_end) endfunction function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort if a:line >= a:end_line " For single lines, just return the one position. return [[[a:line, a:col, a:end_col - a:col + 1]]] endif " Get positions from the first line at the first column, up to a large " integer for highlighting up to the end of the line, followed by " the lines in-between, for highlighting entire lines, and " a highlight for the last line, up to the end column. let l:all_positions = \ [[a:line, a:col, s:MAX_COL_SIZE]] \ + range(a:line + 1, a:end_line - 1) \ + [[a:end_line, 1, a:end_col]] return map( \ range(0, len(l:all_positions) - 1, s:MAX_POS_VALUES), \ 'l:all_positions[v:val : v:val + s:MAX_POS_VALUES - 1]', \) endfunction " Given a loclist for current items to highlight, remove all highlights " except these which have matching loclist item entries. function! ale#highlight#RemoveHighlights() abort if s:has_nvim_highlight call ale#highlight#nvim_buf_clear_namespace(bufnr(''), s:ns_id, 0, -1) else for l:match in getmatches() if l:match.group =~? '\v^ALE(Style)?(Error|Warning|Info)(Line)?$' call matchdelete(l:match.id) endif endfor endif endfunction " Same semantics of matchaddpos but will use nvim_buf_add_highlight if " available. This involves iterating over the position list, switching from " 1-based indexing to 0-based indexing, and translating the multiple ways " that position can be specified for matchaddpos into line + col_start + " col_end. function! s:matchaddpos(group, pos_list) abort if s:has_nvim_highlight for l:pos in a:pos_list let l:line = type(l:pos) == v:t_number \ ? l:pos - 1 \ : l:pos[0] - 1 if type(l:pos) == v:t_number || len(l:pos) == 1 let l:col_start = 0 let l:col_end = s:MAX_COL_SIZE else let l:col_start = l:pos[1] - 1 let l:col_end = l:col_start + get(l:pos, 2, 1) endif call ale#highlight#nvim_buf_add_highlight( \ bufnr(''), \ s:ns_id, \ a:group, \ l:line, \ l:col_start, \ l:col_end, \) endfor else call matchaddpos(a:group, a:pos_list) endif endfunction function! s:highlight_line(bufnr, lnum, group) abort call s:matchaddpos(a:group, [a:lnum]) endfunction function! s:highlight_range(bufnr, range, group) abort " Set all of the positions, which are chunked into Lists which " are as large as will be accepted by matchaddpos. call map( \ ale#highlight#CreatePositions( \ a:range.lnum, \ a:range.col, \ a:range.end_lnum, \ a:range.end_col \ ), \ 's:matchaddpos(a:group, v:val)' \) endfunction function! ale#highlight#UpdateHighlights() abort let l:item_list = get(b:, 'ale_enabled', 1) && g:ale_enabled \ ? get(b:, 'ale_highlight_items', []) \ : [] call ale#highlight#RemoveHighlights() for l:item in l:item_list if l:item.type is# 'W' if get(l:item, 'sub_type', '') is# 'style' let l:group = 'ALEStyleWarning' else let l:group = 'ALEWarning' endif elseif l:item.type is# 'I' let l:group = 'ALEInfo' elseif get(l:item, 'sub_type', '') is# 'style' let l:group = 'ALEStyleError' else let l:group = 'ALEError' endif let l:range = { \ 'lnum': l:item.lnum, \ 'col': l:item.col, \ 'end_lnum': get(l:item, 'end_lnum', l:item.lnum), \ 'end_col': get(l:item, 'end_col', l:item.col) \} call s:highlight_range(l:item.bufnr, l:range, l:group) endfor " If highlights are enabled and signs are not enabled, we should still " offer line highlights by adding a separate set of highlights. if !g:ale_set_signs let l:available_groups = { \ 'ALEWarningLine': hlexists('ALEWarningLine'), \ 'ALEInfoLine': hlexists('ALEInfoLine'), \ 'ALEErrorLine': hlexists('ALEErrorLine'), \} for l:item in l:item_list if l:item.type is# 'W' let l:group = 'ALEWarningLine' elseif l:item.type is# 'I' let l:group = 'ALEInfoLine' else let l:group = 'ALEErrorLine' endif if l:available_groups[l:group] call s:highlight_line(l:item.bufnr, l:item.lnum, l:group) endif endfor endif endfunction function! ale#highlight#BufferHidden(buffer) abort " Remove highlights right away when buffers are hidden. " They will be restored later when buffers are entered. call ale#highlight#RemoveHighlights() endfunction augroup ALEHighlightBufferGroup autocmd! autocmd BufEnter * call ale#highlight#UpdateHighlights() autocmd BufHidden * call ale#highlight#BufferHidden(expand('')) augroup END function! ale#highlight#SetHighlights(buffer, loclist) abort let l:new_list = getbufvar(a:buffer, 'ale_enabled', 1) && g:ale_enabled \ ? filter(copy(a:loclist), 'v:val.bufnr == a:buffer && v:val.col > 0') \ : [] " Set the list in the buffer variable. call setbufvar(str2nr(a:buffer), 'ale_highlight_items', l:new_list) let l:exclude_list = ale#Var(a:buffer, 'exclude_highlights') if !empty(l:exclude_list) call filter(l:new_list, 'empty(ale#util#GetMatches(v:val.text, l:exclude_list))') endif " Update highlights for the current buffer, which may or may not " be the buffer we just set highlights for. call ale#highlight#UpdateHighlights() endfunction ================================================ FILE: autoload/ale/history.vim ================================================ " Author: w0rp " Description: Tools for managing command history " A flag for controlling the maximum size of the command history to store. let g:ale_max_buffer_history_size = get(g:, 'ale_max_buffer_history_size', 20) " Return a shallow copy of the command history for a given buffer number. function! ale#history#Get(buffer) abort return copy(getbufvar(a:buffer, 'ale_history', [])) endfunction function! ale#history#Add(buffer, status, job_id, command) abort if g:ale_max_buffer_history_size <= 0 " Don't save anything if the history isn't a positive number. call setbufvar(a:buffer, 'ale_history', []) return endif let l:history = getbufvar(a:buffer, 'ale_history', []) " Remove the first item if we hit the max history size. if len(l:history) >= g:ale_max_buffer_history_size let l:history = l:history[1:] endif call add(l:history, { \ 'status': a:status, \ 'job_id': a:job_id, \ 'command': a:command, \}) call setbufvar(a:buffer, 'ale_history', l:history) endfunction function! s:FindHistoryItem(buffer, job_id) abort " Search backwards to find a matching job ID. IDs might be recycled, " so finding the last one should be good enough. for l:obj in reverse(ale#history#Get(a:buffer)) if l:obj.job_id == a:job_id return l:obj endif endfor return {} endfunction " Set an exit code for a command which finished. function! ale#history#SetExitCode(buffer, job_id, exit_code) abort let l:obj = s:FindHistoryItem(a:buffer, a:job_id) " If we find a match, then set the code and status. let l:obj.exit_code = a:exit_code let l:obj.status = 'finished' endfunction " Set the output for a command which finished. function! ale#history#RememberOutput(buffer, job_id, output) abort let l:obj = s:FindHistoryItem(a:buffer, a:job_id) let l:obj.output = a:output endfunction ================================================ FILE: autoload/ale/hover.vim ================================================ " Author: w0rp " Description: Hover support for LSP linters. let s:hover_map = {} " Used to get the hover map in tests. function! ale#hover#GetMap() abort return deepcopy(s:hover_map) endfunction " Used to set the hover map in tests. function! ale#hover#SetMap(map) abort let s:hover_map = a:map endfunction function! ale#hover#ClearLSPData() abort let s:hover_map = {} endfunction function! ale#hover#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') is# 'quickinfo' \&& has_key(s:hover_map, a:response.request_seq) let l:options = remove(s:hover_map, a:response.request_seq) if get(a:response, 'success', v:false) is v:true \&& get(a:response, 'body', v:null) isnot v:null let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons') " If we pass the show_documentation flag, we should show the full " documentation, and always in the preview window. if get(l:options, 'show_documentation', 0) let l:documentation = get(a:response.body, 'documentation', '') " displayString is not included here, because it can be very " noisy and run on for many lines for complex types. A less " verbose alternative may be nice in future. if !empty(l:documentation) call ale#preview#Show(split(l:documentation, "\n"), { \ 'filetype': 'ale-preview.message', \ 'stay_here': 1, \}) endif elseif get(l:options, 'hover_from_balloonexpr', 0) \&& exists('*balloon_show') \&& (l:set_balloons is 1 || l:set_balloons is# 'hover') call balloon_show(a:response.body.displayString) elseif get(l:options, 'truncated_echo', 0) if !empty(a:response.body.displayString) call ale#cursor#TruncatedEcho(a:response.body.displayString) endif elseif g:ale_hover_to_floating_preview || g:ale_floating_preview call ale#floating_preview#Show(split(a:response.body.displayString, "\n"), { \ 'filetype': 'ale-preview.message', \}) elseif g:ale_hover_to_preview call ale#preview#Show(split(a:response.body.displayString, "\n"), { \ 'filetype': 'ale-preview.message', \ 'stay_here': 1, \}) else call ale#util#ShowMessage(a:response.body.displayString) endif endif endif endfunction " Convert a language name to another one. " The language name could be an empty string or v:null function! s:ConvertLanguageName(language) abort return a:language endfunction " Cache syntax file (non-)existence to avoid calling globpath repeatedly. let s:syntax_file_exists_cache = {} function! s:SyntaxFileExists(syntax_file) abort if !has_key(s:syntax_file_exists_cache, a:syntax_file) let s:syntax_file_exists_cache[a:syntax_file] = \ !empty(globpath(&runtimepath, a:syntax_file)) endif return s:syntax_file_exists_cache[a:syntax_file] endfunction function! ale#hover#ParseLSPResult(contents) abort let l:includes = {} let l:highlights = [] let l:lines = [] let l:list = type(a:contents) is v:t_list ? a:contents : [a:contents] let l:region_index = 0 for l:item in l:list if !empty(l:lines) call add(l:lines, '') endif if type(l:item) is v:t_dict && has_key(l:item, 'kind') if l:item.kind is# 'markdown' " Handle markdown values as we handle strings below. let l:item = get(l:item, 'value', '') elseif l:item.kind is# 'plaintext' " We shouldn't try to parse plaintext as markdown. " Pass the lines on and skip parsing them. call extend(l:lines, split(get(l:item, 'value', ''), "\n")) continue endif endif let l:marked_list = [] " If the item is a string, then we should parse it as Markdown text. if type(l:item) is v:t_string let l:fence_language = v:null let l:fence_lines = [] for l:line in split(l:item, "\n") if l:fence_language is v:null " Look for the start of a code fence. (```python, etc.) let l:match = matchlist(l:line, '^``` *\([^ ]\+\)\? *$') if !empty(l:match) let l:fence_language = len(l:match) > 1 ? l:match[1] : 'text' if !empty(l:marked_list) call add(l:fence_lines, '') endif else if !empty(l:marked_list) \&& l:marked_list[-1][0] isnot v:null call add(l:marked_list, [v:null, ['']]) endif call add(l:marked_list, [v:null, [l:line]]) endif elseif l:line =~# '^```$' " When we hit the end of a code fence, pass the fenced " lines on to the next steps below. call add(l:marked_list, [l:fence_language, l:fence_lines]) let l:fence_language = v:null let l:fence_lines = [] else " Gather lines inside of a code fence. call add(l:fence_lines, l:line) endif endfor " If the result from the LSP server is a {language: ..., value: ...} " Dictionary, then that should be interpreted as if it was: " " ```${language} " ${value} " ``` elseif type(l:item) is v:t_dict \&& has_key(l:item, 'language') \&& type(l:item.language) is v:t_string \&& has_key(l:item, 'value') \&& type(l:item.value) is v:t_string call add( \ l:marked_list, \ [l:item.language, split(l:item.value, "\n")], \) endif for [l:language, l:marked_lines] in l:marked_list if l:language is v:null " NOTE: We could handle other Markdown formatting here. call map( \ l:marked_lines, \ 'substitute(v:val, ''\\_'', ''_'', ''g'')', \) else let l:language = s:ConvertLanguageName(l:language) if !empty(l:language) let l:syntax_file = printf('syntax/%s.vim', l:language) if s:SyntaxFileExists(l:syntax_file) let l:includes[l:language] = l:syntax_file endif let l:start = len(l:lines) + 1 let l:end = l:start + len(l:marked_lines) let l:region_index += 1 call add(l:highlights, 'syntax region' \ . ' ALE_hover_' . l:region_index \ . ' start=/\%' . l:start . 'l/' \ . ' end=/\%' . l:end . 'l/' \ . ' contains=@ALE_hover_' . l:language \) endif endif call extend(l:lines, l:marked_lines) endfor endfor let l:include_commands = [] for [l:language, l:lang_path] in sort(items(l:includes)) call add(l:include_commands, 'unlet! b:current_syntax') call add( \ l:include_commands, \ printf('syntax include @ALE_hover_%s %s', l:language, l:lang_path), \) endfor return [l:include_commands + l:highlights, l:lines] endfunction function! ale#hover#HandleLSPResponse(conn_id, response) abort if has_key(a:response, 'id') \&& has_key(s:hover_map, a:response.id) let l:options = remove(s:hover_map, a:response.id) " If the call did __not__ come from balloonexpr... if !get(l:options, 'hover_from_balloonexpr', 0) let l:buffer = bufnr('') let [l:line, l:column] = getpos('.')[1:2] let l:end = len(getline(l:line)) if l:buffer isnot l:options.buffer \|| l:line isnot l:options.line \|| min([l:column, l:end]) isnot min([l:options.column, l:end]) " ... Cancel display the message if the cursor has moved. return endif endif " The result can be a Dictionary item, a List of the same, or null. let l:result = get(a:response, 'result', v:null) if l:result is v:null return endif let [l:commands, l:lines] = ale#hover#ParseLSPResult(l:result.contents) if !empty(l:lines) let l:set_balloons = ale#Var(l:options.buffer, 'set_balloons') if get(l:options, 'hover_from_balloonexpr', 0) \&& exists('*balloon_show') \&& (l:set_balloons is 1 || l:set_balloons is# 'hover') call balloon_show(join(l:lines, "\n")) elseif get(l:options, 'truncated_echo', 0) if type(l:lines[0]) is# v:t_list call ale#cursor#TruncatedEcho(join(l:lines[0], '\n')) else call ale#cursor#TruncatedEcho(l:lines[0]) endif elseif g:ale_hover_to_floating_preview || g:ale_floating_preview call ale#floating_preview#Show(l:lines, { \ 'filetype': 'ale-preview.message', \ 'commands': l:commands, \}) elseif g:ale_hover_to_preview call ale#preview#Show(l:lines, { \ 'filetype': 'ale-preview.message', \ 'stay_here': 1, \ 'commands': l:commands, \}) else call ale#util#ShowMessage(join(l:lines, "\n"), { \ 'commands': l:commands, \}) endif endif endif endfunction function! s:OnReady(line, column, opt, linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'hover') return endif let l:buffer = a:lsp_details.buffer 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 = max([ \ min([a:column, len(getbufline(l:buffer, a:line)[0])]), \ 1, \]) 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), \ 'show_documentation': get(a:opt, 'show_documentation', 0), \ 'truncated_echo': get(a:opt, 'truncated_echo', 0), \} endfunction " Obtain Hover information for the specified position " Pass optional arguments in the dictionary opt. " Currently, only one key/value is useful: " - called_from_balloonexpr, this flag marks if we want the result from this " ale#hover#Show to display in a balloon if possible " " Currently, the callbacks displays the info from hover : " - in the balloon if opt.called_from_balloonexpr and balloon_show is detected " - as status message otherwise function! ale#hover#Show(buffer, line, col, opt) abort let l:show_documentation = get(a:opt, 'show_documentation', 0) let l:Callback = function('s:OnReady', [a:line, a:col, a:opt]) for l:linter in ale#lsp_linter#GetEnabled(a:buffer) " Only tsserver supports documentation requests at the moment. if !l:show_documentation || l:linter.lsp is# 'tsserver' call ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback) endif endfor endfunction let s:last_pos = [0, 0, 0] " This function implements the :ALEHover command. function! ale#hover#ShowAtCursor() abort let l:buffer = bufnr('') let l:pos = getpos('.') call ale#hover#Show(l:buffer, l:pos[1], l:pos[2], {}) endfunction function! ale#hover#ShowTruncatedMessageAtCursor() abort let l:buffer = bufnr('') let l:pos = getpos('.')[0:2] if !getbufvar(l:buffer, 'ale_enabled', 1) return endif if l:pos != s:last_pos let s:last_pos = l:pos let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer) if empty(l:loc) call ale#hover#Show( \ l:buffer, \ l:pos[1], \ l:pos[2], \ {'truncated_echo': 1}, \) endif endif endfunction " This function implements the :ALEDocumentation command. function! ale#hover#ShowDocumentationAtCursor() abort let l:buffer = bufnr('') let l:pos = getpos('.') let l:options = {'show_documentation': 1} call ale#hover#Show(l:buffer, l:pos[1], l:pos[2], l:options) endfunction ================================================ FILE: autoload/ale/java.vim ================================================ " 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 assume 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 let l:ant_root = ale#ant#FindProjectRoot(a:buffer) if !empty(l:ant_root) return l:ant_root endif return '' endfunction ================================================ FILE: autoload/ale/job.vim ================================================ " Author: w0rp " Description: APIs for working with Asynchronous jobs, with an API normalised " between Vim 8 and NeoVim. " " Important functions are described below. They are: " " ale#job#Start(command, options) -> job_id " ale#job#IsRunning(job_id) -> 1 if running, 0 otherwise. " ale#job#Stop(job_id) " A setting for wrapping commands. let g:ale_command_wrapper = get(g:, 'ale_command_wrapper', '') if !has_key(s:, 'job_map') let s:job_map = {} endif " A map from timer IDs to jobs, for tracking jobs that need to be killed " with SIGKILL if they don't terminate right away. if !has_key(s:, 'job_kill_timers') let s:job_kill_timers = {} endif function! s:KillHandler(timer) abort let l:job = remove(s:job_kill_timers, a:timer) call job_stop(l:job, 'kill') endfunction function! s:NeoVimCallback(job, data, event) abort let l:info = s:job_map[a:job] if a:event is# 'stdout' let l:info.out_cb_line = ale#util#JoinNeovimOutput( \ a:job, \ l:info.out_cb_line, \ a:data, \ l:info.mode, \ ale#util#GetFunction(l:info.out_cb), \) elseif a:event is# 'stderr' let l:info.err_cb_line = ale#util#JoinNeovimOutput( \ a:job, \ l:info.err_cb_line, \ a:data, \ l:info.mode, \ ale#util#GetFunction(l:info.err_cb), \) else if has_key(l:info, 'out_cb') && !empty(l:info.out_cb_line) call ale#util#GetFunction(l:info.out_cb)(a:job, l:info.out_cb_line) endif if has_key(l:info, 'err_cb') && !empty(l:info.err_cb_line) call ale#util#GetFunction(l:info.err_cb)(a:job, l:info.err_cb_line) endif try call ale#util#GetFunction(l:info.exit_cb)(a:job, a:data) finally " Automatically forget about the job after it's done. if has_key(s:job_map, a:job) call remove(s:job_map, a:job) endif endtry endif endfunction function! s:VimOutputCallback(channel, data) abort let l:job = ch_getjob(a:channel) let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) " Only call the callbacks for jobs which are valid. if l:job_id > 0 && has_key(s:job_map, l:job_id) call ale#util#GetFunction(s:job_map[l:job_id].out_cb)(l:job_id, a:data) endif endfunction function! s:VimErrorCallback(channel, data) abort let l:job = ch_getjob(a:channel) let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) " Only call the callbacks for jobs which are valid. if l:job_id > 0 && has_key(s:job_map, l:job_id) call ale#util#GetFunction(s:job_map[l:job_id].err_cb)(l:job_id, a:data) endif endfunction function! s:VimCloseCallback(channel) abort let l:job = ch_getjob(a:channel) let l:job_id = ale#job#ParseVim8ProcessID(string(l:job)) let l:info = get(s:job_map, l:job_id, {}) if empty(l:info) return endif " job_status() can trigger the exit handler. " The channel can close before the job has exited. if job_status(l:job) is# 'dead' try if !empty(l:info) && has_key(l:info, 'exit_cb') " We have to remove the callback, so we don't call it twice. call ale#util#GetFunction(remove(l:info, 'exit_cb'))(l:job_id, get(l:info, 'exit_code', 1)) endif finally " Automatically forget about the job after it's done. if has_key(s:job_map, l:job_id) call remove(s:job_map, l:job_id) endif endtry endif endfunction function! s:VimExitCallback(job, exit_code) abort let l:job_id = ale#job#ParseVim8ProcessID(string(a:job)) let l:info = get(s:job_map, l:job_id, {}) if empty(l:info) return endif let l:info.exit_code = a:exit_code " The program can exit before the data has finished being read. if ch_status(job_getchannel(a:job)) is# 'closed' try if !empty(l:info) && has_key(l:info, 'exit_cb') " We have to remove the callback, so we don't call it twice. call ale#util#GetFunction(remove(l:info, 'exit_cb'))(l:job_id, a:exit_code) endif finally " Automatically forget about the job after it's done. if has_key(s:job_map, l:job_id) call remove(s:job_map, l:job_id) endif endtry endif endfunction function! ale#job#ParseVim8ProcessID(job_string) abort return matchstr(a:job_string, '\d\+') + 0 endfunction function! ale#job#ValidateArguments(command, options) abort if a:options.mode isnot# 'nl' && a:options.mode isnot# 'raw' throw 'Invalid mode: ' . a:options.mode endif endfunction function! s:PrepareWrappedCommand(original_wrapper, command) abort let l:match = matchlist(a:command, '\v^(.*(\&\&|;)) *(.*)$') let l:prefix = '' let l:command = a:command if !empty(l:match) let l:prefix = l:match[1] . ' ' let l:command = l:match[3] endif let l:format = a:original_wrapper if l:format =~# '%@' let l:wrapped = substitute(l:format, '%@', ale#Escape(l:command), '') else if l:format !~# '%\*' let l:format .= ' %*' endif let l:wrapped = substitute(l:format, '%\*', l:command, '') endif return l:prefix . l:wrapped endfunction function! ale#job#PrepareCommand(buffer, command) abort let l:wrapper = ale#Var(a:buffer, 'command_wrapper') " The command will be executed in a subshell. This fixes a number of " issues, including reading the PATH variables correctly, %PATHEXT% " expansion on Windows, etc. " " NeoVim handles this issue automatically if the command is a String, " but we'll do this explicitly, so we use the same exact command for both " versions. let l:command = !empty(l:wrapper) \ ? s:PrepareWrappedCommand(l:wrapper, a:command) \ : a:command " If a custom shell is specified, use that. if exists('b:ale_shell') let l:ale_shell = b:ale_shell elseif exists('g:ale_shell') let l:ale_shell = g:ale_shell endif if exists('l:ale_shell') let l:shell_arguments = get(b:, 'ale_shell_arguments', get(g:, 'ale_shell_arguments', &shellcmdflag)) return split(l:ale_shell) + split(l:shell_arguments) + [l:command] endif if has('win32') return 'cmd /s/c "' . l:command . '"' endif if &shell =~? 'fish$\|pwsh$' return ['/bin/sh', '-c', l:command] endif return split(&shell) + split(&shellcmdflag) + [l:command] endfunction " Start a job with options which are agnostic to Vim and NeoVim. " " The following options are accepted: " " out_cb - A callback for receiving stdin. Arguments: (job_id, data) " err_cb - A callback for receiving stderr. Arguments: (job_id, data) " exit_cb - A callback for program exit. Arguments: (job_id, status_code) " mode - A mode for I/O. Can be 'nl' for split lines or 'raw'. function! ale#job#Start(command, options) abort call ale#job#ValidateArguments(a:command, a:options) let l:job_info = copy(a:options) let l:job_options = {} if has('nvim') if has_key(a:options, 'out_cb') let l:job_options.on_stdout = function('s:NeoVimCallback') let l:job_info.out_cb_line = '' endif if has_key(a:options, 'err_cb') let l:job_options.on_stderr = function('s:NeoVimCallback') let l:job_info.err_cb_line = '' endif if has_key(a:options, 'exit_cb') let l:job_options.on_exit = function('s:NeoVimCallback') endif let l:job_info.job = jobstart(a:command, l:job_options) let l:job_id = l:job_info.job else let l:job_options = { \ 'in_mode': l:job_info.mode, \ 'out_mode': l:job_info.mode, \ 'err_mode': l:job_info.mode, \} if has_key(a:options, 'out_cb') let l:job_options.out_cb = function('s:VimOutputCallback') else " prevent buffering of output and excessive polling in case close_cb is set let l:job_options.out_cb = {->0} endif if has_key(a:options, 'err_cb') let l:job_options.err_cb = function('s:VimErrorCallback') else " prevent buffering of output and excessive polling in case close_cb is set let l:job_options.err_cb = {->0} endif if has_key(a:options, 'exit_cb') " Set a close callback to which simply calls job_status() " when the channel is closed, which can trigger the exit callback " earlier on. let l:job_options.close_cb = function('s:VimCloseCallback') 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)) endif if l:job_id > 0 " Store the job in the map for later only if we can get the ID. let s:job_map[l:job_id] = l:job_info endif return l:job_id endfunction " Force running commands in a Windows CMD command line. " This means the same command syntax works everywhere. function! ale#job#StartWithCmd(command, options) abort let l:shell = &l:shell let l:shellcmdflag = &l:shellcmdflag let &l:shell = 'cmd' let &l:shellcmdflag = '/c' try let l:job_id = ale#job#Start(a:command, a:options) finally let &l:shell = l:shell let &l:shellcmdflag = l:shellcmdflag endtry return l:job_id endfunction " Send raw data to the job. function! ale#job#SendRaw(job_id, string) abort if has('nvim') call jobsend(a:job_id, a:string) else let l:job = s:job_map[a:job_id].job if ch_status(l:job) is# 'open' call ch_sendraw(job_getchannel(l:job), a:string) endif endif endfunction " Given a job ID, return 1 if the job is currently running. " Invalid job IDs will be ignored. function! ale#job#IsRunning(job_id) abort if has('nvim') 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 return 0 endfunction function! ale#job#HasOpenChannel(job_id) abort if ale#job#IsRunning(a:job_id) if has('nvim') " TODO: Implement a check for NeoVim. return 1 endif " Check if the Job's channel can be written to. return ch_status(s:job_map[a:job_id].job) is# 'open' endif return 0 endfunction " Given a Job ID, stop that job. " Invalid job IDs will be ignored. function! ale#job#Stop(job_id) abort if !has_key(s:job_map, a:job_id) return endif if has('nvim') " FIXME: NeoVim kills jobs on a timer, but will not kill any processes " which are child processes on Unix. Some work needs to be done to " kill child processes to stop long-running processes like pylint. silent! call jobstop(a:job_id) else let l:job = s:job_map[a:job_id].job " We must close the channel for reading the buffer if it is open " when stopping a job. Otherwise, we will get errors in the status line. if ch_status(job_getchannel(l:job)) is# 'open' call ch_close_in(job_getchannel(l:job)) endif " Ask nicely for the job to stop. call job_stop(l:job) if ale#job#IsRunning(l:job) " Set a 100ms delay for killing the job with SIGKILL. let s:job_kill_timers[timer_start(100, function('s:KillHandler'))] = l:job endif endif endfunction ================================================ FILE: autoload/ale/julia.vim ================================================ " 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 ================================================ FILE: autoload/ale/linter.vim ================================================ " Author: w0rp " Description: Linter registration and lazy-loading " Retrieves linters as requested by the engine, loading them if needed. let s:runtime_loaded_map = {} let s:linters = {} " Default filetype aliases. " The user defined aliases will be merged with this Dictionary. " " NOTE: Update the g:ale_linter_aliases documentation when modifying this. let s:default_ale_linter_aliases = { \ 'Dockerfile': 'dockerfile', \ 'bash': 'sh', \ 'csh': 'sh', \ 'javascriptreact': ['javascript', 'jsx'], \ 'plaintex': 'tex', \ 'ps1': 'powershell', \ 'rmarkdown': 'r', \ 'rmd': 'r', \ 'systemverilog': 'verilog', \ 'typescriptreact': ['typescript', 'tsx'], \ 'vader': ['vim', 'vader'], \ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'], \ 'vimwiki': 'markdown', \ 'vue': ['vue', 'javascript'], \ 'xsd': ['xsd', 'xml'], \ 'xslt': ['xslt', 'xml'], \ 'zsh': 'sh', \} " Default linters to run for particular filetypes. " The user defined linter selections will be merged with this Dictionary. " " No linters are used for plaintext files by default. " " Only cargo and rls are 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 = { \ 'apkbuild': ['apkbuild_lint', 'secfixes_check'], \ 'astro': ['eslint'], \ 'csh': ['shell'], \ 'elixir': ['credo', 'dialyxir', 'dogma'], \ 'go': ['gofmt', 'golangci-lint', 'gopls', 'govet'], \ 'groovy': ['npm-groovy-lint'], \ 'hack': ['hack'], \ 'help': [], \ 'inko': ['inko'], \ 'json': ['biome', 'jsonlint', 'spectral', 'vscodejson'], \ 'json5': [], \ 'jsonc': ['biome'], \ 'perl': ['perlcritic'], \ 'perl6': [], \ 'python': ['flake8', 'mypy', 'pylint', 'pyright', 'ruff'], \ 'rust': ['analyzer', 'cargo'], \ 'spec': [], \ 'text': [], \ 'vader': ['vimls'], \ 'vue': ['eslint', 'vls'], \ 'zsh': ['shell'], \ 'v': ['v'], \ 'yaml': ['actionlint', 'spectral', 'yaml-language-server', 'yamllint'], \} " Testing/debugging helper to unload all linters. function! ale#linter#Reset() abort let s:runtime_loaded_map = {} let s:linters = {} endfunction " Return a reference to the linters loaded. " This is only for tests. " Do not call this function. function! ale#linter#GetLintersLoaded() abort " This command will throw from the sandbox. let &l:equalprg=&l:equalprg return s:linters endfunction function! s:IsCallback(value) abort 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) is v:t_number && (a:value == 0 || a:value == 1) endfunction function! ale#linter#PreProcess(filetype, linter) abort if type(a:linter) isnot v:t_dict throw 'The linter object must be a Dictionary' endif let l:obj = { \ 'name': get(a:linter, 'name'), \ 'lsp': get(a:linter, 'lsp', ''), \} if type(l:obj.name) isnot v:t_string throw '`name` must be defined to name the linter' endif let l:needs_address = l:obj.lsp is# 'socket' let l:needs_executable = l:obj.lsp isnot# 'socket' let l:needs_command = l:obj.lsp isnot# 'socket' let l:needs_lsp_details = !empty(l:obj.lsp) if empty(l:obj.lsp) let l:obj.callback = get(a:linter, 'callback') if !s:IsCallback(l:obj.callback) throw '`callback` must be defined with a callback to accept output' endif endif if index(['', 'socket', 'stdio', 'tsserver'], l:obj.lsp) < 0 throw '`lsp` must be either `''lsp''`, `''stdio''`, `''socket''` or `''tsserver''` if defined' endif if !l:needs_executable if has_key(a:linter, 'executable') throw '`executable` cannot be used when lsp == ''socket''' endif elseif has_key(a:linter, 'executable') let l:obj.executable = a:linter.executable if type(l:obj.executable) isnot v:t_string \&& type(l:obj.executable) isnot v:t_func throw '`executable` must be a String or Function if defined' endif else throw '`executable` must be defined' endif if !l:needs_command if has_key(a:linter, 'command') throw '`command` cannot be used when lsp == ''socket''' endif elseif has_key(a:linter, 'command') let l:obj.command = a:linter.command if type(l:obj.command) isnot v:t_string \&& type(l:obj.command) isnot v:t_func throw '`command` must be a String or Function if defined' endif else throw '`command` must be defined' endif if !l:needs_address if has_key(a:linter, 'address') throw '`address` cannot be used when lsp != ''socket''' endif elseif has_key(a:linter, 'address') if type(a:linter.address) isnot v:t_string \&& type(a:linter.address) isnot v:t_func throw '`address` must be a String or Function if defined' endif let l:obj.address = a:linter.address if has_key(a:linter, 'cwd') throw '`cwd` makes no sense for socket LSP connections' endif else throw '`address` must be defined for getting the LSP address' endif if has_key(a:linter, 'cwd') let l:obj.cwd = a:linter.cwd if type(l:obj.cwd) isnot v:t_string \&& type(l:obj.cwd) isnot v:t_func throw '`cwd` must be a String or Function if defined' endif endif if l:needs_lsp_details " Default to using the filetype as the language. let l:obj.language = get(a:linter, 'language', a:filetype) if type(l:obj.language) isnot v:t_string \&& type(l:obj.language) isnot v:t_func throw '`language` must be a String or Function if defined' endif if has_key(a:linter, 'project_root') let l:obj.project_root = a:linter.project_root if type(l:obj.project_root) isnot v:t_string \&& type(l:obj.project_root) isnot v:t_func throw '`project_root` must be a String or Function' endif else throw '`project_root` must be defined for LSP linters' endif if has_key(a:linter, 'completion_filter') let l:obj.completion_filter = a:linter.completion_filter if !s:IsCallback(l:obj.completion_filter) throw '`completion_filter` must be a callback' endif endif if has_key(a:linter, 'initialization_options') let l:obj.initialization_options = a:linter.initialization_options if type(l:obj.initialization_options) isnot v:t_dict \&& type(l:obj.initialization_options) isnot v:t_func throw '`initialization_options` must be a Dictionary or Function if defined' endif endif if has_key(a:linter, 'lsp_config') if type(a:linter.lsp_config) isnot v:t_dict \&& type(a:linter.lsp_config) isnot v:t_func throw '`lsp_config` must be a Dictionary or Function if defined' endif let l:obj.lsp_config = a:linter.lsp_config endif endif let l:obj.output_stream = get(a:linter, 'output_stream', 'stdout') 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 " An option indicating that this linter should only be run against the " file on disk. let l:obj.lint_file = get(a:linter, 'lint_file', 0) if !s:IsBoolean(l:obj.lint_file) && type(l:obj.lint_file) isnot v:t_func throw '`lint_file` must be `0`, `1`, or a Function' endif " An option indicating that the buffer should be read. let l:obj.read_buffer = get(a:linter, 'read_buffer', 1) if !s:IsBoolean(l:obj.read_buffer) throw '`read_buffer` must be `0` or `1`' endif let l:obj.aliases = get(a:linter, 'aliases', []) 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 return l:obj endfunction function! ale#linter#Define(filetype, linter) abort " This command will throw from the sandbox. let &l:equalprg=&l:equalprg let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter) if !has_key(s:linters, a:filetype) let s:linters[a:filetype] = [] endif " Remove previously defined linters with the same name. call filter(s:linters[a:filetype], 'v:val.name isnot# a:linter.name') call add(s:linters[a:filetype], l:new_linter) endfunction " Prevent any linters from being loaded for a given filetype. function! ale#linter#PreventLoading(filetype) abort let s:runtime_loaded_map[a:filetype] = 1 endfunction function! ale#linter#GetAll(filetypes) abort " Don't return linters in the sandbox. " Otherwise a sandboxed script could modify them. if ale#util#InSandbox() return [] endif let l:combined_linters = [] for l:filetype in a:filetypes " Load linters from runtimepath if we haven't done that yet. if !has_key(s:runtime_loaded_map, l:filetype) execute 'silent! runtime! ale_linters/' . l:filetype . '/*.vim' let s:runtime_loaded_map[l:filetype] = 1 endif call extend(l:combined_linters, get(s:linters, l:filetype, [])) endfor return l:combined_linters 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 or String. if type(l:buffer_aliases) is v:t_list \|| type(l:buffer_aliases) is v:t_string return l:buffer_aliases endif " Check for aliased filetypes first in a buffer variable, " then the global variable, " then in the default mapping, " otherwise use the original filetype. for l:dict in [ \ l:buffer_aliases, \ g:ale_linter_aliases, \ s:default_ale_linter_aliases, \] if has_key(l:dict, a:original_filetype) return l:dict[a:original_filetype] endif endfor return a:original_filetype endfunction function! ale#linter#ResolveFiletype(original_filetype) abort let l:filetype = s:GetAliasedFiletype(a:original_filetype) if type(l:filetype) isnot v:t_list return [l:filetype] endif return l:filetype endfunction function! s:GetLinterNames(original_filetype) abort let l:buffer_ale_linters = get(b:, 'ale_linters', {}) " b:ale_linters can be set to 'all' if l:buffer_ale_linters is# 'all' return 'all' endif " b:ale_linters can be set to a List. if type(l:buffer_ale_linters) is v:t_list return l:buffer_ale_linters endif " Try to get a buffer-local setting for the filetype if has_key(l:buffer_ale_linters, a:original_filetype) return l:buffer_ale_linters[a:original_filetype] endif " Try to get a global setting for the filetype if has_key(g:ale_linters, a:original_filetype) return g:ale_linters[a:original_filetype] endif " If the user has configured ALE to only enable linters explicitly, then " don't enable any linters by default. if g:ale_linters_explicit return [] endif " Try to get a default setting for the filetype if has_key(s:default_ale_linters, a:original_filetype) return s:default_ale_linters[a:original_filetype] endif return 'all' endfunction function! ale#linter#Get(original_filetypes) abort let l:possibly_duplicated_linters = [] " Handle dot-separated filetypes. for l:original_filetype in split(a:original_filetypes, '\.') let l:filetype = ale#linter#ResolveFiletype(l:original_filetype) let l:linter_names = s:GetLinterNames(l:original_filetype) let l:all_linters = ale#linter#GetAll(l:filetype) let l:filetype_linters = [] 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) 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 for l:name in l:name_list if index(l:linter_names, l:name) >= 0 call add(l:filetype_linters, l:linter) break endif endfor endfor endif call extend(l:possibly_duplicated_linters, l:filetype_linters) endfor let l:name_list = [] let l:combined_linters = [] " Make sure we override linters so we don't get two with the same name, " like 'eslint' for both 'javascript' and 'typescript' " " Note that the reverse calls here modify the List variables. for l:linter in reverse(l:possibly_duplicated_linters) if index(l:name_list, l:linter.name) < 0 call add(l:name_list, l:linter.name) call add(l:combined_linters, l:linter) endif endfor return reverse(l:combined_linters) endfunction " Given a buffer and linter, get the executable String for the linter. function! ale#linter#GetExecutable(buffer, linter) abort let l:Executable = a:linter.executable return type(l:Executable) is v:t_func \ ? l:Executable(a:buffer) \ : l:Executable endfunction function! ale#linter#GetCwd(buffer, linter) abort let l:Cwd = get(a:linter, 'cwd', v:null) return type(l:Cwd) is v:t_func ? l:Cwd(a:buffer) : l:Cwd endfunction " Given a buffer and linter, get the command String for the linter. function! ale#linter#GetCommand(buffer, linter) abort let l:Command = a:linter.command return type(l:Command) is v:t_func ? l:Command(a:buffer) : l:Command endfunction " Given a buffer and linter, get the address for connecting to the server. function! ale#linter#GetAddress(buffer, linter) abort let l:Address = a:linter.address return type(l:Address) is v:t_func ? l:Address(a:buffer) : l:Address endfunction ================================================ FILE: autoload/ale/list.vim ================================================ " Author: Bjorn Neergaard , modified by Yann fery " Description: Manages the loclist and quickfix lists " This flag dictates if ale open the configured loclist let g:ale_open_list = get(g:, 'ale_open_list', v:false) " This flag dictates if ale keeps open loclist even if there is no error in loclist let g:ale_keep_list_window_open = get(g:, 'ale_keep_list_window_open', 0) " This flag dictates that quickfix windows should be opened vertically let g:ale_list_vertical = get(g:, 'ale_list_vertical', v:false) " The window size to set for the quickfix and loclist windows let g:ale_list_window_size = get(g:, 'ale_list_window_size', 10) " A string format for the loclist messages. let g:ale_loclist_msg_format = get(g:, 'ale_loclist_msg_format', \ get(g:, 'ale_echo_msg_format', '%code: %%s') \) if !exists('s:timer_args') let s:timer_args = {} endif " Return 1 if there is a buffer with buftype == 'quickfix' in buffer list function! ale#list#IsQuickfixOpen() abort let l:res = getqflist({ 'winid' : winnr() }) if has_key(l:res, 'winid') && l:res.winid > 0 return 1 endif let l:res = getloclist(0, { 'winid' : winnr() }) if has_key(l:res, 'winid') && l:res.winid > 0 return 1 endif return 0 endfunction " Check if we should open the list, based on the save event being fired, and " that setting being on, or that the error count is at least as high as the " setting when set to an integer value. function! s:ShouldOpen(buffer, loclist_len) abort let l:val = ale#Var(a:buffer, 'open_list') let l:saved = getbufvar(a:buffer, 'ale_save_event_fired', 0) return l:val > 0 ? a:loclist_len >= l:val : l:val is# 'on_save' && l:saved endfunction " Check if we should close the list, based on the save event being fired, and " that setting being on, or the setting just being set to an integer value. function! s:ShouldClose(buffer) abort let l:val = ale#Var(a:buffer, 'open_list') let l:saved = getbufvar(a:buffer, 'ale_save_event_fired', 0) return !((l:val >= 1) || (l:val is# 'on_save' && l:saved)) endfunction function! s:Deduplicate(list) abort let l:list = a:list call sort(l:list, function('ale#util#LocItemCompareWithText')) call uniq(l:list, function('ale#util#LocItemCompareWithText')) return l:list endfunction function! ale#list#GetCombinedList() abort let l:list = [] for l:info in values(g:ale_buffer_info) call extend(l:list, l:info.loclist) endfor return s:Deduplicate(l:list) endfunction function! s:FixList(buffer, list) abort let l:format = ale#Var(a:buffer, 'loclist_msg_format') let l:new_list = [] for l:item in a:list let l:fixed_item = copy(l:item) let l:fixed_item.text = ale#GetLocItemMessage(l:item, l:format) if l:item.bufnr == -1 " If the buffer number is invalid, remove it. call remove(l:fixed_item, 'bufnr') endif call add(l:new_list, l:fixed_item) endfor return l:new_list endfunction function! s:WinFindBuf(buffer) abort return exists('*win_findbuf') ? win_findbuf(str2nr(a:buffer)) : [0] endfunction function! s:SetListsImpl(timer_id, buffer, loclist) abort let l:title = expand('#' . a:buffer . ':p') if g:ale_set_quickfix let l:quickfix_list = ale#list#GetCombinedList() if has('nvim') call setqflist(s:FixList(a:buffer, l:quickfix_list), ' ', l:title) else call setqflist(s:FixList(a:buffer, l:quickfix_list)) call setqflist([], 'r', {'title': l:title}) endif elseif g:ale_set_loclist " If windows support is off, win_findbuf() may not exist. " We'll set result in the current window, which might not be correct, " but it's better than nothing. let l:ids = s:WinFindBuf(a:buffer) let l:loclist = s:Deduplicate(a:loclist) for l:id in l:ids if has('nvim') call setloclist(l:id, s:FixList(a:buffer, l:loclist), ' ', l:title) else call setloclist(l:id, s:FixList(a:buffer, l:loclist)) call setloclist(l:id, [], 'r', {'title': l:title}) endif endfor endif " Save the current view before opening/closing any window call setbufvar(a:buffer, 'ale_winview', winsaveview()) " Open a window to show the problems if we need to. " " ShouldOpen() checks if the current buffer has enough problems to be " opened. if s:ShouldOpen(a:buffer, len(a:loclist)) let l:winnr = winnr() let l:mode = mode() " open windows vertically instead of default horizontally let l:open_type = '' if ale#Var(a:buffer, 'list_vertical') == 1 let l:open_type = 'vert rightbelow ' endif if g:ale_set_quickfix if !ale#list#IsQuickfixOpen() silent! execute l:open_type . 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) endif elseif g:ale_set_loclist silent! execute l:open_type . 'lopen ' . str2nr(ale#Var(a:buffer, 'list_window_size')) endif " If focus changed, restore it (jump to the last window). if l:winnr isnot# winnr() wincmd p endif " Return to original mode when applicable if mode() != l:mode if l:mode is? 'v' || l:mode is# "\" " Reset our last visual selection normal! gv elseif l:mode is? 's' || l:mode is# "\" " Reset our last character selection normal! "\" endif endif call s:RestoreViewIfNeeded(a:buffer) endif " If ALE isn't currently checking for more problems, close the window if " needed now. This check happens inside of this timer function, so " the window can be closed reliably. if !ale#engine#IsCheckingBuffer(a:buffer) call s:CloseWindowIfNeeded(a:buffer) endif endfunction " Try to restore the window view after closing any of the lists to avoid making " the it moving around, especially useful when on insert mode function! s:RestoreViewIfNeeded(buffer) abort let l:saved_view = getbufvar(a:buffer, 'ale_winview', {}) " Saved view is empty, can't do anything if empty(l:saved_view) return endif " Check whether the cursor has moved since linting was actually requested. If " the user has indeed moved lines, do nothing let l:current_view = winsaveview() if l:current_view['lnum'] != l:saved_view['lnum'] return endif " Anchor view by topline if the list is set to open horizontally if ale#Var(a:buffer, 'list_vertical') == 0 call winrestview({'topline': l:saved_view['topline']}) endif endfunction function! ale#list#SetLists(buffer, loclist) abort if get(g:, 'ale_set_lists_synchronously') == 1 \|| getbufvar(a:buffer, 'ale_save_event_fired', 0) " Update lists immediately if running a test synchronously, or if the " buffer was saved. " " The lists need to be updated immediately when saving a buffer so " that we can reliably close window automatically, if so configured. call s:SetListsImpl(-1, a:buffer, a:loclist) else call ale#util#StartPartialTimer( \ 0, \ function('s:SetListsImpl'), \ [a:buffer, a:loclist], \) endif endfunction function! ale#list#ForcePopulateErrorList(populate_quickfix) abort let l:quickfix_bak = g:ale_set_quickfix let g:ale_set_quickfix = a:populate_quickfix let l:loclist_bak = g:ale_set_loclist let g:ale_set_loclist = !a:populate_quickfix let l:open_list_bak = g:ale_open_list let g:ale_open_list = 1 let l:buffer = bufnr('') let l:loclist = get(g:ale_buffer_info, l:buffer, {'loclist': []}).loclist call s:SetListsImpl(-1, l:buffer, l:loclist) let g:ale_open_list = l:open_list_bak let g:ale_set_loclist = l:loclist_bak let g:ale_set_quickfix = l:quickfix_bak endfunction function! s:CloseWindowIfNeeded(buffer) abort if ale#Var(a:buffer, 'keep_list_window_open') || s:ShouldClose(a:buffer) return endif let l:did_close_any_list = 0 try " Only close windows if the quickfix list or loclist is completely empty, " including errors set through other means. if g:ale_set_quickfix if empty(getqflist()) cclose let l:did_close_any_list = 1 endif else let l:win_ids = s:WinFindBuf(a:buffer) for l:win_id in l:win_ids if g:ale_set_loclist && empty(getloclist(l:win_id)) lclose let l:did_close_any_list = 1 endif endfor endif " Ignore 'Cannot close last window' errors. catch /E444/ endtry if l:did_close_any_list call s:RestoreViewIfNeeded(a:buffer) endif endfunction ================================================ FILE: autoload/ale/loclist_jumping.vim ================================================ " Author: w0rp " Description: This file implements functions for jumping around in a file " based on ALE's internal loclist. " Search for the nearest line either before or after the current position " in the loclist. The argument 'wrap' can be passed to enable wrapping " around the end of the list. " " If there are no items or we have hit the end with wrapping off, an empty " List will be returned, otherwise a pair of [line_number, column_number] will " be returned. function! ale#loclist_jumping#FindNearest(direction, wrap, ...) abort let l:buffer = bufnr('') let l:pos = getpos('.') let l:info = get(g:ale_buffer_info, bufnr('%'), {'loclist': []}) " Copy the list and filter to only the items in this buffer. let l:loclist = filter(copy(l:info.loclist), 'v:val.bufnr == l:buffer') let l:search_item = {'bufnr': l:buffer, 'lnum': l:pos[1], 'col': l:pos[2]} if a:0 > 0 let l:filter = a:1 else let l:filter = 'any' endif if a:0 > 1 let l:subtype_filter = a:2 else let l:subtype_filter = 'any' endif " When searching backwards, so we can find the next smallest match. if a:direction is# 'before' call reverse(l:loclist) endif " Look for items before or after the current position. for l:item in l:loclist " Compare the cursor with a item where the column number is bounded, " such that it's possible for the cursor to actually be on the given " column number, without modifying the cursor number we return. This " will allow us to move through matches, but still let us move the " cursor to a line without changing the column, in some cases. let l:cmp_value = ale#util#LocItemCompare( \ { \ 'bufnr': l:buffer, \ 'lnum': l:item.lnum, \ 'col': min([ \ max([l:item.col, 1]), \ max([len(getline(l:item.lnum)), 1]), \ ]), \ }, \ l:search_item \) if (l:filter is# 'any' || l:filter is# l:item.type) \&& ( \ l:subtype_filter is# 'any' \ || l:subtype_filter is# get(l:item, 'sub_type', '') \) if a:direction is# 'before' && l:cmp_value < 0 return [l:item.lnum, l:item.col] endif if a:direction is# 'after' && l:cmp_value > 0 return [l:item.lnum, l:item.col] endif endif endfor " If we found nothing, and the wrap option is set to 1, then we should " wrap around the list of warnings/errors if a:wrap for l:item in l:loclist if (l:filter is# 'any' || l:filter is# l:item.type) \&& ( \ l:subtype_filter is# 'any' \ || l:subtype_filter is# get(l:item, 'sub_type', '') \) return [l:item.lnum, l:item.col] endif endfor endif return [] endfunction " As before, find the nearest match, but position the cursor at it. function! ale#loclist_jumping#Jump(direction, ...) abort if a:0 > 0 let l:wrap = a:1 else let l:wrap = 0 endif if a:0 > 1 let l:filter = a:2 else let l:filter = 'any' endif if a:0 > 2 let l:subtype_filter = a:3 else let l:subtype_filter = 'any' endif let l:nearest = ale#loclist_jumping#FindNearest(a:direction, \ l:wrap, l:filter, l:subtype_filter) if !empty(l:nearest) normal! m` call cursor([l:nearest[0], max([l:nearest[1], 1])]) endif endfunction function! ale#loclist_jumping#WrapJump(direction, sargs) abort let [l:args, l:rest] = ale#args#Parse(['error', 'warning', 'info', 'wrap', \ 'style', 'nostyle'], a:sargs) let l:wrap = 0 let l:type_filter = 'any' let l:subtype_filter = 'any' if get(l:args, 'wrap', 'nil') is# '' let l:wrap = 1 endif if get(l:args, 'error', 'nil') is# '' let l:type_filter = 'E' elseif get(l:args, 'warning', 'nil') is# '' let l:type_filter = 'W' elseif get(l:args, 'info', 'nil') is# '' let l:type_filter = 'I' endif if get(l:args, 'nostyle', 'nil') is# '' let l:subtype_filter = 'style' elseif get(l:args, 'style', 'nil') is# '' let l:subtype_filter = '' endif call ale#loclist_jumping#Jump(a:direction, l:wrap, l:type_filter, \ l:subtype_filter) endfunction function! ale#loclist_jumping#JumpToIndex(index) abort let l:buffer = bufnr('') let l:info = get(g:ale_buffer_info, l:buffer, {'loclist': []}) let l:loclist = filter(copy(l:info.loclist), 'v:val.bufnr == l:buffer') if empty(l:loclist) return endif let l:item = l:loclist[a:index] if !empty(l:item) normal! m` call cursor([l:item.lnum, l:item.col]) endif endfunction ================================================ FILE: autoload/ale/lsp/message.vim ================================================ " Author: w0rp " Description: Language Server Protocol message implementations " " Messages in this movie will be returned in the format " [is_notification, method_name, params?] " " All functions which accept line and column arguments expect them to be 1-based " (the same format as being returned by getpos() and friends), those then " will be converted to 0-based as specified by LSP. let g:ale_lsp_next_version_id = 1 " The LSP protocols demands that we send every change to a document, including " undo, with incrementing version numbers, so we'll just use one incrementing " ID for everything. function! ale#lsp#message#GetNextVersionID() abort " Use the current ID let l:id = g:ale_lsp_next_version_id " Increment the ID variable. let g:ale_lsp_next_version_id += 1 " When the ID overflows, reset it to 1. By the time we hit the initial ID " again, the messages will be long gone. if g:ale_lsp_next_version_id < 1 let g:ale_lsp_next_version_id = 1 endif return l:id endfunction function! ale#lsp#message#Initialize(root_path, options, capabilities) abort " NOTE: rootPath is deprecated in favour of rootUri return [0, 'initialize', { \ 'processId': getpid(), \ 'rootPath': a:root_path, \ 'capabilities': a:capabilities, \ 'initializationOptions': a:options, \ 'rootUri': ale#util#ToURI(a:root_path), \}] endfunction function! ale#lsp#message#Initialized() abort return [1, 'initialized', {}] endfunction function! ale#lsp#message#Shutdown() abort return [0, 'shutdown'] endfunction function! ale#lsp#message#Exit() abort return [1, 'exit'] endfunction function! ale#lsp#message#DidOpen(buffer, language_id) abort return [1, 'textDocument/didOpen', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ 'languageId': a:language_id, \ 'version': ale#lsp#message#GetNextVersionID(), \ 'text': ale#util#GetBufferContents(a:buffer), \ }, \}] endfunction function! ale#lsp#message#DidChange(buffer) abort " For changes, we simply send the full text of the document to the server. return [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ 'version': ale#lsp#message#GetNextVersionID(), \ }, \ 'contentChanges': [{'text': ale#util#GetBufferContents(a:buffer)}] \}] endfunction function! ale#lsp#message#DidSave(buffer, include_text) abort let l:response = [1, 'textDocument/didSave', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \}] if a:include_text let l:response[2].textDocument.version = ale#lsp#message#GetNextVersionID() let l:response[2].text = ale#util#GetBufferContents(a:buffer) endif return l:response endfunction function! ale#lsp#message#DidClose(buffer) abort return [1, 'textDocument/didClose', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \}] endfunction let s:COMPLETION_TRIGGER_INVOKED = 1 let s:COMPLETION_TRIGGER_CHARACTER = 2 function! ale#lsp#message#Completion(buffer, line, column, trigger_character) abort let l:message = [0, 'textDocument/completion', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \}] if !empty(a:trigger_character) let l:message[2].context = { \ 'triggerKind': s:COMPLETION_TRIGGER_CHARACTER, \ 'triggerCharacter': a:trigger_character, \} endif return l:message endfunction function! ale#lsp#message#Definition(buffer, line, column) abort return [0, 'textDocument/definition', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \}] endfunction function! ale#lsp#message#TypeDefinition(buffer, line, column) abort return [0, 'textDocument/typeDefinition', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \}] endfunction function! ale#lsp#message#Implementation(buffer, line, column) abort return [0, 'textDocument/implementation', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \}] endfunction function! ale#lsp#message#References(buffer, line, column) abort return [0, 'textDocument/references', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \ 'context': {'includeDeclaration': v:false}, \}] 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': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \}] endfunction function! ale#lsp#message#DidChangeConfiguration(buffer, config) abort return [1, 'workspace/didChangeConfiguration', { \ 'settings': a:config, \}] endfunction function! ale#lsp#message#Rename(buffer, line, column, new_name) abort return [0, 'textDocument/rename', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'position': {'line': a:line - 1, 'character': a:column - 1}, \ 'newName': a:new_name, \}] endfunction function! ale#lsp#message#CodeAction(buffer, line, column, end_line, end_column, diagnostics) abort return [0, 'textDocument/codeAction', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \ 'range': { \ 'start': {'line': a:line - 1, 'character': a:column - 1}, \ 'end': {'line': a:end_line - 1, 'character': a:end_column}, \ }, \ 'context': { \ 'diagnostics': a:diagnostics \ }, \}] endfunction function! ale#lsp#message#Diagnostic(buffer) abort return [0, 'textDocument/diagnostic', { \ 'textDocument': { \ 'uri': ale#util#ToURI(expand('#' . a:buffer . ':p')), \ }, \}] endfunction function! ale#lsp#message#ExecuteCommand(command, arguments) abort return [0, 'workspace/executeCommand', { \ 'command': a:command, \ 'arguments': a:arguments, \}] endfunction ================================================ FILE: autoload/ale/lsp/reset.vim ================================================ " Author: w0rp " Description: Functions for resetting LSP servers. function! s:Message(message) abort call ale#util#Execute('echom ' . string(a:message)) endfunction " Stop all LSPs and remove all of the data for them. function! ale#lsp#reset#StopAllLSPs() abort call ale#lsp#StopAll() if exists('*ale#definition#ClearLSPData') " Clear the go to definition mapping for everything. call ale#definition#ClearLSPData() endif if exists('*ale#lsp_linter#ClearLSPData') " Clear the mapping for connections, etc. call ale#lsp_linter#ClearLSPData() " Remove the problems for all of the LSP linters in every buffer. for l:buffer_string in keys(g:ale_buffer_info) let l:buffer = str2nr(l:buffer_string) " Non-ignored and disabled linters are included here so we can " clear results for them after we ignore or disable them. 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, [], 0) endif endfor endfor endif endfunction function! ale#lsp#reset#Complete(arg, line, pos) abort let l:linter_map = ale#lsp_linter#GetLSPLinterMap() let l:candidates = map(values(l:linter_map), {_, linter -> linter.name}) call uniq(sort(l:candidates)) call filter(l:candidates, {_, name -> name =~? a:arg}) return l:candidates endfunction function! ale#lsp#reset#StopLSP(name, bang) abort let l:linter_map = ale#lsp_linter#GetLSPLinterMap() let l:matched = filter( \ items(l:linter_map), \ {_, item -> item[1].name is# a:name} \) if empty(l:matched) if a:bang isnot# '!' call s:Message('No running language server with name: ' . a:name) endif return endif " Stop LSP connections first. for [l:conn_id, l:linter] in l:matched call ale#lsp#Stop(l:conn_id) endfor if exists('*ale#definition#ClearLSPData') " Clear the go to definition mapping for everything. call ale#definition#ClearLSPData() endif " Remove connections from the lsp_linter map. for [l:conn_id, l:linter] in l:matched call remove(l:linter_map, l:conn_id) endfor " Remove the problems for the LSP linters in every buffer. for [l:buffer_string, l:info] in items(g:ale_buffer_info) let l:buffer = str2nr(l:buffer_string) let l:should_clear_buffer = 0 for l:item in l:info.loclist if l:item.linter_name is# a:name let l:should_clear_buffer = 1 break endif endfor if l:should_clear_buffer call ale#engine#HandleLoclist(a:name, l:buffer, [], 0) endif endfor endfunction ================================================ FILE: autoload/ale/lsp/response.vim ================================================ " Author: w0rp " Description: Parsing and transforming of LSP server responses. " Constants for error codes. " Defined by JSON RPC let s:PARSE_ERROR = -32700 let s:INVALID_REQUEST = -32600 let s:METHOD_NOT_FOUND = -32601 let s:INVALID_PARAMS = -32602 let s:INTERNAL_ERROR = -32603 let s:SERVER_ERROR_START = -32099 let s:SERVER_ERROR_END = -32000 let s:SERVER_NOT_INITIALIZED = -32002 let s:UNKNOWN_ERROR_CODE = -32001 " Defined by the protocol. let s:REQUEST_CANCELLED = -32800 " Constants for message severity codes. let s:SEVERITY_ERROR = 1 let s:SEVERITY_WARNING = 2 let s:SEVERITY_INFORMATION = 3 let s:SEVERITY_HINT = 4 " Convert Diagnostic[] data from a language server to an ALE loclist. function! ale#lsp#response#ReadDiagnostics(diagnostics) abort let l:loclist = [] for l:diagnostic in a:diagnostics let l:severity = get(l:diagnostic, 'severity', 0) let l:loclist_item = { \ 'text': l:diagnostic.message, \ 'type': 'E', \ 'lnum': l:diagnostic.range.start.line + 1, \ 'col': l:diagnostic.range.start.character + 1, \ 'end_lnum': l:diagnostic.range.end.line + 1, \ 'end_col': l:diagnostic.range.end.character, \} if l:severity == s:SEVERITY_WARNING let l:loclist_item.type = 'W' elseif l:severity == s:SEVERITY_INFORMATION " TODO: Use 'I' here in future. let l:loclist_item.type = 'W' elseif l:severity == s:SEVERITY_HINT " TODO: Use 'H' here in future let l:loclist_item.type = 'W' endif if has_key(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') \ && l:diagnostic.relatedInformation isnot v:null let l:related = deepcopy(l:diagnostic.relatedInformation) call map(l:related, {key, val -> \ ale#util#ToResource(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') let l:loclist_item.detail = printf( \ '[%s] %s', \ l:diagnostic.source, \ l:diagnostic.message \) endif call add(l:loclist, l:loclist_item) endfor return l:loclist endfunction function! ale#lsp#response#ReadTSServerDiagnostics(response) abort let l:loclist = [] for l:diagnostic in a:response.body.diagnostics let l:loclist_item = { \ 'text': l:diagnostic.text, \ 'type': 'E', \ 'lnum': l:diagnostic.start.line, \ 'col': l:diagnostic.start.offset, \ 'end_lnum': l:diagnostic.end.line, \ 'end_col': l:diagnostic.end.offset - 1, \} if has_key(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' let l:loclist_item.type = 'W' endif if get(l:diagnostic, 'category') is# 'suggestion' let l:loclist_item.type = 'I' endif call add(l:loclist, l:loclist_item) endfor return l:loclist endfunction function! ale#lsp#response#GetErrorMessage(response) abort if type(get(a:response, 'error', 0)) isnot v:t_dict return '' endif let l:code = get(a:response.error, 'code') " Only report things for these error codes. if l:code isnot s:INVALID_PARAMS && l:code isnot s:INTERNAL_ERROR return '' endif let l:message = get(a:response.error, 'message', '') if empty(l:message) return '' endif " 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 v:t_string let l:message .= "\n" . l:error_data elseif type(l:error_data) is v:t_dict let l:traceback = get(l:error_data, 'traceback', []) if type(l:traceback) is v:t_list && !empty(l:traceback) let l:message .= "\n" . join(l:traceback, "\n") endif endif return l:message endfunction ================================================ FILE: autoload/ale/lsp/tsserver_message.vim ================================================ " Author: w0rp " Description: tsserver message implementations " " Messages in this movie will be returned in the format " [is_notification, command_name, params?] " " Every command must begin with the string 'ts@', which will be used to " detect the different message format for tsserver, and this string will " be removed from the actual command name, function! ale#lsp#tsserver_message#Open(buffer) abort return [1, 'ts@open', {'file': expand('#' . a:buffer . ':p')}] endfunction function! ale#lsp#tsserver_message#Close(buffer) abort return [1, 'ts@close', {'file': expand('#' . a:buffer . ':p')}] endfunction function! ale#lsp#tsserver_message#Change(buffer) abort let l:lines = getbufline(a:buffer, 1, '$') " We will always use a very high endLine number, so we can delete " lines from files. tsserver will gladly accept line numbers beyond the " end. return [1, 'ts@change', { \ 'file': expand('#' . a:buffer . ':p'), \ 'line': 1, \ 'offset': 1, \ 'endLine': 1073741824, \ 'endOffset': 1, \ 'insertString': join(l:lines, "\n") . "\n", \}] endfunction function! ale#lsp#tsserver_message#Geterr(buffer) abort return [1, 'ts@geterr', {'files': [expand('#' . a:buffer . ':p')]}] endfunction function! ale#lsp#tsserver_message#Completions( \ buffer, line, column, prefix, include_external) abort return [0, 'ts@completions', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \ 'prefix': a:prefix, \ 'includeExternalModuleExports': a:include_external, \}] endfunction function! ale#lsp#tsserver_message#CompletionEntryDetails(buffer, line, column, entry_names) abort return [0, 'ts@completionEntryDetails', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \ 'entryNames': a:entry_names, \}] endfunction function! ale#lsp#tsserver_message#Definition(buffer, line, column) abort return [0, 'ts@definition', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \}] endfunction function! ale#lsp#tsserver_message#TypeDefinition(buffer, line, column) abort return [0, 'ts@typeDefinition', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \}] endfunction function! ale#lsp#tsserver_message#Implementation(buffer, line, column) abort return [0, 'ts@implementation', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \}] endfunction function! ale#lsp#tsserver_message#References(buffer, line, column) abort return [0, 'ts@references', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \}] endfunction function! ale#lsp#tsserver_message#Quickinfo(buffer, line, column) abort return [0, 'ts@quickinfo', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \}] endfunction function! ale#lsp#tsserver_message#Rename( \ buffer, line, column, find_in_comments, find_in_strings) abort return [0, 'ts@rename', { \ 'line': a:line, \ 'offset': a:column, \ 'file': expand('#' . a:buffer . ':p'), \ 'arguments': { \ 'findInComments': a:find_in_comments, \ 'findInStrings': a:find_in_strings, \ } \}] endfunction function! ale#lsp#tsserver_message#GetEditsForFileRename( \ oldFilePath, newFilePath) abort return [0, 'ts@getEditsForFileRename', { \ 'oldFilePath': a:oldFilePath, \ 'newFilePath': a:newFilePath, \}] endfunction function! ale#lsp#tsserver_message#OrganizeImports(buffer) abort return [0, 'ts@organizeImports', { \ 'scope': { \ 'type': 'file', \ 'args': { \ 'file': expand('#' . a:buffer . ':p'), \ }, \ }, \}] endfunction function! ale#lsp#tsserver_message#GetCodeFixes(buffer, line, column, end_line, end_column, error_codes) abort " The lines and columns are 1-based. " The errors codes must be a list of tsserver error codes to fix. return [0, 'ts@getCodeFixes', { \ 'startLine': a:line, \ 'startOffset': a:column, \ 'endLine': a:end_line, \ 'endOffset': a:end_column + 1, \ 'file': expand('#' . a:buffer . ':p'), \ 'errorCodes': a:error_codes, \}] endfunction function! ale#lsp#tsserver_message#GetApplicableRefactors(buffer, line, column, end_line, end_column) abort " The arguments for this request can also be just 'line' and 'offset' return [0, 'ts@getApplicableRefactors', { \ 'startLine': a:line, \ 'startOffset': a:column, \ 'endLine': a:end_line, \ 'endOffset': a:end_column + 1, \ 'file': expand('#' . a:buffer . ':p'), \}] endfunction function! ale#lsp#tsserver_message#GetEditsForRefactor(buffer, line, column, end_line, end_column, refactor, action) abort return [0, 'ts@getEditsForRefactor', { \ 'startLine': a:line, \ 'startOffset': a:column, \ 'endLine': a:end_line, \ 'endOffset': a:end_column + 1, \ 'file': expand('#' . a:buffer . ':p'), \ 'refactor': a:refactor, \ 'action': a:action, \}] endfunction ================================================ FILE: autoload/ale/lsp.vim ================================================ " Author: w0rp " Description: Language Server Protocol client code " A Dictionary for tracking connections. let s:connections = get(s:, 'connections', {}) let g:ale_lsp_next_message_id = 1 " Given an id, which can be an executable or address, a project path, " and a language string or (bufnr) -> string function " create a new connection if needed. Return a unique ID for the connection. function! ale#lsp#Register(executable_or_address, project, language, 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. " 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, \ 'language': a:language, \ 'open_documents': {}, \ 'initialized': 0, \ 'init_request_id': 0, \ 'init_options': a:init_options, \ 'config': {}, \ 'callback_list': [], \ 'init_queue': [], \ 'capabilities': { \ 'hover': 0, \ 'rename': 0, \ 'filerename': 0, \ 'references': 0, \ 'completion': 0, \ 'completion_trigger_characters': [], \ 'definition': 0, \ 'typeDefinition': 0, \ 'implementation': 0, \ 'pull_model': 0, \ 'symbol_search': 0, \ 'code_actions': 0, \ 'did_save': 0, \ 'includeText': 0, \ }, \} endif return l:conn_id endfunction " Remove an LSP connection with a given ID. This is only for tests. function! ale#lsp#RemoveConnectionWithID(id) abort if has_key(s:connections, a:id) call remove(s:connections, a:id) endif endfunction function! ale#lsp#ResetConnections() abort let s:connections = {} endfunction " Used only in tests. function! ale#lsp#GetConnections() abort " This command will throw from the sandbox. let &l:equalprg=&l:equalprg return s:connections endfunction " This is only needed for tests function! ale#lsp#MarkDocumentAsOpen(id, buffer) abort let l:conn = get(s:connections, a:id, {}) if !empty(l:conn) let l:conn.open_documents[a:buffer] = -1 endif endfunction function! ale#lsp#GetNextMessageID() abort " Use the current ID let l:id = g:ale_lsp_next_message_id " Increment the ID variable. let g:ale_lsp_next_message_id += 1 " When the ID overflows, reset it to 1. By the time we hit the initial ID " again, the messages will be long gone. if g:ale_lsp_next_message_id < 1 let g:ale_lsp_next_message_id = 1 endif return l:id endfunction " TypeScript messages use a different format. function! s:CreateTSServerMessageData(message) abort let l:is_notification = a:message[0] let l:obj = { \ 'seq': v:null, \ 'type': 'request', \ 'command': a:message[1][3:], \} if !l:is_notification let l:obj.seq = ale#lsp#GetNextMessageID() endif if len(a:message) > 2 let l:obj.arguments = a:message[2] 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][:2] is# 'ts@' return s:CreateTSServerMessageData(a:message) endif let l:is_notification = a:message[0] let l:obj = { \ 'method': a:message[1], \ 'jsonrpc': '2.0', \} if !l:is_notification let l:obj.id = ale#lsp#GetNextMessageID() endif if len(a:message) > 2 let l:obj.params = a:message[2] endif let l:body = json_encode(l:obj) let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body return [l:is_notification ? 0 : l:obj.id, l:data] endfunction function! ale#lsp#ReadMessageData(data) abort let l:response_list = [] let l:remainder = a:data while 1 " Look for the end of the HTTP headers let l:body_start_index = matchend(l:remainder, "\r\n\r\n") if l:body_start_index < 0 " No header end was found yet. break endif " Parse the Content-Length header. let l:header_data = l:remainder[:l:body_start_index - 4] let l:length_match = matchlist( \ l:header_data, \ '\vContent-Length: *(\d+)' \) if empty(l:length_match) throw "Invalid JSON-RPC header:\n" . l:header_data endif " Split the body and the remainder of the text. let l:remainder_start_index = l:body_start_index + str2nr(l:length_match[1]) if len(l:remainder) < l:remainder_start_index " We don't have enough data yet. break endif let l:body = l:remainder[l:body_start_index : l:remainder_start_index - 1] let l:remainder = l:remainder[l:remainder_start_index :] " Parse the JSON object and add it to the list. call add(l:response_list, json_decode(l:body)) endwhile return [l:remainder, l:response_list] endfunction " Update capabilities from the server, so we know which features the server " supports. function! ale#lsp#UpdateCapabilities(conn_id, capabilities) abort let l:conn = get(s:connections, a:conn_id, {}) if empty(l:conn) return endif if type(a:capabilities) isnot v:t_dict return endif if get(a:capabilities, 'hoverProvider') is v:true let l:conn.capabilities.hover = 1 endif if type(get(a:capabilities, 'hoverProvider')) is v:t_dict let l:conn.capabilities.hover = 1 endif if get(a:capabilities, 'referencesProvider') is v:true let l:conn.capabilities.references = 1 endif if type(get(a:capabilities, 'referencesProvider')) is v:t_dict let l:conn.capabilities.references = 1 endif if get(a:capabilities, 'renameProvider') is v:true let l:conn.capabilities.rename = 1 endif if type(get(a:capabilities, 'renameProvider')) is v:t_dict let l:conn.capabilities.rename = 1 endif if get(a:capabilities, 'codeActionProvider') is v:true let l:conn.capabilities.code_actions = 1 endif if type(get(a:capabilities, 'codeActionProvider')) is v:t_dict let l:conn.capabilities.code_actions = 1 endif if !empty(get(a:capabilities, 'completionProvider')) let l:conn.capabilities.completion = 1 endif if type(get(a:capabilities, 'completionProvider')) is v:t_dict let l:chars = get(a:capabilities.completionProvider, 'triggerCharacters') if type(l:chars) is v:t_list let l:conn.capabilities.completion_trigger_characters = l:chars endif endif if get(a:capabilities, 'definitionProvider') is v:true let l:conn.capabilities.definition = 1 endif if type(get(a:capabilities, 'definitionProvider')) is v:t_dict let l:conn.capabilities.definition = 1 endif if get(a:capabilities, 'typeDefinitionProvider') is v:true let l:conn.capabilities.typeDefinition = 1 endif if type(get(a:capabilities, 'typeDefinitionProvider')) is v:t_dict let l:conn.capabilities.typeDefinition = 1 endif if get(a:capabilities, 'implementationProvider') is v:true let l:conn.capabilities.implementation = 1 endif if type(get(a:capabilities, 'implementationProvider')) is v:t_dict let l:conn.capabilities.implementation = 1 endif " Check if the language server supports pull model diagnostics. if type(get(a:capabilities, 'diagnosticProvider')) is v:t_dict if type(get(a:capabilities.diagnosticProvider, 'interFileDependencies')) is v:t_bool let l:conn.capabilities.pull_model = 1 endif endif if get(a:capabilities, 'workspaceSymbolProvider') is v:true let l:conn.capabilities.symbol_search = 1 endif if type(get(a:capabilities, 'workspaceSymbolProvider')) is v:t_dict let l:conn.capabilities.symbol_search = 1 endif if type(get(a:capabilities, 'textDocumentSync')) is v:t_dict let l:syncOptions = get(a:capabilities, 'textDocumentSync') if get(l:syncOptions, 'save') is v:true let l:conn.capabilities.did_save = 1 endif if type(get(l:syncOptions, 'save')) is v:t_dict let l:conn.capabilities.did_save = 1 let l:saveOptions = get(l:syncOptions, 'save') if get(l:saveOptions, 'includeText') is v:true let l:conn.capabilities.includeText = 1 endif endif endif endfunction " 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:conn) || a:config ==# l:conn.config " no-custom-checks return 0 endif let l:conn.config = a:config let l:message = ale#lsp#message#DidChangeConfiguration(a:buffer, a:config) call ale#lsp#Send(a:conn_id, l:message) return 1 endfunction function! ale#lsp#CallInitCallbacks(conn_id) abort let l:conn = get(s:connections, a:conn_id, {}) if !empty(l:conn) " Ensure the connection is marked as initialized. " For integration with Neovim's LSP tooling this ensures immediately " call OnInit functions in Vim after the `on_init` callback is called. let l:conn.initialized = 1 " Call capabilities callbacks queued for the project. for l:Callback in l:conn.init_queue call l:Callback() endfor let l:conn.init_queue = [] endif endfunction 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 ale#lsp#UpdateCapabilities(a:conn.id, a:response.result.capabilities) let a:conn.initialized = 1 endif if !a:conn.initialized return endif " The initialized message must be sent before everything else. call ale#lsp#Send(a:conn.id, ale#lsp#message#Initialized()) call ale#lsp#CallInitCallbacks(a:conn.id) endfunction function! ale#lsp#HandleMessage(conn_id, message) abort let l:conn = get(s:connections, a:conn_id, {}) if empty(l:conn) return endif if type(a:message) isnot v:t_string " Ignore messages that aren't strings. return endif let l:conn.data .= a:message " 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) " 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 " 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 " Handle a JSON response from a language server. " This is called from Lua for integration with Neovim's LSP API. function! ale#lsp#HandleResponse(conn_id, response) abort let l:conn = get(s:connections, a:conn_id, {}) if empty(l:conn) return endif for l:Callback in l:conn.callback_list call ale#util#GetFunction(l:Callback)(a:conn_id, a:response) endfor endfunction " 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.typeDefinition = 1 let l:conn.capabilities.implementation = 1 let l:conn.capabilities.symbol_search = 1 let l:conn.capabilities.rename = 1 let l:conn.capabilities.filerename = 1 let l:conn.capabilities.code_actions = 1 endfunction function! s:SendInitMessage(conn) abort let [l:init_id, l:init_data] = ale#lsp#CreateMessageData( \ ale#lsp#message#Initialize( \ a:conn.root, \ a:conn.init_options, \ { \ 'workspace': { \ 'applyEdit': v:false, \ 'didChangeConfiguration': { \ 'dynamicRegistration': v:false, \ }, \ 'symbol': { \ 'dynamicRegistration': v:false, \ }, \ 'workspaceFolders': v:false, \ 'configuration': v:false, \ }, \ 'textDocument': { \ 'synchronization': { \ 'dynamicRegistration': v:false, \ 'willSave': v:false, \ 'willSaveWaitUntil': v:false, \ 'didSave': v:true, \ }, \ 'completion': { \ 'dynamicRegistration': v:false, \ 'completionItem': { \ 'snippetSupport': v:false, \ 'commitCharactersSupport': v:false, \ 'documentationFormat': ['plaintext', 'markdown'], \ 'deprecatedSupport': v:false, \ 'preselectSupport': v:false, \ }, \ 'contextSupport': v:false, \ }, \ 'hover': { \ 'dynamicRegistration': v:false, \ 'contentFormat': ['plaintext', 'markdown'], \ }, \ 'references': { \ 'dynamicRegistration': v:false, \ }, \ 'documentSymbol': { \ 'dynamicRegistration': v:false, \ 'hierarchicalDocumentSymbolSupport': v:false, \ }, \ 'definition': { \ 'dynamicRegistration': v:false, \ 'linkSupport': v:false, \ }, \ 'typeDefinition': { \ 'dynamicRegistration': v:false, \ }, \ 'implementation': { \ 'dynamicRegistration': v:false, \ 'linkSupport': v:false, \ }, \ 'diagnostic': { \ 'dynamicRegistration': v:true, \ 'relatedDocumentSupport': v:true, \ }, \ 'publishDiagnostics': { \ 'relatedInformation': v:true, \ }, \ 'codeAction': { \ 'dynamicRegistration': v:false, \ 'codeActionLiteralSupport': { \ 'codeActionKind': { \ 'valueSet': [] \ } \ } \ }, \ 'rename': { \ 'dynamicRegistration': v:false, \ }, \ }, \ }, \ ), \) let a:conn.init_request_id = l:init_id call s:SendMessageData(a:conn, l:init_data) endfunction " Start a program for LSP servers. " " 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] let l:started = 0 if g:ale_use_neovim_lsp_api && !l:conn.is_tsserver " For Windows from 'cmd /s/c "foo bar"' we need 'foo bar' let l:lsp_cmd = has('win32') && type(a:command) is v:t_string \ ? ['cmd', '/s/c', a:command[10:-2]] \ : a:command " Always call lsp.start, which will either create or re-use a " connection. We'll set `attach` to `false` so we can later use " our OpenDocument function to attach the buffer separately. let l:client_id = luaeval('require("ale.lsp").start(_A)', { \ 'name': a:conn_id, \ 'cmd': l:lsp_cmd, \ 'root_dir': l:conn.root, \ 'init_options': l:conn.init_options, \}) if l:client_id > 0 let l:conn.client_id = l:client_id endif return l:client_id > 0 endif if !has_key(l:conn, 'job_id') || !ale#job#HasOpenChannel(l:conn.job_id) let l:options = { \ 'mode': 'raw', \ 'out_cb': {_, message -> ale#lsp#HandleMessage(a:conn_id, message)}, \ 'exit_cb': { -> ale#lsp#Stop(a:conn_id) }, \} if has('win32') let l:job_id = ale#job#StartWithCmd(a:command, l:options) else let l:job_id = ale#job#Start(a:command, l:options) endif let l:started = 1 else let l:job_id = l:conn.job_id endif if l:job_id > 0 let l:conn.job_id = l:job_id endif if l:started && !l:conn.is_tsserver let l:conn.initialized = 0 call s:SendInitMessage(l:conn) endif return l:job_id > 0 endfunction " Split an address into [host, port]. " The port will either be a number or v:null. function! ale#lsp#SplitAddress(address) abort let l:port_match = matchlist(a:address, '\v:(\d+)$') if !empty(l:port_match) let l:host = a:address[:-len(l:port_match[1]) - 2] let l:port = l:port_match[1] + 0 return [l:host, l:port ? l:port : v:null] endif return [a:address, v:null] endfunction " 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] let l:started = 0 if g:ale_use_neovim_lsp_api && !l:conn.is_tsserver let [l:host, l:port] = ale#lsp#SplitAddress(a:address) let l:client_id = luaeval('require("ale.lsp").start(_A)', { \ 'name': a:conn_id, \ 'host': l:host, \ 'port': l:port, \ 'root_dir': l:conn.root, \ 'init_options': l:conn.init_options, \}) if l:client_id > 0 let l:conn.client_id = l:client_id endif return l:client_id > 0 elseif !has_key(l:conn, 'channel_id') || !ale#socket#IsOpen(l:conn.channel_id) let l:channel_id = ale#socket#Open(a:address, { \ 'callback': {_, mess -> ale#lsp#HandleMessage(a:conn_id, mess)}, \}) let l:started = 1 else let l:channel_id = l:conn.channel_id endif if l:channel_id >= 0 let l:conn.channel_id = l:channel_id endif if l:started call s:SendInitMessage(l:conn) endif 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 = get(s:connections, a:conn_id, {}) if !empty(l:conn) " Add the callback to the List if it's not there already. call uniq(sort(add(l:conn.callback_list, a:callback))) endif endfunction " 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) elseif has_key(l:conn, 'job_id') call ale#job#Stop(l:conn.job_id) endif endif endfunction 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, '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) else return 0 endif return 1 endfunction " Send a message to an LSP server. " Notifications do not need to be handled. " " 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:conn = get(s:connections, a:conn_id, {}) if empty(l:conn) return 0 endif if !l:conn.initialized throw 'LSP server not initialized yet!' endif if g:ale_use_neovim_lsp_api && !l:conn.is_tsserver return luaeval('require("ale.lsp").send_message(_A)', { \ 'client_id': l:conn.client_id, \ 'is_notification': a:message[0] == 1 ? v:true : v:false, \ 'method': a:message[1], \ 'params': get(a:message, 2, v:null) \}) endif let [l:id, l:data] = ale#lsp#CreateMessageData(a:message) call s:SendMessageData(l:conn, l:data) return l:id == 0 ? -1 : l:id endfunction function! ale#lsp#GetLanguage(conn_id, buffer) abort let l:conn = get(s:connections, a:conn_id, {}) let l:Language = get(l:conn, 'language') if empty(l:Language) return getbufvar(a:buffer, '&filetype') endif return type(l:Language) is v:t_func ? l:Language(a:buffer) : l:Language 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, buffer) abort let l:conn = get(s:connections, a:conn_id, {}) let l:opened = 0 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) call ale#lsp#Send(a:conn_id, l:message) elseif g:ale_use_neovim_lsp_api call luaeval('require("ale.lsp").buf_attach(_A)', { \ 'bufnr': a:buffer, \ 'client_id': l:conn.client_id, \}) else let l:language_id = ale#lsp#GetLanguage(a:conn_id, a:buffer) let l:message = ale#lsp#message#DidOpen(a:buffer, l:language_id) call ale#lsp#Send(a:conn_id, l:message) endif let l:conn.open_documents[a:buffer] = getbufvar(a:buffer, 'changedtick') let l:opened = 1 endif return l:opened endfunction " Notify LSP servers or tsserver that a document is closed, if opened before. " If a document is closed, 1 will be returned, otherwise 0 will be returned. " " Only the buffer number is required here. A message will be sent to every " language server that was notified previously of the document being opened. function! ale#lsp#CloseDocument(buffer) abort let l:closed = 0 " The connection keys are sorted so the messages are easier to test, and " so messages are sent in a consistent order. for l:conn_id in sort(keys(s:connections)) let l:conn = s:connections[l:conn_id] if l:conn.initialized && has_key(l:conn.open_documents, a:buffer) if l:conn.is_tsserver let l:message = ale#lsp#tsserver_message#Close(a:buffer) call ale#lsp#Send(l:conn_id, l:message) elseif g:ale_use_neovim_lsp_api call luaeval('require("ale.lsp").buf_detach(_A)', { \ 'bufnr': a:buffer, \ 'client_id': l:conn.client_id, \}) else let l:message = ale#lsp#message#DidClose(a:buffer) call ale#lsp#Send(l:conn_id, l:message) endif call remove(l:conn.open_documents, a:buffer) let l:closed = 1 endif endfor return l:closed 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, 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) let l:new_tick = getbufvar(a:buffer, 'changedtick') if l:conn.open_documents[a:buffer] < l:new_tick if l:conn.is_tsserver let l:message = ale#lsp#tsserver_message#Change(a:buffer) else let l:message = ale#lsp#message#DidChange(a:buffer) endif call ale#lsp#Send(a:conn_id, l:message) let l:conn.open_documents[a:buffer] = l:new_tick let l:notified = 1 endif endif return l:notified endfunction " Wait for an LSP server to be initialized. function! ale#lsp#OnInit(conn_id, Callback) abort let l:conn = get(s:connections, a:conn_id, {}) if empty(l:conn) return endif if l:conn.initialized call a:Callback() else call add(l:conn.init_queue, a:Callback) endif endfunction " Check if an LSP has a given capability. function! ale#lsp#HasCapability(conn_id, capability) abort let l:conn = get(s:connections, a:conn_id, {}) if empty(l:conn) return 0 endif if type(get(l:conn.capabilities, a:capability, v:null)) isnot v:t_number throw 'Invalid capability ' . a:capability endif return l:conn.capabilities[a:capability] endfunction ================================================ FILE: autoload/ale/lsp_linter.vim ================================================ " Author: w0rp " Description: Integration between linters and LSP/tsserver. " This code isn't loaded if a user never users LSP features or linters. " Associates LSP connection IDs with linter names. if !has_key(s:, 'lsp_linter_map') let s:lsp_linter_map = {} endif " Clear LSP linter data for the linting engine. function! ale#lsp_linter#ClearLSPData() abort let s:lsp_linter_map = {} endfunction " Only for internal use. function! ale#lsp_linter#GetLSPLinterMap() abort return s:lsp_linter_map endfunction " Just for tests. function! ale#lsp_linter#SetLSPLinterMap(replacement_map) abort let s:lsp_linter_map = a:replacement_map endfunction " A map for tracking URIs for diagnostic request IDs if !has_key(s:, 'diagnostic_uri_map') let s:diagnostic_uri_map = {} endif " For internal use only. function! ale#lsp_linter#ClearDiagnosticURIMap() abort let s:diagnostic_uri_map = {} endfunction " For internal use only. function! ale#lsp_linter#GetDiagnosticURIMap() abort return s:diagnostic_uri_map endfunction " Just for tests. function! ale#lsp_linter#SetDiagnosticURIMap(replacement_map) abort let s:diagnostic_uri_map = a:replacement_map endfunction " Get all enabled LSP linters. " This list still includes linters ignored with `ale_linters_ignore`. " " `ale_linters_ignore` is designed to allow language servers to be used for " their functionality while ignoring the diagnostics they return. function! ale#lsp_linter#GetEnabled(buffer) abort let l:filetype = getbufvar(a:buffer, '&filetype') " Only LSP linters are included here. let l:linters = filter(ale#linter#Get(l:filetype), '!empty(v:val.lsp)') let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp') " Only load code for ignoring linters if we need it. if ( \ l:disable_lsp is 1 \ || l:disable_lsp is v:true \ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0)) \) let l:linters = ale#engine#ignore#Exclude( \ l:filetype, \ l:linters, \ [], \ l:disable_lsp, \) endif return l:linters endfunction " Check if diagnostics for a particular linter should be ignored. function! s:ShouldIgnoreDiagnostics(buffer, linter) abort let l:config = ale#Var(a:buffer, 'linters_ignore') let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp') " Only load code for ignoring linters if we need it. if ( \ !empty(l:config) \ || l:disable_lsp is 1 \ || l:disable_lsp is v:true \ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0)) \) " Re-use the ignore implementation just for this linter. return empty( \ ale#engine#ignore#Exclude( \ getbufvar(a:buffer, '&filetype'), \ [a:linter], \ l:config, \ l:disable_lsp, \ ) \) endif return 0 endfunction " Handle LSP diagnostics for a given URI. " The special value 'unchanged' can be used for diagnostics to indicate " that diagnostics haven't changed since we last checked. function! ale#lsp_linter#HandleLSPDiagnostics(conn_id, uri, diagnostics) abort let l:linter = get(s:lsp_linter_map, a:conn_id) if empty(l:linter) return endif let l:filename = ale#util#ToResource(a:uri) let l:escaped_name = escape( \ fnameescape(l:filename), \ has('win32') ? '^' : '^,}]' \) let l:buffer = bufnr('^' . l:escaped_name . '$') let l:info = get(g:ale_buffer_info, l:buffer, {}) if empty(l:info) return endif if s:ShouldIgnoreDiagnostics(l:buffer, l:linter) return endif if a:diagnostics is# 'unchanged' call ale#engine#MarkLinterInactive(l:info, l:linter) else let l:loclist = ale#lsp#response#ReadDiagnostics(a:diagnostics) call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0) endif endfunction function! s:HandleTSServerDiagnostics(response, error_type) abort " Re-create a fake linter object for tsserver. let l:linter = { \ 'name': 'tsserver', \ 'aliases': [], \ 'lsp': 'tsserver', \} let l:escaped_name = escape( \ fnameescape(a:response.body.file), \ has('win32') ? '^' : '^,}]' \) let l:buffer = bufnr('^' . l:escaped_name . '$') let l:info = get(g:ale_buffer_info, l:buffer, {}) if empty(l:info) return endif call ale#engine#MarkLinterInactive(l:info, l:linter.name) if s:ShouldIgnoreDiagnostics(l:buffer, l:linter) return 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 elseif a:error_type is# 'semantic' 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 else if len(l:thislist) is 0 && len(get(l:info, 'suggestion_loclist', [])) is 0 let l:no_changes = 1 endif let l:info.suggestion_loclist = l:thislist endif if l:no_changes return endif let l:loclist = get(l:info, 'semantic_loclist', []) \ + get(l:info, 'suggestion_loclist', []) \ + get(l:info, 'syntax_loclist', []) call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0) endfunction function! s:HandleLSPErrorMessage(linter, response) abort if !g:ale_history_enabled || !g:ale_history_log_output return endif if empty(a:linter) return endif let l:message = ale#lsp#response#GetErrorMessage(a:response) if empty(l:message) return endif call ale#lsp_linter#AddErrorMessage(a:linter.name, l:message) endfunction function! ale#lsp_linter#AddErrorMessage(linter_name, message) abort " This global variable is set here so we don't load the debugging.vim file " until someone uses :ALEInfo. let g:ale_lsp_error_messages = get(g:, 'ale_lsp_error_messages', {}) if !has_key(g:ale_lsp_error_messages, a:linter_name) let g:ale_lsp_error_messages[a:linter_name] = [] endif call add(g:ale_lsp_error_messages[a:linter_name], a:message) endfunction function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort let l:method = get(a:response, 'method', '') if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error') let l:linter = get(s:lsp_linter_map, a:conn_id, {}) call s:HandleLSPErrorMessage(l:linter, a:response) elseif l:method is# 'textDocument/publishDiagnostics' let l:uri = a:response.params.uri let l:diagnostics = a:response.params.diagnostics call ale#lsp_linter#HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics) elseif has_key(s:diagnostic_uri_map, get(a:response, 'id')) let l:uri = remove(s:diagnostic_uri_map, a:response.id) let l:diagnostics = a:response.result.kind is# 'unchanged' \ ? 'unchanged' \ : a:response.result.items call ale#lsp_linter#HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics) elseif l:method is# 'window/showMessage' call ale#lsp_window#HandleShowMessage( \ s:lsp_linter_map[a:conn_id].name, \ g:ale_lsp_show_message_format, \ a:response.params \) elseif get(a:response, 'type', '') is# 'event' \&& get(a:response, 'event', '') is# 'semanticDiag' call s:HandleTSServerDiagnostics(a:response, 'semantic') elseif get(a:response, 'type', '') is# 'event' \&& get(a:response, 'event', '') is# 'syntaxDiag' call s:HandleTSServerDiagnostics(a:response, 'syntax') elseif get(a:response, 'type', '') is# 'event' \&& get(a:response, 'event', '') is# 'suggestionDiag' \&& get(g:, 'ale_lsp_suggestions') call s:HandleTSServerDiagnostics(a:response, 'suggestion') endif endfunction function! ale#lsp_linter#GetOptions(buffer, linter) abort if has_key(a:linter, 'initialization_options_callback') return ale#util#GetFunction(a:linter.initialization_options_callback)(a:buffer) endif if has_key(a:linter, 'initialization_options') let l:Options = a:linter.initialization_options if type(l:Options) is v:t_func let l:Options = l:Options(a:buffer) endif return l:Options endif return {} endfunction function! ale#lsp_linter#GetConfig(buffer, linter) abort if has_key(a:linter, 'lsp_config_callback') return ale#util#GetFunction(a:linter.lsp_config_callback)(a:buffer) endif if has_key(a:linter, 'lsp_config') let l:Config = a:linter.lsp_config if type(l:Config) is v:t_func let l:Config = l:Config(a:buffer) endif return l:Config endif return {} endfunction function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort let l:buffer_ale_root = getbufvar(a:buffer, 'ale_root', {}) if type(l:buffer_ale_root) is v:t_string return l:buffer_ale_root endif " Try to get a buffer-local setting for the root if has_key(l:buffer_ale_root, a:linter.name) let l:Root = l:buffer_ale_root[a:linter.name] if type(l:Root) is v:t_func return l:Root(a:buffer) else return l:Root endif endif " Try to get a global setting for the root if has_key(g:ale_root, a:linter.name) let l:Root = g:ale_root[a:linter.name] if type(l:Root) is v:t_func return l:Root(a:buffer) else return l:Root endif endif " Fall back to the linter-specific configuration if has_key(a:linter, 'project_root') let l:Root = a:linter.project_root return type(l:Root) is v:t_func ? l:Root(a:buffer) : l:Root endif return ale#util#GetFunction(a:linter.project_root_callback)(a:buffer) endfunction " This function is accessible so tests can call it. function! ale#lsp_linter#OnInit(linter, details, Callback) abort let l:buffer = a:details.buffer let l:conn_id = a:details.connection_id let l:command = a:details.command let l:config = ale#lsp_linter#GetConfig(l:buffer, a:linter) call ale#lsp#UpdateConfig(l:conn_id, l:buffer, l:config) if ale#lsp#OpenDocument(l:conn_id, l:buffer) if g:ale_history_enabled && !empty(l:command) call ale#history#Add(l:buffer, 'started', l:conn_id, l:command) endif endif " 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:buffer) endif " Tell the relevant buffer that the LSP has started via an autocmd. if l:buffer > 0 if l:buffer == bufnr('') silent doautocmd User ALELSPStarted else execute 'augroup ALELSPStartedGroup' . l:buffer autocmd! execute printf( \ 'autocmd BufEnter ' \ . ' doautocmd User ALELSPStarted', \ l:buffer \) " Replicate ++once behavior for backwards compatibility. execute printf( \ 'autocmd BufEnter ' \ . ' autocmd! ALELSPStartedGroup%d', \ l:buffer, l:buffer \) augroup END endif endif call a:Callback(a:linter, a:details) endfunction function! s:StartLSP(options, address, executable, command) abort let l:buffer = a:options.buffer let l:linter = a:options.linter let l:root = a:options.root let l:Callback = a:options.callback let l:init_options = ale#lsp_linter#GetOptions(l:buffer, l:linter) if l:linter.lsp is# 'socket' let l:conn_id = ale#lsp#Register( \ a:address, \ l:root, \ l:linter.language, \ l:init_options \) let l:ready = ale#lsp#ConnectToAddress(l:conn_id, a:address) let l:command = '' else let l:conn_id = ale#lsp#Register( \ a:executable, \ l:root, \ l:linter.language, \ l:init_options \) " tsserver behaves differently, so tell the LSP API that it is tsserver. if l:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(l:conn_id) endif let l:cwd = ale#linter#GetCwd(l:buffer, l:linter) let l:command = ale#command#FormatCommand( \ l:buffer, \ a:executable, \ a:command, \ 0, \ v:false, \ l:cwd, \ ale#GetFilenameMappings(l:buffer, l:linter.name), \)[1] let l:command = ale#job#PrepareCommand(l:buffer, l:command) let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command) endif if !l:ready if g:ale_history_enabled && !empty(a:command) call ale#history#Add(l:buffer, 'failed', l:conn_id, a:command) endif return 0 endif let l:details = { \ 'buffer': l:buffer, \ 'connection_id': l:conn_id, \ 'command': l:command, \ 'project_root': l:root, \} call ale#lsp#OnInit(l:conn_id, {-> \ ale#lsp_linter#OnInit(l:linter, l:details, l:Callback) \}) return 1 endfunction function! s:StartWithAddress(options, address) abort if ale#command#IsDeferred(a:address) let a:address.result_callback = { \ address -> s:StartWithAddress(a:options, address) \} return 1 endif if empty(a:address) return 0 endif return s:StartLSP(a:options, a:address, '', '') endfunction function! s:StartWithCommand(options, executable, command) abort if ale#command#IsDeferred(a:command) let a:command.result_callback = { \ command -> s:StartWithCommand(a:options, a:executable, command) \} return 1 endif if empty(a:command) return 0 endif return s:StartLSP(a:options, '', a:executable, a:command) endfunction function! s:StartIfExecutable(options, executable) abort if ale#command#IsDeferred(a:executable) let a:executable.result_callback = { \ executable -> s:StartIfExecutable(a:options, executable) \} return 1 endif if !ale#engine#IsExecutable(a:options.buffer, a:executable) return 0 endif let l:command = ale#linter#GetCommand(a:options.buffer, a:options.linter) return s:StartWithCommand(a:options, a:executable, l:command) endfunction " Given a buffer, an LSP linter, start up an LSP linter and get ready to " receive messages for the document. function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let l:command = '' let l:address = '' let l:root = ale#lsp_linter#FindProjectRoot(a:buffer, a:linter) if empty(l:root) && a:linter.lsp isnot# 'tsserver' " If there's no project root, then we can't check files with LSP, " unless we are using tsserver, which doesn't use project roots. call ale#lsp_linter#AddErrorMessage(a:linter.name, "Failed to find project root, language server won't start.") return 0 endif let l:options = { \ 'buffer': a:buffer, \ 'linter': a:linter, \ 'callback': a:Callback, \ 'root': l:root, \} if a:linter.lsp is# 'socket' let l:address = ale#linter#GetAddress(a:buffer, a:linter) return s:StartWithAddress(l:options, l:address) endif let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) return s:StartIfExecutable(l:options, l:executable) endfunction function! s:CheckWithLSP(linter, details) abort let l:buffer = a:details.buffer let l:info = get(g:ale_buffer_info, l:buffer) if empty(l:info) return endif let l:id = a:details.connection_id " Register a callback now for handling errors now. let l:Callback = function('ale#lsp_linter#HandleLSPResponse') call ale#lsp#RegisterCallback(l:id, l:Callback) " Remember the linter this connection is for. let s:lsp_linter_map[l:id] = a:linter if a:linter.lsp is# 'tsserver' let l:message = ale#lsp#tsserver_message#Geterr(l:buffer) let l:notified = ale#lsp#Send(l:id, l:message) != 0 if l:notified call ale#engine#MarkLinterActive(l:info, a:linter) endif elseif !g:ale_use_neovim_lsp_api let l:notified = ale#lsp#NotifyForChanges(l:id, l:buffer) " If this was a file save event, also notify the server of that. if getbufvar(l:buffer, 'ale_save_event_fired', 0) \&& ale#lsp#HasCapability(l:id, 'did_save') let l:include_text = ale#lsp#HasCapability(l:id, 'includeText') let l:save_message = ale#lsp#message#DidSave(l:buffer, l:include_text) let l:notified = ale#lsp#Send(l:id, l:save_message) != 0 endif let l:diagnostic_request_id = 0 " If the document is updated and we can pull diagnostics, try to. if ale#lsp#HasCapability(l:id, 'pull_model') let l:diagnostic_message = ale#lsp#message#Diagnostic(l:buffer) let l:diagnostic_request_id = ale#lsp#Send(l:id, l:diagnostic_message) endif " If we are going to pull diagnostics, then mark the linter as active, " and remember the URI we sent the request for. if l:diagnostic_request_id call ale#engine#MarkLinterActive(l:info, a:linter) let s:diagnostic_uri_map[l:diagnostic_request_id] = \ l:diagnostic_message[2].textDocument.uri endif endif endfunction function! ale#lsp_linter#CheckWithLSP(buffer, linter) abort return ale#lsp_linter#StartLSP(a:buffer, a:linter, function('s:CheckWithLSP')) endfunction function! s:HandleLSPResponseToCustomRequests(conn_id, response) abort if has_key(a:response, 'id') " Get the custom handlers Dictionary from the linter map. let l:linter = get(s:lsp_linter_map, a:conn_id, {}) let l:custom_handlers = get(l:linter, 'custom_handlers', {}) if has_key(l:custom_handlers, a:response.id) let l:Handler = remove(l:custom_handlers, a:response.id) call l:Handler(a:response) endif endif endfunction function! s:OnReadyForCustomRequests(args, linter, lsp_details) abort let l:id = a:lsp_details.connection_id let l:request_id = ale#lsp#Send(l:id, a:args.message) if l:request_id > 0 && has_key(a:args, 'handler') let l:Callback = function('s:HandleLSPResponseToCustomRequests') call ale#lsp#RegisterCallback(l:id, l:Callback) " Remember the linter this connection is for. let s:lsp_linter_map[l:id] = a:linter " Add custom_handlers to the linter Dictionary. if !has_key(a:linter, 'custom_handlers') let a:linter.custom_handlers = {} endif " Put the handler function in the map to call later. let a:linter.custom_handlers[l:request_id] = a:args.handler endif endfunction " Send a custom request to an LSP linter. function! ale#lsp_linter#SendRequest(buffer, linter_name, message, ...) abort let l:filetype = ale#linter#ResolveFiletype(getbufvar(a:buffer, '&filetype')) let l:linter_list = ale#linter#GetAll(l:filetype) let l:linter_list = filter(l:linter_list, {_, v -> v.name is# a:linter_name}) if len(l:linter_list) < 1 throw 'Linter "' . a:linter_name . '" not found!' endif let l:linter = l:linter_list[0] if empty(l:linter.lsp) throw 'Linter "' . a:linter_name . '" does not support LSP!' endif let l:is_notification = a:message[0] let l:callback_args = {'message': a:message} if !l:is_notification && a:0 let l:callback_args.handler = a:1 endif let l:Callback = function('s:OnReadyForCustomRequests', [l:callback_args]) return ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback) endfunction ================================================ FILE: autoload/ale/lsp_window.vim ================================================ " Author: suoto " Description: Handling of window/* LSP methods, although right now only " handles window/showMessage " Constants for message type codes let s:LSP_MESSAGE_TYPE_DISABLED = 0 let s:LSP_MESSAGE_TYPE_ERROR = 1 let s:LSP_MESSAGE_TYPE_WARNING = 2 let s:LSP_MESSAGE_TYPE_INFORMATION = 3 let s:LSP_MESSAGE_TYPE_LOG = 4 " Translate strings from the user config to a number so we can check " severities let s:CFG_TO_LSP_SEVERITY = { \ 'disabled': s:LSP_MESSAGE_TYPE_DISABLED, \ 'error': s:LSP_MESSAGE_TYPE_ERROR, \ 'warning': s:LSP_MESSAGE_TYPE_WARNING, \ 'information': s:LSP_MESSAGE_TYPE_INFORMATION, \ 'info': s:LSP_MESSAGE_TYPE_INFORMATION, \ 'log': s:LSP_MESSAGE_TYPE_LOG \} " Handle window/showMessage response. " - details: dict containing linter name and format (g:ale_lsp_show_message_format) " - params: dict with the params for the call in the form of {type: number, message: string} function! ale#lsp_window#HandleShowMessage(linter_name, format, params) abort let l:message = a:params.message let l:type = a:params.type " Get the configured severity level threshold and check if the message " should be displayed or not let l:configured_severity = tolower(get(g:, 'ale_lsp_show_message_severity', 'error')) " If the user has configured with a value we can't find on the conversion " dict, fall back to warning let l:cfg_severity_threshold = get(s:CFG_TO_LSP_SEVERITY, l:configured_severity, s:LSP_MESSAGE_TYPE_WARNING) if l:type > l:cfg_severity_threshold return endif " Severity will depend on the message type if l:type is# s:LSP_MESSAGE_TYPE_ERROR let l:severity = g:ale_echo_msg_error_str elseif l:type is# s:LSP_MESSAGE_TYPE_INFORMATION let l:severity = g:ale_echo_msg_info_str elseif l:type is# s:LSP_MESSAGE_TYPE_LOG let l:severity = g:ale_echo_msg_log_str else " Default to warning just in case let l:severity = g:ale_echo_msg_warning_str endif let l:string = substitute(a:format, '\V%severity%', l:severity, 'g') let l:string = substitute(l:string, '\V%linter%', a:linter_name, 'g') let l:string = substitute(l:string, '\V%s\>', l:message, 'g') call ale#util#ShowMessage(l:string) endfunction ================================================ FILE: autoload/ale/lua.vim ================================================ " Author: w0rp " Description: Functions for integrating with Lua linters. " Find project root for a Lua language server. function! ale#lua#FindProjectRoot(buffer) abort let l:possible_project_roots = [ \ '.luarc.json', \ '.git', \ bufname(a:buffer), \] for l:possible_root in l:possible_project_roots let l:project_root = ale#path#FindNearestFile(a:buffer, l:possible_root) if empty(l:project_root) let l:project_root = ale#path#FindNearestDirectory(a:buffer, l:possible_root) endif if !empty(l:project_root) " dir:p expands to /full/path/to/dir/ whereas " file:p expands to /full/path/to/file (no trailing slash) " Appending '/' ensures that :h:h removes the path's last segment " regardless of whether it is a directory or not. return fnamemodify(l:project_root . '/', ':p:h:h') endif endfor return '' endfunction ================================================ FILE: autoload/ale/maven.vim ================================================ " Description: Functions for working with Maven projects. " " Given a buffer number, find a Maven project root. function! ale#maven#FindProjectRoot(buffer) abort let l:wrapper_path = ale#path#FindNearestFile(a:buffer, 'mvnw') if !empty(l:wrapper_path) return fnamemodify(l:wrapper_path, ':h') endif let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') if !empty(l:pom_path) return fnamemodify(l:pom_path, ':h') endif return '' endfunction " Given a buffer number, find the path to the executable. " First search on the path for 'mvnw' (mvnw.cmd on Windows), if nothing is found, " try the global command. Returns an empty string if cannot find the executable. function! ale#maven#FindExecutable(buffer) abort let l:wrapper_cmd = has('unix') ? 'mvnw' : 'mvnw.cmd' let l:wrapper_path = ale#path#FindNearestFile(a:buffer, l:wrapper_cmd) if !empty(l:wrapper_path) && executable(l:wrapper_path) return l:wrapper_path endif if executable('mvn') return 'mvn' endif return '' endfunction " Given a buffer number, get a working directory and command to print the " classpath of the root project. " " Returns an empty string for the command if Maven is not detected. function! ale#maven#BuildClasspathCommand(buffer) abort let l:executable = ale#maven#FindExecutable(a:buffer) if !empty(l:executable) let l:project_root = ale#maven#FindProjectRoot(a:buffer) if !empty(l:project_root) return [ \ l:project_root, \ ale#Escape(l:executable) . ' dependency:build-classpath' \] endif endif return ['', ''] endfunction ================================================ FILE: autoload/ale/node.vim ================================================ " Author: w0rp " Description: Functions for working with Node executables. call ale#Set('windows_node_executable_path', 'node.exe') " Create a executable string which executes a Node.js script command with a " Node.js executable if needed. " " The executable string should not be escaped before passing it to this " function, the executable string will be escaped when returned by this " function. " " The executable is only prefixed for Windows machines function! ale#node#Executable(buffer, executable) abort if has('win32') && a:executable =~? '\.js$' let l:node = ale#Var(a:buffer, 'windows_node_executable_path') return ale#Escape(l:node) . ' ' . ale#Escape(a:executable) endif return ale#Escape(a:executable) endfunction ================================================ FILE: autoload/ale/organize_imports.vim ================================================ " Author: Jerko Steiner " Description: Organize imports support for tsserver function! ale#organize_imports#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') isnot# 'organizeImports' return endif if get(a:response, 'success', v:false) isnot v:true return endif let l:file_code_edits = a:response.body call ale#code_action#HandleCodeAction( \ { \ 'description': 'Organize Imports', \ 'changes': l:file_code_edits, \ }, \ { \ 'conn_id': a:conn_id, \ 'should_save': g:ale_save_hidden || !&hidden, \ }, \) endfunction function! s:OnReady(linter, lsp_details) abort let l:id = a:lsp_details.connection_id if a:linter.lsp isnot# 'tsserver' call ale#util#Execute('echom ''OrganizeImports currently only works with tsserver''') return endif let l:buffer = a:lsp_details.buffer let l:Callback = function('ale#organize_imports#HandleTSServerResponse') call ale#lsp#RegisterCallback(l:id, l:Callback) let l:message = ale#lsp#tsserver_message#OrganizeImports(l:buffer) let l:request_id = ale#lsp#Send(l:id, l:message) endfunction function! s:OrganizeImports(linter) abort let l:buffer = bufnr('') let [l:line, l:column] = getpos('.')[1:2] if a:linter.lsp isnot# 'tsserver' let l:column = min([l:column, len(getline(l:line))]) endif let l:Callback = function('s:OnReady') call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction function! ale#organize_imports#Execute() abort for l:linter in ale#lsp_linter#GetEnabled(bufnr('')) call s:OrganizeImports(l:linter) endfor endfunction ================================================ FILE: autoload/ale/other_source.vim ================================================ " 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 ================================================ FILE: autoload/ale/path.vim ================================================ " Author: w0rp " Description: Functions for working with paths in the filesystem. " simplify a path, and fix annoying issues with paths on Windows. " " Forward slashes are changed to back slashes so path equality works better " on Windows. Back slashes are changed to forward slashes on Unix. " " Unix paths can technically contain back slashes, but in practice no path " should, and replacing back slashes with forward slashes makes linters work " in environments like MSYS. " " Paths starting with more than one forward slash are changed to only one " forward slash, to prevent the paths being treated as special MSYS paths. function! ale#path#Simplify(path) abort if has('unix') let l:unix_path = substitute(a:path, '\\', '/', 'g') return substitute(simplify(l:unix_path), '^//\+', '/', 'g') " no-custom-checks endif let l:win_path = substitute(a:path, '/', '\\', 'g') return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks endfunction " Simplify a path without a Windows drive letter. " This function can be used for checking if paths are equal. function! ale#path#RemoveDriveLetter(path) abort return has('win32') && a:path[1:2] is# ':\' \ ? ale#path#Simplify(a:path[2:]) \ : ale#path#Simplify(a:path) endfunction " Given a buffer and a filename, find the nearest file by searching upwards " through the paths relative to the given buffer. function! ale#path#FindNearestFile(buffer, filename) abort let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') let l:buffer_filename = fnameescape(l:buffer_filename) let l:relative_path = findfile(a:filename, l:buffer_filename . ';') if !empty(l:relative_path) return fnamemodify(l:relative_path, ':p') endif return '' endfunction " Given a buffer and a directory name, find the nearest directory by searching upwards " through the paths relative to the given buffer. function! ale#path#FindNearestDirectory(buffer, directory_name) abort let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') let l:buffer_filename = fnameescape(l:buffer_filename) let l:relative_path = finddir(a:directory_name, l:buffer_filename . ';') if !empty(l:relative_path) return fnamemodify(l:relative_path, ':p') endif return '' endfunction " Given a buffer and a filename, find the nearest file or directory by " searching upwards through the paths relative to the given buffer. function! ale#path#FindNearestFileOrDirectory(buffer, filename) abort let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') let l:buffer_filename = fnameescape(l:buffer_filename) let l:relative_path_file = findfile(a:filename, l:buffer_filename . ';') let l:relative_path_dir = finddir(a:filename, l:buffer_filename . ';') " If we find both a file and directory, choose the shorter response by " making the longer one empty instead. if !empty(l:relative_path_file) && !empty(l:relative_path_dir) if strlen(l:relative_path_file) > strlen(l:relative_path_dir) let l:relative_path_dir = '' else let l:relative_path_file = '' endif endif if !empty(l:relative_path_file) return fnamemodify(l:relative_path_file, ':p') endif if !empty(l:relative_path_dir) return fnamemodify(l:relative_path_dir, ':p') endif return '' endfunction " Given a buffer, a string to search for, and a global fallback for when " the search fails, look for a file in parent paths, and if that fails, " use the global fallback path instead. function! ale#path#ResolveLocalPath(buffer, search_string, global_fallback) abort " Search for a locally installed file first. let l:path = ale#path#FindNearestFile(a:buffer, a:search_string) " If the search fails, try the global executable instead. if empty(l:path) let l:path = a:global_fallback endif return l:path endfunction " Given a buffer number, a base variable name, and a list of paths to search " for in ancestor directories, detect the executable path for a program. function! ale#path#FindNearestExecutable(buffer, path_list) abort for l:path in a:path_list if ale#path#IsAbsolute(l:path) let l:executable = filereadable(l:path) ? l:path : '' else let l:executable = ale#path#FindNearestFile(a:buffer, l:path) endif if !empty(l:executable) return l:executable endif endfor return '' endfunction " Given a buffer number, a base variable name, and a list of paths to search " for in ancestor directories, detect the executable path for a program. " " The use_global and executable options for the relevant program will be used. function! ale#path#FindExecutable(buffer, base_var_name, path_list) abort if ale#Var(a:buffer, a:base_var_name . '_use_global') return ale#Var(a:buffer, a:base_var_name . '_executable') endif let l:nearest = ale#path#FindNearestExecutable(a:buffer, a:path_list) if !empty(l:nearest) return l:nearest endif return ale#Var(a:buffer, a:base_var_name . '_executable') endfunction " Return 1 if a path is an absolute path. function! ale#path#IsAbsolute(filename) abort if has('win32') return a:filename[:0] =~# '[\\/]' || a:filename[0:2] =~? '[A-Z]:[/\\]' else return a:filename[:0] is# '/' endif endfunction let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h:h')) let s:resolved_temp_dir = resolve(s:temp_dir) " Given a filename, return 1 if the file represents some temporary file " created by Vim. If the temporary location is symlinked (e.g. macOS), some " linters may report the resolved version of the path, so both are checked. function! ale#path#IsTempName(filename) abort let l:filename = ale#path#Simplify(a:filename) return l:filename[:len(s:temp_dir) - 1] is# s:temp_dir \|| l:filename[:len(s:resolved_temp_dir) - 1] is# s:resolved_temp_dir endfunction " Given a base directory, which must not have a trailing slash, and a " filename, which may have an absolute path a path relative to the base " directory, return the absolute path to the file. function! ale#path#GetAbsPath(base_directory, filename) abort if ale#path#IsAbsolute(a:filename) return ale#path#Simplify(a:filename) endif let l:sep = has('win32') ? '\' : '/' 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# '/' || (has('win32') && 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 " If the path is one of many different names for stdin, we have a match. if a:complex_filename is# '-' \|| a:complex_filename is# 'stdin' \|| a:complex_filename[:0] is# '<' return 1 endif let l:test_filename = ale#path#Simplify(a:complex_filename) if l:test_filename[:1] is# './' let l:test_filename = l:test_filename[2:] endif if l:test_filename[:1] is# '..' " Remove ../../ etc. from the front of the path. let l:test_filename = substitute(l:test_filename, '\v^(\.\.[/\\])+', '/', '') endif " Use the basename for temporary files, as they are likely our files. if ale#path#IsTempName(l:test_filename) let l:test_filename = fnamemodify(l:test_filename, ':t') endif let l:buffer_filename = expand('#' . a:buffer . ':p') return l:buffer_filename is# l:test_filename \ || l:buffer_filename[-len(l:test_filename):] is# l:test_filename endfunction " Given a path, return every component of the path, moving upwards. function! ale#path#Upwards(path) abort let l:pattern = has('win32') ? '\v/+|\\+' : '\v/+' let l:sep = has('win32') ? '\' : '/' let l:parts = split(ale#path#Simplify(a:path), l:pattern) let l:path_list = [] while !empty(l:parts) call add(l:path_list, join(l:parts, l:sep)) let l:parts = l:parts[:-2] endwhile if has('win32') && a:path =~# '^[a-zA-z]:\' " Add \ to C: for C:\, etc. let l:path_list[-1] .= '\' elseif a:path[0] is# '/' " If the path starts with /, even on Windows, add / and / to all paths. call map(l:path_list, '''/'' . v:val') call add(l:path_list, '/') endif return l:path_list endfunction " Convert a filesystem path to a file:// URI " relatives paths will not be prefixed with the protocol. " For Windows paths, the `:` in C:\ etc. will not be percent-encoded. function! ale#path#ToFileURI(path) abort let l:has_drive_letter = a:path[1:2] is# ':\' return substitute( \ ((l:has_drive_letter || a:path[:0] is# '/') ? 'file://' : '') \ . (l:has_drive_letter ? '/' . a:path[:2] : '') \ . ale#uri#Encode(l:has_drive_letter ? a:path[3:] : a:path), \ '\\', \ '/', \ 'g', \) endfunction function! ale#path#FromFileURI(uri) abort if a:uri[:6] is? 'file://' let l:encoded_path = a:uri[7:] elseif a:uri[:4] is? 'file:' let l:encoded_path = a:uri[5:] else let l:encoded_path = a:uri endif let l:path = ale#uri#Decode(l:encoded_path) " If the path is like /C:/foo/bar, it should be C:\foo\bar instead. if has('win32') && l:path =~# '^/[a-zA-Z][:|]' let l:path = substitute(l:path[1:], '/', '\\', 'g') let l:path = l:path[0] . ':' . l:path[2:] endif return l:path endfunction ================================================ FILE: autoload/ale/pattern_options.vim ================================================ " Author: w0rp " Description: Set options in files based on regex patterns. " These variables are used to cache the sorting of patterns below. let s:last_pattern_options = {} let s:sorted_items = [] function! s:CmpPatterns(left_item, right_item) abort if a:left_item[0] < a:right_item[0] return -1 endif if a:left_item[0] > a:right_item[0] return 1 endif return 0 endfunction function! ale#pattern_options#SetOptions(buffer) abort let l:pattern_options = get(g:, 'ale_pattern_options', {}) if empty(l:pattern_options) " Stop if no options are set. return endif " The items will only be sorted whenever the patterns change. if l:pattern_options != s:last_pattern_options let s:last_pattern_options = deepcopy(l:pattern_options) " The patterns are sorted, so they are applied consistently. let s:sorted_items = sort( \ items(l:pattern_options), \ function('s:CmpPatterns') \) endif let l:filename = expand('#' . a:buffer . ':p') for [l:pattern, l:options] in s:sorted_items if match(l:filename, l:pattern) >= 0 for [l:key, l:value] in items(l:options) call setbufvar(a:buffer, l:key, l:value) endfor endif endfor endfunction ================================================ FILE: autoload/ale/powershell.vim ================================================ " Author: zigford " Description: Functions for integrating with Powershell linters. " Write a powershell script to a temp file for execution " return the command used to execute it function! s:TemporaryPSScript(buffer, input) abort let l:filename = 'script.ps1' " Create a temp dir to house our temp .ps1 script " a temp dir is needed as powershell needs the .ps1 " extension let l:tempdir = ale#util#Tempname() . (has('win32') ? '\' : '/') let l:tempscript = l:tempdir . l:filename " Create the temporary directory for the file, unreadable by 'other' " users. call mkdir(l:tempdir, '', 0750) " Automatically delete the directory later. call ale#command#ManageDirectory(a:buffer, l:tempdir) " Write the script input out to a file. call ale#util#Writefile(a:buffer, a:input, l:tempscript) return l:tempscript endfunction function! ale#powershell#RunPowerShell(buffer, base_var_name, command) abort let l:executable = ale#Var(a:buffer, a:base_var_name . '_executable') let l:tempscript = s:TemporaryPSScript(a:buffer, a:command) return ale#Escape(l:executable) \ . ' -Exe Bypass -NoProfile -File ' \ . ale#Escape(l:tempscript) \ . ' %t' endfunction ================================================ FILE: autoload/ale/preview.vim ================================================ " Author: w0rp " Description: Preview windows for showing whatever information in. if !has_key(s:, 'last_list') let s:last_list = [] endif if !has_key(s:, 'last_options') let s:last_options = {} endif function! ale#preview#SetLastSelection(item_list, options) abort let s:last_list = a:item_list let s:last_options = { \ 'open_in': get(a:options, 'open_in', 'current-buffer'), \ 'use_relative_paths': get(a:options, 'use_relative_paths', 0), \} endfunction " Open a preview window and show some lines in it. " A second argument can be passed as a Dictionary with options. They are... " " filetype - The filetype to use, defaulting to 'ale-preview' " stay_here - If 1, stay in the window you came from. function! ale#preview#Show(lines, ...) abort let l:options = get(a:000, 0, {}) silent pedit ALEPreviewWindow wincmd P setlocal modifiable setlocal noreadonly setlocal nobuflisted 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') for l:command in get(l:options, 'commands', []) call execute(l:command) endfor if get(l:options, 'stay_here') wincmd p endif endfunction " Close the preview window if the filetype matches the given one. function! ale#preview#CloseIfTypeMatches(filetype) abort for l:win in getwininfo() let l:wintype = gettabwinvar(l:win.tabnr, l:win.winnr, '&filetype') if l:wintype is# a:filetype silent! pclose! endif endfor endfunction " Show a location selection preview window, given some items. " Each item should have 'filename', 'line', and 'column' keys. function! ale#preview#ShowSelection(item_list, ...) abort let l:options = get(a:000, 0, {}) let l:sep = has('win32') ? '\' : '/' let l:lines = [] " Create lines to display to users. for l:item in a:item_list let l:match = get(l:item, 'match', '') let l:filename = l:item.filename if get(l:options, 'use_relative_paths') let l:cwd = getcwd() " no-custom-checks let l:filename = substitute(l:filename, '^' . l:cwd . l:sep, '', '') endif call add( \ l:lines, \ l:filename \ . ':' . l:item.line \ . ':' . l:item.column \ . ale#Pad(l:match), \) endfor call ale#preview#Show(l:lines, {'filetype': 'ale-preview-selection'}) let b:ale_preview_item_list = a:item_list let b:ale_preview_item_open_in = get(l:options, 'open_in', 'current-buffer') " Jump to an index for a previous selection, if set. if has_key(l:options, 'jump_to_index') let l:pos = getpos('.') let l:pos[1] = l:options.jump_to_index + 1 call setpos('.', l:pos) endif " Remember preview state, so we can repeat it later. call ale#preview#SetLastSelection(a:item_list, l:options) endfunction function! ale#preview#RepeatSelection() abort if !empty(s:last_list) call ale#preview#ShowSelection(s:last_list, s:last_options) endif endfunction function! s:Open(open_in) abort let l:item_list = get(b:, 'ale_preview_item_list', []) let l:index = getpos('.')[1] - 1 let l:item = get(l:item_list, l:index, {}) if empty(l:item) return endif " Remember an index to jump to when repeating a selection. let s:last_options.jump_to_index = l:index :q! call ale#util#Open( \ l:item.filename, \ l:item.line, \ l:item.column, \ {'open_in': a:open_in}, \) endfunction function! ale#preview#OpenSelection() abort call s:Open(b:ale_preview_item_open_in) endfunction function! ale#preview#OpenSelectionInTab() abort call s:Open('tab') endfunction ================================================ FILE: autoload/ale/proselint.vim ================================================ call ale#Set('proselint_executable', 'proselint') function! ale#proselint#GetExecutable(buffer) abort return ale#Var(a:buffer, 'proselint_executable') endfunction function! ale#proselint#GetCommand(buffer, version) abort let l:executable = ale#proselint#GetExecutable(a:buffer) let l:escaped_exec = ale#Escape(l:executable) if ale#semver#GTE(a:version, [0, 16, 0]) return l:escaped_exec . ' check %t' else return l:escaped_exec . ' %t' endif endfunction function! ale#proselint#GetCommandWithVersionCheck(buffer) abort return ale#semver#RunWithVersionCheck( \ a:buffer, \ ale#proselint#GetExecutable(a:buffer), \ '%e version --output-format json', \ function('ale#proselint#GetCommand') \) endfunction ================================================ FILE: autoload/ale/python.vim ================================================ " Author: w0rp " Description: Functions for integrating with Python linters. call ale#Set('python_auto_pipenv', '0') call ale#Set('python_auto_poetry', '0') call ale#Set('python_auto_uv', '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' " The default virtualenv directory names are ordered from the likely most " common names down to the least common. `.env` might be more common, but it's " also likely to conflict with a `.env` file for environment variables, so we " search for it last. (People really shouldn't use that name.) let g:ale_virtualenv_dir_names = get(g:, 'ale_virtualenv_dir_names', [ \ '.venv', \ 'env', \ 've', \ 'venv', \ 'virtualenv', \ '.env', \]) function! ale#python#FindProjectRootIni(buffer) abort for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) " If you change this, update ale-python-root documentation. if filereadable(l:path . '/MANIFEST.in') \|| filereadable(l:path . '/setup.cfg') \|| filereadable(l:path . '/tox.ini') \|| filereadable(l:path . '/.pyre_configuration.local') \|| filereadable(l:path . '/mypy.ini') \|| filereadable(l:path . '/.mypy.ini') \|| filereadable(l:path . '/pycodestyle.cfg') \|| filereadable(l:path . '/.flake8') \|| filereadable(l:path . '/.flake8rc') \|| filereadable(l:path . '/pylama.ini') \|| filereadable(l:path . '/pylintrc') \|| filereadable(l:path . '/.pylintrc') \|| filereadable(l:path . '/pyrightconfig.json') \|| filereadable(l:path . '/pyrightconfig.toml') \|| filereadable(l:path . '/Pipfile') \|| filereadable(l:path . '/Pipfile.lock') \|| filereadable(l:path . '/poetry.lock') \|| filereadable(l:path . '/pyproject.toml') \|| filereadable(l:path . '/.tool-versions') \|| filereadable(l:path . '/uv.lock') return l:path endif endfor return '' endfunction " Given a buffer number, find the project root directory for Python. " The root directory is defined as the first directory found while searching " upwards through paths, including the current directory, until a path " containing an configuration file is found. (See list above) " " If it is not possible to find the project root directory via configuration " file, then it will be defined as the first directory found searching upwards " through paths, including the current directory, until no __init__.py files " is found. function! ale#python#FindProjectRoot(buffer) abort let l:ini_root = ale#python#FindProjectRootIni(a:buffer) if !empty(l:ini_root) return l:ini_root endif for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) if !filereadable(l:path . '/__init__.py') return l:path endif endfor return '' endfunction " Given a buffer number, find a virtualenv path for Python. function! ale#python#FindVirtualenv(buffer) abort for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) " Skip empty path components returned in MSYS. if empty(l:path) continue endif for l:dirname in ale#Var(a:buffer, 'virtualenv_dir_names') let l:venv_dir = ale#path#Simplify( \ join([l:path, l:dirname], s:sep) \) let l:script_filename = ale#path#Simplify( \ join([l:venv_dir, s:bin_dir, 'activate'], s:sep) \) if filereadable(l:script_filename) return l:venv_dir endif endfor endfor return $VIRTUAL_ENV endfunction " Automatically determine virtualenv environment variables and build " a string of them to prefix linter commands with. function! ale#python#AutoVirtualenvEnvString(buffer) abort let l:venv_dir = ale#python#FindVirtualenv(a:buffer) if !empty(l:venv_dir) let l:strs = [ ] " venv/bin directory let l:pathdir = join([l:venv_dir, s:bin_dir], s:sep) " expand PATH correctly inside of the appropriate shell. " set VIRTUAL_ENV to point to venv if has('win32') call add(l:strs, 'set PATH=' . ale#Escape(l:pathdir) . ';%PATH% && ') call add(l:strs, 'set VIRTUAL_ENV=' . ale#Escape(l:venv_dir) . ' && ') else call add(l:strs, 'PATH=' . ale#Escape(l:pathdir) . '":$PATH" ') call add(l:strs, 'VIRTUAL_ENV=' . ale#Escape(l:venv_dir) . ' ') endif return join(l:strs, '') endif return '' endfunction " Given a buffer number and a command name, find the path to the executable. " First search on a virtualenv for Python, if nothing is found, try the global " command. Returns an empty string if cannot find the executable function! ale#python#FindExecutable(buffer, base_var_name, path_list) abort if ale#Var(a:buffer, a:base_var_name . '_use_global') return ale#Var(a:buffer, a:base_var_name . '_executable') endif let l:virtualenv = ale#python#FindVirtualenv(a:buffer) if !empty(l:virtualenv) for l:path in a:path_list let l:ve_executable = ale#path#Simplify( \ join([l:virtualenv, s:bin_dir, l:path], s:sep) \) if executable(l:ve_executable) return l:ve_executable endif endfor endif return ale#Var(a:buffer, a:base_var_name . '_executable') endfunction " Handle traceback.print_exception() output starting in the first a:limit lines. function! ale#python#HandleTraceback(lines, limit) abort let l:nlines = len(a:lines) let l:limit = a:limit > l:nlines ? l:nlines : a:limit let l:start = 0 while l:start < l:limit if a:lines[l:start] is# 'Traceback (most recent call last):' break endif let l:start += 1 endwhile if l:start >= l:limit return [] endif let l:end = l:start + 1 " Traceback entries are always prefixed with 2 spaces. " SyntaxError marker (if present) is prefixed with at least 4 spaces. " Final exc line starts with exception class name (never a space). while l:end < l:nlines && a:lines[l:end][0] is# ' ' let l:end += 1 endwhile let l:exc_line = l:end < l:nlines \ ? a:lines[l:end] \ : 'An exception was thrown.' return [{ \ 'lnum': 1, \ 'text': l:exc_line . ' (See :ALEDetail)', \ 'detail': join(a:lines[(l:start):(l:end)], "\n"), \}] 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 " Detects whether a poetry environment is present. function! ale#python#PoetryPresent(buffer) abort return findfile('poetry.lock', expand('#' . a:buffer . ':p:h') . ';') isnot# '' endfunction " Detects whether a uv environment is present. function! ale#python#UvPresent(buffer) abort return findfile('uv.lock', expand('#' . a:buffer . ':p:h') . ';') isnot# '' endfunction ================================================ FILE: autoload/ale/racket.vim ================================================ function! ale#racket#FindProjectRoot(buffer) abort let l:cwd = expand('#' . a:buffer . ':p:h') let l:highest_init = l:cwd for l:path in ale#path#Upwards(l:cwd) if filereadable(l:path.'/init.rkt') let l:highest_init = l:path endif endfor return l:highest_init endfunction ================================================ FILE: autoload/ale/references.vim ================================================ let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer') let g:ale_references_show_contents = get(g:, 'ale_references_show_contents', 1) let g:ale_references_use_fzf = get(g:, 'ale_references_use_fzf', 0) let s:references_map = {} " Used to get the references map in tests. function! ale#references#GetMap() abort return deepcopy(s:references_map) endfunction " Used to set the references map in tests. function! ale#references#SetMap(map) abort let s:references_map = a:map endfunction function! ale#references#ClearLSPData() abort let s:references_map = {} endfunction function! ale#references#FormatResponseItem(response_item, options) abort let l:filename = get(a:response_item, 'filename', '') let l:column = get(a:response_item, 'column', 0) let l:line = get(a:response_item, 'line', 0) let l:line_text = get(a:response_item, 'line_text', '') try let l:line_text = substitute( \ l:line_text, \ '^\s*\(.\{-}\)\s*$', '\1', '' \) catch " This happens in tests endtry if get(a:options, 'use_fzf') == 1 " grep-style output (filename:line:col:text) so that fzf can properly " show matches and previews using ':' as delimiter return l:filename . ':' . l:line . ':' . l:column . ':' . l:line_text endif if get(a:options, 'open_in') is# 'quickfix' return { \ 'filename': l:filename, \ 'lnum': l:line, \ 'col': l:column, \ 'text': l:line_text, \} else return { \ 'filename': l:filename, \ 'line': l:line, \ 'column': l:column, \ 'match': l:line_text, \} endif endfunction function! ale#references#DisplayReferences(item_list, options) abort if empty(a:item_list) call ale#util#Execute('echom ''No references found.''') else if get(a:options, 'use_fzf') == 1 if !exists('*fzf#run') throw 'fzf#run function not found. You also need Vim plugin from the main fzf repository (i.e. junegunn/fzf *and* junegunn/fzf.vim)' endif call ale#fzf#ShowReferences(a:item_list, a:options) elseif get(a:options, 'open_in') is# 'quickfix' call setqflist([], 'r') call setqflist(a:item_list, 'a') call ale#util#Execute('cc 1') else call ale#preview#ShowSelection(a:item_list, a:options) endif endif endfunction function! ale#references#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') is# 'references' \&& has_key(s:references_map, a:response.request_seq) let l:options = remove(s:references_map, a:response.request_seq) let l:format_options = copy(l:options) if get(a:response, 'success', v:false) is v:true let l:item_list = [] for l:response_item in a:response.body.refs let l:format_response_item = { \ 'filename': l:response_item.file, \ 'line': l:response_item.start.line, \ 'column': l:response_item.start.offset, \ 'line_text': l:response_item.lineText, \ } call add( \ l:item_list, \ ale#references#FormatResponseItem(l:format_response_item, l:format_options) \) endfor call ale#references#DisplayReferences(l:item_list, l:format_options) endif endif endfunction function! ale#references#HandleLSPResponse(conn_id, response) abort if ! (has_key(a:response, 'id') && has_key(s:references_map, a:response.id)) return endif let l:options = remove(s:references_map, a:response.id) " The result can be a Dictionary item, a List of the same, or null. let l:result = get(a:response, 'result', []) let l:item_list = [] if type(l:result) is v:t_list for l:response_item in l:result let l:filename = ale#util#ToResource(get(l:response_item, 'uri', '')) let l:read_line = l:response_item.range.start.line let l:line = l:read_line + 1 let l:format_response_item = { \ 'filename': l:filename, \ 'line': l:line, \ 'column': l:response_item.range.start.character + 1, \ 'line_text': get(l:options, 'show_contents') == 1 \ ? readfile(l:filename)[l:read_line] \ : '', \ } call add(l:item_list, \ ale#references#FormatResponseItem(l:format_response_item, l:options) \) endfor endif call ale#references#DisplayReferences(l:item_list, l:options) endfunction function! s:OnReady(line, column, options, linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'references') return endif let l:buffer = a:lsp_details.buffer 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] = { \ 'use_relative_paths': has_key(a:options, 'use_relative_paths') ? a:options.use_relative_paths : 0, \ 'open_in': get(a:options, 'open_in', 'current-buffer'), \ 'show_contents': a:options.show_contents, \ 'use_fzf': get(a:options, 'use_fzf', g:ale_references_use_fzf), \} endfunction function! ale#references#Find(...) abort let l:options = {} if len(a:000) > 0 for l:option in a:000 if l:option is? '-relative' let l:options.use_relative_paths = 1 elseif l:option is? '-tab' let l:options.open_in = 'tab' elseif l:option is? '-split' let l:options.open_in = 'split' elseif l:option is? '-vsplit' let l:options.open_in = 'vsplit' elseif l:option is? '-quickfix' let l:options.open_in = 'quickfix' elseif l:option is? '-contents' let l:options.show_contents = 1 elseif l:option is? '-fzf' let l:options.use_fzf = 1 endif endfor endif if !has_key(l:options, 'open_in') let l:default_navigation = ale#Var(bufnr(''), 'default_navigation') if index(['tab', 'split', 'vsplit'], l:default_navigation) >= 0 let l:options.open_in = l:default_navigation endif endif if !has_key(l:options, 'show_contents') let l:options.show_contents = ale#Var(bufnr(''), 'references_show_contents') endif let l:buffer = bufnr('') let [l:line, l:column] = getpos('.')[1:2] let l:column = min([l:column, len(getline(l:line))]) let l:Callback = function('s:OnReady', [l:line, l:column, l:options]) for l:linter in ale#lsp_linter#GetEnabled(l:buffer) call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) endfor endfunction ================================================ FILE: autoload/ale/rename.vim ================================================ " Author: Jerko Steiner " Description: Rename symbol support for LSP / tsserver let s:rename_map = {} " Used to get the rename map in tests. function! ale#rename#GetMap() abort return deepcopy(s:rename_map) endfunction " Used to set the rename map in tests. function! ale#rename#SetMap(map) abort let s:rename_map = a:map endfunction function! ale#rename#ClearLSPData() abort let s:rename_map = {} endfunction let g:ale_rename_tsserver_find_in_comments = get(g:, 'ale_rename_tsserver_find_in_comments', v:false) let g:ale_rename_tsserver_find_in_strings = get(g:, 'ale_rename_tsserver_find_in_strings', v:false) function! s:message(message) abort call ale#util#Execute('echom ' . string(a:message)) endfunction function! ale#rename#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') isnot# 'rename' return endif if !has_key(s:rename_map, a:response.request_seq) return endif let l:options = remove(s:rename_map, a:response.request_seq) let l:old_name = l:options.old_name let l:new_name = l:options.new_name if get(a:response, 'success', v:false) is v:false let l:message = get(a:response, 'message', 'unknown') call s:message('Error renaming "' . l:old_name . '" to: "' . l:new_name \ . '". Reason: ' . l:message) return endif let l:changes = [] for l:response_item in a:response.body.locs let l:filename = l:response_item.file let l:text_changes = [] for l:loc in l:response_item.locs call add(l:text_changes, { \ 'start': { \ 'line': l:loc.start.line, \ 'offset': l:loc.start.offset, \ }, \ 'end': { \ 'line': l:loc.end.line, \ 'offset': l:loc.end.offset, \ }, \ 'newText': l:new_name, \}) endfor call add(l:changes, { \ 'fileName': l:filename, \ 'textChanges': l:text_changes, \}) endfor if empty(l:changes) call s:message('Error renaming "' . l:old_name . '" to: "' . l:new_name . '"') return endif call ale#code_action#HandleCodeAction( \ { \ 'description': 'rename', \ 'changes': l:changes, \ }, \ { \ 'conn_id': a:conn_id, \ 'should_save': g:ale_save_hidden || !&hidden, \ }, \) endfunction function! ale#rename#HandleLSPResponse(conn_id, response) abort if has_key(a:response, 'id') \&& has_key(s:rename_map, a:response.id) let l:options = remove(s:rename_map, a:response.id) if !has_key(a:response, 'result') call s:message('No rename result received from server') return endif let l:changes_map = ale#code_action#GetChanges(a:response.result) if empty(l:changes_map) call s:message('No changes received from server') return endif let l:changes = ale#code_action#BuildChangesList(l:changes_map) call ale#code_action#HandleCodeAction( \ { \ 'description': 'rename', \ 'changes': l:changes, \ }, \ { \ 'conn_id': a:conn_id, \ 'should_save': g:ale_save_hidden || !&hidden, \ }, \) endif endfunction function! s:OnReady(line, column, options, linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'rename') return endif let l:buffer = a:lsp_details.buffer let l:Callback = a:linter.lsp is# 'tsserver' \ ? function('ale#rename#HandleTSServerResponse') \ : function('ale#rename#HandleLSPResponse') call ale#lsp#RegisterCallback(l:id, l:Callback) if a:linter.lsp is# 'tsserver' let l:message = ale#lsp#tsserver_message#Rename( \ l:buffer, \ a:line, \ a:column, \ g:ale_rename_tsserver_find_in_comments, \ g:ale_rename_tsserver_find_in_strings, \) else " Send a message saying the buffer has changed first, or the " rename position probably won't make sense. call ale#lsp#NotifyForChanges(l:id, l:buffer) let l:message = ale#lsp#message#Rename( \ l:buffer, \ a:line, \ a:column, \ a:options.new_name \) endif let l:request_id = ale#lsp#Send(l:id, l:message) let s:rename_map[l:request_id] = a:options endfunction function! s:ExecuteRename(linter, options) abort let l:buffer = bufnr('') let [l:line, l:column] = getpos('.')[1:2] if a:linter.lsp isnot# 'tsserver' let l:column = min([l:column, len(getline(l:line))]) endif let l:Callback = function('s:OnReady', [l:line, l:column, a:options]) call ale#lsp_linter#StartLSP(l:buffer, a:linter, l:Callback) endfunction function! ale#rename#Execute() abort let l:linters = ale#lsp_linter#GetEnabled(bufnr('')) if empty(l:linters) call s:message('No active LSPs') return endif let l:old_name = expand('') let l:new_name = ale#util#Input('New name: ', l:old_name) if empty(l:new_name) call s:message('New name cannot be empty!') return endif for l:linter in l:linters call s:ExecuteRename(l:linter, { \ 'old_name': l:old_name, \ 'new_name': l:new_name, \}) endfor endfunction ================================================ FILE: autoload/ale/ruby.vim ================================================ " Author: Eddie Lebow https://github.com/elebow " Description: Functions for integrating with Ruby tools " Find the nearest dir containing "app", "db", and "config", and assume it is " the root of a Rails app. function! ale#ruby#FindRailsRoot(buffer) abort for l:name in ['app', 'config', 'db'] let l:dir = fnamemodify( \ ale#path#FindNearestDirectory(a:buffer, l:name), \ ':h:h' \) if l:dir isnot# '.' \&& isdirectory(l:dir . '/app') \&& isdirectory(l:dir . '/config') \&& isdirectory(l:dir . '/db') return l:dir endif endfor 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 " Handle output from rubocop and linters that depend on it (e.b. standardrb) function! ale#ruby#HandleRubocopOutput(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#ruby#rubocop#GetType(l:error['severity']), \}) endfor return l:output endfunction function! ale#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 ================================================ FILE: autoload/ale/semver.vim ================================================ let s:version_cache = {} " Reset the version cache used for parsing the version. function! ale#semver#ResetVersionCache() abort let s:version_cache = {} endfunction function! ale#semver#ParseVersion(version_lines) abort for l:line in a:version_lines let l:match = matchlist(l:line, '\v(\d+)\.(\d+)(\.(\d+))?') if !empty(l:match) return [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0] endif endfor return [] endfunction " Given an executable name and some lines of output, which can be empty, " parse the version from the lines of output, or return the cached version " triple [major, minor, patch] " " If the version cannot be found, an empty List will be returned instead. function! s:GetVersion(executable, version_lines) abort let l:version = get(s:version_cache, a:executable, []) let l:parsed_version = ale#semver#ParseVersion(a:version_lines) if !empty(l:parsed_version) let l:version = l:parsed_version let s:version_cache[a:executable] = l:version endif return l:version endfunction function! ale#semver#RunWithVersionCheck(buffer, executable, command, Callback) abort if empty(a:executable) return '' endif let l:cache = s:version_cache if has_key(s:version_cache, a:executable) return a:Callback(a:buffer, s:version_cache[a:executable]) endif return ale#command#Run( \ a:buffer, \ a:command, \ {_, output -> a:Callback(a:buffer, s:GetVersion(a:executable, output))}, \ {'output_stream': 'both', 'executable': a:executable} \) endfunction " Given two triples of integers [major, minor, patch], compare the triples " and return 1 if the LHS is greater than or equal to the RHS. " " Pairs of [major, minor] can also be used for either argument. " " 0 will be returned if the LHS is an empty List. function! ale#semver#GTE(lhs, rhs) abort if empty(a:lhs) return 0 endif if a:lhs[0] > a:rhs[0] return 1 elseif a:lhs[0] == a:rhs[0] if a:lhs[1] > a:rhs[1] return 1 elseif a:lhs[1] == a:rhs[1] return get(a:lhs, 2) >= get(a:rhs, 2) endif endif return 0 endfunction ================================================ FILE: autoload/ale/sign.vim ================================================ scriptencoding utf8 " Author: w0rp " Description: Draws error and warning signs into signcolumn " This flag can be set to some integer to control the maximum number of signs " that ALE will set. let g:ale_max_signs = get(g:, 'ale_max_signs', -1) " This flag can be set to 1 to enable changing the sign column colors when " there are errors. let g:ale_change_sign_column_color = get(g:, 'ale_change_sign_column_color', v:false) " These variables dictate what signs are used to indicate errors and warnings. let g:ale_sign_error = get(g:, 'ale_sign_error', 'E') let g:ale_sign_style_error = get(g:, 'ale_sign_style_error', g:ale_sign_error) let g:ale_sign_warning = get(g:, 'ale_sign_warning', 'W') let g:ale_sign_style_warning = get(g:, 'ale_sign_style_warning', g:ale_sign_warning) let g:ale_sign_info = get(g:, 'ale_sign_info', 'I') let g:ale_sign_priority = get(g:, 'ale_sign_priority', 30) " This variable sets an offset which can be set for sign IDs. " This ID can be changed depending on what IDs are set for other plugins. " The dummy sign will use the ID exactly equal to the offset. let g:ale_sign_offset = get(g:, 'ale_sign_offset', 1000000) " This flag can be set to 1 to keep sign gutter always open let g:ale_sign_column_always = get(g:, 'ale_sign_column_always', v:false) let g:ale_sign_highlight_linenrs = get(g:, 'ale_sign_highlight_linenrs', v:false) let s:supports_sign_groups = has('nvim-0.4.2') || has('patch-8.1.614') if !hlexists('ALEErrorSign') highlight link ALEErrorSign error endif if !hlexists('ALEStyleErrorSign') highlight link ALEStyleErrorSign ALEErrorSign endif if !hlexists('ALEWarningSign') highlight link ALEWarningSign todo endif if !hlexists('ALEStyleWarningSign') highlight link ALEStyleWarningSign ALEWarningSign endif if !hlexists('ALEInfoSign') highlight link ALEInfoSign ALEWarningSign endif if !hlexists('ALESignColumnWithErrors') highlight link ALESignColumnWithErrors error endif function! ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() abort let l:verbose = &verbose set verbose=0 let l:output = execute('highlight SignColumn', 'silent') let &verbose = l:verbose let l:highlight_syntax = join(split(l:output)[2:]) let l:match = matchlist(l:highlight_syntax, '\vlinks to (.+)$') if !empty(l:match) execute 'highlight link ALESignColumnWithoutErrors ' . l:match[1] elseif l:highlight_syntax isnot# 'cleared' execute 'highlight ALESignColumnWithoutErrors ' . l:highlight_syntax endif endfunction if !hlexists('ALESignColumnWithoutErrors') call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() endif " Spaces and backslashes need to be escaped for signs. function! s:EscapeSignText(sign_text) abort return substitute(substitute(a:sign_text, ' *$', '', ''), '\\\| ', '\\\0', 'g') endfunction " Signs show up on the left for error markers. execute 'sign define ALEErrorSign text=' . s:EscapeSignText(g:ale_sign_error) \ . ' texthl=ALEErrorSign linehl=ALEErrorLine' execute 'sign define ALEStyleErrorSign text=' . s:EscapeSignText(g:ale_sign_style_error) \ . ' texthl=ALEStyleErrorSign linehl=ALEErrorLine' execute 'sign define ALEWarningSign text=' . s:EscapeSignText(g:ale_sign_warning) \ . ' texthl=ALEWarningSign linehl=ALEWarningLine' execute 'sign define ALEStyleWarningSign text=' . s:EscapeSignText(g:ale_sign_style_warning) \ . ' texthl=ALEStyleWarningSign linehl=ALEWarningLine' execute 'sign define ALEInfoSign text=' . s:EscapeSignText(g:ale_sign_info) \ . ' texthl=ALEInfoSign linehl=ALEInfoLine' sign define ALEDummySign text=\ texthl=SignColumn if g:ale_sign_highlight_linenrs && (has('nvim-0.3.2') || has('patch-8.2.3874')) if !hlexists('ALEErrorSignLineNr') highlight link ALEErrorSignLineNr CursorLineNr endif if !hlexists('ALEStyleErrorSignLineNr') highlight link ALEStyleErrorSignLineNr CursorLineNr endif if !hlexists('ALEWarningSignLineNr') highlight link ALEWarningSignLineNr CursorLineNr endif if !hlexists('ALEStyleWarningSignLineNr') highlight link ALEStyleWarningSignLineNr CursorLineNr endif if !hlexists('ALEInfoSignLineNr') highlight link ALEInfoSignLineNr CursorLineNr endif sign define ALEErrorSign numhl=ALEErrorSignLineNr sign define ALEStyleErrorSign numhl=ALEStyleErrorSignLineNr sign define ALEWarningSign numhl=ALEWarningSignLineNr sign define ALEStyleWarningSign numhl=ALEStyleWarningSignLineNr sign define ALEInfoSign numhl=ALEInfoSignLineNr endif function! ale#sign#GetSignName(sublist) abort let l:priority = g:ale#util#style_warning_priority " Determine the highest priority item for the line. for l:item in a:sublist let l:item_priority = ale#util#GetItemPriority(l:item) if l:item_priority > l:priority let l:priority = l:item_priority endif endfor if l:priority is# g:ale#util#error_priority return 'ALEErrorSign' endif if l:priority is# g:ale#util#warning_priority return 'ALEWarningSign' endif if l:priority is# g:ale#util#style_error_priority return 'ALEStyleErrorSign' endif if l:priority is# g:ale#util#style_warning_priority return 'ALEStyleWarningSign' endif if l:priority is# g:ale#util#info_priority return 'ALEInfoSign' endif " Use the error sign for invalid severities. return 'ALEErrorSign' endfunction function! s:PriorityCmd() abort if s:supports_sign_groups return ' priority=' . g:ale_sign_priority . ' ' else return '' endif endfunction function! s:GroupCmd() abort if s:supports_sign_groups return ' group=ale_signs ' else return ' ' endif endfunction " Read sign data for a buffer to a list of lines. function! ale#sign#ReadSigns(buffer) abort let l:output = execute( \ 'sign place ' . s:GroupCmd() . s:PriorityCmd() \ . ' buffer=' . a:buffer \ ) return split(l:output, "\n") endfunction function! ale#sign#ParsePattern() abort if s:supports_sign_groups " Matches output like : " line=4 id=1 group=ale_signs name=ALEErrorSign " строка=1 id=1000001 группа=ale_signs имя=ALEErrorSign " 行=1 識別子=1000001 グループ=ale_signs 名前=ALEWarningSign " línea=12 id=1000001 grupo=ale_signs nombre=ALEWarningSign " riga=1 id=1000001 gruppo=ale_signs nome=ALEWarningSign " Zeile=235 id=1000001 Gruppe=ale_signs Name=ALEErrorSign let l:pattern = '\v^.*\=(\d+).*\=(\d+).*\=ale_signs>.*\=(ALE[a-zA-Z]+Sign)' else " Matches output like : " line=4 id=1 name=ALEErrorSign " строка=1 id=1000001 имя=ALEErrorSign " 行=1 識別子=1000001 名前=ALEWarningSign " línea=12 id=1000001 nombre=ALEWarningSign " riga=1 id=1000001 nome=ALEWarningSign " Zeile=235 id=1000001 Name=ALEErrorSign let l:pattern = '\v^.*\=(\d+).*\=(\d+).*\=(ALE[a-zA-Z]+Sign)' endif return l:pattern endfunction " Given a buffer number, return a List of placed signs [line, id, group] function! ale#sign#ParseSignsWithGetPlaced(buffer) abort let l:signs = sign_getplaced(a:buffer, { 'group': s:supports_sign_groups ? 'ale_signs' : '' })[0].signs let l:result = [] let l:is_dummy_sign_set = 0 for l:sign in l:signs if l:sign['name'] is# 'ALEDummySign' let l:is_dummy_sign_set = 1 else call add(l:result, [ \ str2nr(l:sign['lnum']), \ str2nr(l:sign['id']), \ l:sign['name'], \]) endif endfor return [l:is_dummy_sign_set, l:result] endfunction " Given a list of lines for sign output, return a List of [line, id, group] function! ale#sign#ParseSigns(line_list) abort let l:pattern =ale#sign#ParsePattern() let l:result = [] let l:is_dummy_sign_set = 0 for l:line in a:line_list let l:match = matchlist(l:line, l:pattern) if len(l:match) > 0 if l:match[3] is# 'ALEDummySign' let l:is_dummy_sign_set = 1 else call add(l:result, [ \ str2nr(l:match[1]), \ str2nr(l:match[2]), \ l:match[3], \]) endif endif endfor return [l:is_dummy_sign_set, l:result] endfunction function! ale#sign#FindCurrentSigns(buffer) abort if exists('*sign_getplaced') return ale#sign#ParseSignsWithGetPlaced(a:buffer) else let l:line_list = ale#sign#ReadSigns(a:buffer) return ale#sign#ParseSigns(l:line_list) endif endfunction " Given a loclist, group the List into with one List per line. function! s:GroupLoclistItems(buffer, loclist) abort let l:grouped_items = [] let l:last_lnum = -1 for l:obj in a:loclist if l:obj.bufnr != a:buffer continue endif " Create a new sub-List when we hit a new line. if l:obj.lnum != l:last_lnum call add(l:grouped_items, []) endif call add(l:grouped_items[-1], l:obj) let l:last_lnum = l:obj.lnum endfor return l:grouped_items endfunction function! s:UpdateLineNumbers(buffer, current_sign_list, loclist) abort let l:line_map = {} let l:line_numbers_changed = 0 for [l:line, l:sign_id, l:name] in a:current_sign_list let l:line_map[l:sign_id] = l:line endfor for l:item in a:loclist if l:item.bufnr == a:buffer let l:lnum = get(l:line_map, get(l:item, 'sign_id', 0), 0) if l:lnum && l:item.lnum != l:lnum let l:item.lnum = l:lnum let l:line_numbers_changed = 1 endif endif endfor " When the line numbers change, sort the list again if l:line_numbers_changed call sort(a:loclist, 'ale#util#LocItemCompare') endif endfunction function! s:BuildSignMap(buffer, current_sign_list, grouped_items) abort let l:max_signs = ale#Var(a:buffer, 'max_signs') if l:max_signs is 0 let l:selected_grouped_items = [] 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 endif let l:sign_map = {} let l:sign_offset = g:ale_sign_offset for [l:line, l:sign_id, l:name] in a:current_sign_list let l:sign_info = get(l:sign_map, l:line, { \ 'current_id_list': [], \ 'current_name_list': [], \ 'new_id': 0, \ 'new_name': '', \ 'items': [], \}) " Increment the sign offset for new signs, by the maximum sign ID. if l:sign_id > l:sign_offset let l:sign_offset = l:sign_id endif " Remember the sign names and IDs in separate Lists, so they are easy " to work with. call add(l:sign_info.current_id_list, l:sign_id) call add(l:sign_info.current_name_list, l:name) let l:sign_map[l:line] = l:sign_info endfor for l:group in l:selected_grouped_items let l:line = l:group[0].lnum let l:sign_info = get(l:sign_map, l:line, { \ 'current_id_list': [], \ 'current_name_list': [], \ 'new_id': 0, \ 'new_name': '', \ 'items': [], \}) let l:sign_info.new_name = ale#sign#GetSignName(l:group) let l:sign_info.items = l:group let l:index = index( \ l:sign_info.current_name_list, \ l:sign_info.new_name \) if l:index >= 0 " We have a sign with this name already, so use the same ID. let l:sign_info.new_id = l:sign_info.current_id_list[l:index] else " This sign name replaces the previous name, so use a new ID. let l:sign_info.new_id = l:sign_offset + 1 let l:sign_offset += 1 endif let l:sign_map[l:line] = l:sign_info endfor return l:sign_map endfunction function! ale#sign#GetSignCommands(buffer, was_sign_set, sign_map) abort let l:command_list = [] let l:is_dummy_sign_set = a:was_sign_set " Set the dummy sign if we need to. " The dummy sign is needed to keep the sign column open while we add " and remove signs. if !l:is_dummy_sign_set && (!empty(a:sign_map) || g:ale_sign_column_always) call add(l:command_list, 'sign place ' \ . g:ale_sign_offset \ . s:GroupCmd() \ . s:PriorityCmd() \ . ' line=1 name=ALEDummySign ' \ . ' buffer=' . a:buffer \) let l:is_dummy_sign_set = 1 endif " Place new items first. for [l:line_str, l:info] in items(a:sign_map) if l:info.new_id " Save the sign IDs we are setting back on our loclist objects. " These IDs will be used to preserve items which are set many times. for l:item in l:info.items let l:item.sign_id = l:info.new_id endfor if index(l:info.current_id_list, l:info.new_id) < 0 call add(l:command_list, 'sign place ' \ . (l:info.new_id) \ . s:GroupCmd() \ . s:PriorityCmd() \ . ' line=' . l:line_str \ . ' name=' . (l:info.new_name) \ . ' buffer=' . a:buffer \) endif endif endfor " Remove signs without new IDs. for l:info in values(a:sign_map) for l:current_id in l:info.current_id_list if l:current_id isnot l:info.new_id call add(l:command_list, 'sign unplace ' \ . l:current_id \ . s:GroupCmd() \ . ' buffer=' . a:buffer \) endif endfor endfor " Remove the dummy sign to close the sign column if we need to. if l:is_dummy_sign_set && !g:ale_sign_column_always call add(l:command_list, 'sign unplace ' \ . g:ale_sign_offset \ . s:GroupCmd() \ . ' buffer=' . a:buffer \) endif return l:command_list endfunction " This function will set the signs which show up on the left. function! ale#sign#SetSigns(buffer, loclist) abort if !bufexists(str2nr(a:buffer)) " Stop immediately when attempting to set signs for a buffer which " does not exist. return endif " Find the current markers let [l:is_dummy_sign_set, l:current_sign_list] = \ ale#sign#FindCurrentSigns(a:buffer) " Update the line numbers for items from before which may have moved. call s:UpdateLineNumbers(a:buffer, l:current_sign_list, a:loclist) " Group items after updating the line numbers. let l:grouped_items = s:GroupLoclistItems(a:buffer, a:loclist) " Build a map of current and new signs, with the lines as the keys. let l:sign_map = s:BuildSignMap( \ a:buffer, \ l:current_sign_list, \ l:grouped_items, \) let l:command_list = ale#sign#GetSignCommands( \ a:buffer, \ l:is_dummy_sign_set, \ l:sign_map, \) " Change the sign column color if the option is on. if g:ale_change_sign_column_color && !empty(a:loclist) highlight clear SignColumn highlight link SignColumn ALESignColumnWithErrors endif for l:command in l:command_list silent! execute l:command endfor " Reset the sign column color when there are no more errors. if g:ale_change_sign_column_color && empty(a:loclist) highlight clear SignColumn highlight link SignColumn ALESignColumnWithoutErrors endif endfunction " Remove all signs. function! ale#sign#Clear() abort if s:supports_sign_groups sign unplace group=ale_signs * else sign unplace * endif endfunction ================================================ FILE: autoload/ale/socket.vim ================================================ " Author: w0rp " Description: APIs for working with asynchronous sockets, with an API " normalised between Vim 8 and NeoVim. Socket connections only work in NeoVim " 0.3+, and silently do nothing in earlier NeoVim versions. " " Important functions are described below. They are: " " ale#socket#Open(address, options) -> channel_id (>= 0 if successful) " ale#socket#IsOpen(channel_id) -> 1 if open, 0 otherwise " ale#socket#Close(channel_id) " ale#socket#Send(channel_id, data) " ale#socket#GetAddress(channel_id) -> Return the address for a job let s:channel_map = get(s:, 'channel_map', {}) function! s:VimOutputCallback(channel, data) abort let l:channel_id = ch_info(a:channel).id " Only call the callbacks for jobs which are valid. if l:channel_id >= 0 && has_key(s:channel_map, l:channel_id) call ale#util#GetFunction(s:channel_map[l:channel_id].callback)(l:channel_id, a:data) endif endfunction function! s:NeoVimOutputCallback(channel_id, data, event) abort let l:info = s:channel_map[a:channel_id] if a:event is# 'data' let l:info.last_line = ale#util#JoinNeovimOutput( \ a:channel_id, \ l:info.last_line, \ a:data, \ l:info.mode, \ ale#util#GetFunction(l:info.callback), \) endif endfunction " Open a socket for a given address. The following options are accepted: " " callback - A callback for receiving input. (required) " " A non-negative number representing a channel ID will be returned is the " connection was successful. 0 is a valid channel ID in Vim, so test if the " connection ID is >= 0. function! ale#socket#Open(address, options) abort let l:mode = get(a:options, 'mode', 'raw') let l:Callback = a:options.callback let l:channel_info = { \ 'address': a:address, \ 'mode': l:mode, \ 'callback': a:options.callback, \} if !has('nvim') " Vim 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') " NeoVim 0.3+ try let l:channel_id = sockconnect(stridx(a:address, ':') != -1 ? 'tcp' : 'pipe', \ a:address, {'on_data': function('s:NeoVimOutputCallback')}) let l:channel_info.last_line = '' catch /connection failed/ let l:channel_id = -1 endtry " 0 means the connection failed some times in NeoVim, so make the ID " invalid to match Vim. if l:channel_id is 0 let l:channel_id = -1 endif let l:channel_info.channel = l:channel_id else " Other Vim versions. let l:channel_id = -1 endif if l:channel_id >= 0 let s:channel_map[l:channel_id] = l:channel_info endif return l:channel_id endfunction " Return 1 is a channel is open, 0 otherwise. function! ale#socket#IsOpen(channel_id) abort if !has_key(s:channel_map, a:channel_id) return 0 endif if has('nvim') " In NeoVim, we have to check if this channel is in the global list. return index(map(nvim_list_chans(), 'v:val.id'), a:channel_id) >= 0 endif let l:channel = s:channel_map[a:channel_id].channel return ch_status(l:channel) is# 'open' endfunction " Close a socket, if it's still open. function! ale#socket#Close(channel_id) abort " IsRunning isn't called here, so we don't check nvim_list_chans() if !has_key(s:channel_map, a:channel_id) return 0 endif let l:channel = remove(s:channel_map, a:channel_id).channel if has('nvim') silent! call chanclose(l:channel) elseif ch_status(l:channel) is# 'open' call ch_close(l:channel) endif endfunction " Send some data to a socket. function! ale#socket#Send(channel_id, data) abort if !has_key(s:channel_map, a:channel_id) return endif let l:channel = s:channel_map[a:channel_id].channel if has('nvim') call chansend(l:channel, a:data) else call ch_sendraw(l:channel, a:data) endif endfunction " Get an address for a channel, or an empty string. function! ale#socket#GetAddress(channel_id) abort return get(get(s:channel_map, a:channel_id, {}), 'address', '') endfunction ================================================ FILE: autoload/ale/statusline.vim ================================================ " Author: KabbAmine " Additions by: petpetpetpet " Description: Statusline related function(s) function! s:CreateCountDict() abort " Keys 0 and 1 are for backwards compatibility. " The count object used to be a List of [error_count, warning_count]. return { \ '0': 0, \ '1': 0, \ 'error': 0, \ 'warning': 0, \ 'info': 0, \ 'style_error': 0, \ 'style_warning': 0, \ 'total': 0, \} endfunction " Update the buffer error/warning count with data from loclist. function! ale#statusline#Update(buffer, loclist) abort if !exists('g:ale_buffer_info') || !has_key(g:ale_buffer_info, a:buffer) return endif let l:loclist = filter(copy(a:loclist), 'v:val.bufnr == a:buffer') let l:count = s:CreateCountDict() let l:count.total = len(l:loclist) " Allows easy access to the first instance of each problem type. let l:first_problems = {} for l:entry in l:loclist if l:entry.type is# 'W' if get(l:entry, 'sub_type', '') is# 'style' let l:count.style_warning += 1 if l:count.style_warning == 1 let l:first_problems.style_warning = l:entry endif else let l:count.warning += 1 if l:count.warning == 1 let l:first_problems.warning = l:entry endif endif elseif l:entry.type is# 'I' let l:count.info += 1 if l:count.info == 1 let l:first_problems.info = l:entry endif elseif get(l:entry, 'sub_type', '') is# 'style' let l:count.style_error += 1 if l:count.style_error == 1 let l:first_problems.style_error = l:entry endif else let l:count.error += 1 if l:count.error == 1 let l:first_problems.error = l:entry endif endif endfor " Set keys for backwards compatibility. let l:count[0] = l:count.error + l:count.style_error let l:count[1] = l:count.total - l:count[0] let g:ale_buffer_info[a:buffer].count = l:count let g:ale_buffer_info[a:buffer].first_problems = l:first_problems endfunction " Get the counts for the buffer, and update the counts if needed. function! s:UpdateCacheIfNecessary(buffer) abort " Cache is cold, so manually ask for an update. if !has_key(g:ale_buffer_info[a:buffer], 'count') call ale#statusline#Update( \ a:buffer, \ g:ale_buffer_info[a:buffer].loclist \) endif endfunction function! s:BufferCacheExists(buffer) abort if !exists('g:ale_buffer_info') || !has_key(g:ale_buffer_info, a:buffer) return 0 endif return 1 endfunction " Get the counts for the buffer, and update the counts if needed. function! s:GetCounts(buffer) abort if !s:BufferCacheExists(a:buffer) return s:CreateCountDict() endif call s:UpdateCacheIfNecessary(a:buffer) return g:ale_buffer_info[a:buffer].count endfunction " Get the dict of first_problems, update the buffer info cache if necessary. function! s:GetFirstProblems(buffer) abort if !s:BufferCacheExists(a:buffer) return {} endif call s:UpdateCacheIfNecessary(a:buffer) return g:ale_buffer_info[a:buffer].first_problems endfunction " Returns a Dictionary with counts for use in third party integrations. function! ale#statusline#Count(buffer) abort " The Dictionary is copied here before exposing it to other plugins. return copy(s:GetCounts(a:buffer)) endfunction " Returns a copy of the *first* locline instance of the specified problem " type. (so this would allow an external integration to know all the info " about the first style warning in the file, for example.) function! ale#statusline#FirstProblem(buffer, type) abort let l:first_problems = s:GetFirstProblems(a:buffer) if !empty(l:first_problems) && has_key(l:first_problems, a:type) return copy(l:first_problems[a:type]) endif return {} endfunction ================================================ FILE: autoload/ale/swift.vim ================================================ " Author: Dan Loman " Description: Functions for integrating with Swift tools " Find the nearest dir containing a Package.swift file and assume it is the root of the Swift project. function! ale#swift#FindProjectRoot(buffer) abort let l:swift_config = ale#path#FindNearestFile(a:buffer, 'Package.swift') if !empty(l:swift_config) return fnamemodify(l:swift_config, ':h') endif return '' endfunction " Support Apple Swift Format {{{1 call ale#Set('swift_appleswiftformat_executable', 'swift-format') call ale#Set('swift_appleswiftformat_use_swiftpm', 0) " Return the executable depending on whether or not to use Swift Package Manager. " " If not asked to use Swift Package Manager (use_swiftpm = 0), the returned " value is the global executable, else the returned value is 'swift' because " the final command line will be `swift run swift-format ...`. " " Failure is expected if use_swiftpm is `1` but no Package.swift can be located. function! ale#swift#GetAppleSwiftFormatExecutable(buffer) abort if !ale#Var(a:buffer, 'swift_appleswiftformat_use_swiftpm') return ale#Var(a:buffer, 'swift_appleswiftformat_executable') endif if ale#path#FindNearestFile(a:buffer, 'Package.swift') is# '' " If there is no Package.swift file, we don't use swift-format even if it exists, " so we return '' to indicate failure. return '' endif return 'swift' endfunction " Return the command depending on whether or not to use Swift Package Manager. " " If asked to use Swift Package Manager (use_swiftpm = 1), the command " arguments are prefixed with 'swift run'. " " In either case, the configuration file is located and added to the command. function! ale#swift#GetAppleSwiftFormatCommand(buffer) abort let l:executable = ale#swift#GetAppleSwiftFormatExecutable(a:buffer) let l:command_args = '' if ale#Var(a:buffer, 'swift_appleswiftformat_use_swiftpm') let l:command_args = ' ' . 'run swift-format' endif return ale#Escape(l:executable) . l:command_args endfunction " Locate the nearest '.swift-format' configuration file, and return the " arguments, else return an empty string. function! ale#swift#GetAppleSwiftFormatConfigArgs(buffer) abort let l:config_filepath = ale#path#FindNearestFile(a:buffer, '.swift-format') if l:config_filepath isnot# '' return '--configuration' . ' ' . l:config_filepath endif return '' endfunction " }}} ================================================ FILE: autoload/ale/symbol.vim ================================================ 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#util#ToResource(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, l:options) endif endif endfunction function! s:OnReady(query, options, linter, lsp_details) abort let l:id = a:lsp_details.connection_id if !ale#lsp#HasCapability(l:id, 'symbol_search') return endif 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: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, \ 'use_relative_paths': has_key(a:options, 'use_relative_paths') ? a:options.use_relative_paths : 0 \} endfunction function! ale#symbol#Search(args) abort let [l:opts, l:query] = ale#args#Parse(['relative'], a:args) if empty(l:query) throw 'A non-empty string must be provided!' endif let l:buffer = bufnr('') let l:options = {} if has_key(l:opts, 'relative') let l:options.use_relative_paths = 1 endif " Set a flag so we only make one request. call setbufvar(l:buffer, 'ale_symbol_request_made', 0) let l:Callback = function('s:OnReady', [l:query, l:options]) for l:linter in ale#lsp_linter#GetEnabled(l:buffer) if l:linter.lsp isnot# 'tsserver' call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) endif endfor endfunction ================================================ FILE: autoload/ale/test.vim ================================================ " Author: w0rp " Description: Functions for making testing ALE easier. " " This file should not typically be loaded during the normal execution of ALE. " Change the directory for checking things in particular test directories " " This function will set the g:dir variable, which represents the working " directory after changing the path. This variable allows a test to change " directories, and then switch back to a directory at the start of the test " run. " " This function should be run in a Vader Before: block. function! ale#test#SetDirectory(docker_path) abort if a:docker_path[:len('/testplugin/') - 1] isnot# '/testplugin/' throw 'docker_path must start with /testplugin/!' endif " Try to switch directory, which will fail when running tests directly, " and not through the Docker image. silent! execute 'cd ' . fnameescape(a:docker_path) let g:dir = getcwd() " no-custom-checks endfunction " When g:dir is defined, switch back to the directory we saved, and then " delete that variable. " " The filename will be reset to dummy.txt " " This function should be run in a Vader After: block. function! ale#test#RestoreDirectory() abort call ale#test#SetFilename('dummy.txt') silent execute 'cd ' . fnameescape(g:dir) unlet! g:dir endfunction " Get a filename for the current buffer using a relative path to the script. " " If a g:dir variable is set, it will be used as the path to the directory " containing the test file. function! ale#test#GetFilename(path) abort let l:dir = get(g:, 'dir', '') if empty(l:dir) let l:dir = getcwd() " no-custom-checks endif let l:full_path = ale#path#IsAbsolute(a:path) \ ? a:path \ : l:dir . '/' . a:path return ale#path#Simplify(l:full_path) endfunction " Change the filename for the current buffer using a relative path to " the script without running autocmd commands. " " If a g:dir variable is set, it will be used as the path to the directory " containing the test file. function! ale#test#SetFilename(path) abort let l:full_path = ale#test#GetFilename(a:path) silent! noautocmd execute 'file ' . fnameescape(l:full_path) endfunction function! RemoveNewerKeys(results) abort for l:item in a:results if has_key(l:item, 'module') call remove(l:item, 'module') endif if has_key(l:item, 'end_col') call remove(l:item, 'end_col') endif if has_key(l:item, 'end_lnum') call remove(l:item, 'end_lnum') endif endfor endfunction " Return loclist data with only the keys supported by the lowest Vim versions. function! ale#test#GetLoclistWithoutNewerKeys() abort let l:results = getloclist(0) call RemoveNewerKeys(l:results) return l:results endfunction " Return quickfix data with only the keys supported by the lowest Vim versions. function! ale#test#GetQflistWithoutNewerKeys() abort let l:results = getqflist() call RemoveNewerKeys(l:results) return l:results endfunction function! ale#test#GetPreviewWindowText() abort for l:window in range(1, winnr('$')) if getwinvar(l:window, '&previewwindow', 0) let l:buffer = winbufnr(l:window) return getbufline(l:buffer, 1, '$') endif endfor endfunction " This function can be called with a timeout to wait for all jobs to finish. " If the jobs to not finish in the given number of milliseconds, " an exception will be thrown. " " The time taken will be a very rough approximation, and more time may be " permitted than is specified. function! ale#test#WaitForJobs(deadline) abort let l:start_time = ale#events#ClockMilliseconds() if l:start_time == 0 throw 'Failed to read milliseconds from the clock!' endif let l:job_list = [] " Gather all of the jobs from every buffer. for [l:buffer, l:data] in items(ale#command#GetData()) call extend(l:job_list, map(keys(l:data.jobs), 'str2nr(v:val)')) endfor " NeoVim has a built-in API for this, so use that. if has('nvim') let l:nvim_code_list = jobwait(l:job_list, a:deadline) if index(l:nvim_code_list, -1) >= 0 throw 'Jobs did not complete on time!' endif return endif let l:should_wait_more = 1 while l:should_wait_more let l:should_wait_more = 0 for l:job_id in l:job_list if ale#job#IsRunning(l:job_id) let l:now = ale#events#ClockMilliseconds() if l:now - l:start_time > a:deadline " Stop waiting after a timeout, so we don't wait forever. throw 'Jobs did not complete on time!' endif " Wait another 10 milliseconds let l:should_wait_more = 1 sleep 10ms break endif endfor endwhile " Sleep for a small amount of time after all jobs finish. " This seems to be enough to let handlers after jobs end run, and " prevents the occasional failure where this function exits after jobs " end, but before handlers are run. sleep 10ms " We must check the buffer data again to see if new jobs started for " linters with chained commands. let l:has_new_jobs = 0 " Check again to see if any jobs are running. for l:info in values(g:ale_buffer_info) for [l:job_id, l:linter] in get(l:info, 'job_list', []) if ale#job#IsRunning(l:job_id) let l:has_new_jobs = 1 break endif endfor endfor if l:has_new_jobs " We have to wait more. Offset the timeout by the time taken so far. let l:now = ale#events#ClockMilliseconds() let l:new_deadline = a:deadline - (l:now - l:start_time) if l:new_deadline <= 0 " Enough time passed already, so stop immediately. throw 'Jobs did not complete on time!' endif call ale#test#WaitForJobs(l:new_deadline) endif endfunction function! ale#test#FlushJobs() abort " The variable is checked for in a loop, as calling one series of " callbacks can trigger a further series of callbacks. while exists('g:ale_run_synchronously_callbacks') let l:callbacks = g:ale_run_synchronously_callbacks unlet g:ale_run_synchronously_callbacks for l:Callback in l:callbacks call l:Callback() endfor endwhile endfunction ================================================ FILE: autoload/ale/toggle.vim ================================================ function! s:EnablePreamble() abort " Set pattern options again, if enabled. if get(g:, 'ale_pattern_options_enabled', 0) call ale#pattern_options#SetOptions(bufnr('')) endif " Lint immediately, including running linters against the file. call ale#Queue(0, 'lint_file') endfunction function! s:DisablePostamble() abort " Remove highlights for the current buffer now. if g:ale_set_highlights call ale#highlight#UpdateHighlights() endif if g:ale_virtualtext_cursor isnot# 'disabled' && g:ale_virtualtext_cursor != 0 call ale#virtualtext#Clear(bufnr('')) endif endfunction function! ale#toggle#Toggle() abort let g:ale_enabled = !get(g:, 'ale_enabled') if g:ale_enabled call s:EnablePreamble() if g:ale_set_balloons call ale#balloon#Enable() endif else call ale#engine#CleanupEveryBuffer() call s:DisablePostamble() if exists('*ale#balloon#Disable') call ale#balloon#Disable() endif endif call ale#events#Init() endfunction function! ale#toggle#Enable() abort if !g:ale_enabled call ale#toggle#Toggle() endif endfunction function! ale#toggle#Disable() abort if g:ale_enabled call ale#toggle#Toggle() endif endfunction function! ale#toggle#Reset() abort call ale#engine#CleanupEveryBuffer() call ale#highlight#UpdateHighlights() endfunction function! ale#toggle#ToggleBuffer(buffer) abort " Get the new value for the toggle. let l:enabled = !getbufvar(a:buffer, 'ale_enabled', 1) " Disabling ALE globally removes autocmd events, so we cannot enable " linting locally when linting is disabled globally if l:enabled && !g:ale_enabled " no-custom-checks echom 'ALE cannot be enabled locally when disabled globally' return endif call setbufvar(a:buffer, 'ale_enabled', l:enabled) if l:enabled call s:EnablePreamble() else " Stop all jobs and clear the results for everything, and delete " all of the data we stored for the buffer. call ale#engine#Cleanup(a:buffer) call s:DisablePostamble() endif endfunction function! ale#toggle#EnableBuffer(buffer) abort " ALE is enabled by default for all buffers. if !getbufvar(a:buffer, 'ale_enabled', 1) call ale#toggle#ToggleBuffer(a:buffer) endif endfunction function! ale#toggle#DisableBuffer(buffer) abort if getbufvar(a:buffer, 'ale_enabled', 1) call ale#toggle#ToggleBuffer(a:buffer) endif endfunction function! ale#toggle#ResetBuffer(buffer) abort call ale#engine#Cleanup(a:buffer) call ale#highlight#UpdateHighlights() endfunction ================================================ FILE: autoload/ale/uri/jdt.vim ================================================ " Author: yoshi1123 " Description: Functions for working with jdt:// URIs. function! s:OpenJDTLink(root, uri, line, column, options, result) abort if has_key(a:result, 'error') " no-custom-checks echoerr a:result.error.message return endif let l:contents = a:result['result'] if type(l:contents) is# type(v:null) " no-custom-checks echoerr 'File content not found' endif " disable autocmd when opening buffer autocmd! AleURISchemes call ale#util#Open(a:uri, a:line, a:column, a:options) autocmd AleURISchemes BufNewFile,BufReadPre jdt://** call ale#uri#jdt#ReadJDTLink(expand('')) if !empty(getbufvar(bufnr(''), 'ale_root', '')) return endif let b:ale_root = a:root set filetype=java call setline(1, split(l:contents, '\n')) call cursor(a:line, a:column) normal! zz setlocal buftype=nofile nomodified nomodifiable readonly endfunction " Load new buffer with jdt:// contents and jump to line and column. function! ale#uri#jdt#OpenJDTLink(encoded_uri, line, column, options, conn_id) abort let l:found_eclipselsp = v:false " We should only arrive here from a 'go to definition' request, so we'll " assume the eclipselsp linter is enabled. for l:linter in ale#linter#Get('java') if l:linter.name is# 'eclipselsp' let l:found_eclipselsp = v:true endif endfor if !l:found_eclipselsp throw 'eclipselsp not running' endif let l:root = a:conn_id[stridx(a:conn_id, ':')+1:] let l:uri = a:encoded_uri call ale#lsp_linter#SendRequest( \ bufnr(''), \ 'eclipselsp', \ [0, 'java/classFileContents', {'uri': ale#util#ToURI(l:uri)}], \ function('s:OpenJDTLink', [l:root, l:uri, a:line, a:column, a:options]) \) endfunction function! s:ReadClassFileContents(uri, result) abort if has_key(a:result, 'error') " no-custom-checks echoerr a:result.error.message return endif let l:contents = a:result['result'] if type(l:contents) is# type(v:null) " no-custom-checks echoerr 'File content not found' endif call setline(1, split(l:contents, '\n')) setlocal buftype=nofile nomodified nomodifiable readonly endfunction " Read jdt:// contents, as part of current project, into current buffer. function! ale#uri#jdt#ReadJDTLink(encoded_uri) abort if !empty(getbufvar(bufnr(''), 'ale_root', '')) return endif let l:linter_map = ale#lsp_linter#GetLSPLinterMap() for [l:conn_id, l:linter] in items(l:linter_map) if l:linter.name is# 'eclipselsp' let l:root = l:conn_id[stridx(l:conn_id, ':')+1:] endif endfor if l:root is# v:null throw 'eclipselsp not running' endif let l:uri = a:encoded_uri let b:ale_root = l:root set filetype=java call ale#lsp_linter#SendRequest( \ bufnr(''), \ 'eclipselsp', \ [0, 'java/classFileContents', {'uri': ale#util#ToURI(l:uri)}], \ function('s:ReadClassFileContents', [l:uri]) \) endfunction ================================================ FILE: autoload/ale/uri.vim ================================================ function! s:EncodeChar(char) abort let l:result = '' for l:index in range(strlen(a:char)) let l:result .= printf('%%%02x', char2nr(a:char[l:index])) endfor return l:result endfunction function! ale#uri#Encode(value) abort return substitute( \ a:value, \ '\([^a-zA-Z0-9\\/$\-_.!*''(),]\)', \ '\=s:EncodeChar(submatch(1))', \ 'g' \) endfunction function! ale#uri#Decode(value) abort return substitute( \ a:value, \ '%\(\x\x\)', \ '\=printf("%c", str2nr(submatch(1), 16))', \ 'g' \) endfunction let s:uri_handlers = { \ 'jdt': { \ 'OpenURILink': function('ale#uri#jdt#OpenJDTLink'), \ } \} function! ale#uri#GetURIHandler(uri) abort for l:scheme in keys(s:uri_handlers) if a:uri =~# '^'.l:scheme.'://' return s:uri_handlers[scheme] endif endfor return v:null endfunction ================================================ FILE: autoload/ale/util.vim ================================================ " Author: w0rp " Description: Contains miscellaneous functions " A wrapper function for mode() so we can test calls for it. function! ale#util#Mode(...) abort return call('mode', a:000) endfunction " A wrapper function for feedkeys so we can test calls for it. function! ale#util#FeedKeys(...) abort return call('feedkeys', a:000) endfunction " Show a message in as small a window as possible. " " Vim 8 does not support echoing long messages from asynchronous callbacks, " but NeoVim does. Small messages can be echoed in Vim 8, and larger messages " have to be shown in preview windows. function! ale#util#ShowMessage(string, ...) abort let l:options = get(a:000, 0, {}) if !has('nvim') call ale#preview#CloseIfTypeMatches('ale-preview.message') endif " We have to assume the user is using a monospace font. if has('nvim') || (a:string !~? "\n" && len(a:string) < &columns) " no-custom-checks echo a:string else call ale#preview#Show(split(a:string, "\n"), extend( \ { \ 'filetype': 'ale-preview.message', \ 'stay_here': 1, \ }, \ l:options, \)) endif endfunction " A wrapper function for execute, so we can test executing some commands. function! ale#util#Execute(expr) abort execute a:expr endfunction if !exists('g:ale#util#nul_file') " A null file for sending output to nothing. let g:ale#util#nul_file = '/dev/null' if has('win32') let g:ale#util#nul_file = 'nul' endif endif " Given a job, a buffered line of data, a list of parts of lines, a mode data " is being read in, and a callback, join the lines of output for a NeoVim job " or socket together, and call the callback with the joined output. " " Note that jobs and IDs are the same thing on NeoVim. 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 let l:lines = a:data[:-2] if len(a:data) > 1 let l:lines[0] = a:last_line . l:lines[0] let l:new_last_line = a:data[-1] else let l:new_last_line = a:last_line . get(a:data, 0, '') endif for l:line in l:lines call a:callback(a:job, l:line) endfor return l:new_last_line endfunction " Return the number of lines for a given buffer. function! ale#util#GetLineCount(buffer) abort return len(getbufline(a:buffer, 1, '$')) endfunction function! ale#util#GetFunction(string_or_ref) abort if type(a:string_or_ref) is v:t_string return function(a:string_or_ref) endif return a:string_or_ref endfunction " Open the file (at the given line). " options['open_in'] can be: " current-buffer (default) " tab " split " vsplit function! ale#util#Open(filename, line, column, options) abort let l:open_in = get(a:options, 'open_in', 'current-buffer') let l:args_to_open = '+' . a:line . ' ' . fnameescape(a:filename) if l:open_in is# 'tab' call ale#util#Execute('tabedit ' . l:args_to_open) elseif l:open_in is# 'split' call ale#util#Execute('split ' . l:args_to_open) elseif l:open_in is# 'vsplit' call ale#util#Execute('vsplit ' . l:args_to_open) elseif bufnr(a:filename) isnot bufnr('') " Open another file only if we need to. call ale#util#Execute('edit ' . l:args_to_open) else normal! m` endif call cursor(a:line, a:column) normal! zz endfunction let g:ale#util#error_priority = 5 let g:ale#util#warning_priority = 4 let g:ale#util#info_priority = 3 let g:ale#util#style_error_priority = 2 let g:ale#util#style_warning_priority = 1 function! ale#util#GetItemPriority(item) abort if a:item.type is# 'I' return g:ale#util#info_priority endif if a:item.type is# 'W' if get(a:item, 'sub_type', '') is# 'style' return g:ale#util#style_warning_priority endif return g:ale#util#warning_priority endif if get(a:item, 'sub_type', '') is# 'style' return g:ale#util#style_error_priority endif return g:ale#util#error_priority endfunction " Compare two loclist items for ALE, sorted by their buffers, filenames, and " line numbers and column numbers. function! ale#util#LocItemCompare(left, right) abort if a:left.bufnr < a:right.bufnr return -1 endif if a:left.bufnr > a:right.bufnr return 1 endif if a:left.bufnr == -1 if a:left.filename < a:right.filename return -1 endif if a:left.filename > a:right.filename return 1 endif endif if a:left.lnum < a:right.lnum return -1 endif if a:left.lnum > a:right.lnum return 1 endif if a:left.col < a:right.col return -1 endif if a:left.col > a:right.col return 1 endif " When either of the items lacks a problem type, then the two items should " be considered equal. This is important for loclist jumping. if !has_key(a:left, 'type') || !has_key(a:right, 'type') return 0 endif let l:left_priority = ale#util#GetItemPriority(a:left) let l:right_priority = ale#util#GetItemPriority(a:right) if l:left_priority < l:right_priority return -1 endif if l:left_priority > l:right_priority return 1 endif return 0 endfunction " Compare two loclist items, including the text for the items. " " This function can be used for de-duplicating lists. function! ale#util#LocItemCompareWithText(left, right) abort let l:cmp_value = ale#util#LocItemCompare(a:left, a:right) if l:cmp_value return l:cmp_value endif if a:left.text < a:right.text return -1 endif if a:left.text > a:right.text return 1 endif return 0 endfunction " This function will perform a binary search and a small sequential search " on the list to find the last problem in the buffer and line which is " on or before the column. The index of the problem will be returned. " " -1 will be returned if nothing can be found. function! ale#util#BinarySearch(loclist, buffer, line, column) abort let l:min = 0 let l:max = len(a:loclist) - 1 while 1 if l:max < l:min return -1 endif let l:mid = (l:min + l:max) / 2 let l:item = a:loclist[l:mid] " Binary search for equal buffers, equal lines, then near columns. if l:item.bufnr < a:buffer let l:min = l:mid + 1 elseif l:item.bufnr > a:buffer let l:max = l:mid - 1 elseif l:item.lnum < a:line let l:min = l:mid + 1 elseif l:item.lnum > a:line let l:max = l:mid - 1 else " This part is a small sequential search. let l:index = l:mid " Search backwards to find the first problem on the line. while l:index > 0 \&& a:loclist[l:index - 1].bufnr == a:buffer \&& a:loclist[l:index - 1].lnum == a:line let l:index -= 1 endwhile " Find the last problem on or before this column. while l:index < l:max \&& a:loclist[l:index + 1].bufnr == a:buffer \&& a:loclist[l:index + 1].lnum == a:line \&& a:loclist[l:index + 1].col <= a:column let l:index += 1 endwhile " Scan forwards to find the last item on the column for the item " we found, which will have the most serious problem. let l:item_column = a:loclist[l:index].col while l:index < l:max \&& a:loclist[l:index + 1].bufnr == a:buffer \&& a:loclist[l:index + 1].lnum == a:line \&& a:loclist[l:index + 1].col == l:item_column let l:index += 1 endwhile return l:index endif endwhile endfunction " A function for testing if a function is running inside a sandbox. " See :help sandbox function! ale#util#InSandbox() abort try let &l:equalprg=&l:equalprg catch /E48/ " E48 is the sandbox error. return 1 endtry return 0 endfunction function! ale#util#Tempname() abort let l:clear_tempdir = 0 if exists('$TMPDIR') && empty($TMPDIR) let l:clear_tempdir = 1 let $TMPDIR = '/tmp' endif try let l:name = tempname() " no-custom-checks finally if l:clear_tempdir let $TMPDIR = '' endif endtry return l:name endfunction " Given a single line, or a List of lines, and a single pattern, or a List " of patterns, return all of the matches for the lines(s) from the given " patterns, using matchlist(). " " 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) 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 let l:match = matchlist(l:line, l:pattern) if !empty(l:match) call add(l:matches, l:match) break endif endfor endfor return l:matches endfunction " Given a single line, or a List of lines, and a single pattern, or a List of " patterns, and a callback function for mapping the items matches, return the " result of mapping all of the matches for the lines from the given patterns, " using matchlist() " " Only the first pattern which matches a line will be returned. function! ale#util#MapMatches(lines, patterns, Callback) abort return map(ale#util#GetMatches(a:lines, a:patterns), 'a:Callback(v:val)') endfunction function! s:LoadArgCount(function) abort try let l:output = execute('function a:function') catch /E123/ return 0 endtry let l:match = matchstr(split(l:output, "\n")[0], '\v\([^)]+\)')[1:-2] let l:arg_list = filter(split(l:match, ', '), 'v:val isnot# ''...''') return len(l:arg_list) endfunction " Given the name of a function, a Funcref, or a lambda, return the number " of named arguments for a function. function! ale#util#FunctionArgCount(function) abort let l:Function = ale#util#GetFunction(a:function) let l:count = s:LoadArgCount(l:Function) " If we failed to get the count, forcibly load the autoload file, if the " function is an autoload function. autoload functions aren't normally " defined until they are called. if l:count == 0 let l:function_name = matchlist(string(l:Function), 'function([''"]\(.\+\)[''"])')[1] if l:function_name =~# '#' execute 'runtime autoload/' . join(split(l:function_name, '#')[:-2], '/') . '.vim' let l:count = s:LoadArgCount(l:Function) endif endif return l:count endfunction " Escape a string so the characters in it will be safe for use inside of PCRE " or RE2 regular expressions without characters having special meanings. function! ale#util#EscapePCRE(unsafe_string) abort return substitute(a:unsafe_string, '\([\-\[\]{}()*+?.^$|]\)', '\\\1', 'g') endfunction " Escape a string so that it can be used as a literal string inside an evaled " vim command. function! ale#util#EscapeVim(unsafe_string) abort return "'" . substitute(a:unsafe_string, "'", "''", 'g') . "'" endfunction " Given a String or a List of String values, try and decode the string(s) " as a JSON value which can be decoded with json_decode. If the JSON string " is invalid, the default argument value will be returned instead. " " This function is useful in code where the data can't be trusted to be valid " JSON, and where throwing exceptions is mostly just irritating. function! ale#util#FuzzyJSONDecode(data, default) abort if empty(a:data) return a:default endif let l:str = type(a:data) is v:t_string ? a:data : join(a:data, '') try let l:result = json_decode(l:str) " Vim 8 only uses the value v:none for decoding blank strings. if !has('nvim') && l:result is v:none return a:default endif return l:result catch /E474\|E491/ return a:default endtry endfunction " Write a file, including carriage return characters for DOS files. " " The buffer number is required for determining the fileformat setting for " the buffer. function! ale#util#Writefile(buffer, lines, filename) abort let l:corrected_lines = getbufvar(a:buffer, '&fileformat') is# 'dos' \ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')') \ : a:lines " Set binary flag if buffer doesn't have eol and nofixeol to avoid appending newline let l:flags = !getbufvar(a:buffer, '&eol') && exists('+fixeol') && !&fixeol ? 'bS' : 'S' call writefile(l:corrected_lines, a:filename, l:flags) " no-custom-checks endfunction if !exists('s:patial_timers') let s:partial_timers = {} endif function! s:ApplyPartialTimer(timer_id) abort if has_key(s:partial_timers, a:timer_id) let [l:Callback, l:args] = remove(s:partial_timers, a:timer_id) call call(l:Callback, [a:timer_id] + l:args) endif endfunction " Given a delay, a callback, a List of arguments, start a timer with " timer_start() and call the callback provided with [timer_id] + args. " " The timer must not be stopped with timer_stop(). " Use ale#util#StopPartialTimer() instead, which can stop any timer, and will " clear any arguments saved for executing callbacks later. function! ale#util#StartPartialTimer(delay, callback, args) abort let l:timer_id = timer_start(a:delay, function('s:ApplyPartialTimer')) let s:partial_timers[l:timer_id] = [a:callback, a:args] return l:timer_id endfunction function! ale#util#StopPartialTimer(timer_id) abort call timer_stop(a:timer_id) if has_key(s:partial_timers, a:timer_id) call remove(s:partial_timers, a:timer_id) endif endfunction " Given a possibly multi-byte string and a 1-based character position on a " line, return the 1-based byte position on that line. function! ale#util#Col(str, chr) abort if a:chr < 2 return a:chr endif 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 = getpos('.') 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 function! ale#util#Input(message, value, ...) abort if a:0 > 0 return input(a:message, a:value, a:1) else return input(a:message, a:value) endif endfunction function! ale#util#HasBuflineApi() abort return exists('*deletebufline') && exists('*setbufline') endfunction " Sets buffer contents to lines function! ale#util#SetBufferContents(buffer, lines) abort let l:has_bufline_api = ale#util#HasBuflineApi() if !l:has_bufline_api && a:buffer isnot bufnr('') return endif " 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:new_lines = getbufvar(a:buffer, '&fileformat') is# 'dos' \ ? map(copy(a:lines), 'substitute(v:val, ''\r\+$'', '''', '''')') \ : a:lines let l:first_line_to_remove = len(l:new_lines) + 1 " Use a Vim API for setting lines in other buffers, if available. if l:has_bufline_api if has('nvim') " save and restore signs to avoid flickering let signs = sign_getplaced(a:buffer, {'group': 'ale'})[0].signs call nvim_buf_set_lines(a:buffer, 0, l:first_line_to_remove, 0, l:new_lines) " restore signs (invalid line numbers will be skipped) call sign_placelist(map(signs, {_, v -> extend(v, {'buffer': a:buffer})})) else call setbufline(a:buffer, 1, l:new_lines) endif call deletebufline(a:buffer, l:first_line_to_remove, '$') " Fall back on setting lines the old way, for the current buffer. else let l:old_line_length = line('$') if l:old_line_length >= l:first_line_to_remove let l:save = winsaveview() silent execute \ l:first_line_to_remove . ',' . l:old_line_length . 'd_' call winrestview(l:save) endif call setline(1, l:new_lines) endif return l:new_lines endfunction function! ale#util#GetBufferContents(buffer) abort return join(getbufline(a:buffer, 1, '$'), "\n") . "\n" endfunction function! ale#util#ToURI(resource) abort let l:uri_handler = ale#uri#GetURIHandler(a:resource) if l:uri_handler is# v:null " resource is a filesystem path let l:uri = ale#path#ToFileURI(a:resource) else " resource is a URI let l:uri = a:resource endif return l:uri endfunction function! ale#util#ToResource(uri) abort let l:uri_handler = ale#uri#GetURIHandler(a:uri) if l:uri_handler is# v:null " resource is a filesystem path let l:resource = ale#path#FromFileURI(a:uri) else " resource is a URI let l:resource = a:uri endif return l:resource endfunction ================================================ FILE: autoload/ale/virtualtext.vim ================================================ scriptencoding utf-8 " Author: w0rp " Author: Luan Santos " Description: Shows lint message for the current line as virtualtext, if any if !hlexists('ALEVirtualTextError') highlight link ALEVirtualTextError Comment endif if !hlexists('ALEVirtualTextStyleError') highlight link ALEVirtualTextStyleError ALEVirtualTextError endif if !hlexists('ALEVirtualTextWarning') highlight link ALEVirtualTextWarning Comment endif if !hlexists('ALEVirtualTextStyleWarning') highlight link ALEVirtualTextStyleWarning ALEVirtualTextWarning endif if !hlexists('ALEVirtualTextInfo') highlight link ALEVirtualTextInfo ALEVirtualTextWarning endif let g:ale_virtualtext_prefix = \ get(g:, 'ale_virtualtext_prefix', '%comment% %type%: ') " Controls the milliseconds delay before showing a message. let g:ale_virtualtext_delay = get(g:, 'ale_virtualtext_delay', 10) " Controls the positioning of virtualtext let g:ale_virtualtext_column = get(g:, 'ale_virtualtext_column', 0) let g:ale_virtualtext_maxcolumn = get(g:, 'ale_virtualtext_maxcolumn', 0) " If 1, only show the first problem with virtualtext. let g:ale_virtualtext_single = get(g:, 'ale_virtualtext_single', v:true) let s:cursor_timer = get(s:, 'cursor_timer', -1) let s:last_pos = get(s:, 'last_pos', [0, 0, 0]) let s:hl_list = get(s:, 'hl_list', []) let s:last_message = '' if !has_key(s:, 'has_virt_text') let s:has_virt_text = 0 let s:emulate_virt = 0 let s:last_virt = -1 if has('nvim-0.3.2') let s:ns_id = nvim_create_namespace('ale') let s:has_virt_text = 1 elseif has('textprop') && has('popupwin') let s:has_virt_text = 1 let s:emulate_virt = !has('patch-9.0.0297') if s:emulate_virt call prop_type_add('ale', {}) endif endif endif 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#ResetDataForTests() abort let s:last_pos = [0, 0, 0] let s:last_message = '' endfunction function! ale#virtualtext#GetLastMessageForTests() abort return s:last_message endfunction function! ale#virtualtext#GetComment(buffer) abort let l:filetype = getbufvar(a:buffer, '&filetype') let l:split = split(getbufvar(a:buffer, '&commentstring'), '%s') return !empty(l:split) ? trim(l:split[0]) : '#' endfunction function! ale#virtualtext#Clear(buffer) abort if !s:has_virt_text || !bufexists(str2nr(a:buffer)) return endif if has('nvim') call nvim_buf_clear_namespace(a:buffer, s:ns_id, 0, -1) else if s:emulate_virt && s:last_virt != -1 call prop_remove({'type': 'ale'}) call popup_close(s:last_virt) let s:last_virt = -1 elseif !empty(s:hl_list) call prop_remove({ \ 'types': s:hl_list, \ 'all': 1, \ 'bufnr': a:buffer, \}) endif endif endfunction function! ale#virtualtext#GetGroup(item) abort let l:type = get(a:item, 'type', 'E') let l:sub_type = get(a:item, 'sub_type', '') if l:type is# 'E' if l:sub_type is# 'style' return 'ALEVirtualTextStyleError' endif return 'ALEVirtualTextError' endif if l:type is# 'W' if l:sub_type is# 'style' return 'ALEVirtualTextStyleWarning' endif return 'ALEVirtualTextWarning' endif return 'ALEVirtualTextInfo' endfunction function! ale#virtualtext#GetColumnPadding(buffer, line) abort let l:mincol = ale#Var(a:buffer, 'virtualtext_column') let l:maxcol = ale#Var(a:buffer, 'virtualtext_maxcolumn') let l:win = bufwinnr(a:buffer) if l:mincol[len(l:mincol)-1] is# '%' let l:mincol = (winwidth(l:win) * l:mincol) / 100 endif if l:maxcol[len(l:maxcol)-1] is# '%' let l:maxcol = (winwidth(l:win) * l:maxcol) / 100 endif " Calculate padding for virtualtext alignment if l:mincol > 0 || l:maxcol > 0 let l:line_width = strdisplaywidth(getline(a:line)) if l:line_width < l:mincol return l:mincol - l:line_width elseif l:maxcol > 0 && l:line_width >= l:maxcol " Stop processing if virtualtext would start beyond maxcol return -1 endif endif " no padding. return 0 endfunction function! ale#virtualtext#ShowMessage(buffer, item) abort if !s:has_virt_text || !bufexists(str2nr(a:buffer)) return endif let l:line = max([1, a:item.lnum]) let l:hl_group = ale#virtualtext#GetGroup(a:item) " Get a language-appropriate comment character, or default to '#'. let l:comment = ale#virtualtext#GetComment(a:buffer) let l:prefix = ale#Var(a:buffer, 'virtualtext_prefix') let l:prefix = ale#GetLocItemMessage(a:item, l:prefix) let l:prefix = substitute(l:prefix, '\V%comment%', '\=l:comment', 'g') let l:msg = l:prefix . substitute(a:item.text, '\n', ' ', 'g') let l:col_pad = ale#virtualtext#GetColumnPadding(a:buffer, l:line) " Store the last message we're going to set so we can read it in tests. let s:last_message = l:msg " Discard virtualtext if padding is negative. if l:col_pad < 0 return endif if has('nvim') call nvim_buf_set_virtual_text( \ a:buffer, \ s:ns_id, l:line - 1, \ [[l:msg, l:hl_group]], \ {} \) elseif s:emulate_virt let l:left_pad = col('$') call prop_add(l:line, l:left_pad, {'type': 'ale'}) let s:last_virt = popup_create(l:msg, { \ 'line': -1, \ 'padding': [0, 0, 0, 1], \ 'mask': [[1, 1, 1, 1]], \ 'textprop': 'ale', \ 'highlight': l:hl_group, \ 'fixed': 1, \ 'wrap': 0, \ 'zindex': 2 \}) else let l:type = prop_type_get(l:hl_group) if l:type == {} call prop_type_add(l:hl_group, {'highlight': l:hl_group}) endif " Add highlight groups to the list so we can clear them later. if index(s:hl_list, l:hl_group) == -1 call add(s:hl_list, l:hl_group) endif " We ignore all errors from prop_add. silent! call prop_add(l:line, 0, { \ 'type': l:hl_group, \ 'text': ' ' . l:msg, \ 'bufnr': a:buffer, \ 'text_padding_left': l:col_pad, \}) endif endfunction function! ale#virtualtext#ShowCursorWarning(...) abort if g:ale_virtualtext_cursor isnot# 'current' \&& g:ale_virtualtext_cursor != 1 return endif let l:buffer = bufnr('') if mode(1) isnot# 'n' \|| g:ale_use_neovim_diagnostics_api \|| ale#ShouldDoNothing(l:buffer) return endif let [l:info, l:item] = ale#util#FindItemAtCursor(l:buffer) call ale#virtualtext#Clear(l:buffer) if !empty(l:item) call ale#virtualtext#ShowMessage(l:buffer, l:item) endif endfunction function! ale#virtualtext#ShowCursorWarningWithDelay() abort let l:buffer = bufnr('') if g:ale_virtualtext_cursor isnot# 'current' \&& g:ale_virtualtext_cursor != 1 return endif call s:StopCursorTimer() if mode(1) isnot# 'n' \|| g:ale_use_neovim_diagnostics_api return endif let l:pos = getpos('.')[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 function! ale#virtualtext#CompareSeverityPerLine(left, right) abort " Compare lines if a:left.lnum < a:right.lnum return -1 endif if a:left.lnum > a:right.lnum return 1 endif let l:left_priority = ale#util#GetItemPriority(a:left) let l:right_priority = ale#util#GetItemPriority(a:right) " Put highest priority items first. if l:left_priority > l:right_priority return -1 endif if l:left_priority < l:right_priority return 1 endif " Put the first seen problem first. return a:left.col - a:right.col endfunction function! ale#virtualtext#SetTexts(buffer, loclist) abort if !has('nvim') && s:emulate_virt return endif call ale#virtualtext#Clear(a:buffer) let l:buffer_list = filter(copy(a:loclist), 'v:val.bufnr == a:buffer') if ale#Var(a:buffer,'virtualtext_single') " If we want a single problem per line, sort items on each line by " highest severity and then lowest column position, then de-duplicate " the items by line. call uniq( \ sort(l:buffer_list, function('ale#virtualtext#CompareSeverityPerLine')), \ {a, b -> a.lnum - b.lnum} \) endif for l:item in l:buffer_list call ale#virtualtext#ShowMessage(a:buffer, l:item) endfor endfunction ================================================ FILE: autoload/ale.vim ================================================ " Author: w0rp , David Alexander " Description: Primary code path for the plugin " Manages execution of linters when requested by autocommands " Strings used for severity in the echoed message let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error') let g:ale_echo_msg_info_str = get(g:, 'ale_echo_msg_info_str', 'Info') let g:ale_echo_msg_log_str = get(g:, 'ale_echo_msg_log_str', 'Log') let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning') " LSP window/showMessage format let g:ale_lsp_show_message_format = get(g:, 'ale_lsp_show_message_format', '%severity%:%linter%: %s') " Valid values mimic LSP definitions (error, warning and information; log is " never shown) let g:ale_lsp_show_message_severity = get(g:, 'ale_lsp_show_message_severity', 'error') let s:lint_timer = -1 let s:getcmdwintype_exists = exists('*getcmdwintype') " Return 1 if a file is too large for ALE to handle. function! ale#FileTooLarge(buffer) abort let l:max = getbufvar(a:buffer, 'ale_maximum_file_size', get(g:, 'ale_maximum_file_size', 0)) return l:max > 0 ? (line2byte(line('$') + 1) > l:max) : 0 endfunction " 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 endif " Don't perform any checks when newer NeoVim versions are exiting. if get(v:, 'exiting', v:null) isnot v:null return 1 endif let l:filetype = getbufvar(a:buffer, '&filetype') " Do nothing when there's no filetype. if l:filetype is# '' return 1 endif " Do nothing for diff buffers. if getbufvar(a:buffer, '&diff') && !get(g:, 'ale_lint_diff', 0) return 1 endif " Do nothing for blacklisted files. if index(get(g:, 'ale_filetype_blacklist', []), l:filetype) >= 0 return 1 endif " Do nothing if running from command mode. if s:getcmdwintype_exists && !empty(getcmdwintype()) return 1 endif let l:filename = fnamemodify(bufname(a:buffer), ':t') " Do nothing for directories. if l:filename is# '.' 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 endif " Do nothing if the file is too large. if ale#FileTooLarge(a:buffer) return 1 endif " Do nothing from CtrlP buffers with CtrlP-funky. if exists(':CtrlPFunky') is 2 \&& getbufvar(a:buffer, '&l:statusline') =~# 'CtrlPMode.*funky' return 1 endif 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) let l:ignore_config = ale#Var(a:buffer, 'linters_ignore') let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp') " Load code to ignore linters only if we need to. if ( \ !empty(l:ignore_config) \ || l:disable_lsp is 1 \ || l:disable_lsp is v:true \ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0)) \) let l:linters = ale#engine#ignore#Exclude( \ l:filetype, \ l:linters, \ l:ignore_config, \ l:disable_lsp, \) endif " Tell other sources that they can start checking the buffer now. let g:ale_want_results_buffer = a:buffer silent doautocmd 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 let l:buffer = get(a:000, 1, v:null) if l:buffer is v:null let l:buffer = bufnr('') endif if type(l:buffer) isnot v:t_number throw 'buffer_number must be a Number' endif if ale#ShouldDoNothing(l:buffer) return 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 if a:delay > 0 let s:lint_timer = timer_start( \ a:delay, \ function('s:Lint', [l:buffer, l:should_lint_file]) \) else call s:Lint(l:buffer, l:should_lint_file, 0) endif endfunction let s:current_ale_version = [4, 0, 0] " A function used to check for ALE features in files outside of the project. function! ale#Has(feature) abort let l:match = matchlist(a:feature, '\c\v^ale-(\d+)\.(\d+)(\.(\d+))?$') if !empty(l:match) let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0] return ale#semver#GTE(s:current_ale_version, l:version) endif return 0 endfunction " Given a buffer number and a variable name, look for that variable in the " buffer scope, then in global scope. If the name does not exist in the global " scope, an exception will be thrown. " " Every variable name will be prefixed with 'ale_'. function! ale#Var(buffer, variable_name) abort let l:full_name = 'ale_' . a:variable_name let l:vars = getbufvar(str2nr(a:buffer), '', {}) return get(l:vars, l:full_name, g:[l:full_name]) endfunction " Initialize a variable with a default value, if it isn't already set. " " Every variable name will be prefixed with 'ale_'. function! ale#Set(variable_name, default) abort let l:full_name = 'ale_' . a:variable_name if !has_key(g:, l:full_name) let g:[l:full_name] = a:default endif endfunction " Given a string for adding to a command, return the string padded with a " space on the left if it is not empty. Otherwise return an empty string. " " This can be used for making command strings cleaner and easier to test. function! ale#Pad(string) abort return !empty(a:string) ? ' ' . a:string : '' endfunction " Given a environment variable name and a value, produce part of a command for " setting an environment variable before running a command. The syntax will be " valid for cmd on Windows, or most shells on Unix. function! ale#Env(variable_name, value) abort if has('win32') return 'set ' . ale#Escape(a:variable_name . '=' . a:value) . ' && ' endif return a:variable_name . '=' . ale#Escape(a:value) . ' ' endfunction " Escape a string suitably for each platform. " shellescape does not work on Windows. function! ale#Escape(str) abort if fnamemodify(&shell, ':t') is? 'cmd.exe' " If the string contains spaces, it will be surrounded by quotes. " Otherwise, special characters will be escaped with carets (^). return substitute( \ a:str =~# ' ' \ ? '"' . substitute(a:str, '"', '""', 'g') . '"' \ : substitute(a:str, '\v([&|<>^])', '^\1', 'g'), \ '%', \ '%%', \ 'g', \) endif return shellescape (a:str) endfunction " Get the loclist item message according to a given format string. " " See `:help g:ale_loclist_msg_format` and `:help g:ale_echo_msg_format` function! ale#GetLocItemMessage(item, format_string) abort let l:msg = a:format_string let l:severity = g:ale_echo_msg_warning_str let l:code = get(a:item, 'code', '') let l:type = get(a:item, 'type', 'E') let l:linter_name = get(a:item, 'linter_name', '') let l:code_repl = !empty(l:code) ? '\=submatch(1) . l:code . submatch(2)' : '' if l:type is# 'E' let l:severity = g:ale_echo_msg_error_str elseif l:type is# 'I' let l:severity = g:ale_echo_msg_info_str endif " Replace special markers with certain information. " \=l:variable is used to avoid escaping issues. let l:msg = substitute(l:msg, '\v\%([^\%]*)code([^\%]*)\%', l:code_repl, 'g') let l:msg = substitute(l:msg, '\V%severity%', '\=l:severity', 'g') let l:msg = substitute(l:msg, '\V%type%', '\=l:type', 'g') let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g') " Replace %s with the text. let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g') " Windows may insert carriage return line endings (^M), strip these characters. let l:msg = substitute(l:msg, '\r', '', 'g') return l:msg endfunction " Given a buffer and a linter or fixer name, return an Array of two-item " Arrays describing how to map filenames to and from the local to foreign file " systems. function! ale#GetFilenameMappings(buffer, name) abort let l:linter_mappings = ale#Var(a:buffer, 'filename_mappings') if type(l:linter_mappings) is v:t_list return l:linter_mappings endif let l:name = a:name if !has_key(l:linter_mappings, l:name) " Use * as a default setting for all tools. let l:name = '*' endif return get(l:linter_mappings, l:name, []) endfunction ================================================ FILE: autoload/asyncomplete/sources/ale.vim ================================================ function! asyncomplete#sources#ale#get_source_options(...) abort let l:default = extend({ \ 'name': 'ale', \ 'completor': function('asyncomplete#sources#ale#completor'), \ 'whitelist': ['*'], \ 'triggers': asyncomplete#sources#ale#get_triggers(), \ }, a:0 >= 1 ? a:1 : {}) return extend(l:default, {'refresh_pattern': '\k\+$'}) endfunction function! asyncomplete#sources#ale#get_triggers() abort let l:triggers = ale#completion#GetAllTriggers() let l:triggers['*'] = l:triggers[''] return l:triggers endfunction function! asyncomplete#sources#ale#completor(options, context) abort let l:keyword = matchstr(a:context.typed, '\w\+$') let l:startcol = a:context.col - len(l:keyword) call ale#completion#GetCompletions('ale-callback', { 'callback': {completions -> \ asyncomplete#complete(a:options.name, a:context, l:startcol, completions) \ }}) endfunction ================================================ FILE: doc/ale-ada.txt ================================================ =============================================================================== ALE Ada Integration *ale-ada-options* =============================================================================== cspell *ale-ada-cspell* See |ale-cspell-options| =============================================================================== gcc *ale-ada-gcc* *ale-options.ada_gcc_executable* *g:ale_ada_gcc_executable* *b:ale_ada_gcc_executable* ada_gcc_executable g:ale_ada_gcc_executable Type: |String| Default: `'gcc'` This variable can be changed to use a different executable for gcc. *ale-options.ada_gcc_options* *g:ale_ada_gcc_options* *b:ale_ada_gcc_options* ada_gcc_options g:ale_ada_gcc_options Type: |String| Default: `'-gnatwa -gnatq'` This variable can be set to pass additional options to gcc. =============================================================================== gnatpp *ale-ada-gnatpp* *ale-options.ada_gnatpp_options* *g:ale_ada_gnatpp_options* *b:ale_ada_gnatpp_options* ada_gnatpp_options g:ale_ada_gnatpp_options Type: |String| Default: `''` This variable can be set to pass extra options to the gnatpp fixer. =============================================================================== ada-language-server *ale-ada-language-server* *ale-options.ada_adals_executable* *g:ale_ada_adals_executable* *b:ale_ada_adals_executable* ada_adals_executable g:ale_ada_adals_executable Type: |String| Default: `'ada_language_server'` This variable can be changed to use a different executable for Ada Language Server. *ale-options.ada_adals_project* *g:ale_ada_adals_project* *b:ale_ada_adals_project* ada_adals_project g:ale_ada_adals_project Type: |String| Default: `'default.gpr'` This variable can be changed to use a different GPR file for Ada Language Server. *ale-options.ada_adals_encoding* *g:ale_ada_adals_encoding* *b:ale_ada_adals_encoding* ada_adals_encoding g:ale_ada_adals_encoding Type: |String| Default: `'utf-8'` This variable can be changed to use a different file encoding for Ada Language Server. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-ansible.txt ================================================ =============================================================================== ALE Ansible Integration *ale-ansible-options* =============================================================================== ansible-language-server *ale-ansible-language-server* *ale-options.ansible_language_server_executable* *g:ale_ansible_language_server_executable* *b:ale_ansible_language_server_executable* ansible_language_server_executable g:ale_ansible_language_server_executable Type: |String| Default: `'ansible-language-server'` Variable can be used to modify the executable used for Ansible language server. *ale-options.ansible_language_server_config* *g:ale_ansible_language_server_config* *b:ale_ansible_language_server_config* ansible_language_server_config g:ale_ansible_language_server_config Type: |Dictionary| Default: `'{}'` Configuration parameters sent to the language server on start. Refer to the ansible language server configuration documentation for list of available options: https://als.readthedocs.io/en/latest/settings/ =============================================================================== ansible-lint *ale-ansible-ansible-lint* *ale-options.ansible_ansible_lint_executable* *g:ale_ansible_ansible_lint_executable* *b:ale_ansible_ansible_lint_executable* ansible_ansible_lint_executable g:ale_ansible_ansible_lint_executable Type: |String| Default: `'ansible-lint'` This variable can be changed to modify the executable used for ansible-lint. *ale-options.ansible_ansible_lint_auto_pipenv* *g:ale_ansible_ansible_lint_auto_pipenv* *b:ale_ansible_ansible_lint_auto_pipenv* ansible_ansible_lint_auto_pipenv g:ale_ansible_ansible_lint_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-options.ansible_ansible_lint_auto_poetry* *g:ale_ansible_ansible_lint_auto_poetry* *b:ale_ansible_ansible_lint_auto_poetry* ansible_ansible_lint_auto_poetry g:ale_ansible_ansible_lint_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.ansible_ansible_lint_auto_uv* *g:ale_ansible_ansible_lint_auto_uv* *b:ale_ansible_ansible_lint_auto_uv* ansible_ansible_lint_auto_uv g:ale_ansible_ansible_lint_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-apkbuild.txt ================================================ =============================================================================== ALE APKBUILD Integration *ale-apkbuild-options* =============================================================================== apkbuild-fixer *ale-apkbuild-apkbuild-fixer* *ale-options.apkbuild_apkbuild_fixer_options* *g:ale_apkbuild_apkbuild_fixer_options* *b:ale_apkbuild_apkbuild_fixer_options* apkbuild_apkbuild_fixer_options g:ale_apkbuild_apkbuild_fixer_options Type: |String| Default: `''` This variable can be set to pass additional options to the apkbuild_fixer fixer. *ale-options.apkbuild_apkbuild_fixer_executable* *g:ale_apkbuild_apkbuild_fixer_executable* *b:ale_apkbuild_apkbuild_fixer_executable* apkbuild_apkbuild_fixer_executable g:ale_apkbuild_apkbuild_fixer_executable Type: |String| Default: `'apkbuild-fixer'` This variable can be modified to change the executable path for `apkbuild-fixer`. *ale-options.apkbuild_apkbuild_fixer_lint_executable* *g:ale_apkbuild_apkbuild_fixer_lint_executable* *b:ale_apkbuild_apkbuild_fixer_lint_executable* apkbuild_apkbuild_fixer_lint_executable g:ale_apkbuild_apkbuild_fixer_lint_executable Type: |String| Default: `'apkbuild-fixer'` This variable can be modified to change the executable path for `apkbuild-lint`, the binary used to find violations. =============================================================================== apkbuild-lint *ale-apkbuild-apkbuild-lint* *ale-options.apkbuild_apkbuild_lint_executable* *g:ale_apkbuild_apkbuild_lint_executable* *b:ale_apkbuild_apkbuild_lint_executable* apkbuild_apkbuild_lint_executable g:ale_apkbuild_apkbuild_lint_executable Type: |String| Default: `'apkbuild-lint'` This variable can be set to change the path to apkbuild-lint =============================================================================== secfixes-check *ale-apkbuild-secfixes-check* *ale-options.apkbuild_secfixes_check_executable* *g:ale_apkbuild_secfixes_check_executable* *b:ale_apkbuild_secfixes_check_executable* apkbuild_secfixes_check_executable g:ale_apkbuild_secfixes_check_executable Type: |String| Default: `'secfixes-check'` This variable can be set to change the path to secfixes-check =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-asciidoc.txt ================================================ =============================================================================== ALE AsciiDoc Integration *ale-asciidoc-options* =============================================================================== cspell *ale-asciidoc-cspell* See |ale-cspell-options| =============================================================================== write-good *ale-asciidoc-write-good* See |ale-write-good-options| =============================================================================== textlint *ale-asciidoc-textlint* See |ale-text-textlint| =============================================================================== redpen *ale-asciidoc-redpen* See |ale-redpen-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-asm.txt ================================================ =============================================================================== ALE ASM Integration *ale-asm-options* =============================================================================== gcc *ale-asm-gcc* *ale-options.asm_gcc_executable* *g:ale_asm_gcc_executable* *b:ale_asm_gcc_executable* asm_gcc_executable g:ale_asm_gcc_executable Type: |String| Default: `'gcc'` This variable can be changed to use a different executable for gcc. *ale-options.asm_gcc_options* *g:ale_asm_gcc_options* *b:ale_asm_gcc_options* asm_gcc_options g:ale_asm_gcc_options Type: |String| Default: `'-Wall'` This variable can be set to pass additional options to gcc. =============================================================================== llvm_mc *ale-asm-llvm_mc* *ale-options.asm_llvm_mc_executable* *g:ale_asm_llvm_mc_executable* *b:ale_asm_llvm_mc_executable* asm_llvm_mc_executable g:ale_asm_llvm_mc_executable Type: |String| Default: `'llvm-mc'` This variable can be changed to use a different executable for llvm-mc. *ale-options.asm_llvm_mc_options* *g:ale_asm_llvm_mc_options* *b:ale_asm_llvm_mc_options* asm_llvm_mc_options g:ale_asm_llvm_mc_options Type: |String| Default: `''` This variable can be set to pass additional options to llvm-mc. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-astro.txt ================================================ =============================================================================== ALE Astro Integration *ale-astro-options* =============================================================================== eslint *ale-astro-eslint* See |ale-javascript-eslint| for information about the available options. =============================================================================== prettier *ale-astro-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-avra.txt ================================================ =============================================================================== ALE AVRA Integration *ale-avra-options* =============================================================================== avra *ale-avra-avra* *ale-options.avra_avra_executable* *g:ale_avra_avra_executable* *b:ale_avra_avra_executable* avra_avra_executable g:ale_avra_avra_executable Type: |String| Default `'avra'` This variable can be changed to use different executable for AVRA. *ale-options.avra_avra_options* *g:ale_avra_avra_options* *b:ale_avra_avra_options* avra_avra_options g:ale_avra_avra_options Type: |String| Default: `''` This variable can be set to pass additional options to AVRA. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-awk.txt ================================================ =============================================================================== ALE Awk Integration *ale-awk-options* =============================================================================== gawk *ale-awk-gawk* *ale-options.awk_gawk_executable* *g:ale_awk_gawk_executable* *b:ale_awk_gawk_executable* awk_gawk_executable g:ale_awk_gawk_executable Type: |String| Default: `'gawk'` This variable sets executable used for gawk. *ale-options.awk_gawk_options* *g:ale_awk_gawk_options* *b:ale_awk_gawk_options* awk_gawk_options g:ale_awk_gawk_options Type: |String| Default: `''` With this variable we are able to pass extra arguments for gawk for invocation. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-bats.txt ================================================ =============================================================================== ALE Bats Integration *ale-bats-options* =============================================================================== shellcheck *ale-bats-shellcheck* The `shellcheck` linter for Bats uses the sh options for `shellcheck`; see: |ale-sh-shellcheck|. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-bazel.txt ================================================ =============================================================================== ALE Bazel Integration *ale-bazel-options* =============================================================================== buildifier *ale-bazel-buildifier* *ale-options.bazel_buildifier_executable* *g:ale_bazel_buildifier_executable* *b:ale_bazel_buildifier_executable* bazel_buildifier_executable g:ale_bazel_buildifier_executable Type: |String| Default: `'buildifier'` See |ale-integrations-local-executables| *ale-options.bazel_buildifier_options* *g:ale_bazel_buildifier_options* *b:ale_bazel_buildifier_options* bazel_buildifier_options g:ale_bazel_buildifier_options Type: |String| Default: `''` This variable can be set to pass extra options to buildifier. *ale-options.bazel_buildifier_use_global* *g:ale_bazel_buildifier_use_global* *b:ale_bazel_buildifier_use_global* bazel_buildifier_use_global g:ale_bazel_buildifier_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-bib.txt ================================================ =============================================================================== ALE BibTeX Integration *ale-bib-options* =============================================================================== bibclean *ale-bib-bibclean* *ale-options.bib_bibclean_executable* *g:ale_bib_bibclean_executable* *b:ale_bib_bibclean_executable* bib_bibclean_executable g:ale_bib_bibclean_executable Type: |String| Default: `'bibclean'` *ale-options.bib_bibclean_options* *g:ale_bib_bibclean_options* *b:ale_bib_bibclean_options* bib_bibclean_options g:ale_bib_bibclean_options Type: |String| Default: `'-align-equals'` =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-bicep.txt ================================================ =============================================================================== ALE Bicep Integration *ale-bicep-options* =============================================================================== bicep *ale-bicep-bicep* *ale-options.bicep_bicep_executable* *g:ale_bicep_bicep_executable* *b:ale_bicep_bicep_executable* bicep_bicep_executable g:ale_bicep_bicep_executable Type: |String| Default: `'bicep'` This variable can be set to change the path to bicep. *ale-options.bicep_bicep_options* *g:ale_bicep_bicep_options* *b:ale_bicep_bicep_options* bicep_bicep_options g:ale_bicep_bicep_options Type: |String| Default: `''` This variable can be set to pass additional options to bicep. =============================================================================== az_bicep *ale-bicep-az_bicep* *ale-options.bicep_az_bicep_executable* *g:ale_bicep_az_bicep_executable* *b:ale_bicep_az_bicep_executable* bicep_az_bicep_executable g:ale_bicep_az_bicep_executable Type: |String| Default: `'az'` This variable can be set to change the path to az_bicep. *ale-options.bicep_az_bicep_options* *g:ale_bicep_az_bicep_options* *b:ale_bicep_az_bicep_options* bicep_az_bicep_options g:ale_bicep_az_bicep_options Type: |String| Default: `''` This variable can be set to pass additional options to az_bicep. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-bindzone.txt ================================================ =============================================================================== ALE BINDZone Integration *ale-bindzone-options* =============================================================================== checkzone *ale-bindzone-checkzone* *ale-options.bindzone_checkzone_executable* *g:ale_bindzone_checkzone_executable* *b:ale_bindzone_checkzone_executable* bindzone_checkzone_executable g:ale_bindzone_checkzone_executable Type: |String| Default: `named-checkzone` This variable can be changed to set the path to named-checkzone executable. *ale-options.bindzone_checkzone_options* *g:ale_bindzone_checkzone_options* *b:ale_bindzone_checkzone_options* bindzone_checkzone_options g:ale_bindzone_checkzone_options Type: |String| Default: `-c IN` This variable can be changed to add additional command-line arguments. All available options can be found at: https://bind9.readthedocs.io/en/stable/manpages.html#named-checkzone-zone-file-validation-tool =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-bitbake.txt ================================================ =============================================================================== ALE BitBake Integration *ale-bitbake-options* =============================================================================== oelint-adv *ale-bitbake-oelint_adv* *ale-options.bitbake_oelint_adv_executable* *g:ale_bitbake_oelint_adv_executable* *b:ale_bitbake_oelint_adv_executable* bitbake_oelint_adv_executable g:ale_bitbake_oelint_adv_executable Type: |String| Default: `'oelint-adv'` This variable can be changed to use a different executable for oelint-adv. *ale-options.bitbake_oelint_adv_options* *g:ale_bitbake_oelint_adv_options* *b:ale_bitbake_oelint_adv_options* bitbake_oelint_adv_options g:ale_bitbake_oelint_adv_options Type: |String| Default: `''` This variable can be set to pass additional options to oelint-adv. *ale-options.bitbake_oelint_adv_config* *g:ale_bitbake_oelint_adv_config* *b:ale_bitbake_oelint_adv_config* g:ale_bitbake_oelint_adv_config Type: |String| Default: `'.oelint.cfg'` This variable can be set to use a different config file. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-c.txt ================================================ =============================================================================== ALE C Integration *ale-c-options* For basic checking of problems with C files, ALE offers the `cc` linter, which runs either `clang`, or `gcc`. See |ale-c-cc|. =============================================================================== Global Options *ale-options.c_always_make* *g:ale_c_always_make* *b:ale_c_always_make* c_always_make g:ale_c_always_make Type: |Number| Default: `has('unix') && !has('macunix')` If set to `1`, use `--always-make` for `make`, which means that output will always be parsed from `make` dry runs with GNU make. BSD `make` does not support this option, so you probably want to turn this option off when using a BSD variant. *ale-options.c_build_dir_names* *g:ale_c_build_dir_names* *b:ale_c_build_dir_names* c_build_dir_names g:ale_c_build_dir_names Type: |List| Default: `['build', 'build/Debug', 'build/Release', 'bin']` A list of directory names to be used when searching upwards from C files to discover compilation databases with. For directory named `'foo'`, ALE will search for `'foo/compile_commands.json'` in all directories on and above the directory containing the C file to find path to compilation database. This feature is useful for the clang tools wrapped around LibTooling (namely here, clang-tidy) *ale-options.c_build_dir* *g:ale_c_build_dir* *b:ale_c_build_dir* c_build_dir g:ale_c_build_dir Type: |String| Default: `''` 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|. *ale-options.c_parse_compile_commands* *g:ale_c_parse_compile_commands* *b:ale_c_parse_compile_commands* c_parse_compile_commands g:ale_c_parse_compile_commands Type: |Number| Default: `1` 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|. *ale-options.c_parse_makefile* *g:ale_c_parse_makefile* *b:ale_c_parse_makefile* c_parse_makefile g:ale_c_parse_makefile Type: |Number| Default: `0` If set to `1`, ALE will run `make -n` to automatically determine flags to set for C or C++ compilers. This can make it easier to determine the correct build flags to use for different files. NOTE: When using this option on BSD, you may need to set |g:ale_c_always_make| to `0`, and `make -n` will not provide consistent results if binaries have already been built, so use `make clean` when editing your files. WARNING: Running `make -n` automatically can execute arbitrary code, even though it's supposed to be a dry run, so enable this option with care. You might prefer to use the buffer-local version of the option instead with |g:ale_pattern_options|, or you own code for checking which project you're in. You might want to disable this option if `make -n` takes too long to run for projects you work on. If |g:ale_c_parse_compile_commands| or |b:ale_c_parse_compile_commands| is set to `1`, flags taken from `compile_commands.json` will be preferred over `make -n` output. =============================================================================== astyle *ale-c-astyle* *ale-options.c_astyle_executable* *g:ale_c_astyle_executable* *b:ale_c_astyle_executable* c_astyle_executable g:ale_c_astyle_executable Type: |String| Default: `'astyle'` This variable can be changed to use a different executable for astyle. *ale-options.c_astyle_project_options* *g:ale_c_astyle_project_options* *b:ale_c_astyle_project_options* c_astyle_project_options g:ale_c_astyle_project_options Type: |String| Default: `''` This variable can be changed to use an option file for project level configurations. Provide only the filename of the option file that should be present at the project's root directory. For example, if .astylrc is specified, the file is searched in the parent directories of the source file's directory. =============================================================================== cc *ale-c-cc* *ale-c-gcc* *ale-c-clang* *ale-options.c_cc_executable* *g:ale_c_cc_executable* *b:ale_c_cc_executable* c_cc_executable g:ale_c_cc_executable Type: |String| Default: `''` This variable can be changed to use a different executable for a C compiler. ALE will try to use `clang` if Clang is available, otherwise ALE will default to checking C code with `gcc`. *ale-options.c_cc_options* *g:ale_c_cc_options* *b:ale_c_cc_options* c_cc_options g:ale_c_cc_options Type: |String| Default: `'-std=c11 -Wall'` This variable can be changed to modify flags given to the C compiler. *ale-options.c_cc_use_header_lang_flag* *g:ale_c_cc_use_header_lang_flag* *b:ale_c_cc_use_header_lang_flag* c_cc_use_header_lang_flag g:ale_c_cc_use_header_lang_flag Type: |Number| Default: `-1` By default, ALE will use `'-x c-header'` instead of `'-x c'` for header files when using Clang. This variable can be changed to manually activate or deactivate this flag for header files. - When set to `-1`, the default beviour is used, `'-x c-header'` is used with Clang and `'-x c'` is used with other compilers. - When set to `0`, the flag is deactivated, `'-x c'` is always used independently of the compiler. - When set to `1`, the flag is activated, `'-x c-header'` is always used independently of the compiler. Gcc does not support `'-x c-header'` when using `'-'` as input filename, which is what ALE does. This why, by default, ALE only uses `'-x c-header'` with Clang. *ale-options.c_cc_header_exts* *g:ale_c_cc_header_exts* *b:ale_c_cc_header_exts* c_cc_header_exts g:ale_c_cc_header_exts Type: |List| Default: `['h']` This variable can be changed to modify the list of extensions of the files considered as header files. This variable is only used when `'-x c-header'` is used instead of `'-x c'`, see |g:ale_c_cc_use_header_lang_flag|. =============================================================================== ccls *ale-c-ccls* *ale-options.c_ccls_executable* *g:ale_c_ccls_executable* *b:ale_c_ccls_executable* c_ccls_executable g:ale_c_ccls_executable Type: |String| Default: `'ccls'` This variable can be changed to use a different executable for ccls. *ale-options.c_ccls_init_options* *g:ale_c_ccls_init_options* *b:ale_c_ccls_init_options* c_ccls_init_options g:ale_c_ccls_init_options Type: |Dictionary| Default: `{}` This variable can be changed to customize ccls initialization options. For example: > let g:ale_c_ccls_init_options = { \ 'cacheDirectory': '/tmp/ccls', \ 'cacheFormat': 'binary', \ 'diagnostics': { \ 'onOpen': 0, \ 'opChange': 1000, \ }, \} < For all available options and explanations, visit https://github.com/MaskRay/ccls/wiki/Customization#initialization-options. =============================================================================== clangcheck *ale-c-clangcheck* `clang-check` will be run only when files are saved to disk, so that `compile_commands.json` files can be used. It is recommended to use this linter in combination with `compile_commands.json` files. Therefore, `clang-check` linter reads the options |g:ale_c_build_dir| and |g:ale_c_build_dir_names|. Also, setting |g:ale_c_build_dir| actually overrides |g:ale_c_build_dir_names|. ------------------------------------------------------------------------------- Options *ale-options.c_clangcheck_executable* *g:ale_c_clangcheck_executable* *b:ale_c_clangcheck_executable* c_clangcheck_executable g:ale_c_clangcheck_executable Type: |String| Default: `'clang-check'` This variable can be changed to use a different executable for clangcheck. *ale-options.c_clangcheck_options* *g:ale_c_clangcheck_options* *b:ale_c_clangcheck_options* c_clangcheck_options g:ale_c_clangcheck_options Type: |String| Default: `''` This variable can be changed to modify flags given to clang-check. This variable should not be set to point to build subdirectory with `-p path/to/build` option, as it is handled by the |g:ale_c_build_dir| option. =============================================================================== clangd *ale-c-clangd* *ale-options.c_clangd_executable* *g:ale_c_clangd_executable* *b:ale_c_clangd_executable* c_clangd_executable g:ale_c_clangd_executable Type: |String| Default: `'clangd'` This variable can be changed to use a different executable for clangd. *ale-options.c_clangd_options* *g:ale_c_clangd_options* *b:ale_c_clangd_options* c_clangd_options g:ale_c_clangd_options Type: |String| Default: `''` This variable can be changed to modify flags given to clangd. =============================================================================== clang-format *ale-c-clangformat* *ale-options.c_clangformat_executable* *g:ale_c_clangformat_executable* *b:ale_c_clangformat_executable* c_clangformat_executable g:ale_c_clangformat_executable Type: |String| Default: `'clang-format'` This variable can be changed to use a different executable for clang-format. *ale-options.c_clangformat_options* *g:ale_c_clangformat_options* *b:ale_c_clangformat_options* c_clangformat_options g:ale_c_clangformat_options Type: |String| Default: `''` This variable can be changed to modify flags given to clang-format. *ale-options.c_clangformat_style_option* *g:ale_c_clangformat_style_option* *b:ale_c_clangformat_style_option* c_clangformat_style_option g:ale_c_clangformat_style_option Type: |String| Default: `''` This variable can be changed to modify only the style flag given to clang-format. The contents of the variable are passed directly to the -style flag of clang-format. Example: > let g:ale_c_clangformat_style_option = { \ 'BasedOnStyle': 'Microsoft', \ 'ColumnLimit': 80, \ 'AllowShortBlocksOnASingleLine': 'Always', \ 'AllowShortFunctionsOnASingleLine': 'Inline', \} < If you set this variable, ensure you don't modify -style in |g:ale_c_clangformat_options|, as this will cause clang-format to error. *ale-options.c_clangformat_use_local_file* *g:ale_c_clangformat_use_local_file* *b:ale_c_clangformat_use_local_file* c_clangformat_use_local_file g:ale_c_clangformat_use_local_file Type: |Number| Default: `0` This variable can be changed to modify whether to use a local .clang-format file. If the file is found, the flag '-style=file' is passed to clang-format and any options configured via |g:ale_c_clangformat_style_option| are not passed. If this option is enabled but no .clang-format file is found, default back to |g:ale_c_clangformat_style_option|, if it set. If you set this variable, ensure you don't modify -style in |g:ale_c_clangformat_options|, as this will cause clang-format to error. =============================================================================== clangtidy *ale-c-clangtidy* `clang-tidy` will be run only when files are saved to disk, so that `compile_commands.json` files can be used. It is recommended to use this linter in combination with `compile_commands.json` files. Therefore, `clang-tidy` linter reads the options |g:ale_c_build_dir| and |g:ale_c_build_dir_names|. Also, setting |g:ale_c_build_dir| actually overrides |g:ale_c_build_dir_names|. ------------------------------------------------------------------------------- Options *ale-options.c_clangtidy_checks* *g:ale_c_clangtidy_checks* *b:ale_c_clangtidy_checks* c_clangtidy_checks g:ale_c_clangtidy_checks Type: |List| Default: `[]` The checks to enable for clang-tidy 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. Not all of clangtidy checks are applicable for C. You should consult the clang documentation for an up-to-date list of compatible checks: http://clang.llvm.org/extra/clang-tidy/checks/list.html *ale-options.c_clangtidy_executable* *g:ale_c_clangtidy_executable* *b:ale_c_clangtidy_executable* c_clangtidy_executable g:ale_c_clangtidy_executable Type: |String| Default: `'clang-tidy'` This variable can be changed to use a different executable for clangtidy. *ale-options.c_clangtidy_options* *g:ale_c_clangtidy_options* *b:ale_c_clangtidy_options* c_clangtidy_options g:ale_c_clangtidy_options Type: |String| Default: `''` This variable can be changed to modify compiler flags given to clang-tidy. - Setting this variable to a non-empty string, - and working in a buffer where no compilation database is found using |g:ale_c_build_dir_names| or |g:ale_c_build_dir|, will cause the `--` argument to be passed to `clang-tidy`, which will mean that detection of `compile_commands.json` files for compile command databases will be disabled. Only set this option if you want to control compiler flags entirely manually, and no `compile_commands.json` file is in one of the |g:ale_c_build_dir_names| directories of the project tree. *ale-options.c_clangtidy_extra_options* *g:ale_c_clangtidy_extra_options* *b:ale_c_clangtidy_extra_options* c_clangtidy_extra_options g:ale_c_clangtidy_extra_options Type: |String| Default: `''` This variable can be changed to modify flags given to clang-tidy. *ale-options.c_clangtidy_fix_errors* *g:ale_c_clangtidy_fix_errors* *b:ale_c_clangtidy_fix_errors* c_clangtidy_fix_errors g:ale_c_clangtidy_fix_errors Type: |Number| Default: `1` This variable can be changed to disable the `-fix-errors` option for the |clangtidy| fixer. =============================================================================== cppcheck *ale-c-cppcheck* *ale-options.c_cppcheck_executable* *g:ale_c_cppcheck_executable* *b:ale_c_cppcheck_executable* c_cppcheck_executable g:ale_c_cppcheck_executable Type: |String| Default: `'cppcheck'` This variable can be changed to use a different executable for cppcheck. *ale-options.c_cppcheck_options* *g:ale_c_cppcheck_options* *b:ale_c_cppcheck_options* c_cppcheck_options g:ale_c_cppcheck_options Type: |String| Default: `'--enable=style'` This variable can be changed to modify flags given to cppcheck. =============================================================================== cquery *ale-c-cquery* *ale-options.c_cquery_executable* *g:ale_c_cquery_executable* *b:ale_c_cquery_executable* c_cquery_executable g:ale_c_cquery_executable Type: |String| Default: `'cquery'` This variable can be changed to use a different executable for cquery. *ale-options.c_cquery_cache_directory* *g:ale_c_cquery_cache_directory* *b:ale_c_cquery_cache_directory* c_cquery_cache_directory g:ale_c_cquery_cache_directory Type: |String| Default: `'~/.cache/cquery'` This variable can be changed to decide which directory cquery uses for its cache. =============================================================================== cspell *ale-c-cspell* See |ale-cspell-options| =============================================================================== flawfinder *ale-c-flawfinder* *ale-options.c_flawfinder_executable* *g:ale_c_flawfinder_executable* *b:ale_c_flawfinder_executable* c_flawfinder_executable g:ale_c_flawfinder_executable Type: |String| Default: `'flawfinder'` This variable can be changed to use a different executable for flawfinder. *ale-options.c_flawfinder_minlevel* *g:ale_c_flawfinder_minlevel* *b:ale_c_flawfinder_minlevel* c_flawfinder_minlevel g:ale_c_flawfinder_minlevel Type: |Number| Default: `1` This variable can be changed to ignore risks under the given risk threshold. *ale-options.c_flawfinder_options* *g:ale_c_flawfinder_options* *b:ale-c-flawfinder* c_flawfinder_options g:ale_c_flawfinder_options Type: |String| Default: `''` This variable can be used to pass extra options into the flawfinder command. *ale-options.c_flawfinder_error_severity* *g:ale_c_flawfinder_error_severity* *b:ale_c_flawfinder_error_severity* c_flawfinder_error_severity g:ale_c_flawfinder_error_severity Type: |Number| Default: `6` This variable can be changed to set the minimum severity to be treated as an error. This setting also applies to flawfinder for c++. =============================================================================== uncrustify *ale-c-uncrustify* *ale-options.c_uncrustify_executable* *g:ale_c_uncrustify_executable* *b:ale_c_uncrustify_executable* c_uncrustify_executable g:ale_c_uncrustify_executable Type: |String| Default: `'uncrustify'` This variable can be changed to use a different executable for uncrustify. *ale-options.c_uncrustify_options* *g:ale_c_uncrustify_options* *b:ale_c_uncrustify_options* c_uncrustify_options g:ale_c_uncrustify_options Type: |String| Default: `''` This variable can be change to modify flags given to uncrustify. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-c3.txt ================================================ =============================================================================== ALE C3 Integration *ale-c3-options* =============================================================================== c3lsp *ale-c3-c3lsp* *ale-options.c3_c3lsp_executable* *g:ale_c3_c3lsp_executable* *b:ale_c3_c3lsp_executable* c3_c3lsp_executable g:ale_c3_c3lsp_executable Type: |String| Default: `c3lsp` This variable can be changed to set the path to c3lsp executable. *ale-options.c3_c3lsp_options* *g:ale_c3_c3lsp_options* *b:ale_c3_c3lsp_options* c3_c3lsp_options g:ale_c3_c3lsp_options Type: |String| Default: `''` Add command line options to the c3lsp executable. This is useful to specify the path to the C3 standard library with '-stdlib-path='. *ale-options.c3_c3lsp_init_options* *g:ale_c3_c3lsp_init_options* *b:ale_c3_c3lsp_init_options* c3_c3lsp_init_options g:ale_c3_c3lsp_init_options Type: |Dictionary| Default: `{}` Dictionary containing configuration settings that will be passed to the language server. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-cairo.txt ================================================ =============================================================================== ALE Cairo Integration *ale-cairo-options* =============================================================================== scarb *ale-cairo-scarb* *ale-options.cairo_scarb_executable* *g:ale_cairo_scarb_executable* *b:ale_cairo_scarb_executable* cairo_scarb_executable g:ale_cairo_scarb_executable Type: |String| Default: `'scarb build'` For Cairo1 projects using Scarb For more information read 'https://docs.swmansion.com/scarb/' =============================================================================== starknet *ale-cairo-starknet* *ale-options.cairo_starknet_executable* *g:ale_cairo_starknet_executable* *b:ale_cairo_starknet_executable* cairo_starknet_executable g:ale_cairo_starknet_executable Type: |String| Default: `'starknet-compile'` Overrides the starknet-compile binary after installing the cairo-language. For more information read 'https://starknet.io/docs/quickstart.html' =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-chef.txt ================================================ =============================================================================== ALE Chef Integration *ale-chef-options* =============================================================================== cookstyle *ale-chef-cookstyle* *ale-options.chef_cookstyle_options* *g:ale_chef_cookstyle_options* *b:ale_chef_cookstyle_options* chef_cookstyle_options g:ale_chef_cookstyle_options Type: |String| Default: `''` This variable can be changed to modify flags given to cookstyle. *ale-options.chef_cookstyle_executable* *g:ale_chef_cookstyle_executable* *b:ale_chef_cookstyle_executable* chef_cookstyle_executable g:ale_chef_cookstyle_executable Type: |String| Default: `'cookstyle'` This variable can be changed to point to the cookstyle binary in case it's not on the $PATH or a specific version/path must be used. =============================================================================== foodcritic *ale-chef-foodcritic* *ale-options.chef_foodcritic_options* *g:ale_chef_foodcritic_options* *b:ale_chef_foodcritic_options* chef_foodcritic_options g:ale_chef_foodcritic_options Type: |String| Default: `''` This variable can be changed to modify flags given to foodcritic. *ale-options.chef_foodcritic_executable* *g:ale_chef_foodcritic_executable* *b:ale_chef_foodcritic_executable* chef_foodcritic_executable g:ale_chef_foodcritic_executable Type: |String| Default: `'foodcritic'` This variable can be changed to point to the foodcritic binary in case it's not on the $PATH or a specific version/path must be used. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-clojure.txt ================================================ =============================================================================== ALE Clojure Integration *ale-clojure-options* =============================================================================== clj-kondo *ale-clojure-clj-kondo* A minimal and opinionated linter for code that sparks joy. https://github.com/borkdude/clj-kondo ------------------------------------------------------------------------------- Options *ale-options.clojure_clj_kondo_options* *g:ale_clojure_clj_kondo_options* *b:ale_clojure_clj_kondo_options* clojure_clj_kondo_options g:ale_clojure_clj_kondo_options Type: |String| Default: `'--cache'` This variable can be changed to modify options passed to clj-kondo. =============================================================================== cljfmt *ale-clojure-cljfmt* cljfmt is a linter and fixer for Clojure code, with defaults adhering to the Clojure Style Guide (see https://guide.clojure.style/ ) https://github.com/weavejester/cljfmt Linting options are not configurable by ale, but instead are controlled by Leiningen, or a cljfmt file in the current or parent directories. see https://github.com/weavejester/cljfmt#Configuration for more information. =============================================================================== joker *ale-clojure-joker* Joker is a small Clojure interpreter and linter written in Go. https://github.com/candid82/joker Linting options are not configurable by ale, but instead are controlled by a `.joker` file in same directory as the file (or current working directory if linting stdin), a parent directory relative to the file, or the users home directory. see https://github.com/candid82/joker#linter-mode for more information. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-cloudformation.txt ================================================ =============================================================================== ALE CloudFormation Integration *ale-cloudformation-options* =============================================================================== cfn-python-lint *ale-cloudformation-cfn-python-lint* cfn-python-lint is a linter for AWS CloudFormation template file. Website: https://github.com/awslabs/cfn-python-lint ------------------------------------------------------------------------------- Installation Install cfn-python-lint using either pip or brew: > pip install cfn-lint < If pip is not available use setuptools. > python setup.py clean --all python setup.py install < You can install the linter via brew on macOS. > brew install cfn-lint < ------------------------------------------------------------------------------- Configuration To get cloudformation linter to work on only CloudFormation files we must set the buffer |filetype| to `yaml.cloudformation`. This causes ALE to lint the file with linters configured for cloudformation and YAML files. Just put the following in `ftdetect/cloudformation.vim`: > au BufRead,BufNewFile *.template.yaml set filetype=yaml.cloudformation This will get both cloudformation and yaml linters to work on any file with `.template.yaml` extension. =============================================================================== checkov *ale-cloudformation-checkov* *ale-options.cloudformation_checkov_executable* *g:ale_cloudformation_checkov_executable* *b:ale_cloudformation_checkov_executable* cloudformation_checkov_executable g:ale_cloudformation_checkov_executable Type: |String| Default: `'checkov'` This variable can be changed to use a different executable for checkov. *ale-options.cloudformation_checkov_options* *g:ale_cloudformation_checkov_options* *b:ale_cloudformation_checkov_options* cloudformation_checkov_options g:ale_cloudformation_checkov_options Type: |String| Default: `''` This variable can be changed to set additional options for checkov. ------------------------------------------------------------------------------- Configuration To get chekov to work with cloudformation files (rather than general yaml files) we must set the buffer |filetype| to `yaml.cloudformation`. This causes ALE to lint the file with linters configured for cloudformation and YAML files. One option is to put the following in `ftdetect/cloudformation.vim`: > au BufRead,BufNewFile *.template.yaml set filetype=yaml.cloudformation This will get both cloudformation and yaml linters to work on any file with `.template.yaml` extension. Another option is to check for the presence of 'AWSTemplateFormatVersion' in the yaml file: > au BufRead,BufNewFile *.yaml,*.yml if search('AWSTemplateFormatVersion', 'nw') | set filetype=yaml.cloudformation | endif < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-cmake.txt ================================================ =============================================================================== ALE CMake Integration *ale-cmake-options* =============================================================================== cmakelint *ale-cmake-cmakelint* *ale-options.cmake_cmakelint_executable* *g:ale_cmake_cmakelint_executable* *b:ale_cmake_cmakelint_executable* cmake_cmakelint_executable g:ale_cmake_cmakelint_executable Type: |String| Default: `'cmakelint'` This variable can be set to change the path the cmakelint. *ale-options.cmake_cmakelint_options* *g:ale_cmake_cmakelint_options* *b:ale_cmake_cmakelint_options* cmake_cmakelint_options g:ale_cmake_cmakelint_options Type: |String| Default: `''` This variable can be set to pass additional options to cmakelint. =============================================================================== cmake-lint *ale-cmake-cmake-lint* *ale-options.cmake_cmake_lint_executable* *g:ale_cmake_cmake_lint_executable* *b:ale_cmake_cmake_lint_executable* cmake_cmake_lint_executable g:ale_cmake_cmake_lint_executable Type: |String| Default: `'cmake-lint'` This variable can be set to change the path the cmake-lint. *ale-options.cmake_cmake_lint_options* *g:ale_cmake_cmake_lint_options* *b:ale_cmake_cmake_lint_options* cmake_cmake_lint_options g:ale_cmake_cmake_lint_options Type: |String| Default: `''` This variable can be set to pass additional options to cmake-lint. =============================================================================== cmake-format *ale-cmake-cmakeformat* *ale-options.cmake_cmakeformat_executable* *g:ale_cmake_cmakeformat_executable* *b:ale_cmake_cmakeformat_executable* cmake_cmakeformat_executable g:ale_cmake_cmakeformat_executable Type: |String| Default: `'cmakeformat'` This variable can be set to change the path the cmake-format. *ale-options.cmake_cmakeformat_options* *g:ale_cmake_cmakeformat_options* *b:ale_cmake_cmakeformat_options* cmake_cmakeformat_options g:ale_cmake_cmakeformat_options Type: |String| Default: `''` This variable can be set to pass additional options to cmake-format. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-cpp.txt ================================================ =============================================================================== ALE C++ Integration *ale-cpp-options* For basic checking of problems with C++ files, ALE offers the `cc` linter, which runs either `clang++`, or `gcc`. See |ale-cpp-cc|. =============================================================================== Global Options The following C options also apply to some C++ linters too. * |g:ale_c_always_make| * |g:ale_c_build_dir_names| * |g:ale_c_build_dir| * |g:ale_c_parse_makefile| * |g:ale_c_parse_compile_commands| =============================================================================== astyle *ale-cpp-astyle* *ale-options.cpp_astyle_executable* *g:ale_cpp_astyle_executable* *b:ale_cpp_astyle_executable* cpp_astyle_executable g:ale_cpp_astyle_executable Type: |String| Default: `'astyle'` This variable can be changed to use a different executable for astyle. *ale-options.cpp_astyle_project_options* *g:ale_cpp_astyle_project_options* *b:ale_cpp_astyle_project_options* cpp_astyle_project_options g:ale_cpp_astyle_project_options Type: |String| Default: `''` This variable can be changed to use an option file for project level configurations. Provide only the filename of the option file that should be present at the project's root directory. For example, if .astylrc is specified, the file is searched in the parent directories of the source file's directory. =============================================================================== cc *ale-cpp-cc* *ale-cpp-gcc* *ale-cpp-clang* *ale-options.cpp_cc_executable* *g:ale_cpp_cc_executable* *b:ale_cpp_cc_executable* cpp_cc_executable g:ale_cpp_cc_executable Type: |String| Default: `''` This variable can be changed to use a different executable for a C++ compiler. ALE will try to use `clang++` if Clang is available, otherwise ALE will default to checking C++ code with `gcc`. *ale-options.cpp_cc_options* *g:ale_cpp_cc_options* *b:ale_cpp_cc_options* cpp_cc_options g:ale_cpp_cc_options Type: |String| Default: `'-std=c++14 -Wall'` This variable can be changed to modify flags given to the C++ compiler. *ale-options.cpp_cc_use_header_lang_flag* *g:ale_cpp_cc_use_header_lang_flag* *b:ale_cpp_cc_use_header_lang_flag* cpp_cc_use_header_lang_flag g:ale_cpp_cc_use_header_lang_flag Type: |Number| Default: `-1` By default, ALE will use `'-x c++-header'` instead of `'-x c++'` for header files when using Clang. This variable can be changed to manually activate or deactivate this flag for header files. - When set to `-1`, the default behavior is used, `'-x c++-header'` is used with Clang and `'-x c++'` is used with other compilers. - When set to `0`, the flag is deactivated, `'-x c++'` is always used independently of the compiler. - When set to `1`, the flag is activated, `'-x c++-header'` is always used independently of the compiler. GCC does not support `'-x c++-header'` when using `'-'` as input filename, which is what ALE does. This why, by default, ALE only uses `'-x c++-header'` with Clang. *ale-options.cpp_cc_header_exts* *g:ale_cpp_cc_header_exts* *b:ale_cpp_cc_header_exts* cpp_cc_header_exts g:ale_cpp_cc_header_exts Type: |List| Default: `['h', 'hpp']` This variable can be changed to modify the list of extensions of the files considered as header files. This variable is only used when `'-x c++-header'` is used instead of `'-x c++'`, see |g:ale_cpp_cc_use_header_lang_flag|. =============================================================================== ccls *ale-cpp-ccls* *ale-options.cpp_ccls_executable* *g:ale_cpp_ccls_executable* *b:ale_cpp_ccls_executable* cpp_ccls_executable g:ale_cpp_ccls_executable Type: |String| Default: `'ccls'` This variable can be changed to use a different executable for ccls. *ale-options.cpp_ccls_init_options* *g:ale_cpp_ccls_init_options* *b:ale_cpp_ccls_init_options* cpp_ccls_init_options g:ale_cpp_ccls_init_options Type: |Dictionary| Default: `{}` This variable can be changed to customize ccls initialization options. Example: > let g:ale_cpp_ccls_init_options = { \ '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. =============================================================================== clangcheck *ale-cpp-clangcheck* `clang-check` will be run only when files are saved to disk, so that `compile_commands.json` files can be used. It is recommended to use this linter in combination with `compile_commands.json` files. Therefore, `clang-check` linter reads the options |g:ale_c_build_dir| and |g:ale_c_build_dir_names|. Also, setting |g:ale_c_build_dir| actually overrides |g:ale_c_build_dir_names|. ------------------------------------------------------------------------------- Options *ale-options.cpp_clangcheck_executable* *g:ale_cpp_clangcheck_executable* *b:ale_cpp_clangcheck_executable* cpp_clangcheck_executable g:ale_cpp_clangcheck_executable Type: |String| Default: `'clang-check'` This variable can be changed to use a different executable for clangcheck. *ale-options.cpp_clangcheck_options* *g:ale_cpp_clangcheck_options* *b:ale_cpp_clangcheck_options* cpp_clangcheck_options g:ale_cpp_clangcheck_options Type: |String| Default: `''` This variable can be changed to modify flags given to clang-check. This variable should not be set to point to build subdirectory with `-p path/to/build` option, as it is handled by the |g:ale_c_build_dir| option. =============================================================================== clangd *ale-cpp-clangd* *ale-options.cpp_clangd_executable* *g:ale_cpp_clangd_executable* *b:ale_cpp_clangd_executable* cpp_clangd_executable g:ale_cpp_clangd_executable Type: |String| Default: `'clangd'` This variable can be changed to use a different executable for clangd. *ale-options.cpp_clangd_options* *g:ale_cpp_clangd_options* *b:ale_cpp_clangd_options* cpp_clangd_options g:ale_cpp_clangd_options Type: |String| Default: `''` This variable can be changed to modify flags given to clangd. =============================================================================== clang-format *ale-cpp-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for C++. =============================================================================== clangtidy *ale-cpp-clangtidy* `clang-tidy` will be run only when files are saved to disk, so that `compile_commands.json` files can be used. It is recommended to use this linter in combination with `compile_commands.json` files. Therefore, `clang-tidy` linter reads the options |g:ale_c_build_dir| and |g:ale_c_build_dir_names|. Also, setting |g:ale_c_build_dir| actually overrides |g:ale_c_build_dir_names|. ------------------------------------------------------------------------------- Options *ale-options.cpp_clangtidy_checks* *g:ale_cpp_clangtidy_checks* *b:ale_cpp_clangtidy_checks* cpp_clangtidy_checks g:ale_cpp_clangtidy_checks Type: |List| Default: `[]` The checks to enable for clang-tidy 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. *ale-options.cpp_clangtidy_executable* *g:ale_cpp_clangtidy_executable* *b:ale_cpp_clangtidy_executable* cpp_clangtidy_executable g:ale_cpp_clangtidy_executable Type: |String| Default: `'clang-tidy'` This variable can be changed to use a different executable for clangtidy. *ale-options.cpp_clangtidy_options* *g:ale_cpp_clangtidy_options* *b:ale_cpp_clangtidy_options* cpp_clangtidy_options g:ale_cpp_clangtidy_options Type: |String| Default: `''` This variable can be changed to modify compiler flags given to clang-tidy. - Setting this variable to a non-empty string, - and working in a buffer where no compilation database is found using |g:ale_c_build_dir_names| or |g:ale_c_build_dir|, will cause the `--` argument to be passed to `clang-tidy`, which will mean that detection of `compile_commands.json` files for compile command databases will be disabled. Only set this option if you want to control compiler flags entirely manually, and no `compile_commands.json` file is in one of the |g:ale_c_build_dir_names| directories of the project tree. *ale-options.cpp_clangtidy_extra_options* *g:ale_cpp_clangtidy_extra_options* *b:ale_cpp_clangtidy_extra_options* cpp_clangtidy_extra_options g:ale_cpp_clangtidy_extra_options Type: |String| Default: `''` This variable can be changed to modify flags given to clang-tidy. *ale-options.cpp_clangtidy_fix_errors* *g:ale_cpp_clangtidy_fix_errors* *b:ale_cpp_clangtidy_fix_errors* cpp_clangtidy_fix_errors g:ale_cpp_clangtidy_fix_errors Type: |Number| Default: `1` This variable can be changed to disable the `-fix-errors` option for the |clangtidy| fixer. =============================================================================== clazy *ale-cpp-clazy* *ale-options.cpp_clazy_executable* *g:ale_cpp_clazy_executable* *b:ale_cpp_clazy_executable* cpp_clazy_executable g:ale_cpp_clazy_executable Type: |String| Default: `'clazy-standalone'` This variable can be changed to use a different executable for clazy. *ale-options.cpp_clazy_checks* *g:ale_cpp_clazy_checks* *b:ale_cpp_clazy_checks* cpp_clazy_checks g: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. *ale-options.cpp_clazy_options* *g:ale_cpp_clazy_options* *b:ale_cpp_clazy_options* cpp_clazy_options g:ale_cpp_clazy_options Type: |String| Default: `''` This variable can be changed to modify flags given to clazy. =============================================================================== cppcheck *ale-cpp-cppcheck* *ale-options.cpp_cppcheck_executable* *g:ale_cpp_cppcheck_executable* *b:ale_cpp_cppcheck_executable* cpp_cppcheck_executable g:ale_cpp_cppcheck_executable Type: |String| Default: `'cppcheck'` This variable can be changed to use a different executable for cppcheck. *ale-options.cpp_cppcheck_options* *g:ale_cpp_cppcheck_options* *b:ale_cpp_cppcheck_options* cpp_cppcheck_options g:ale_cpp_cppcheck_options Type: |String| Default: `'--enable=style'` This variable can be changed to modify flags given to cppcheck. =============================================================================== cpplint *ale-cpp-cpplint* *ale-options.cpp_cpplint_executable* *g:ale_cpp_cpplint_executable* *b:ale_cpp_cpplint_executable* cpp_cpplint_executable g:ale_cpp_cpplint_executable Type: |String| Default: `'cpplint'` This variable can be changed to use a different executable for cpplint. *ale-options.cpp_cpplint_options* *g:ale_cpp_cpplint_options* *b:ale_cpp_cpplint_options* cpp_cpplint_options g:ale_cpp_cpplint_options Type: |String| Default: `''` This variable can be changed to modify flags given to cpplint. *ale-options.c_cpplint_executable* *g:ale_c_cpplint_executable* *b:ale_c_cpplint_executable* c_cpplint_executable g:ale_c_cpplint_executable Type: |String| Default: `'cpplint'` This variable can be changed to use a different executable for cpplint. *ale-options.c_cpplint_options* *g:ale_c_cpplint_options* *b:ale_c_cpplint_options* c_cpplint_options g:ale_c_cpplint_options Type: |String| Default: `''` This variable can be changed to modify flags given to cpplint. =============================================================================== cquery *ale-cpp-cquery* *ale-options.cpp_cquery_executable* *g:ale_cpp_cquery_executable* *b:ale_cpp_cquery_executable* cpp_cquery_executable g:ale_cpp_cquery_executable Type: |String| Default: `'cquery'` This variable can be changed to use a different executable for cquery. *ale-options.cpp_cquery_cache_directory* *g:ale_cpp_cquery_cache_directory* *b:ale_cpp_cquery_cache_directory* cpp_cquery_cache_directory g:ale_cpp_cquery_cache_directory Type: |String| Default: `'~/.cache/cquery'` This variable can be changed to decide which directory cquery uses for its cache. =============================================================================== cspell *ale-cpp-cspell* See |ale-cspell-options| =============================================================================== flawfinder *ale-cpp-flawfinder* *ale-options.cpp_flawfinder_executable* *g:ale_cpp_flawfinder_executable* *b:ale_cpp_flawfinder_executable* cpp_flawfinder_executable g:ale_cpp_flawfinder_executable Type: |String| Default: `'flawfinder'` This variable can be changed to use a different executable for flawfinder. *ale-options.cpp_flawfinder_minlevel* *g:ale_cpp_flawfinder_minlevel* *b:ale_cpp_flawfinder_minlevel* cpp_flawfinder_minlevel g:ale_cpp_flawfinder_minlevel Type: |Number| Default: `1` This variable can be changed to ignore risks under the given risk threshold. *ale-options.cpp_flawfinder_options* *g:ale_cpp_flawfinder_options* *b:ale-cpp-flawfinder* cpp_flawfinder_options g:ale_cpp_flawfinder_options Type: |String| Default: `''` This variable can be used to pass extra options into the flawfinder command. =============================================================================== uncrustify *ale-cpp-uncrustify* See |ale-c-uncrustify| for information about the available options. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-cs.txt ================================================ =============================================================================== 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 =============================================================================== clang-format *ale-cs-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for C#. =============================================================================== csc *ale-cs-csc* The |ale-cs-csc| linter checks for semantic errors when files are opened or saved. See |ale-lint-file-linters| for more information on linters which do not check for problems while you type. The csc linter uses the mono csc compiler, providing full C# 7 and newer support, to generate a temporary module target file (/t:module). The module includes all '*.cs' files contained in the directory tree rooted at the path defined by the |g:ale_cs_csc_source| or |b:ale_cs_csc_source| variable and all sub directories. It will in future replace the |ale-cs-mcs| and |ale-cs-mcsc| linters as both utilize the mcsc compiler which, according to the mono project, is no longer actively developed, and only receives maintenance updates. However, because the csc compiler does not support the -syntax option, this linter does not offer any as-you-type syntax checking, similar to the |ale-cs-mcsc| linter. The paths to search for additional assembly files can be specified using the |g:ale_cs_csc_assembly_path| or |b:ale_cs_csc_assembly_path| variables. NOTE: ALE will not find any errors in files apart from syntax errors if any one of the source files contains a syntax error. Syntax errors must be fixed first before other errors will be shown. ------------------------------------------------------------------------------- Options *ale-options.cs_csc_options* *g:ale_cs_csc_options* *b:ale_cs_csc_options* cs_csc_options g:ale_cs_csc_options Type: |String| Default: `''` This option can be set to pass additional arguments to the `csc` compiler. For example, to add the dotnet package which is not added per default: > let g:ale_cs_mcs_options = ' /warn:4 /langversion:7.2' < NOTE: the `/unsafe` option is always passed to `csc`. *ale-options.cs_csc_source* *g:ale_cs_csc_source* *b:ale_cs_csc_source* cs_csc_source g:ale_cs_csc_source Type: |String| Default: `''` This variable defines the root path of the directory tree searched for the '*.cs' files to be linted. If this option is empty, the source file's directory will be used. NOTE: Currently it is not possible to specify sub directories and directory sub trees which shall not be searched for *.cs files. *ale-options.cs_csc_assembly_path* *g:ale_cs_csc_assembly_path* *b:ale_cs_csc_assembly_path* cs_csc_assembly_path g:ale_cs_csc_assembly_path Type: |List| Default: `[]` This variable defines a list of path strings to be searched for external assembly files. The list is passed to the csc compiler using the `/lib:` flag. *ale-options.cs_csc_assemblies* *g:ale_cs_csc_assemblies* *b:ale_cs_csc_assemblies* cs_csc_assemblies g:ale_cs_csc_assemblies Type: |List| Default: `[]` This variable defines a list of external assembly (*.dll) files required by the mono mcs compiler to generate a valid module target. The list is passed the csc compiler using the `/r:` flag. For example: > " Compile C# programs with the Unity engine DLL file on Mac. let g:ale_cs_mcsc_assemblies = [ \ '/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll', \ 'path-to-unityproject/obj/Debug', \] < =============================================================================== cspell *ale-cs-cspell* See |ale-cspell-options| =============================================================================== dotnet-format *ale-cs-dotnet-format* ------------------------------------------------------------------------------- Installation Installing .NET SDK should probably ensure that `dotnet` is in your `$PATH`. For .NET 6 the `dotnet format` tool is already included in the .NET SDK. For .NET 5 or below you will have to manually install it using the instructions from listed in this repository: https://github.com/dotnet/format ------------------------------------------------------------------------------- Options *ale-options.cs_dotnet_format_executable* *g:ale_cs_dotnet_format_executable* *b:ale_cs_dotnet_format_executable* cs_dotnet_format_executable g:ale_cs_dotnet_format_executable Type: |String| Default: `'dotnet'` This variable can be set to specify an absolute path to the `dotnet` executable (or to specify an alternate executable). *ale-options.cs_dotnet_format_options* *g:ale_cs_dotnet_format_options* *b:ale_cs_dotnet_format_options* cs_dotnet_format_options g:ale_cs_dotnet_format_options Type: |String| Default: `''` This variable can be set to pass additional options to the `dotnet format` fixer. =============================================================================== mcs *ale-cs-mcs* The `mcs` linter looks only for syntax errors while you type. See |ale-cs-mcsc| for the separately configured linter for checking for semantic errors. ------------------------------------------------------------------------------- Options *ale-options.cs_mcs_options* *g:ale_cs_mcs_options* *b:ale_cs_mcs_options* cs_mcs_options g:ale_cs_mcs_options Type: |String| Default: `''` This variable can be changed to pass additional flags given to mcs. NOTE: The -unsafe flag is selected implicitly and thus does not need to be explicitly included in the |g:ale_cs_mcs_options| or |b:ale_cs_mcs_options| parameter. =============================================================================== mcsc *ale-cs-mcsc* The mcsc linter checks for semantic errors when files are opened or saved See |ale-lint-file-linters| for more information on linters which do not check for problems while you type. The mcsc linter uses the mono mcs compiler to generate a temporary module target file (-t:module). The module includes including all '*.cs' files contained in the directory tree rooted at the path defined by the |g:ale_cs_mcsc_source| or |b:ale_cs_mcsc_source| variable. variable and all sub directories. The paths to search for additional assembly files can be specified using the |g:ale_cs_mcsc_assembly_path| or |b:ale_cs_mcsc_assembly_path| variables. NOTE: ALE will not find any errors in files apart from syntax errors if any one of the source files contains a syntax error. Syntax errors must be fixed first before other errors will be shown. ------------------------------------------------------------------------------- Options *ale-options.cs_mcsc_options* *g:ale_cs_mcsc_options* *b:ale_cs_mcsc_options* cs_mcsc_options g:ale_cs_mcsc_options Type: |String| Default: `''` This option can be set to pass additional arguments to the `mcs` compiler. For example, to add the dotnet package which is not added per default: > let g:ale_cs_mcs_options = '-pkg:dotnet' < NOTE: the `-unsafe` option is always passed to `mcs`. *ale-options.cs_mcsc_source* *g:ale_cs_mcsc_source* *b:ale_cs_mcsc_source* cs_mcsc_source g:ale_cs_mcsc_source Type: |String| Default: `''` This variable defines the root path of the directory tree searched for the '*.cs' files to be linted. If this option is empty, the source file's directory will be used. NOTE: Currently it is not possible to specify sub directories and directory sub trees which shall not be searched for *.cs files. *ale-options.cs_mcsc_assembly_path* *g:ale_cs_mcsc_assembly_path* *b:ale_cs_mcsc_assembly_path* cs_mcsc_assembly_path g:ale_cs_mcsc_assembly_path Type: |List| Default: `[]` This variable defines a list of path strings to be searched for external assembly files. The list is passed to the mcs compiler using the `-lib:` flag. *ale-options.cs_mcsc_assemblies* *g:ale_cs_mcsc_assemblies* *b:ale_cs_mcsc_assemblies* cs_mcsc_assemblies g:ale_cs_mcsc_assemblies Type: |List| Default: `[]` This variable defines a list of external assembly (*.dll) files required by the mono mcs compiler to generate a valid module target. The list is passed the mcs compiler using the `-r:` flag. For example: > " Compile C# programs with the Unity engine DLL file on Mac. let g:ale_cs_mcsc_assemblies = [ \ '/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll', \ 'path-to-unityproject/obj/Debug', \] < =============================================================================== 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: ================================================ FILE: doc/ale-css.txt ================================================ =============================================================================== ALE CSS Integration *ale-css-options* =============================================================================== cspell *ale-css-cspell* See |ale-cspell-options| =============================================================================== css-beautify *ale-css-css-beautify* *ale-options.css_css_beautify_executable* *g:ale_css_css_beautify_executable* *b:ale_css_css_beautify_executable* css_css_beautify_executable g:ale_css_css_beautify_executable Type: |String| Default: `'css-beautify'` See |ale-integrations-local-executables| *ale-options.css_css_beautify_options* *g:ale_css_css_beautify_options* *b:ale_css_css_beautify_options* css_css_beautify_options g:ale_css_css_beautify_options Type: |String| Default: `''` This variable can be set to pass additional options to css-beautify. *ale-options.css_css_beautify_use_global* *g:ale_css_css_beautify_use_global* *b:ale_css_css_beautify_use_global* css_css_beautify_use_global g:ale_css_css_beautify_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== fecs *ale-css-fecs* `fecs` options for CSS is the same as the options for JavaScript, and both of them reads `./.fecsrc` as the default configuration file. See: |ale-javascript-fecs|. =============================================================================== prettier *ale-css-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== stylelint *ale-css-stylelint* *ale-options.css_stylelint_executable* *g:ale_css_stylelint_executable* *b:ale_css_stylelint_executable* css_stylelint_executable g:ale_css_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.css_stylelint_options* *g:ale_css_stylelint_options* *b:ale_css_stylelint_options* css_stylelint_options g:ale_css_stylelint_options Type: |String| Default: `''` This variable can be set to pass additional options to stylelint. *ale-options.css_stylelint_use_global* *g:ale_css_stylelint_use_global* *b:ale_css_stylelint_use_global* css_stylelint_use_global g:ale_css_stylelint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vscodecss *ale-css-vscode* Website: https://github.com/hrsh7th/vscode-langservers-extracted ------------------------------------------------------------------------------- Installation Install VSCode css language server either globally or locally: > npm install -g vscode-langservers-extracted < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-cuda.txt ================================================ =============================================================================== ALE CUDA Integration *ale-cuda-options* =============================================================================== clang-format *ale-cuda-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for CUDA. =============================================================================== clangd *ale-cuda-clangd* *ale-options.cuda_clangd_executable* *g:ale_cuda_clangd_executable* *b:ale_cuda_clangd_executable* cuda_clangd_executable g:ale_cuda_clangd_executable Type: |String| Default: `'clangd'` This variable can be changed to use a different executable for clangd. *ale-options.cuda_clangd_options* *g:ale_cuda_clangd_options* *b:ale_cuda_clangd_options* cuda_clangd_options g:ale_cuda_clangd_options Type: |String| Default: `''` This variable can be changed to modify flags given to clangd. =============================================================================== nvcc *ale-cuda-nvcc* *ale-options.cuda_nvcc_executable* *g:ale_cuda_nvcc_executable* *b:ale_cuda_nvcc_executable* cuda_nvcc_executable g:ale_cuda_nvcc_executable Type: |String| Default: `'nvcc'` This variable can be changed to use a different executable for nvcc. Currently only nvcc 8.0 is supported. *ale-options.cuda_nvcc_options* *g:ale_cuda_nvcc_options* *b:ale_cuda_nvcc_options* cuda_nvcc_options g:ale_cuda_nvcc_options Type: |String| Default: `'-std=c++11'` This variable can be changed to modify flags given to nvcc. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-d.txt ================================================ =============================================================================== ALE D Integration *ale-d-options* =============================================================================== dfmt *ale-d-dfmt* *ale-options.d_dfmt_options* *g:ale_d_dfmt_options* *b:ale_d_dfmt_options* d_dfmt_options g:ale_d_dfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the dfmt fixer. =============================================================================== dls *ale-d-dls* *ale-options.d_dls_executable* *g:ale_d_dls_executable* *b:ale_d_dls_executable* d_dls_executable g: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: ================================================ FILE: doc/ale-dafny.txt ================================================ =============================================================================== ALE Dafny Integration *ale-dafny-options* =============================================================================== dafny *ale-dafny-dafny* *ale-options.dafny_dafny_timelimit* *g:ale_dafny_dafny_timelimit* *b:ale_dafny_dafny_timelimit* dafny_dafny_timelimit g:ale_dafny_dafny_timelimit Type: |Number| Default: `10` This variable sets the `/timeLimit` used for dafny. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-dart.txt ================================================ =============================================================================== ALE Dart Integration *ale-dart-options* =============================================================================== analysis_server *ale-dart-analysis_server* ------------------------------------------------------------------------------- Installation Install Dart via whatever means. `analysis_server` will be included in the SDK. In case that `dart` is not in your path, try to set the executable option to its absolute path. : > " Set the executable path for dart to the absolute path to it. let g:ale_dart_analysis_server_executable = '/usr/local/bin/dart' < ------------------------------------------------------------------------------- Options *ale-options.dart_analysis_server_executable* *g:ale_dart_analysis_server_executable* *b:ale_dart_analysis_server_executable* dart_analysis_server_executable g:ale_dart_analysis_server_executable Type: |String| Default: `'dart'` This variable can be set to change the path of dart. *ale-options.dart_analysis_server_enable_language_server* *g:ale_dart_analysis_server_enable_language_server* *b:ale_dart_analysis_server_enable_language_server* dart_analysis_server_enable_language_server g:ale_dart_analysis_server_enable_language_server Type: |Number| Default: `1` When set to `1`, ALE will use the new `dart language-server` command, available from Dart version 2.16.0, to launch the language server. When set to `0`, ALE will instead use the deprecated `./snapshots/analysis_server.dart.snapshot --lsp` command used by older versions of Dart. =============================================================================== dart-analyze *ale-dart-analyze* ------------------------------------------------------------------------------- Installation Installing Dart should probably ensure that `dart` is in your `$PATH`. In case it is not, try to set the executable option to its absolute path. : > " Set the executable path for dart to the absolute path to it. let g:ale_dart_format_executable = '/usr/lib/dart/bin/dart' > Install Dart via whatever means. `dart analyze` will be included in the SDK. ------------------------------------------------------------------------------- Options *ale-options.dart_analyze_executable* *g:ale_dart_analyze_executable* *b:ale_dart_analyze_executable* dart_analyze_executable g:ale_dart_analyze_executable Type: |String| Default: `'dart'` This variable can be set to specify an absolute path to the format executable (or to specify an alternate executable). =============================================================================== dart-format *ale-dart-format* ------------------------------------------------------------------------------- Installation Installing Dart should probably ensure that `dart` is in your `$PATH`. In case it is not, try to set the executable option to its absolute path: > " Set the executable path for dart to the absolute path to it. let g:ale_dart_format_executable = '/usr/lib/dart/bin/dart' < ------------------------------------------------------------------------------- Options *ale-options.dart_format_executable* *g:ale_dart_format_executable* *b:ale_dart_format_executable* dart_format_executable g:ale_dart_format_executable Type: |String| Default: `'dart'` This variable can be set to specify an absolute path to the format executable (or to specify an alternate executable). *ale-options.dart_format_options* *g:ale_dart_format_options* *b:ale_dart_format_options* dart_format_options g:ale_dart_format_options Type: |String| Default: `''` This variable can be set to pass additional options to the dart format fixer. =============================================================================== dartfmt *ale-dart-dartfmt* ------------------------------------------------------------------------------- Installation Installing Dart should probably ensure that `dartfmt` is in your `$PATH`. In case it is not, try to set the executable option to its absolute path: > " Set the executable path for dartfmt to the absolute path to it. let g:ale_dart_dartfmt_executable = '/usr/lib/dart/bin/dartfmt' < ------------------------------------------------------------------------------- Options *ale-options.dart_dartfmt_executable* *g:ale_dart_dartfmt_executable* *b:ale_dart_dartfmt_executable* dart_dartfmt_executable g:ale_dart_dartfmt_executable Type: |String| Default: `''` This variable can be set to specify an absolute path to the dartfmt executable (or to specify an alternate executable). *ale-options.dart_dartfmt_options* *g:ale_dart_dartfmt_options* *b:ale_dart_dartfmt_options* dart_dartfmt_options g:ale_dart_dartfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the dartfmt fixer. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-desktop.txt ================================================ =============================================================================== ALE desktop Integration *ale-desktop-options* =============================================================================== desktop-file-validate *ale-desktop-desktop-file-validate* ALE supports checking .desktop files with `desktop-file-validate.` ------------------------------------------------------------------------------- Options *ale-options.desktop_desktop_file_validate_options* *g:ale_desktop_desktop_file_validate_options* *b:ale_desktop_desktop_file_validate_options* desktop_desktop_file_validate_options g:ale_desktop_desktop_file_validate_options Type: |String| Default: `''` This variable can be changed to set options for `desktop-file-validate`, such as `'--warn-kde'`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-development.txt ================================================ *ale-development.txt* For Vim version 8.0. *ale-dev* *ale-development* ALE Development Documentation =============================================================================== CONTENTS *ale-development-contents* 1. Introduction.........................|ale-development-introduction| 2. Design Goals.........................|ale-design-goals| 3. Coding Standards.....................|ale-coding-standards| 4. Testing ALE..........................|ale-development-tests| 4.1. Writing Linter Tests.............|ale-development-linter-tests| 4.2. Writing Fixer Tests..............|ale-development-fixer-tests| 4.3. Running Tests in a Windows VM....|ale-development-windows-tests| 5. Contributing.........................|ale-development-contributing| 5.1. Preparing a Release..............|ale-development-release| =============================================================================== 1. Introduction *ale-development-introduction* This document contains helpful information for ALE developers, including design goals, information on how to run the tests, coding standards, and so on. You should read this document if you want to get involved with ALE development. =============================================================================== 2. Design Goals *ale-design-goals* This section lists design goals for ALE, in no particular order. They are as follows. ALE code should be almost 100% VimL. This makes the plugin as portable as possible. ALE should run without needing any other plugins to be installed, to make installation simple. ALE can integrate with other plugins for more advanced functionality, non-essential functionality, or improving on basic first party functionality. ALE should check files with as many tools as possible by default, except where they cause security issues or make excessive use of resources on modern machines. ALE should be free of breaking changes to the public API, which is comprised of documented functions and options, until a major version is planned. Breaking changes should be preceded by a deprecation phase complete with warnings. Changes required for security may be an exception. ALE supports Vim 8 and above, and Neovim 0.7.0 or newer. These are the earliest versions of Vim and Neovim which support |+job|, |+timer|, |+closure|, and |+lambda| features. All ALE code should be written so it is compatible with these versions of Vim, or with version checks so particular features can degrade or fail gracefully. Just about everything should be documented and covered with tests. By and large, people shouldn't pay for the functionality they don't use. Care should be taken when adding new features, so supporting new features doesn't degrade the general performance of anything ALE does. LSP support will become more important as time goes on. ALE should provide better support for LSP features as time goes on. When merging pull requests, you should respond with `Cheers! :beers:`, purely for comedy value. =============================================================================== 3. Coding Standards *ale-coding-standards* The following general coding standards should be adhered to for Vim code. * Check your Vim code with `Vint` and do everything it says. ALE will check your Vim code with Vint automatically. See: https://github.com/Kuniwak/vint Read ALE's `Dockerfile` to see which version of `Vint` it uses. * Try to write descriptive and concise names for variables and functions. Names shouldn't be too short or too long. Think about others reading your code later on. * Use `snake_case` names for variables and arguments, and `PascalCase` names for functions. Prefix every variable name with its scope. (`l:`, `g:`, etc.) * Try to keep lines no longer than 80 characters, but this isn't an absolute requirement. * Use 4 spaces for every level of indentation in Vim code. * Add a blank line before every `function`, `if`, `for`, `while`, `try`, or `return`, which doesn't start a new level of indentation. When adding more code on the same indentation level, also add blank lines after every corresponding end for those mentioned keywords. This makes the logic in your code easier to follow. * End every file with a trailing newline character, but not with extra blank lines. Remove trailing whitespace from the ends of lines. * Write the full names of commands instead of abbreviations. For example, write `function` instead of `func`, and `endif` instead of `end`. * Write functions with `!`, so files can be reloaded. Use the |abort| keyword for all functions, so functions exit on the first error. * Make sure to credit yourself in files you have authored with `Author:` and `Description:` comments. In addition to the above general guidelines for the style of your code, you should also follow some additional rules designed to prevent mistakes. Some of these are reported with ALE's `custom-linting-rules` script. See |ale-development-tests|. * Don't leave stray `:echo` lines in code. Write `" no-custom-checks` above the line if you must echo something. * For strings use |is#| instead of |==#|, `is?` instead of `==?`, `isnot#` instead of `!=#`, and `isnot?` instead of `!=?`. This is because `'x' ==# 0` returns 1, while `'x' is# 0` returns 0, so you will experience fewer issues when numbers are compared with strings. `is` and `isnot` also do not throw errors when other objects like List or Dictionaries are compared with strings. * Don't use the `getcwd()` function in the ALE codebase. Most of ALE's code runs from asynchronous callback functions, and these functions can execute from essentially random buffers. Therefore, the `getcwd()` output is useless. Use `expand('#' . a:buffer . ':p:h')` instead. Don't use `expand('%...')` for the same reason. * Don't use the `simplify()` function. It doesn't simplify paths enough. Use `ale#path#Simplify()` instead. * Don't use the `shellescape()` function. It doesn't escape arguments properly on Windows. Use `ale#Escape()` instead, which will avoid escaping where it isn't needed, and generally escape arguments better on Windows. * Don't use the `tempname()` function. It doesn't work when `$TMPDIR` isn't set. Use `ale#util#Tempname()` instead, which temporarily sets `$TMPDIR` appropriately where needed. * 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. * Use 2 spaces for Vader test files, instead of the 4 spaces for Vim files. * If you write `Before` and `After` blocks, you should typically write them at the top of the file, so they run for all tests. There may be some tests where it make sense to modify the `Before` and `After` code part of the way through the file. * If you modify any settings or global variables, reset them in `After` blocks. The Vader `Save` and `Restore` commands can be useful for this purpose. * If you load or define linters in tests, write `call ale#linter#Reset()` in an `After` block. * Just write `Execute` blocks for Vader tests, and don't bother writing `Then` blocks. `Then` blocks execute after `After` blocks in older versions, and that can be confusing. Apply the following rules when writing Bash scripts. * Run `shellcheck`, and do everything it says. See: https://github.com/koalaman/shellcheck * Try to write scripts so they will run on Linux, BSD, or Mac OSX. =============================================================================== 4. Testing ALE *ale-development-tests* *ale-dev-tests* *ale-tests* ALE is tested with a suite of tests executed via GitHub Actions and AppVeyor. ALE runs tests with the following versions of Vim in the following environments. 1. Vim 8.0.0027 on Linux via GitHub Actions. 2. Vim 9.0.0297 on Linux via GitHub Actions. 3. Neovim 0.7.0 on Linux via GitHub Actions. 4. Neovim 0.8.0 on Linux via GitHub Actions. 6. Vim 8 (stable builds) on Windows via AppVeyor. If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs tests by installing Docker and running the `run-tests` script. Follow the instructions on the Docker site for installing Docker. See: https://docs.docker.com/install/ NOTE: Don't forget to add your user to the `docker` group on Linux, or Docker just won't work. See: https://docs.docker.com/install/linux/linux-postinstall/ If you run simply `./run-tests` from the ALE repository root directory, the latest Docker image for tests will be downloaded if needed, and the script will run all of the tests in Vader, Vint checks, and several Bash scripts for finding extra issues. Run `./run-tests --help` to see all of the options the script supports. Note that the script supports selecting particular test files. Once you get used to dealing with Vim and NeoVim compatibility issues, you probably want to use `./run-tests --fast -q` for running tests with only the fastest available Vim version, and with success messages from tests suppressed. Generally write tests for any changes you make. The following types of tests are recommended for the following types of code. * New/edited error handler callbacks -> Write tests in `test/handler` * New/edited linter definition -> Write tests in `test/linter` * New/edited fixer functions -> Write tests in `test/fixers` Look at existing tests in the codebase for examples of how to write tests. Refer to the Vader documentation for general information on how to write Vader tests: https://github.com/junegunn/vader.vim If you need to add any supporting files for tests, such as empty files present to test searching upwards through paths for configuration files, they can be added to the `test/test-files` directory. See |ale-development-linter-tests| for more information on how to write linter tests. When you add new linters or fixers, make sure to add them into the tables in supported-tools.md and |ale-supported-languages-and-tools.txt|. If you forget to keep them both in sync, you should see an error like the following in the builds run for GitHub Actions. > ======================================== diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables ======================================== Differences follow: --- /tmp/readme.qLjNhJdB 2018-07-01 16:29:55.590331972 +0100 +++ /tmp/doc.dAi8zfVE 2018-07-01 16:29:55.582331877 +0100 @@ -1 +1 @@ - ASM: gcc, foobar + ASM: gcc < Make sure to list documentation entries for linters and fixers in individual help files in the table of contents, and to align help tags to the right margin. For example, if you add a heading for an `aardvark` tool to `ale-python.txt` with a badly aligned doc tag, you will see errors like so. > ======================================== Look for badly aligned doc tags ======================================== Badly aligned tags follow: doc/ale-python.txt:aardvark ... ======================================== Look for table of contents issues ======================================== Check for bad ToC sorting: Check for mismatched ToC and headings: --- /tmp/table-of-contents.mwCFOgSI 2018-07-01 16:33:25.068811878 +0100 +++ /tmp/headings.L4WU0hsO 2018-07-01 16:33:25.076811973 +0100 @@ -168,6 +168,7 @@ pyrex (cython), ale-pyrex-options cython, ale-pyrex-cython python, ale-python-options + aardvark, ale-python-aardvark autopep8, ale-python-autopep8 black, ale-python-black flake8, ale-python-flake8 < Make sure to make the table of contents match the headings, and to keep the doc tags on the right margin. =============================================================================== 4.1 Writing Linter Tests *ale-development-linter-tests* Tests for ALE linters take two forms. 1. Tests for handling the output of commands. 2. Tests for checking which commands are run, or connections are made. Tests of the first form should go in the `test/handler` directory, and should be written like so. > Before: " Load the file which defines the linter. runtime ale_linters/filetype/linter_name_here.vim After: " Unload all linters again. call ale#linter#Reset() Execute(The output should be correct): " Test that the right loclist items are parsed from the handler. AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': 'Something went wrong', \ }, \ ], \ ale_linters#filetype#linter_name#Handle(bufnr(''), [ \ '1:Something went wrong', \ ] < Tests for what ALE runs should go in the `test/linter` directory, and should be written like so. > Before: " Load the linter and set up a series of commands, reset linter variables, " clear caches, etc. " " Vader's 'Save' command will be called here for linter variables. call ale#assert#SetUpLinterTest('filetype', 'linter_name') After: " Reset linters, variables, etc. " " Vader's 'Restore' command will be called here. call ale#assert#TearDownLinterTest() Execute(The default command should be correct): " AssertLinter checks the executable and command. " Pass expected_executable, expected_command AssertLinter 'some-command', ale#Escape('some-command') . ' --foo' Execute(Check chained commands): " GivenCommandOutput can be called with 1 or more list for passing output " to chained commands. The output for each callback defaults to an empty " list. GivenCommandOutput ['v2.1.2'] " Given a List of commands, check all of them. " Given a String, only the last command in the chain will be checked. AssertLinter 'some-command', [ \ ale#Escape('some-command') . ' --version', \ ale#Escape('some-command') . ' --foo', \] < The full list of commands that will be temporarily defined for linter tests given the above setup are as follows. `GivenCommandOutput [...]` - Define output for ale#command#Run. `AssertLinterCwd cwd` - Check the `cwd` for the linter. `AssertLinter executable, command` - Check the executable and command. `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. =============================================================================== 4.2 Writing Fixer Tests *ale-development-fixer-tests* Tests for ALE fixers should go in the `test/fixers` directory, and should be written like so. > Before: " Load the fixer and set up a series of commands, reset fixer variables, " clear caches, etc. " " Vader's 'Save' command will be called here for fixer variables. call ale#assert#SetUpFixerTest('filetype', 'fixer_name') After: " Reset fixers, variables, etc. " " Vader's 'Restore' command will be called here. call ale#assert#TearDownFixerTest() Execute(The default command should be correct): " AssertFixer checks the result of the loaded fixer function. AssertFixer {'command': ale#Escape('some-command') . ' --foo'} Execute(Check chained commands): " Same as above for linter tests. GivenCommandOutput ['v2.1.2'] " Given a List of commands, check all of them. " Given anything else, only the last result will be checked. AssertFixer [ \ ale#Escape('some-command') . ' --version', \ {'command': ale#Escape('some-command') . ' --foo'} \] < The full list of commands that will be temporarily defined for fixer tests given the above setup are as follows. `GivenCommandOutput [...]` - Define output for ale#command#Run. `AssertFixerCwd cwd` - Check the `cwd` for the fixer. `AssertFixer results` - Check the fixer results `AssertFixerNotExecuted` - Check that fixers will not be executed. =============================================================================== 4.3 Running Tests in a Windows VM *ale-development-windows-tests* Tests are run for ALE in a build of Vim 8 for Windows via AppVeyor. These tests can frequently break due to minor differences in paths and how escaping is done for commands on Windows. If you are a Linux or Mac user, running these tests locally can be difficult. Here is a process that will make that easier. First, you want to install a Windows image with VirtualBox. Install VirtualBox and grab a VirtualBox image for Windows such as from here: https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/ NOTE: If you need to enter a password for the virtual machine at any point, the password is "Passw0rd!" without the double quotes. NOTE: If your trial period for Windows runs out, run the commands like the wallpaper tells you to. Your virtual machine will need to have PowerShell installed. Before you go any further, confirm that PowerShell is installed in your Windows virtual machine. Consult the VirtualBox documentation on how to install "Guest Additions." You probably want to install "Guest Additions" for most things to work properly. After you've loaded your virtual machine image, go into "Settings" for your virtual machine, and "Shared Folders." Add a shared folder with the name "ale", and set the "Folder Path" to the path to your ALE repository, for example: "/home/w0rp/ale" Find out which drive letter "ale" has been mounted as in Windows. We'll use "E:" as the drive letter, for example. Open the command prompt as an administrator by typing in `cmd` in the start menu, right clicking on the command prompt application, and clicking "Run as administrator." Click "Yes" when prompted to ask if you're sure you want to run the command prompt. You should type in the following command to mount the "ale" directory for testing, where "E:" is replaced with your drive letter. > mklink /D C:\testplugin E: < Close the administrator Command Prompt, and try running the command `type C:\testplugin\LICENSE` in a new Command Prompt which you are NOT running as administrator. You should see the license for ALE in your terminal. After you have confirmed that you have mounted ALE on your machine, search in the Start Menu for "power shell," run PowerShell as an administrator, and issue the following commands to install the correct Vim and Vader versions for running tests. > Add-Type -A System.IO.Compression.FileSystem Invoke-WebRequest https://github.com/dense-analysis/ale/releases/download/v4.0.0/vim80-586w32.zip -OutFile C:\vim.zip [IO.Compression.ZipFile]::ExtractToDirectory('C:\vim.zip', 'C:\vim') rm C:\vim.zip Invoke-WebRequest https://github.com/dense-analysis/ale/releases/download/v4.0.0/vim80-586rt.zip -OutFile C:\rt.zip [IO.Compression.ZipFile]::ExtractToDirectory('C:\rt.zip', 'C:\vim') rm C:\rt.zip Invoke-WebRequest https://github.com/junegunn/vader.vim/archive/c6243dd81c98350df4dec608fa972df98fa2a3af.zip -OutFile C:\vader.zip [IO.Compression.ZipFile]::ExtractToDirectory('C:\vader.zip', 'C:\') mv C:\vader.vim-c6243dd81c98350df4dec608fa972df98fa2a3af C:\vader rm C:\vader.zip < After you have finished installing everything, you can run all of the tests in Windows by opening a Command Prompt NOT as an administrator by navigating to the directory where you've mounted the ALE code, which must be named `C:\testplugin`, and by running the `run-tests.bat` batch file. > cd C:\testplugin run-tests < It will probably take several minutes for all of the tests to run. Be patient. You can run a specific test by passing the filename as an argument to the batch file, for example: `run-tests test/test_c_flag_parsing.vader` . This will give you results much more quickly. =============================================================================== 5. Contributing *ale-development-contributing* All integration of new code into ALE is done through GitHub pull requests. Using that tool streamlines the process and minimizes the time and effort required to e.g. ensure test suites are run for every change. As for any project hosted by GitHub, the choice of platform demands every contributor to take care to setup an account and configure it accordingly. Due to details of our process, a difference to many other GitHub hosted projects is that contributors who wish to keep the author fields for their commits unaltered need to configure a public email address in their account and profile settings. See: https://docs.github.com/en/account-and-profile/ Unless configuring GitHub to expose contact details, commits will be rewritten to appear by `USERNAME ` . =============================================================================== 5.1 Preparing a Release *ale-development-release* ALE offers release packages through GitHub, for two reasons: 1. Some users like to target specific release versions rather than simply installing the plugin from `master`. This includes users who create Linux distribution specific packages from GitHub releases. 2. The releases provide a nice way to get an overview of what has changed in ALE over time. ALE has no fixed release schedule. Release versions are created whenever the ALE developers feel the need to create one. ALE release versions follow the typical Semantic Versioning scheme. See: https://semver.org/ Minor version releases for ALE should be the most common, followed by patch releases. Every minor version release should be followed by a `vA.B.x` branch such as `v2.0.x` for version `2.0.0` and every following patch version before `2.1.0`. The `git` branch strategy for patches is to first merge a bug fix to `master`, and then `git cherry-pick` a patch to a branch for a specific version. ALE developers do not generally support anything but `master` or the last minor version. Generally ALE releases hit a major version only when there are breaking changes to a public ALE setting or function. A "public" setting or function is defined as any setting or function documented in the `:help` |ale.txt| file. Major ALE versions ought to be so rare that they only come once a year at most. ALE should not typically introduce any breaking changes. If there are ever to be any breaking changes made for ALE, there should first come a minor version release for ALE documenting all of the coming breaking changes to ALE. It should be described how users can prepare for a breaking change that is coming before it is done. To create a release for ALE, you will need sufficient permissions in GitHub. Once you do, follow these steps. 1. Create a new release draft, or edit an existing one. It helps to craft drafts ahead of time and write the last commit ID checked for release notes on the last update to a draft. See the releases page: https://github.com/dense-analysis/ale/releases 2. Examine `git log` and read changes made between the last ID checked, or the git tag of the previous release, and the current commit in `master`. 3. Write updates in separate sections (except where empty) for: 3.a. Breaking Changes 3.b. Deprecated Features 3.c. New Features 3.d. New Linters 3.e. New Fixers 3.f. Linter Enhancements 3.g. Fixer Enhancements 3.h. Bugs Fixed 4. Once you've finished writing the draft for the release, bump `s:current_ale_version` in `autoload/ale.vim` to the current version, and add a line to `test/test_ale_has.vader` to test for the version. See |ale#Has()| documentation for more information. 5. Commit the changes after `./run-tests --fast -q` passes. 6. Tag the release with `git tag vA.B.C`, replacing `A`, `B`, and `C` with the version numbers. See `git tag --list` for examples. 7. Run `git push` and `git push --tags` to push the commit and the tag. 8. Edit the release draft in GitHub, select the tag you just pushed, and publish the draft. 9. If you're creating a new major or minor version: `git checkout -b vA.B.x`, replacing `A` and `B` with the major and minor versions. `git push` the new branch, and the GitHub branch protection settings should automatically apply to the new release branch. 10. You have already completed the last step. Have fun creating ALE releases. Drink responsibly, or not at all, which is the preference of w0rp. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-dhall.txt ================================================ =============================================================================== ALE Dhall Integration *ale-dhall-options* Dhall - https://dhall-lang.org/ *ale-options.dhall_executable* *g:ale_dhall_executable* *b:ale_dhall_executable* dhall_executable g:ale_dhall_executable Type: |String| Default: `'dhall'` *ale-options.dhall_options* *g:ale_dhall_options* *b:ale_dhall_options* dhall_options g:ale_dhall_options Type: |String| Default: `''` This variable can be set to pass additional options to the 'dhall` executable. This is shared with `dhall-freeze` and `dhall-lint`. > let g:ale_dhall_options = '--ascii' < =============================================================================== dhall-format *ale-dhall-format* =============================================================================== dhall-freeze *ale-dhall-freeze* ------------------------------------------------------------------------------- Options *ale-options.dhall_freeze_options* *g:ale_dhall_freeze_options* *b:ale_dhall_freeze_options* dhall_freeze_options g:ale_dhall_freeze_options Type: |String| Default: `''` This variable can be set to pass additional options to the 'dhall freeze` executable. > let g:ale_dhall_freeze_options = '--all' < =============================================================================== dhall-lint *ale-dhall-lint* =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-dockerfile.txt ================================================ =============================================================================== ALE Dockerfile Integration *ale-dockerfile-options* =============================================================================== dockerfile_lint *ale-dockerfile-dockerfile_lint* *ale-options.dockerfile_dockerfile_lint_executable* *g:ale_dockerfile_dockerfile_lint_executable* *b:ale_dockerfile_dockerfile_lint_executable* dockerfile_dockerfile_lint_executable g:ale_dockerfile_dockerfile_lint_executable Type: |String| Default: `'dockerfile_lint'` This variable can be changed to specify the executable used to run dockerfile_lint. *ale-options.dockerfile_dockerfile_lint_options* *g:ale_dockerfile_dockerfile_lint_options* *b:ale_dockerfile_dockerfile_lint_options* dockerfile_dockerfile_lint_options g: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. =============================================================================== dockerlinter *ale-dockerfile-dockerlinter* *ale-options.dockerfile_dockerlinter_executable* *g:ale_dockerfile_dockerlinter_executable* *b:ale_dockerfile_dockerlinter_executable* dockerfile_dockerlinter_executable g:ale_dockerfile_dockerlinter_executable Type: |String| Default: `'dockerlinter'` This variable can be changed to specify the executable used to run dockerlinter. *ale-options.dockerfile_dockerlinter_options* *g:ale_dockerfile_dockerlinter_options* *b:ale_dockerfile_dockerlinter_options* dockerfile_dockerlinter_options g:ale_dockerfile_dockerlinter_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. =============================================================================== dprint *ale-dockerfile-dprint* See |ale-dprint-options| and https://dprint.dev/plugins/dockerfile =============================================================================== hadolint *ale-dockerfile-hadolint* hadolint can be found at: https://github.com/hadolint/hadolint ------------------------------------------------------------------------------- Options *ale-options.dockerfile_hadolint_options* *g:ale_dockerfile_hadolint_options* *b:ale_dockerfile_hadolint_options* dockerfile_hadolint_options g:ale_dockerfile_hadolint_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the hadolint invocation. These arguments will be used whether docker is being used or not (see below). *ale-options.dockerfile_hadolint_use_docker* *g:ale_dockerfile_hadolint_use_docker* *b:ale_dockerfile_hadolint_use_docker* dockerfile_hadolint_use_docker g:ale_dockerfile_hadolint_use_docker Type: |String| Default: `'never'` This variable controls if docker and the hadolint image are used to run this linter: if 'never', docker will never be used; 'always' means docker will always be used; 'yes' and docker will be used if the hadolint executable cannot be found. For now, the default is 'never'. This may change as ale's support for using docker to lint evolves. *ale-options.dockerfile_hadolint_image* *g:ale_dockerfile_hadolint_image* *b:ale_dockerfile_hadolint_image* dockerfile_hadolint_image g:ale_dockerfile_hadolint_image Type: |String| Default: `'hadolint/hadolint'` This variable controls the docker image used to run hadolint. The default is hadolint's author's build, and can be found at: https://hub.docker.com/r/hadolint/hadolint/ =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-elixir.txt ================================================ =============================================================================== ALE Elixir Integration *ale-elixir-options* =============================================================================== mix *ale-elixir-mix* The `mix` linter is disabled by default, as it can be too expensive to run. See `:help g:ale_linters` *ale-options.elixir_mix_options* *g:ale_elixir_mix_options* *b:ale_elixir_mix_options* elixir_mix_options g:ale_elixir_mix_options Type: |String| Default: `'mix'` This variable can be changed to specify the mix executable. =============================================================================== mix_format *ale-elixir-mix-format* *ale-options.elixir_mix_format_options* *g:ale_elixir_mix_format_options* *b:ale_elixir_mix_format_options* elixir_mix_format_options g:ale_elixir_mix_format_options Type: |String| Default: `''` This variable can be changed to specify the mix options passed to the mix_format fixer =============================================================================== dialyxir *ale-elixir-dialyxir* Dialyzer, a DIscrepancy AnaLYZer for ERlang programs. http://erlang.org/doc/man/dialyzer.html It can be used with elixir through dialyxir https://github.com/jeremyjh/dialyxir Options for dialyzer are not configurable by ale, but they are instead configured on your project's `mix.exs`. 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) *ale-options.elixir_elixir_ls_release* *g:ale_elixir_elixir_ls_release* *b:ale_elixir_elixir_ls_release* elixir_elixir_ls_release g: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). *ale-options.elixir_elixir_ls_config* *g:ale_elixir_elixir_ls_config* *b:ale_elixir_elixir_ls_config* elixir_elixir_ls_config g: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: > let g:ale_elixir_elixir_ls_config = { \ 'elixirLS': { \ 'dialyzerEnabled': v:false, \ }, \} < Consult the ElixirLS documentation for more information about settings. =============================================================================== credo *ale-elixir-credo* Credo (https://github.com/rrrene/credo) *ale-options.elixir_credo_strict* *g:ale_elixir_credo_strict* *b:ale_elixir_credo_strict* elixir_credo_strict g:ale_elixir_credo_strict Type: |Integer| Default: `0` Tells credo to run in strict mode or suggest mode. Set variable to 1 to enable --strict mode. *ale-options.elixir_credo_config_file* *g:ale_elixir_credo_config_file* *b:ale_elixir_credo_config_file* elixir_credo_config_file g:ale_elixir_credo_config_file Type: |String| Default: `''` Tells credo to use a custom configuration file. =============================================================================== cspell *ale-elixir-cspell* See |ale-cspell-options| =============================================================================== lexical *ale-elixir-lexical* Lexical (https://github.com/lexical-lsp/lexical) *ale-options.elixir_lexical_release* *g:ale_elixir_lexical_release* *b:ale_elixir_lexical_release* elixir_lexical_release g:ale_elixir_lexical_release Type: |String| Default: `'lexical'` Location of the lexical release directory. This directory must contain the language server scripts (start_lexical.sh and start_lexical.bat). For example, set release to: `/home/projects/lexical/_build/dev/rel/lexical` There are currently no configuration options for lexical. =============================================================================== expert *ale-elixir-expert* Expert (https://github.com/elixir-lang/expert) *ale-options.elixir_expert_executable* *g:ale_elixir_expert_executable* *b:ale_elixir_expert_executable* elixir_expert_executable g:ale_elixir_expert_executable Type: |String| Default: `/usr/bin/elixir-expert` Location of the expert executable. For example, set release to: `/home/projects/expert/apps/expert/burrito_out/expert_linux_amd64` There are currently no configuration options for expert. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-elm.txt ================================================ =============================================================================== ALE Elm Integration *ale-elm-options* =============================================================================== elm-format *ale-elm-elm-format* *ale-options.elm_format_executable* *g:ale_elm_format_executable* *b:ale_elm_format_executable* elm_format_executable g:ale_elm_format_executable Type: |String| Default: `'elm-format'` See |ale-integrations-local-executables| *ale-options.elm_format_use_global* *g:ale_elm_format_use_global* *b:ale_elm_format_use_global* elm_format_use_global g:ale_elm_format_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.elm_format_options* *g:ale_elm_format_options* *b:ale_elm_format_options* elm_format_options g:ale_elm_format_options Type: |String| Default: `'--yes'` This variable can be set to pass additional options to elm-format. =============================================================================== elm-ls *ale-elm-elm-ls* *ale-options.elm_ls_executable* *g:ale_elm_ls_executable* *b:ale_elm_ls_executable* elm_ls_executable g:ale_elm_ls_executable Type: |String| Default: `'elm-language-server'` See |ale-integrations-local-executables| *ale-options.elm_ls_use_global* *g:ale_elm_ls_use_global* *b:ale_elm_ls_use_global* elm_ls_use_global g:ale_elm_ls_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 1)` See |ale-integrations-local-executables| *ale-options.elm_ls_elm_path* *g:ale_elm_ls_elm_path* *b:ale_elm_ls_elm_path* elm_ls_elm_path g:ale_elm_ls_elm_path Type: |String| Default: `''` See |ale-integrations-local-executables| *ale-options.elm_ls_elm_format_path* *g:ale_elm_ls_elm_format_path* *b:ale_elm_ls_elm_format_path* elm_ls_elm_format_path g:ale_elm_ls_elm_format_path Type: |String| Default: `''` See |ale-integrations-local-executables| *ale-options.elm_ls_elm_test_path* *g:ale_elm_ls_elm_test_path* *b:ale_elm_ls_elm_test_path* elm_ls_elm_test_path g:ale_elm_ls_elm_test_path Type: |String| Default: `''` See |ale-integrations-local-executables| *ale-options.elm_ls_elm_analyse_trigger* *g:ale_elm_ls_elm_analyse_trigger* *b:ale_elm_ls_elm_analyse_trigger* elm_ls_elm_analyse_trigger g:ale_elm_ls_elm_analyse_trigger Type: |String| Default: `'change'` One of 'change', 'save' or 'never' =============================================================================== elm-make *ale-elm-elm-make* *ale-options.elm_make_executable* *g:ale_elm_make_executable* *b:ale_elm_make_executable* elm_make_executable g:ale_elm_make_executable Type: |String| Default: `'elm'` See |ale-integrations-local-executables| *ale-options.elm_make_use_global* *g:ale_elm_make_use_global* *b:ale_elm_make_use_global* elm_make_use_global g:ale_elm_make_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-erlang.txt ================================================ =============================================================================== ALE Erlang Integration *ale-erlang-options* =============================================================================== dialyzer *ale-erlang-dialyzer* *ale-options.erlang_dialyzer_executable* *g:ale_erlang_dialyzer_executable* *b:ale_erlang_dialyzer_executable* erlang_dialyzer_executable g:ale_erlang_dialyzer_executable Type: |String| Default: `'dialyzer'` This variable can be changed to specify the dialyzer executable. *ale-options.erlang_dialyzer_options* *g:ale_erlang_dialyzer_options* *b:ale_erlang_dialyzer_options* erlang_dialyzer_options g:ale_erlang_dialyzer_options Type: |String| Default: `'-Wunmatched_returns -Werror_handling -Wrace_conditions -Wunderspec'` This variable can be changed to specify the options to pass to the dialyzer executable. *ale-options.erlang_dialyzer_plt_file* *g:ale_erlang_dialyzer_plt_file* *b:ale_erlang_dialyzer_plt_file* erlang_dialyzer_plt_file g:ale_erlang_dialyzer_plt_file Type: |String| Default: `''` This variable can be changed to specify the path to the PLT file. By default, it will search for the PLT file inside the `_build` directory. If there isn't one, it will fallback to the path `$REBAR_PLT_DIR/dialyzer/plt`. Otherwise, it will default to `$HOME/.dialyzer_plt`. *ale-options.erlang_dialyzer_rebar3_profile* *g:ale_erlang_dialyzer_rebar3_profile* *b:ale_erlang_dialyzer_rebar3_profile* erlang_dialyzer_rebar3_profile g:ale_erlang_dialyzer_rebar3_profile Type: |String| Default: `'default'` This variable can be changed to specify the profile that is used to run dialyzer with rebar3. =============================================================================== elvis *ale-erlang-elvis* *ale-options.erlang_elvis_executable* *g:ale_erlang_elvis_executable* *b:ale_erlang_elvis_executable* erlang_elvis_executable g:ale_erlang_elvis_executable Type: |String| Default: `'elvis'` This variable can be changed to specify the elvis executable. =============================================================================== erlang-mode *ale-erlang-erlang-mode* *ale-options.erlang_erlang_mode_emacs_executable* *g:ale_erlang_erlang_mode_emacs_executable* *b:ale_erlang_erlang_mode_emacs_executable* erlang_erlang_mode_emacs_executable g:ale_erlang_erlang_mode_emacs_executable Type: |String| Default: `'emacs'` This variable can be changed to specify the Emacs executable. *ale-options.erlang_erlang_mode_indent_level* *g:ale_erlang_erlang_mode_indent_level* *b:ale_erlang_erlang_mode_indent_level* erlang_erlang_mode_indent_level g:ale_erlang_erlang_mode_indent_level Type: |Number| Default: `4` Indentation of Erlang calls/clauses within blocks. *ale-options.erlang_erlang_mode_icr_indent* *g:ale_erlang_erlang_mode_icr_indent* *b:ale_erlang_erlang_mode_icr_indent* erlang_erlang_mode_icr_indent g:ale_erlang_erlang_mode_icr_indent Type: `'nil'` or |Number| Default: `'nil'` Indentation of Erlang if/case/receive patterns. `'nil'` means keeping default behavior. When non-`'nil'`, indent to the column of if/case/receive. *ale-options.erlang_erlang_mode_indent_guard* *g:ale_erlang_erlang_mode_indent_guard* *b:ale_erlang_erlang_mode_indent_guard* erlang_erlang_mode_indent_guard g:ale_erlang_erlang_mode_indent_guard Type: |Number| Default: `2` Indentation of Erlang guards. *ale-options.erlang_erlang_mode_argument_indent* *g:ale_erlang_erlang_mode_argument_indent* *b:ale_erlang_erlang_mode_argument_indent* erlang_erlang_mode_argument_indent g:ale_erlang_erlang_mode_argument_indent Type: `'nil'` or |Number| Default: `2` Indentation of the first argument in a function call. When `'nil'`, indent to the column after the `'('` of the function. *ale-options.erlang_erlang_mode_indent_tabs_mode* *g:ale_erlang_erlang_mode_indent_tabs_mode* *b:ale_erlang_erlang_mode_indent_tabs_mode* erlang_erlang_mode_indent_tabs_mode g:ale_erlang_erlang_mode_indent_tabs_mode Type: `'nil'` or `'t'` Default: `'nil'` Indentation can insert tabs if this is non-`'nil'`. =============================================================================== erlang_ls *ale-erlang-erlang_ls* *ale-options.erlang_erlang_ls_executable* *g:ale_erlang_erlang_ls_executable* *b:ale_erlang_erlang_ls_executable* erlang_erlang_ls_executable g:ale_erlang_erlang_ls_executable Type: |String| Default: `'erlang_ls'` This variable can be changed to specify the erlang_ls executable. *ale-options.erlang_erlang_ls_log_dir* *g:ale_erlang_erlang_ls_log_dir* *b:ale_erlang_erlang_ls_log_dir* erlang_erlang_ls_log_dir g:ale_erlang_erlang_ls_log_dir Type: |String| Default: `''` If set this variable overrides default directory where logs will be written. *ale-options.erlang_erlang_ls_log_level* *g:ale_erlang_erlang_ls_log_level* *b:ale_erlang_erlang_ls_log_level* erlang_erlang_ls_log_level g:ale_erlang_erlang_ls_log_level Type: |String| Default: `'info'` This variable can be changed to specify log level. =============================================================================== erlc *ale-erlang-erlc* *ale-options.erlang_erlc_executable* *g:ale_erlang_erlc_executable* *b:ale_erlang_erlc_executable* erlang_erlc_executable g:ale_erlang_erlc_executable Type: |String| Default: `'erlc'` This variable can be changed to specify the erlc executable. *ale-options.erlang_erlc_options* *g:ale_erlang_erlc_options* *b:ale_erlang_erlc_options* erlang_erlc_options g:ale_erlang_erlc_options Type: |String| Default: `''` This variable controls additional parameters passed to `erlc`, such as `-I` or `-pa`. =============================================================================== erlfmt *ale-erlang-erlfmt* *ale-options.erlang_erlfmt_executable* *g:ale_erlang_erlfmt_executable* *b:ale_erlang_erlfmt_executable* erlang_erlfmt_executable g:ale_erlang_erlfmt_executable Type: |String| Default: `'erlfmt'` This variable can be changed to specify the erlfmt executable. *ale-options.erlang_erlfmt_options* *g:ale_erlang_erlfmt_options* *b:ale_erlang_erlfmt_options* erlang_erlfmt_options g:ale_erlang_erlfmt_options Type: |String| Default: `''` This variable controls additional parameters passed to `erlfmt`, such as `--insert-pragma` or `--print-width`. =============================================================================== syntaxerl *ale-erlang-syntaxerl* *ale-options.erlang_syntaxerl_executable* *g:ale_erlang_syntaxerl_executable* *b:ale_erlang_syntaxerl_executable* erlang_syntaxerl_executable g:ale_erlang_syntaxerl_executable Type: |String| Default: `'syntaxerl'` This variable can be changed to specify the syntaxerl executable. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-eruby.txt ================================================ =============================================================================== ALE Eruby Integration *ale-eruby-options* There are four linters for `eruby` files: - `erb` - `erblint` - `erubis` - `erubi` - `htmlbeautifier` - `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. `ruumba` can extract Ruby from eruby files and run rubocop on the result. To selectively enable a subset, see |g:ale_linters|. =============================================================================== erb-formatter *ale-eruby-erbformatter* *ale-options.eruby_erbformatter_executable* *g:ale_eruby_erbformatter_executable* *b:ale_eruby_erbformatter_executable* eruby_erbformatter_executable g:ale_eruby_erbformatter_executable Type: |String| Default: `'erb-formatter'` Override the invoked erb-formatter binary. This is useful for running erb-formatter from binstubs or a bundle. =============================================================================== erblint *ale-eruby-erblint* *ale-options.eruby_erblint_executable* *g:ale_eruby_erblint_executable* *b:ale_eruby_erblint_executable* eruby_erblint_executable g:ale_eruby_erblint_executable Type: |String| Default: `'erblint'` Override the invoked erblint binary. This is useful for running erblint from binstubs or a bundle. *ale-options.eruby_erblint_options* *g:ale_eruby_erblint_options* *b:ale_ruby_erblint_options* eruby_erblint_options g:ale_eruby_erblint_options Type: |String| Default: `''` This variable can be change to modify flags given to erblint. =============================================================================== htmlbeautifier *ale-eruby-htmlbeautifier* *ale-options.eruby_htmlbeautifier_executable* *g:ale_eruby_htmlbeautifier_executable* *b:ale_eruby_htmlbeautifier_executable* eruby_htmlbeautifier_executable g:ale_eruby_htmlbeautifier_executable Type: |String| Default: `'htmlbeautifier'` Override the invoked htmlbeautifier binary. This is useful for running htmlbeautifier from binstubs or a bundle. =============================================================================== ruumba *ale-eruby-ruumba* *ale-options.eruby_ruumba_executable* *g:ale_eruby_ruumba_executable* *b:ale_eruby_ruumba_executable* eruby_ruumba_executable g:ale_eruby_ruumba_executable Type: |String| Default: `'ruumba'` Override the invoked ruumba binary. This is useful for running ruumba from binstubs or a bundle. *ale-options.eruby_ruumba_options* *g:ale_eruby_ruumba_options* *b:ale_ruby_ruumba_options* eruby_ruumba_options g:ale_eruby_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: ================================================ FILE: doc/ale-fish.txt ================================================ =============================================================================== ALE Fish Integration *ale-fish-options* Lints fish files using `fish -n`. Note that `fish -n` is not foolproof: it sometimes gives false positives or errors that are difficult to parse without more context. This integration skips displaying errors if an error message is not found. If ALE is not showing any errors but your file does not run as expected, run `fish -n ` from the command line. =============================================================================== fish_indent *ale-fish-fish_indent* *ale-options.fish_fish_indent_executable* *g:ale_fish_fish_indent_executable* *b:ale_fish_fish_indent_executable* fish_fish_indent_executable g:ale_fish_fish_indent_executable Type: |String| Default: `'fish_indent'` This variable can be changed to use a different executable for fish_indent. *ale-options.fish_fish_indent_options* *g:ale_fish_fish_indent_options* *b:ale_fish_fish_indent_options* fish_fish_indent_options g:ale_fish_fish_indent_options Type: |String| Default: `''` This variable can be set to pass additional options to fish_indent. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-fortran.txt ================================================ =============================================================================== ALE Fortran Integration *ale-fortran-options* =============================================================================== fortitude *ale-fortran-fortitude* *ale-options.fortran_fortitude_executable* *g:fortran_fortitude_executable* *b:fortran_fortitude_executable* fortran_fortitude_executable g:fortran_fortitude_executable Type: |String| Default: 'fortitude' This variable can be changed to modify the executable used for fortitude. *ale-options.fortran_fortitude_options* *g:fortran_fortitude_options* *b:fortran_fortitude_options* fortran_fortitude_options g:fortran_fortitude_options Type: |String| Default: '' This variable can be changed to modify options given to fortitude check. =============================================================================== gcc *ale-fortran-gcc* *ale-options.fortran_gcc_executable* *g:ale_fortran_gcc_executable* *b:ale_fortran_gcc_executable* fortran_gcc_executable g:ale_fortran_gcc_executable Type: |String| Default: `'gcc'` This variable can be changed to modify the executable used for checking Fortran code with GCC. *ale-options.fortran_gcc_options* *g:ale_fortran_gcc_options* *b:ale_fortran_gcc_options* fortran_gcc_options g:ale_fortran_gcc_options Type: |String| Default: `'-Wall'` This variable can be changed to modify flags given to gcc. *ale-options.fortran_gcc_use_free_form* *g:ale_fortran_gcc_use_free_form* *b:ale_fortran_gcc_use_free_form* fortran_gcc_use_free_form g:ale_fortran_gcc_use_free_form Type: |Number| Default: `1` When set to `1`, the `-ffree-form` flag will be used for GCC, to check files with the free form layout. When set to `0`, `-ffixed-form` will be used instead, for checking files with fixed form layouts. =============================================================================== language_server *ale-fortran-language-server* *ale-options.fortran_language_server_executable* *g:ale_fortran_language_server_executable* *b:ale_fortran_language_server_executable* fortran_language_server_executable g:ale_fortran_language_server_executable Type: |String| Default: `'fortls'` This variable can be changed to modify the executable used for the Fortran Language Server. *ale-options.fortran_language_server_use_global* *g:ale_fortran_language_server_use_global* *b:ale_fortran_language_server_use_global* fortran_language_server_use_global g:ale_fortran_language_server_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-fountain.txt ================================================ =============================================================================== ALE Fountain Integration *ale-fountain-options* =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-fuse.txt ================================================ =============================================================================== ALE FusionScript Integration *ale-fuse-options* =============================================================================== fusion-lint *ale-fuse-fusionlint* *ale-options.fusion_fusionlint_executable* *g:ale_fusion_fusionlint_executable* *b:ale_fuse_fusionlint_executable* fusion_fusionlint_executable g:ale_fusion_fusionlint_executable Type: |String| Default: `'fusion-lint'` This variable can be changed to change the path to fusion-lint. *ale-options.fuse_fusionlint_options* *g:ale_fuse_fusionlint_options* *b:ale_fuse_fusionlint_options* fuse_fusionlint_options g:ale_fuse_fusionlint_options Type: |String| Default: `''` This variable can be set to pass additional options to fusion-lint. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-gitcommit.txt ================================================ =============================================================================== ALE Git Commit Integration *ale-gitcommit-options* =============================================================================== gitlint *ale-gitcommit-gitlint* *ale-options.gitcommit_gitlint_executable* *g:ale_gitcommit_gitlint_executable* *b:ale_gitcommit_gitlint_executable* gitcommit_gitlint_executable g:ale_gitcommit_gitlint_executable Type: |String| Default: `'gitlint'` This variable can be changed to modify the executable used for gitlint. *ale-options.gitcommit_gitlint_options* *g:ale_gitcommit_gitlint_options* *b:ale_gitcommit_gitlint_options* gitcommit_gitlint_options g:ale_gitcommit_gitlint_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the gitlint invocation. For example, you can specify the path to a configuration file. > let g:ale_gitcommit_gitlint_options = '-C /home/user/.config/gitlint.ini' < You can also disable particular error codes using this option. For example, you can ignore errors for git commits with a missing body. > let g:ale_gitcommit_gitlint_options = '--ignore B6' < *ale-options.gitcommit_gitlint_use_global* *g:ale_gitcommit_gitlint_use_global* *b:ale_gitcommit_gitlint_use_global* gitcommit_gitlint_use_global g:ale_gitcommit_gitlint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable controls whether or not ALE will search for gitlint in a virtualenv directory first. If this variable is set to `1`, then ALE will always use |g:ale_gitcommit_gitlint_executable| for the executable path. Both variables can be set with `b:` buffer variables instead. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-gleam.txt ================================================ =============================================================================== ALE Gleam Integration *ale-gleam-options* *ale-integration-gleam* =============================================================================== gleam_format *ale-gleam-gleam_format* *ale-options.gleam_gleam_format_executable* *g:ale_gleam_gleam_format_executable* *b:ale_gleam_gleam_format_executable* gleam_gleam_format_executable g:ale_gleam_gleam_format_executable Type: |String| Default: `'gleam'` This variable can be modified to change the executable path for `gleam format`. =============================================================================== gleamlsp *ale-gleam-gleamlsp* *ale-options.gleam_gleamlsp_executable* *g:ale_gleam_gleamlsp_executable* *b:ale_gleam_gleamlsp_executable* gleam_gleamlsp_executable g:ale_gleam_gleamlsp_executable Type: |String| Default: `'gleam'` This variable can be modified to change the executable path for `gleamlsp`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-glsl.txt ================================================ =============================================================================== ALE GLSL Integration *ale-glsl-options* *ale-integration-glsl* =============================================================================== Integration Information Since Vim does not detect the glsl file types out-of-the-box, you need the runtime files for glsl from here: https://github.com/tikhomirov/vim-glsl Note that the current glslang-based linter expects glslangValidator in standard paths. If it's not installed system-wide you can set |g:ale_glsl_glslang_executable| to a specific path. =============================================================================== glslang *ale-glsl-glslang* *ale-options.glsl_glslang_executable* *g:ale_glsl_glslang_executable* *b:ale_glsl_glslang_executable* glsl_glslang_executable g:ale_glsl_glslang_executable Type: |String| Default: `'glslangValidator'` This variable can be changed to change the path to glslangValidator. *ale-options.glsl_glslang_options* *g:ale_glsl_glslang_options* *b:ale_glsl_glslang_options* glsl_glslang_options g:ale_glsl_glslang_options Type: |String| Default: `''` This variable can be set to pass additional options to glslangValidator. =============================================================================== glslls *ale-glsl-glslls* *ale-options.glsl_glslls_executable* *g:ale_glsl_glslls_executable* *b:ale_glsl_glslls_executable* glsl_glslls_executable g:ale_glsl_glslls_executable Type: |String| Default: `'glslls'` This variable can be changed to change the path to glslls. See |ale-integrations-local-executables| *ale-options.glsl_glslls_logfile* *g:ale_glsl_glslls_logfile* *b:ale_glsl_glslls_logfile* glsl_glslls_logfile g:ale_glsl_glslls_logfile Type: |String| Default: `''` Setting this variable to a writeable file path will enable logging to that file. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-go.txt ================================================ =============================================================================== ALE Go Integration *ale-go-options* =============================================================================== Integration Information ALE enables `gofmt`, `gopls` and `go vet` by default. It also supports `staticcheck`, `go build, ``gosimple`, `golangserver`, `golangci-lint`, and `goimports`. To enable `golangci-lint`, update |g:ale_linters| as appropriate. A possible configuration is to enable golangci-lint and `gofmt: > " Enable all of the linters you want for Go. let g:ale_linters = {'go': ['golangci-lint', 'gofmt']} < *ale-options.go_go_executable* *g:ale_go_go_executable* *b:ale_go_go_executable* go_go_executable g:ale_go_go_executable Type: |String| Default: `'go'` The executable that will be run for the `gobuild` and `govet` linters, and the `gomod` fixer. *ale-options.go_go111module* *g:ale_go_go111module* *b:ale_go_go111module* go_go111module g:ale_go_go111module Type: |String| Default: `''` Override the value of the `$GO111MODULE` environment variable for golang tools. =============================================================================== bingo *ale-go-bingo* *ale-options.go_bingo_executable* *g:ale_go_bingo_executable* *b:ale_go_bingo_executable* go_bingo_executable g:ale_go_bingo_executable Type: |String| Default: `'bingo'` Location of the bingo binary file. *ale-options.go_bingo_options* *g:ale_go_bingo_options* *b:ale_go_bingo_options* go_bingo_options g:ale_go_bingo_options Type: |String| Default: `''` =============================================================================== cspell *ale-go-cspell* See |ale-cspell-options| =============================================================================== gobuild *ale-go-gobuild* *ale-options.go_gobuild_options* *g:ale_go_gobuild_options* *b:ale_go_gobuild_options* go_gobuild_options g:ale_go_gobuild_options Type: |String| Default: `''` This variable can be set to pass additional options to the gobuild linter. They are injected directly after "go test". =============================================================================== gofmt *ale-go-gofmt* *ale-options.go_gofmt_options* *g:ale_go_gofmt_options* *b:ale_go_gofmt_options* go_gofmt_options g:ale_go_gofmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the gofmt fixer. =============================================================================== gofumpt *ale-go-gofumpt* *ale-options.go_gofumpt_executable* *g:ale_go_gofumpt_executable* *b:ale_go_gofumpt_executable* go_gofumpt_executable g:ale_go_gofumpt_executable Type: |String| Default: `'gofumpt'` Executable to run to use as the gofumpt fixer. *ale-options.go_gofumpt_options* *g:ale_go_gofumpt_options* *b:ale_go_gofumpt_options* go_gofumpt_options g:ale_go_gofumpt_options Type: |String| Default: `''` Options to pass to the gofumpt fixer. =============================================================================== goimports *ale-go-goimports* *ale-options.go_goimports_executable* *g:ale_go_goimports_executable* *b:ale_go_goimports_executable* go_goimports_executable g:ale_go_goimports_executable Type: |String| Default: `'goimports'` This variable can be set to change the executable path for goimports. *ale-options.go_goimports_options* *g:ale_go_goimports_options* *b:ale_go_goimports_options* go_goimports_options g:ale_go_goimports_options Type: |String| Default: `''` This variable can be set to pass additional options to the goimports fixer. =============================================================================== 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| *ale-options.go_golangci_lint_executable* *g:ale_go_golangci_lint_executable* *b:ale_go_golangci_lint_executable* go_golangci_lint_executable g:ale_go_golangci_lint_executable Type: |String| Default: `'golangci-lint'` The executable that will be run for golangci-lint. *ale-options.go_golangci_lint_options* *g:ale_go_golangci_lint_options* *b:ale_go_golangci_lint_options* go_golangci_lint_options g:ale_go_golangci_lint_options Type: |String| Default: `''` This variable can be changed to alter the command-line arguments to the golangci-lint run invocation. *ale-options.go_golangci_lint_package* *g:ale_go_golangci_lint_package* *b:ale_go_golangci_lint_package* go_golangci_lint_package g: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. golangci_lint can also be user as a fixer to format go source files. In this case the following configuration variables can be used to configure the formatters: *ale-options.go_golangci_formatter_executable* *g:ale_go_golangci_formatter_executable* *b:ale_go_golangci_formatter_executable* go_golangci_formatter_executable g:ale_go_golangci_formatter_executable Type: |String| Default: `'golangci-lint'` The executable that will be run for golangci-lint. *ale-options.go_golangci_formatter_options* *g:ale_go_golangci_formatter_options* *b:ale_go_golangci_formatter_options* go_golangci_formatter_options g:ale_go_golangci_formatter_options Type: |String| Default: `''` This variable can be changed to alter the command-line arguments to the golangci-lint fmt invocation. =============================================================================== golangserver *ale-go-golangserver* *ale-options.go_langserver_executable* *g:ale_go_langserver_executable* *b:ale_go_langserver_executable* go_langserver_executable g:ale_go_langserver_executable Type: |String| Default: `'go-langserver'` Location of the go-langserver binary file. *ale-options.go_langserver_options* *g:ale_go_langserver_options* *b:ale_go_langserver_options* go_langserver_options g: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. =============================================================================== golines *ale-go-golines* *ale-options.go_golines_executable* *g:ale_go_golines_executable* *b:ale_go_lines_executable* go_golines_executable g:ale_go_golines_executable Type: |String| Default: `'golines'` Location of the golines binary file *ale-options.go_golines_options* *g:ale_go_golines_options* *b:ale_go_golines_options* go_golines_options g:ale_go_golines_options Type: |String| Default: `''` Additional options passed to the golines command. By default golines has --max-length=100 (lines above 100 characters will be wrapped) =============================================================================== gopls *ale-go-gopls* gopls is the official Go language server, and is enabled for use with ALE by default. To install the latest stable version of `gopls` to your `$GOPATH`, try the following command: > GO111MODULE=on go get golang.org/x/tools/gopls@latest < If `$GOPATH` is readable by ALE, it should probably work without you having to do anything else. See the `gopls` README file for more information: https://github.com/golang/tools/blob/master/gopls/README.md ------------------------------------------------------------------------------- Options *ale-options.go_gopls_executable* *g:ale_go_gopls_executable* *b:ale_go_gopls_executable* go_gopls_executable g:ale_go_gopls_executable Type: |String| Default: `'gopls'` See |ale-integrations-local-executables| ALE will search for `gopls` in locally installed directories first by default, and fall back on a globally installed `gopls` if it can't be found otherwise. *ale-options.go_gopls_options* *g:ale_go_gopls_options* *b:ale_go_gopls_options* go_gopls_options g:ale_go_gopls_options Type: |String| Default: `''` Command-line options passed to the gopls executable. See `gopls -h`. *ale-options.go_gopls_fix_executable* *g:ale_go_gopls_fix_executable* *b:ale_go_gopls_fix_executable* go_gopls_fix_executable g:ale_go_gopls_fix_executable Type: |String| Default: `'gopls'` Executable to run to use as the gopls fixer. *ale-options.go_gopls_fix_options* *g:ale_go_gopls_fix_options* *b:ale_go_gopls_fix_options* go_gopls_fix_options g:ale_go_gopls_fix_options Type: |String| Default: `''` Options to pass to the gopls fixer. *ale-options.go_gopls_init_options* *g:ale_go_gopls_init_options* *b:ale_go_gopls_init_options* go_gopls_init_options g:ale_go_gopls_init_options Type: |Dictionary| Default: `{}` LSP initialization options passed to gopls. This can be used to configure the behaviour of gopls. For example: > let g:ale_go_gopls_init_options = { \ 'ui.diagnostic.analyses': { \ 'composites': v:false, \ 'unusedparams': v:true, \ 'unusedresult': v:true, \ }, \} < For a full list of supported analyzers, see: https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md *ale-options.go_gopls_use_global* *g:ale_go_gopls_use_global* *b:ale_go_gopls_use_global* go_gopls_use_global g:ale_go_gopls_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== govet *ale-go-govet* *ale-options.go_govet_options* *g:ale_go_govet_options* *b:ale_go_govet_options* go_govet_options g:ale_go_govet_options Type: |String| Default: `''` This variable can be set to pass additional options to the go vet linter. =============================================================================== revive *ale-go-revive* *ale-options.go_revive_executable* *g:ale_go_revive_executable* *b:ale_go_revive_executable* go_revive_executable g:ale_go_revive_executable Type: |String| Default: `'revive'` This variable can be set to change the revive executable path. *ale-options.go_revive_options* *g:ale_go_revive_options* *b:ale_go_revive_options* go_revive_options g:ale_go_revive_options Type: |String| Default: `''` This variable can be set to pass additional options to the revive =============================================================================== staticcheck *ale-go-staticcheck* *ale-options.go_staticcheck_executable* *g:ale_go_staticcheck_executable* *b:ale_go_staticcheck_executable* go_staticcheck_executable g:ale_go_staticcheck_executable Type: |String| Default: `'staticcheck'` See |ale-integrations-local-executables| ALE will search for `staticcheck` in locally installed directories first by default, and fall back on a globally installed `staticcheck` if it can't be found otherwise. *ale-options.go_staticcheck_options* *g:ale_go_staticcheck_options* *b:ale_go_staticcheck_options* go_staticcheck_options g:ale_go_staticcheck_options Type: |String| Default: `''` This variable can be set to pass additional options to the staticcheck linter. *ale-options.go_staticcheck_lint_package* *g:ale_go_staticcheck_lint_package* *b:ale_go_staticcheck_lint_package* go_staticcheck_lint_package g:ale_go_staticcheck_lint_package Type: |Number| Default: `1` When set to `1`, the whole Go package will be checked instead of only the current file. *ale-options.go_staticcheck_use_global* *g:ale_go_staticcheck_use_global* *b:ale_go_staticcheck_use_global* go_staticcheck_use_global g:ale_go_staticcheck_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-gohtmltmpl.txt ================================================ =============================================================================== ALE Go HTML Template Integration *ale-gohtmltmpl-options* =============================================================================== djlint *ale-gohtmltmpl-djlint* See |ale-html-djlint| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-graphql.txt ================================================ =============================================================================== ALE GraphQL Integration *ale-graphql-options* =============================================================================== eslint *ale-graphql-eslint* The `eslint` linter for GraphQL uses the JavaScript options for `eslint`; see: |ale-javascript-eslint|. You will need the GraphQL ESLint plugin installed for this to work. =============================================================================== gqlint *ale-graphql-gqlint* =============================================================================== prettier *ale-graphql-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-groovy.txt ================================================ =============================================================================== ALE Groovy Integration *ale-groovy-options* =============================================================================== Integration Information Linting and fixing of Groovy files is enabled with the integration of `npm-groovy-lint`. =============================================================================== npm-groovy-lint *ale-groovy-npm-groovy-lint* *ale-options.groovy_npmgroovylint_executable* *g:ale_groovy_npmgroovylint_executable* *b:ale_groovy_npmgroovylint_executable* groovy_npmgroovylint_executable g:ale_groovy_npmgroovylint_executable Type: |String| Default: `'npm-groovy-lint'` Location of the npm-groovy-lint binary file. *ale-options.groovy_npmgroovylint_options* *g:ale_groovy_npmgroovylint_options* *b:ale_groovy_npmgroovylint_options* groovy_npmgroovylint_options g:ale_groovy_npmgroovylint_options Type: |String| Default: `'--loglevel warning'` Additional npm-groovy-lint linter options. *ale-options.groovy_npmgroovylint_fix_options* *g:ale_groovy_npmgroovylint_fix_options* *b:ale_groovy_npmgroovylint_fix_options* groovy_npmgroovylint_fix_options g:ale_groovy_npmgroovylint_fix_options Type: |String| Default: `'--fix'` This variable can be used to configure fixing with npm-groovy-lint. It must contain either `--fix` or `--format` for the fixer to work. See `npm-groovy-lint --help` for more information on possible fix rules. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-hack.txt ================================================ =============================================================================== 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 in ftplugin files like so: > let b:ale_linters = ['hack', 'hhast'] < Or in Lua: > require("ale").setup.buffer({linters = {"hack", "hhast"}}) < =============================================================================== hack *ale-hack-hack* *ale-options.hack_hack_executable* *g:ale_hack_hack_executable* *b:ale_hack_hack_executable* hack_hack_executable g: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* *ale-options.hack_hackfmt_options* *g:ale_hack_hackfmt_options* *b:ale_hack_hackfmt_options* hack_hackfmt_options g:ale_hack_hackfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the hackfmt fixer. =============================================================================== hhast *ale-hack-hhast* *ale-options.hack_hhast_executable* *g:ale_hack_hhast_executable* *b:ale_hack_hhast_executable* hack_hhast_executable g: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: ================================================ FILE: doc/ale-handlebars.txt ================================================ =============================================================================== ALE Handlebars Integration *ale-handlebars-options* =============================================================================== djlint *ale-handlebars-djlint* See |ale-html-djlint| =============================================================================== prettier *ale-handlebars-prettier* See |ale-javascript-prettier| for information about the available options. Uses glimmer parser by default. =============================================================================== ember-template-lint *ale-handlebars-embertemplatelint* *ale-options.handlebars_embertemplatelint_executable* *g:ale_handlebars_embertemplatelint_executable* *b:ale_handlebars_embertemplatelint_executable* handlebars_embertemplatelint_executable g:ale_handlebars_embertemplatelint_executable Type: |String| Default: `'ember-template-lint'` See |ale-integrations-local-executables| *ale-options.handlebars_embertemplatelint_use_global* *g:ale_handlebars_embertemplatelint_use_global* *b:ale_handlebars_embertemplatelint_use_global* handlebars_embertemplatelint_use_global g:ale_handlebars_embertemplatelint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-haskell.txt ================================================ =============================================================================== ALE Haskell Integration *ale-haskell-options* =============================================================================== brittany *ale-haskell-brittany* *ale-options.haskell_brittany_executable* *g:ale_haskell_brittany_executable* *b:ale_haskell_brittany_executable* haskell_brittany_executable g:ale_haskell_brittany_executable Type: |String| Default: `'brittany'` This variable can be changed to use a different executable for brittany. =============================================================================== cspell *ale-haskell-cspell* See |ale-cspell-options| =============================================================================== floskell *ale-haskell-floskell* *ale-options.haskell_floskell_executable* *g:ale_haskell_floskell_executable* *b:ale_haskell_floskell_executable* haskell_floskell_executable g:ale_haskell_floskell_executable Type: |String| Default: `'floskell'` This variable can be changed to use a different executable for floskell. =============================================================================== ghc *ale-haskell-ghc* *ale-options.haskell_ghc_options* *g:ale_haskell_ghc_options* *b:ale_haskell_ghc_options* haskell_ghc_options g:ale_haskell_ghc_options Type: |String| Default: `'-fno-code -v0'` This variable can be changed to modify flags given to ghc. =============================================================================== ghc-mod *ale-haskell-ghc-mod* *ale-options.haskell_ghc_mod_executable* *g:ale_haskell_ghc_mod_executable* *b:ale_haskell_ghc_mod_executable* haskell_ghc_mod_executable g: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* *ale-options.haskell_cabal_ghc_options* *g:ale_haskell_cabal_ghc_options* *b:ale_haskell_cabal_ghc_options* haskell_cabal_ghc_options g:ale_haskell_cabal_ghc_options Type: |String| Default: `'-fno-code -v0'` This variable can be changed to modify flags given to ghc through cabal exec. =============================================================================== hdevtools *ale-haskell-hdevtools* *ale-options.haskell_hdevtools_executable* *g:ale_haskell_hdevtools_executable* *b:ale_haskell_hdevtools_executable* haskell_hdevtools_executable g:ale_haskell_hdevtools_executable Type: |String| Default: `'hdevtools'` This variable can be changed to use a different executable for hdevtools. *ale-options.haskell_hdevtools_options* *g:ale_haskell_hdevtools_options* *b:ale_haskell_hdevtools_options* haskell_hdevtools_options g:ale_haskell_hdevtools_options Type: |String| Default: `get(g:, 'hdevtools_options', '-g -Wall')` This variable can be changed to modify flags given to hdevtools. The hdevtools documentation recommends setting GHC options for `hdevtools` with `g:hdevtools_options`. ALE will use the value of `g:hdevtools_options` for the value of `g:ale_haskell_hdevtools_options` by default, so this option can be respected and overridden specifically for ALE. =============================================================================== hfmt *ale-haskell-hfmt* *ale-options.haskell_hfmt_executable* *g:ale_haskell_hfmt_executable* *b:ale_haskell_hfmt_executable* haskell_hfmt_executable g:ale_haskell_hfmt_executable Type: |String| Default: `'hfmt'` This variable can be changed to use a different executable for hfmt. =============================================================================== hindent *ale-haskell-hindent* *ale-options.haskell_hindent_executable* *g:ale_haskell_hindent_executable* *b:ale_haskell_hindent_executable* haskell_hindent_executable g:ale_haskell_hindent_executable Type: |String| Default: `'hindent'` This variable can be changed to use a different executable for hindent. =============================================================================== hlint *ale-haskell-hlint* *ale-options.haskell_hlint_executable* *g:ale_haskell_hlint_executable* *b:ale_haskell_hlint_executable* haskell_hlint_executable g:ale_haskell_hlint_executable Type: |String| Default: `'hlint'` This variable can be changed to use a different executable for hlint. *ale-options.haskell_hlint_options* *g:ale_haskell_hlint_options* *b:ale_haskell_hlint_options* haskell_hlint_options g:ale_haskell_hlint_options Type: |String| Default: `''` This variable can be used to pass extra options to the underlying hlint executable. =============================================================================== hls *ale-haskell-hls* *ale-options.haskell_hls_executable* *g:ale_haskell_hls_executable* *b:ale_haskell_hls_executable* haskell_hls_executable g:ale_haskell_hls_executable Type: |String| Default: `'haskell-language-server-wrapper'` This variable can be changed to use a different executable for the haskell language server. *ale-options.haskell_hls_config* *g:ale_haskell_hls_config* *b:ale_haskell_hls_config* haskell_hls_config g:ale_haskell_hls_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for HLS. For example, to see more completions: > let g:ale_haskell_hls_config = {'haskell': {'maxCompletions': 250}} < Refer to HLS documentation for possible settings: https://haskell-language-server.readthedocs.io/en/latest/configuration.html#language-specific-server-options =============================================================================== stack-build *ale-haskell-stack-build* *ale-options.haskell_stack_build_options* *g:ale_haskell_stack_build_options* *b:ale_haskell_stack_build_options* haskell_stack_build_options g:ale_haskell_stack_build_options Type: |String| Default: `'--fast'` We default to using `'--fast'`. Since Stack generates binaries, your programs will be slower unless you separately rebuild them outside of ALE. =============================================================================== stack-ghc *ale-haskell-stack-ghc* *ale-options.haskell_stack_ghc_options* *g:ale_haskell_stack_ghc_options* *b:ale_haskell_stack_ghc_options* haskell_stack_ghc_options g:ale_haskell_stack_ghc_options Type: |String| Default: `'-fno-code -v0'` This variable can be changed to modify flags given to ghc through `stack ghc` =============================================================================== stylish-haskell *ale-haskell-stylish-haskell* *ale-options.haskell_stylish_haskell_executable* *g:ale_haskell_stylish_haskell_executable* *b:ale_haskell_stylish_haskell_executable* haskell_stylish_haskell_executable g: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* *ale-options.haskell_hie_executable* *g:ale_haskell_hie_executable* *b:ale_haskell_hie_executable* haskell_hie_executable g: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'` =============================================================================== ormolu *ale-haskell-ormolu* *ale-options.haskell_ormolu_executable* *g:ale_haskell_ormolu_executable* *b:ale_haskell_ormolu_executable* haskell_ormolu_executable g:ale_haskell_ormolu_executable Type: |String| Default: `'ormolu'` This variable can be changed to use a different executable for ormolu. *ale-options.haskell_ormolu_options* *g:ale_haskell_ormolu_options* *b:ale_haskell_ormolu_options* haskell_ormolu_options g:ale_haskell_ormolu_options Type: |String| Default: `''` This variable can be used to pass extra options to the underlying ormolu executable. =============================================================================== fourmolu *ale-haskell-fourmolu* *ale-options.haskell_fourmolu_executable* *g:ale_haskell_fourmolu_executable* *b:ale_haskell_fourmolu_executable* haskell_fourmolu_executable g:ale_haskell_fourmolu_executable Type: |String| Default: `'fourmolu'` This variable can be changed to use a different executable for fourmolu. *ale-options.haskell_fourmolu_options* *g:ale_haskell_fourmolu_options* *b:ale_haskell_fourmolu_options* haskell_fourmolu_options g:ale_haskell_fourmolu_options Type: |String| Default: `''` This variable can be used to pass extra options to the underlying fourmolu executable. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-hcl.txt ================================================ =============================================================================== ALE HCL Integration *ale-hcl-options* =============================================================================== packer-fmt *ale-hcl-packer-fmt* See |ale-packer-fmt-fixer| for information about the available options. =============================================================================== terraform-fmt *ale-hcl-terraform-fmt* See |ale-terraform-fmt-fixer| for information about the available options. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-help.txt ================================================ =============================================================================== ALE Help Integration *ale-help-options* =============================================================================== cspell *ale-help-cspell* See |ale-cspell-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-html.txt ================================================ =============================================================================== ALE HTML Integration *ale-html-options* =============================================================================== angular *ale-html-angular* ALE supports language server features for Angular. You can install it via `npm`: > $ npm install --save-dev @angular/language-server < Angular 11 and up are supported. *ale-options.html_angular_executable* *g:ale_html_angular_executable* *b:ale_html_angular_executable* html_angular_executable g:ale_html_angular_executable Type: |String| Default: `'ngserver'` See |ale-integrations-local-executables| *ale-options.html_angular_use_global* *g:ale_html_angular_use_global* *b:ale_html_angular_use_global* html_angular_use_global g:ale_html_angular_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== cspell *ale-html-cspell* See |ale-cspell-options| =============================================================================== djlint *ale-html-djlint* `djlint` options for HTML are the same as the options for htmlangular, htmldjango, jinja, handlebars, nunjucks and gotmplhtml. *ale-options.html_djlint_executable* *g:ale_html_djlint_executable* *b:ale_html_djlint_executable* html_djlint_executable g:ale_html_djlint_executable Type: |String| Default: `'djlint'` See |ale-integrations-local-executables| *ale-options.html_djlint_options* *g:ale_html_djlint_options* *b:ale_html_djlint_options* html_djlint_options g:ale_html_djlint_options Type: |String| Default: `''` This variable can be changed to modify flags given to djlint. =============================================================================== fecs *ale-html-fecs* `fecs` options for HTML are the same as the options for JavaScript, and both of them read `./.fecsrc` as the default configuration file. See: |ale-javascript-fecs|. =============================================================================== html-beautify *ale-html-beautify* *ale-options.html_beautify_executable* *g:ale_html_beautify_executable* *b:ale_html_beautify_executable* html_beautify_executable g:ale_html_beautify_executable Type: |String| Default: `'html-beautify'` See |ale-integrations-local-executables| *ale-options.html_beautify_options* *g:ale_html_beautify_options* *b:ale_html_beautify_options* html_beautify_options g:ale_html_beautify_options Type: |String| Default: `''` This variable can be changed to modify flags given to html-beautify. *ale-options.html_beautify_use_global* *g:ale_html_beautify_use_global* *b:ale_html_beautify_use_global* html_beautify_use_global g:ale_html_beautify_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== htmlhint *ale-html-htmlhint* *ale-options.html_htmlhint_executable* *g:ale_html_htmlhint_executable* *b:ale_html_htmlhint_executable* html_htmlhint_executable g:ale_html_htmlhint_executable Type: |String| Default: `'htmlhint'` See |ale-integrations-local-executables| *ale-options.html_htmlhint_options* *g:ale_html_htmlhint_options* *b:ale_html_htmlhint_options* html_htmlhint_options g:ale_html_htmlhint_options Type: |String| Default: `''` This variable can be changed to modify flags given to HTMLHint. *ale-options.html_htmlhint_use_global* *g:ale_html_htmlhint_use_global* *b:ale_html_htmlhint_use_global* html_htmlhint_use_global g:ale_html_htmlhint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== prettier *ale-html-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== rustywind *ale-html-rustywind* *ale-options.html_rustywind_executable* *g:ale_html_rustywind_executable* *b:ale_html_rustywind_executable* html_rustywind_executable g:ale_html_rustywind_executable Type: |String| Default: `'rustywind'` See |ale-integrations-local-executables| *ale-options.html_rustywind_options* *g:ale_html_rustywind_options* *b:ale_html_rustywind_options* html_rustywind_options g:ale_html_rustywind_options Type: |String| Default: `''` This variable can be changed to modify flags given to rustywind. =============================================================================== stylelint *ale-html-stylelint* *ale-options.html_stylelint_executable* *g:ale_html_stylelint_executable* *b:ale_html_stylelint_executable* html_stylelint_executable g:ale_html_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.html_stylelint_options* *g:ale_html_stylelint_options* *b:ale_html_stylelint_options* html_stylelint_options g:ale_html_stylelint_options Type: |String| Default: `''` This variable can be set to pass additional options to stylelint. *ale-options.html_stylelint_use_global* *g:ale_html_stylelint_use_global* *b:ale_html_stylelint_use_global* html_stylelint_use_global g:ale_html_stylelint_use_global Type: |String| Default: `0` See |ale-integrations-local-executables| =============================================================================== superhtml *ale-html-superhtml* g:ale_html_superhtml_executable *g:ale_html_superhtml_executable* *b:ale_html_superhtml_executable* Type: |String| Default: `'superhtml'` This variable can be changed to use a different executable for superhtml. g:ale_html_superhtml_use_global *g:ale_html_superhtml_use_global* *b:ale_html_superhtml_use_global* Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== tidy *ale-html-tidy* `tidy` is a console application which corrects and cleans up HTML and XML documents by fixing markup errors and upgrading legacy code to modern standards. Note: `/usr/bin/tidy` on macOS (installed by default) is too old. It was released on 31 Oct 2006. It does not consider modern HTML specs (HTML5) and shows outdated warnings. So |ale| ignores `/usr/bin/tidy` on macOS. To use `tidy` on macOS, please install the latest version with Homebrew: > $ brew install tidy-html5 < `/usr/local/bin/tidy` is installed. ------------------------------------------------------------------------------- Options *ale-options.html_tidy_executable* *g:ale_html_tidy_executable* *b:ale_html_tidy_executable* html_tidy_executable g:ale_html_tidy_executable Type: |String| Default: `'tidy'` This variable can be changed to change the path to tidy. *ale-options.html_tidy_options* *g:ale_html_tidy_options* *b:ale_html_tidy_options* html_tidy_options g:ale_html_tidy_options Type: |String| Default: `'-q -e -language en'` This variable can be changed to change the arguments provided to the executable. ALE will attempt to automatically detect the appropriate file encoding to provide to html-tidy, and fall back to UTF-8 when encoding detection fails. The recognized file encodings are as follows: ascii, big5, cp1252 (win1252), cp850 (ibm858), cp932 (shiftjis), iso-2022-jp (iso-2022), latin1, macroman (mac), sjis (shiftjis), utf-16le, utf-16, utf-8 *ale-options.html_tidy_use_global* *g:ale_html_tidy_use_global* html_tidy_use_global g:ale_html_tidy_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vscodehtml *ale-html-vscode* Website: https://github.com/hrsh7th/vscode-langservers-extracted ------------------------------------------------------------------------------- Installation Install VSCode html language server either globally or locally: > npm install -g vscode-langservers-extracted < =============================================================================== write-good *ale-html-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-htmlangular.txt ================================================ =============================================================================== ALE HTML Angular Template Integration *ale-htmlangular-options* =============================================================================== djlint *ale-htmlangular-djlint* See |ale-html-djlint| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-htmldjango.txt ================================================ =============================================================================== ALE HTML Django Template Integration *ale-htmldjango-options* =============================================================================== djlint *ale-htmldjango-djlint* See |ale-html-djlint| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-http.txt ================================================ =============================================================================== ALE HTTP Integration *ale-http-options* =============================================================================== kulala_fmt *ale-http-kulala_fmt* *ale-options.http_kulala_fmt_executable* *g:ale_http_kulala_fmt_executable* *b:ale_http_kulala_fmt_executable* http_kulala_fmt g:ale_http_kulala_fmt Type: |String| Default: `'kulala_fmt'` Override the invoked kulala_fmt binary. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-hurl.txt ================================================ =============================================================================== ALE Hurl Integration *ale-hurl-options* =============================================================================== hurlfmt *ale-hurl-hurlfmt* *ale-options.hurl_hurlfmt_executable* *g:ale_hurl_hurlfmt_executable* *b:ale_hurl_hurlfmt_executable* hurl_hurlfmt_executable g:ale_hurl_hurlfmt_executable Type: |String| Default: `'hurlfmt'` Override the invoked hurlfmt binary. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-idris.txt ================================================ =============================================================================== ALE Idris Integration *ale-idris-options* =============================================================================== idris *ale-idris-idris* *ale-options.idris_idris_executable* *g:ale_idris_idris_executable* *b:ale_idris_idris_executable* idris_idris_executable g:ale_idris_idris_executable Type: |String| Default: `'idris'` This variable can be changed to change the path to idris. *ale-options.idris_idris_options* *g:ale_idris_idris_options* *b:ale_idris_idris_options* idris_idris_options g:ale_idris_idris_options Type: |String| Default: `'--total --warnpartial --warnreach --warnipkg'` This variable can be changed to modify flags given to idris. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-ink.txt ================================================ =============================================================================== ALE Ink Integration *ale-ink-options* =============================================================================== ink-language-server *ale-ink-language-server* Ink Language Server - https://github.com/ephraim/ink-language-server *ale-options.ink_ls_executable* *g:ale_ink_ls_executable* *b:ale_ink_ls_executable* ink_ls_executable g:ale_ink_ls_executable Type: |String| Default: `'ink-language-server'` Ink language server executable. *ale-options.ink_ls_initialization_options* *g:ale_ink_ls_initialization_options* *b:ale_ink_ls_initialization_options* ink_ls_initialization_options g:ale_ink_ls_initialization_options Type: |Dictionary| Default: `{}` Dictionary containing configuration settings that will be passed to the language server at startup. For certain platforms and certain story structures, the defaults will suffice. However, many projects will need to change these settings - see the ink-language-server website for more information. An example of setting non-default options: > let g:ale_ink_ls_initialization_options = { \ 'ink': { \ 'mainStoryPath': 'init.ink', \ 'inklecateExecutablePath': '/usr/local/bin/inklecate', \ 'runThroughMono': v:false, \ }, \} < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-inko.txt ================================================ =============================================================================== ALE Inko Integration *ale-inko-options* *ale-integration-inko* =============================================================================== inko *ale-inko-inko* *ale-options.inko_inko_executable* *g:ale_inko_inko_executable* *b:ale_inko_inko_executable* inko_inko_executable g:ale_inko_inko_executable Type: |String| Default: `'inko'` This variable can be modified to change the executable path for `inko`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-ispc.txt ================================================ =============================================================================== ALE ISPC Integration *ale-ispc-options* =============================================================================== ispc *ale-ispc-ispc* *ale-options.ispc_ispc_executable* *g:ale_ispc_ispc_executable* *b:ale_ispc_ispc_executable* ispc_ispc_executable g:ale_ispc_ispc_executable Type: |String| Default: `'ispc'` This variable can be changed to use a different executable for ispc. *ale-options.ispc_ispc_options* *g:ale_ispc_ispc_options* *b:ale_ispc_ispc_options* ispc_ispc_options g: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: ================================================ FILE: doc/ale-java.txt ================================================ =============================================================================== ALE Java Integration *ale-java-options* =============================================================================== checkstyle *ale-java-checkstyle* *ale-options.java_checkstyle_config* *g:ale_java_checkstyle_config* *b:ale_java_checkstyle_config* java_checkstyle_config g:ale_java_checkstyle_config Type: |String| Default: `'/google_checks.xml'` A path to a checkstyle configuration file. If a configuration file is specified with |g:ale_java_checkstyle_options|, it will be preferred over this setting. The path to the configuration file can be an absolute path or a relative path. ALE will search for the relative path in parent directories. *ale-options.java_checkstyle_executable* *g:ale_java_checkstyle_executable* *b:ale_java_checkstyle_executable* java_checkstyle_executable g:ale_java_checkstyle_executable Type: |String| Default: `'checkstyle'` This variable can be changed to modify the executable used for checkstyle. *ale-options.java_checkstyle_options* *g:ale_java_checkstyle_options* *b:ale_java_checkstyle_options* java_checkstyle_options g:ale_java_checkstyle_options Type: |String| Default: `''` This variable can be changed to modify flags given to checkstyle. If a configuration file is specified with `-c`, it will be used instead of configuration files set with |g:ale_java_checkstyle_config|. =============================================================================== clang-format *ale-java-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for Java. =============================================================================== cspell *ale-java-cspell* See |ale-cspell-options| =============================================================================== javac *ale-java-javac* *ale-options.java_javac_classpath* *g:ale_java_javac_classpath* *b:ale_java_javac_classpath* java_javac_classpath g:ale_java_javac_classpath Type: |String| or |List| Default: `''` This variable can be set to change the global classpath for Java. *ale-options.java_javac_executable* *g:ale_java_javac_executable* *b:ale_java_javac_executable* java_javac_executable g:ale_java_javac_executable Type: |String| Default: `'javac'` This variable can be set to change the executable path used for javac. *ale-options.java_javac_options* *g:ale_java_javac_options* *b:ale_java_javac_options* java_javac_options g:ale_java_javac_options Type: |String| Default: `''` This variable can be set to pass additional options to javac. *ale-options.java_javac_sourcepath* *g:ale_java_javac_sourcepath* *b:ale_java_javac_sourcepath* java_javac_sourcepath g:ale_java_javac_sourcepath Type: |String| or |List| Default: `''` This variable can set multiple source code paths, the source code path is a relative path (relative to the project root directory). The source path can be set as a String with a system-dependent path separator. Note that the Unix path separator is a colon (`:`), and on Windows the path separator is a semicolon (`;`). > let g:ale_java_javac_sourcepath = 'build/gen/source/xx/main:build/gen/source' < The source path can be set as a List so ALE will add the appropriate path separator for the host system automatically. > let g:ale_java_javac_sourcepath = [ \ 'build/generated/source/querydsl/main', \ 'target/generated-sources/source/querydsl/main', \] < =============================================================================== google-java-format *ale-java-google-java-format* *ale-options.java_google_java_format_executable* *g:ale_java_google_java_format_executable* *b:ale_java_google_java_format_executable* java_google_java_format_executable g:ale_java_google_java_format_executable Type: |String| Default: `'google-java-format'` See |ale-integrations-local-executables| *ale-options.java_google_java_format_options* *g:ale_java_google_java_format_options* *b:ale_java_google_java_format_options* java_google_java_format_options g:ale_java_google_java_format_options Type: |String| Default: `''` This variable can be set to pass additional options =============================================================================== pmd *ale-java-pmd* *ale-options.java_pmd_options* *g:ale_java_pmd_options* *b:ale_java_pmd_options* java_pmd_options g:ale_java_pmd_options Type: |String| Default: `'-R category/java/bestpractices'` This variable can be changed to modify flags given to PMD. Do not specify -f and -d. They are added automatically. =============================================================================== 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/java-language-server. Before building the language server you need to install pre-requisites: npm, maven, and protobuf. You also need to have Java 13 and JAVA_HOME properly set. After downloading the source code and installing all pre-requisites you can build the language server with the included build.sh script: `scripts/build.sh` This will create launch scripts for Linux, Mac, and Windows in the dist folder within the repo: - `lang_server_linux.sh` - `lang_server_mac.sh` - `lang_server_windows.sh` To let ALE use this language server you need to set the executable, as documented below. *ale-options.java_javalsp_executable* *g:ale_java_javalsp_executable* *b:ale_java_javalsp_executable* java_javalsp_executable g:ale_java_javalsp_executable Type: |String| Default: `''` This variable must be set to the absolute path of the language server launcher executable. For example: > let g:ale_java_javalsp_executable = '/java-language-server/dist/lang_server_linux.sh' < *ale-options.java_javalsp_config* *g:ale_java_javalsp_config* *b:ale_java_javalsp_config* java_javalsp_config g:ale_java_javalsp_config Type: |Dictionary| Default: `{}` The javalsp linter automatically detects external dependencies for Maven and Gradle projects. In case the javalsp fails to detect some of them, you can specify them configuring settings for the language server, such as in your ftplugin file. > let b:ale_java_javalsp_config = { \ 'java': { \ 'externalDependencies': [ \ 'junit:junit:jar:4.12:test', \ 'junit:junit:4.1' \ ], \ 'classPath': [ \ 'lib/some-dependency.jar', \ '/android-sdk/platforms/android-28.jar', \ ], \ }, \} < Or in Lua: > require("ale").setup.buffer({ java_lsp_config = { java = { externalDependencies = { "junit:junit:jar:4.12:test", "junit:junit:4.1" }, classPath = { "lib/some-dependency.jar", "/android-sdk/platforms/android-28.jar", }, }, } }) < The Java language server will look for the dependencies you specify in `externalDependencies` array in your Maven and Gradle caches ~/.m2 and ~/.gradle. =============================================================================== eclipselsp *ale-java-eclipselsp* To enable Eclipse JDT LSP linter you need to clone and build the eclipse.jdt.ls language server from https://github.com/eclipse/eclipse.jdt.ls. Simply clone the source code repo and then build the plugin: `./mvnw clean verify` Note: currently, the build can only run when launched with JDK 11. More recent versions can be used to run the server though. After build completes the files required to run the language server will be located inside the repository folder `eclipse.jdt.ls`. Please ensure to set |g:ale_java_eclipselsp_path| to the absolute path of that folder. You could customize compiler options and code assists of the server. Under your project folder, modify the file `.settings/org.eclipse.jdt.core.prefs` with options presented at https://help.eclipse.org/neon/topic/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/JavaCore.html. *ale-options.java_eclipselsp_path* *g:ale_java_eclipselsp_path* *b:ale_java_eclipselsp_path* java_eclipselsp_path g:ale_java_eclipselsp_path Type: |String| Default: `'$HOME/eclipse.jdt.ls'` Absolute path to the location of the eclipse.jdt.ls repository folder. Or if you have VSCode extension installed the absolute path to the VSCode extensions folder (e.g. $HOME/.vscode/extensions/redhat.java-0.4x.0 in Linux). *ale-options.java_eclipselsp_executable* *g:ale_java_eclipselsp_executable* *b:ale_java_eclipse_executable* java_eclipselsp_executable g:ale_java_eclipselsp_executable Type: |String| Default: `'java'` This variable can be set to change the executable path used for java. *ale-options.java_eclipselsp_config_path* *g:ale_java_eclipselsp_config_path* *b:ale_java_eclipse_config_path* java_eclipselsp_config_path g:ale_java_eclipselsp_config_path Type: |String| Default: `''` Set this variable to change the configuration directory path used by eclipselsp (e.g. `$HOME/.jdtls` in Linux). By default ALE will attempt to use the configuration within the installation directory. This setting is particularly useful when eclipselsp is installed in a non-writable directory like `/usr/share/java/jdtls`, as is the case when installed via system package. *ale-options.java_eclipselsp_workspace_path* *g:ale_java_eclipselsp_workspace_path* *b:ale_java_eclipselsp_workspace_path* java_eclipselsp_workspace_path g:ale_java_eclipselsp_workspace_path Type: |String| Default: `''` If you have Eclipse installed it is a good idea to set this variable to the absolute path of the Eclipse workspace. If not set this value will be set to the parent folder of the project root. *ale-options.java_eclipselsp_javaagent* *g:ale_java_eclipselsp_javaagent* *b:ale_java_eclipselsp_javaagent* java_eclipselsp_javaagent g:ale_java_eclipselsp_javaagent Type: |String| Default: `''` A variable to add java agent for annotation processing such as Lombok. If you have multiple java agent files, use space to separate them. For example: > let g:ale_java_eclipselsp_javaagent='/eclipse/lombok.jar /eclipse/jacoco.jar' < =============================================================================== 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: ================================================ FILE: doc/ale-javascript.txt ================================================ =============================================================================== ALE JavaScript Integration *ale-javascript-options* *ale-eslint-nested-configuration-files* For fixing files with ESLint, nested configuration files with `root: false` are not supported. This is because ALE fixes files by writing the contents of buffers to temporary files, and then explicitly sets the configuration file. Configuration files which are set explicitly must be root configuration files. If you are using nested configuration files, you should restructure your project so your configuration files use `extends` instead. See the ESLint documentation here: http://eslint.org/docs/user-guide/configuring#extending-configuration-files You should change the structure of your project from this: > /path/foo/.eslintrc.js # root: true /path/foo/bar/.eslintrc.js # root: false < To this: > /path/foo/.base-eslintrc.js # Base configuration here /path/foo/.eslintrc.js # extends: ["/path/foo/.base-eslintrc.js"] /path/foo/bar/.eslintrc.js # extends: ["/path/foo/.base-eslintrc.js"] < =============================================================================== biome *ale-javascript-biome* Check the docs over at |ale-typescript-biome|. =============================================================================== clang-format *ale-javascript-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for JavaScript. =============================================================================== cspell *ale-javascript-cspell* See |ale-cspell-options| =============================================================================== deno *ale-javascript-deno* Check the docs over at |ale-typescript-deno|. =============================================================================== dprint *ale-javascript-dprint* See |ale-dprint-options| and https://dprint.dev/plugins/typescript =============================================================================== eslint *ale-javascript-eslint* *ale-options.javascript_eslint_executable* *g:ale_javascript_eslint_executable* *b:ale_javascript_eslint_executable* javascript_eslint_executable g:ale_javascript_eslint_executable Type: |String| Default: `'eslint'` See |ale-integrations-local-executables| *ale-options.javascript_eslint_options* *g:ale_javascript_eslint_options* *b:ale_javascript_eslint_options* javascript_eslint_options g:ale_javascript_eslint_options Type: |String| Default: `''` This variable can be set to pass additional options to eslint. *ale-options.javascript_eslint_use_global* *g:ale_javascript_eslint_use_global* *b:ale_javascript_eslint_use_global* javascript_eslint_use_global g:ale_javascript_eslint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.javascript_eslint_suppress_eslintignore* *g:ale_javascript_eslint_suppress_eslintignore* *b:ale_javascript_eslint_suppress_eslintignore* javascript_eslint_suppress_eslintignore g:ale_javascript_eslint_suppress_eslintignore Type: |Number| Default: `0` This variable can be set to `1` to disable warnings for files being ignored by eslint. *ale-options.javascript_eslint_suppress_missing_config* *g:ale_javascript_eslint_suppress_missing_config* *b:ale_javascript_eslint_suppress_missing_config* javascript_eslint_suppress_missing_config g:ale_javascript_eslint_suppress_missing_config Type: |Number| Default: `0` This variable can be set to `1` to disable errors for missing eslint configuration files. When turning this option on, eslint will not report any problems when no configuration files are found. =============================================================================== fecs *ale-javascript-fecs* `fecs` is a lint tool for HTML/CSS/JavaScript, can be installed via: `$ npm install --save-dev fecs` And the configuration file is located at `./fecsrc`, see http://fecs.baidu.com for more options. *ale-options.javascript_fecs_executable* *g:ale_javascript_fecs_executable* *b:ale_javascript_fecs_executable* javascript_fecs_executable g:ale_javascript_fecs_executable Type: |String| Default: `'fecs'` See |ale-integrations-local-executables| *ale-options.javascript_fecs_use_global* *g:ale_javascript_fecs_use_global* *b:ale_javascript_fecs_use_global* javascript_fecs_use_global g:ale_javascript_fecs_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== flow *ale-javascript-flow* *ale-options.javascript_flow_executable* *g:ale_javascript_flow_executable* *b:ale_javascript_flow_executable* javascript_flow_executable g:ale_javascript_flow_executable Type: |String| Default: `'flow'` See |ale-integrations-local-executables| *ale-options.javascript_flow_use_home_config* *g:ale_javascript_flow_use_home_config* *b:ale_javascript_flow_use_home_config* javascript_flow_use_home_config g:ale_javascript_flow_use_home_config Type: |Number| Default: `0` When set to `1`, ALE will allow Flow to be executed with configuration files from your home directory. ALE will not run Flow with home directory configuration files by default, as doing so can lead to Vim consuming all of your RAM and CPU power. *ale-options.javascript_flow_use_global* *g:ale_javascript_flow_use_global* *b:ale_javascript_flow_use_global* javascript_flow_use_global g:ale_javascript_flow_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.javascript_flow_use_respect_pragma* *g:ale_javascript_flow_use_respect_pragma* *b:ale_javascript_flow_use_respect_pragma* javascript_flow_use_respect_pragma g:ale_javascript_flow_use_respect_pragma Type: |Number| Default: `1` By default, ALE will use the `--respect-pragma` option for `flow`, so only files with the `@flow` pragma are checked by ALE. This option can be set to `0` to disable that behavior, so all files can be checked by `flow`. =============================================================================== importjs *ale-javascript-importjs* *ale-options.javascript_importjs_executable* *g:ale_javascript_importjs_executable* *b:ale_javascript_importjs_executable* javascript_importjs_executable g:ale_javascript_importjs_executable Type: |String| Default: `'importjs'` =============================================================================== jscs *ale-javascript-jscs* *ale-options.javascript_jscs_executable* *g:ale_javascript_jscs_executable* *b:ale_javascript_jscs_executable* javascript_jscs_executable g:ale_javascript_jscs_executable Type: |String| Default: `'jscs'` See |ale-integrations-local-executables| *ale-options.javascript_jscs_use_global* *g:ale_javascript_jscs_use_global* *b:ale_javascript_jscs_use_global* javascript_jscs_use_global g:ale_javascript_jscs_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== jshint *ale-javascript-jshint* *ale-options.javascript_jshint_executable* *g:ale_javascript_jshint_executable* *b:ale_javascript_jshint_executable* javascript_jshint_executable g:ale_javascript_jshint_executable Type: |String| Default: `'jshint'` See |ale-integrations-local-executables| *ale-options.javascript_jshint_use_global* *g:ale_javascript_jshint_use_global* *b:ale_javascript_jshint_use_global* javascript_jshint_use_global g:ale_javascript_jshint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== prettier *ale-javascript-prettier* *ale-options.javascript_prettier_executable* *g:ale_javascript_prettier_executable* *b:ale_javascript_prettier_executable* javascript_prettier_executable g:ale_javascript_prettier_executable Type: |String| Default: `'prettier'` See |ale-integrations-local-executables| *ale-options.javascript_prettier_options* *g:ale_javascript_prettier_options* *b:ale_javascript_prettier_options* javascript_prettier_options g:ale_javascript_prettier_options Type: |String| Default: `''` This variable can be set to pass additional options to prettier. *ale-options.javascript_prettier_use_global* *g:ale_javascript_prettier_use_global* *b:ale_javascript_prettier_use_global* javascript_prettier_use_global g:ale_javascript_prettier_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== prettier-eslint *ale-javascript-prettier-eslint* *ale-options.javascript_prettier_eslint_executable* *g:ale_javascript_prettier_eslint_executable* *b:ale_javascript_prettier_eslint_executable* javascript_prettier_eslint_executable g:ale_javascript_prettier_eslint_executable Type: |String| Default: `'prettier-eslint'` See |ale-integrations-local-executables| *ale-options.javascript_prettier_eslint_options* *g:ale_javascript_prettier_eslint_options* *b:ale_javascript_prettier_eslint_options* javascript_prettier_eslint_options g:ale_javascript_prettier_eslint_options Type: |String| Default: `''` This variable can be set to pass additional options to prettier-eslint. *ale-options.javascript_prettier_eslint_use_global* *g:ale_javascript_prettier_eslint_use_global* *b:ale_javascript_prettier_eslint_use_global* javascript_prettier_eslint_use_global g:ale_javascript_prettier_eslint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== prettier-standard *ale-javascript-prettier-standard* *ale-options.javascript_prettier_standard_executable* *g:ale_javascript_prettier_standard_executable* *b:ale_javascript_prettier_standard_executable* javascript_prettier_standard_executable g:ale_javascript_prettier_standard_executable Type: |String| Default: `'prettier-standard'` See |ale-integrations-local-executables| *ale-options.javascript_prettier_standard_options* *g:ale_javascript_prettier_standard_options* *b:ale_javascript_prettier_standard_options* javascript_prettier_standard_options g:ale_javascript_prettier_standard_options Type: |String| Default: `''` This variable can be set to pass additional options to prettier-standard. *ale-options.javascript_prettier_standard_use_global* *g:ale_javascript_prettier_standard_use_global* *b:ale_javascript_prettier_standard_use_global* javascript_prettier_standard_use_global g:ale_javascript_prettier_standard_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== standard *ale-javascript-standard* *ale-options.javascript_standard_executable* *g:ale_javascript_standard_executable* *b:ale_javascript_standard_executable* javascript_standard_executable g:ale_javascript_standard_executable Type: |String| Default: `'standard'` See |ale-integrations-local-executables| *ale-options.javascript_standard_options* *g:ale_javascript_standard_options* *b:ale_javascript_standard_options* javascript_standard_options g:ale_javascript_standard_options Type: |String| Default: `''` This variable can be set to pass additional options to standard. *ale-options.javascript_standard_use_global* *g:ale_javascript_standard_use_global* *b:ale_javascript_standard_use_global* javascript_standard_use_global g:ale_javascript_standard_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== xo *ale-javascript-xo* *ale-options.javascript_xo_executable* *g:ale_javascript_xo_executable* *b:ale_javascript_xo_executable* javascript_xo_executable g:ale_javascript_xo_executable Type: |String| Default: `'xo'` See |ale-integrations-local-executables| *ale-options.javascript_xo_options* *g:ale_javascript_xo_options* *b:ale_javascript_xo_options* javascript_xo_options g:ale_javascript_xo_options Type: |String| Default: `''` This variable can be set to pass additional options to xo. *ale-options.javascript_xo_use_global* *g:ale_javascript_xo_use_global* *b:ale_javascript_xo_use_global* javascript_xo_use_global g:ale_javascript_xo_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-jinja.txt ================================================ =============================================================================== ALE Jinja Integration *ale-jinja-options* =============================================================================== djlint *ale-jinja-djlint* See |ale-html-djlint| =============================================================================== j2lint *ale-jinja-j2lint* =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-json.txt ================================================ =============================================================================== ALE JSON Integration *ale-json-options* =============================================================================== biome *ale-json-biome* Check the docs over at |ale-typescript-biome|. =============================================================================== clang-format *ale-json-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for JSON. =============================================================================== cspell *ale-json-cspell* See |ale-cspell-options| =============================================================================== dprint *ale-json-dprint* See |ale-dprint-options| and https://dprint.dev/plugins/json =============================================================================== eslint *ale-json-eslint* The `eslint` linter for JSON uses the JavaScript options for `eslint`; see: |ale-javascript-eslint|. You will need a JSON ESLint plugin installed for this to work. =============================================================================== fixjson *ale-json-fixjson* fixjson is a JSON file fixer/formatter for humans using (relaxed) JSON5. It provides: - Pretty-prints JSON input - Fixes various failures while humans writing JSON - Fixes trailing commas objects or arrays - Fixes missing commas for elements of objects or arrays - Adds quotes to keys in objects - Newlines in strings - Hex numbers - Fixes single quotes to double quotes You can install it using npm: > $ npm install -g fixjson < ALE provides fixjson integration as a fixer. See |ale-fix|. ------------------------------------------------------------------------------- Options *ale-options.json_fixjson_executable* *g:ale_json_fixjson_executable* *b:ale_json_fixjson_executable* json_fixjson_executable g:ale_json_fixjson_executable Type: |String| Default: `'fixjson'` The executable that will be run for fixjson. *ale-options.json_fixjson_options* *g:ale_json_fixjson_options* *b:ale_json_fixjson_options* json_fixjson_options g:ale_json_fixjson_options Type: |String| Default: `''` This variable can add extra options to the command executed for running fixjson. *ale-options.json_fixjson_use_global* *g:ale_json_fixjson_use_global* *b:ale_json_fixjson_use_global* json_fixjson_use_global g:ale_json_fixjson_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== pytool *ale-json-pytool* Use python's json.tool module to reformat json. *ale-options.json_pytool_executable* *g:ale_json_pytool_executable* *b:ale_json_pytool_executable* json_pytool_executable g:ale_json_pytool_executable Type: |String| Default: `'python'` The python executable that run to use its json.tool module. This fixer requires python 3, which includes the json module. *ale-options.json_pytool_options* *g:ale_json_pytool_options* *b:ale_json_pytool_options* json_pytool_options g:ale_json_pytool_options Type: |String| Default: `''` These options are passed to the json.tool module. Example: > let g:ale_json_pytool_options = '--sort-keys --indent 2' < See docs for all options: https://docs.python.org/3/library/json.html#module-json.tool *ale-options.json_pytool_use_global* *g:ale_json_pytool_use_global* *b:ale_json_pytool_use_global* json_pytool_use_global g:ale_json_pytool_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== jsonlint *ale-json-jsonlint* *ale-options.json_jsonlint_executable* *g:ale_json_jsonlint_executable* *b:ale_json_jsonlint_executable* json_jsonlint_executable g:ale_json_jsonlint_executable Type: |String| Default: `'jsonlint'` The executable that will be run for jsonlint. *ale-options.json_jsonlint_use_global* *g:ale_json_jsonlint_use_global* *b:ale_json_jsonlint_use_global* json_jsonlint_use_global g:ale_json_jsonlint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== jq *ale-json-jq* *ale-options.json_jq_executable* *g:ale_json_jq_executable* *b:ale_json_jq_executable* json_jq_executable g:ale_json_jq_executable Type: |String| Default: `'jq'` This option can be changed to change the path for `jq`. *ale-options.json_jq_options* *g:ale_json_jq_options* *b:ale_json_jq_options* json_jq_options g:ale_json_jq_options Type: |String| Default: `''` This option can be changed to pass extra options to `jq`. *ale-options.json_jq_filters* *g:ale_json_jq_filters* *b:ale_json_jq_filters* json_jq_filters g:ale_json_jq_filters Type: |String| Default: `'.'` This option can be changed to pass custom filters to `jq`. =============================================================================== prettier *ale-json-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== spectral *ale-json-spectral* Website: https://github.com/stoplightio/spectral ------------------------------------------------------------------------------- Installation Install spectral either globally or locally: > npm install @stoplight/spectral -g # global npm install @stoplight/spectral # local < ------------------------------------------------------------------------------- Options *ale-options.json_spectral_executable* *g:ale_json_spectral_executable* *b:ale_json_spectral_executable* json_spectral_executable g:ale_json_spectral_executable Type: |String| Default: `'spectral'` This variable can be set to change the path to spectral. *ale-options.json_spectral_use_global* *g:ale_json_spectral_use_global* *b:ale_json_spectral_use_global* json_spectral_use_global g:ale_json_spectral_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vscodejson *ale-json-vscode* Website: https://github.com/hrsh7th/vscode-langservers-extracted ------------------------------------------------------------------------------- Installation Install VSCode json language server either globally or locally: > npm install -g vscode-langservers-extracted < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-json5.txt ================================================ =============================================================================== ALE JSON5 Integration *ale-json5-options* =============================================================================== eslint *ale-json5-eslint* The `eslint` linter for JSON uses the JavaScript options for `eslint`; see: |ale-javascript-eslint|. You will need a JSON5 ESLint plugin installed for this to work. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-jsonc.txt ================================================ =============================================================================== ALE JSONC Integration *ale-jsonc-options* =============================================================================== biome *ale-jsonc-biome* Check the docs over at |ale-typescript-biome|. =============================================================================== eslint *ale-jsonc-eslint* The `eslint` linter for JSON uses the JavaScript options for `eslint`; see: |ale-javascript-eslint|. You will need a JSONC ESLint plugin installed for this to work. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-jsonnet.txt ================================================ =============================================================================== ALE Jsonnet Integration *ale-jsonnet-options* =============================================================================== jsonnetfmt *ale-jsonnet-jsonnetfmt* *ale-options.jsonnet_jsonnetfmt_executable* *g:ale_jsonnet_jsonnetfmt_executable* *b:ale_jsonnet_jsonnetfmt_executable* jsonnet_jsonnetfmt_executable g:ale_jsonnet_jsonnetfmt_executable Type: |String| Default: `'jsonnetfmt'` This option can be changed to change the path for `jsonnetfmt`. *ale-options.jsonnet_jsonnetfmt_options* *g:ale_jsonnet_jsonnetfmt_options* *b:ale_jsonnet_jsonnetfmt_options* jsonnet_jsonnetfmt_options g:ale_jsonnet_jsonnetfmt_options Type: |String| Default: `''` This option can be changed to pass extra options to `jsonnetfmt`. =============================================================================== jsonnet-lint *ale-jsonnet-jsonnet-lint* *ale-options.jsonnet_jsonnet_lint_executable* *g:ale_jsonnet_jsonnet_lint_executable* *b:ale_jsonnet_jsonnet_lint_executable* jsonnet_jsonnet_lint_executable g:ale_jsonnet_jsonnet_lint_executable Type: |String| Default: `'jsonnet-lint'` This option can be changed to change the path for `jsonnet-lint`. *ale-options.jsonnet_jsonnet_lint_options* *g:ale_jsonnet_jsonnet_lint_options* *b:ale_jsonnet_jsonnet_lint_options* jsonnet_jsonnet_lint_options g:ale_jsonnet_jsonnet_lint_options Type: |String| Default: `''` This option can be changed to pass extra options to `jsonnet-lint`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-julia.txt ================================================ =============================================================================== 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. *ale-options.julia_executable* *g:ale_julia_executable* *b:ale_julia_executable* julia_executable g:ale_julia_executable Type: |String| Default: `'julia'` Path to the julia exetuable. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-kotlin.txt ================================================ =============================================================================== ALE Kotlin Integration *ale-kotlin-options* *ale-integration-kotlin* =============================================================================== Integration Information Make sure your setup has support for the kotlin file type. A filetype plugin can be found here: https://github.com/udalov/kotlin-vim Note: Make sure you have a working kotlin compiler =============================================================================== kotlinc *ale-kotlin-kotlinc* *ale-options.kotlin_kotlinc_options* *g:ale_kotlin_kotlinc_options* *b:ale_kotlin_kotlinc_options* kotlin_kotlinc_options g:ale_kotlin_kotlinc_options Type: |String| Default: `''` Additional options to pass to the kotlin compiler *ale-options.kotlin_kotlinc_enable_config* *g:ale_kotlin_kotlinc_enable_config* *b:ale_kotlin_kotlinc_enable_config* kotlin_kotlinc_enable_config g:ale_kotlin_kotlinc_enable_config Type: |Number| Default: `0` Setting this variable to `1` tells the linter to load a configuration file. This should be set in your vimrc *ale-options.kotlin_kotlinc_config_file* *g:ale_kotlin_kotlinc_config_file* *b:ale_kotlin_kotlinc_config_file* kotlin_kotlinc_config_file g:ale_kotlin_kotlinc_config_file Type: |String| Default: `'.ale_kotlin_kotlinc_config'` Filename of the configuration file. This should be set in your vimrc *ale-options.kotlin_kotlinc_classpath* *g:ale_kotlin_kotlinc_classpath* *b:ale_kotlin_kotlinc_classpath* kotlin_kotlinc_classpath g:ale_kotlin_kotlinc_classpath Type: |String| Default: `''` A string containing the paths (separated by the appropriate path separator) of the source directories. *ale-options.kotlin_kotlinc_sourcepath* *g:ale_kotlin_kotlinc_sourcepath* *b:ale_kotlin_kotlinc_sourcepath* kotlin_kotlinc_sourcepath g:ale_kotlin_kotlinc_sourcepath Type: |String| Default: `''` A string containing the paths (separated by space) of the source directories. *ale-options.kotlin_kotlinc_use_module_file* *g:ale_kotlin_kotlinc_use_module_file* *b:ale_kotlin_kotlinc_use_module_file* kotlin_kotlinc_use_module_file g:ale_kotlin_kotlinc_use_module_file Type: |Number| Default: `0` This option indicates whether the linter should use a module file. It is off by default. *ale-options.kotlin_kotlinc_module_filename* *g:ale_kotlin_kotlinc_module_filename* *b:ale_kotlin_kotlinc_module_filename* kotlin_kotlinc_module_filename g:ale_kotlin_kotlinc_module_filename Type: |String| Default: `'module.xml'` The filename of the module file that the linter should pass to the kotlin compiler. =============================================================================== ktlint *ale-kotlin-ktlint* *ale-options.kotlin_ktlint_executable* *g:ale_kotlin_ktlint_executable* *b:ale_kotlin_ktlint_executable* kotlin_ktlint_executable g:ale_kotlin_ktlint_executable Type: |String| Default: `''` The Ktlint executable. Posix-compliant shell scripts are the only executables that can be found on Ktlint's github release page. If you are not on such a system, your best bet will be to download the ktlint jar and set this option to something similar to `'java -jar /path/to/ktlint.jar'` *ale-options.kotlin_ktlint_rulesets* *g:ale_kotlin_ktlint_rulesets* *b:ale_kotlin_ktlint_rulesets* kotlin_ktlint_rulesets g:ale_kotlin_ktlint_rulesets Type: |List| Default: `[]` This list should contain paths to ruleset jars and/or strings of maven artifact triples. Example: > let g:ale_kotlin_ktlint_rulesets = ['/path/to/custom-ruleset.jar', 'com.ktlint.rulesets:mycustomrule:1.0.0'] < *ale-options.kotlin_ktlint_options* *g:ale_kotlin_ktlint_options* *b:ale_kotlin_ktlint_options* kotlin_ktlint_options g:ale_kotlin_ktlint_options Type: |String| Default: `''` Options to pass to ktlint for both linting and fixing. For example: > let g:ale_kotlin_ktlint_options = '--android' < =============================================================================== languageserver *ale-kotlin-languageserver* *ale-options.kotlin_languageserver_executable* *g:ale_kotlin_languageserver_executable* *b:ale_kotlin_languageserver_executable* kotlin_languageserver_executable g:ale_kotlin_languageserver_executable Type: |String| Default: `''` The kotlin-language-server executable. Executables are located inside the bin/ folder of the language server release. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-latex.txt ================================================ =============================================================================== ALE LaTeX Integration *ale-latex-options* =============================================================================== cspell *ale-latex-cspell* =============================================================================== write-good *ale-latex-write-good* See |ale-write-good-options| =============================================================================== textlint *ale-latex-textlint* See |ale-text-textlint| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-lean.txt ================================================ =============================================================================== ALE Lean Integration *ale-lean-options* *ale-integration-lean* =============================================================================== Integration Information Currently, the only supported LSP for Lean 4 is lake. =============================================================================== lake *ale-lean-lake* g:ale_lean_lake_executable *g:ale_lean_lake_executable* *b:ale_lean_lake_executable* Type: |String| Default: `'lake'` This variable can be modified to change the executable path for `lake`. g:ale_lean_lake_config *g:ale_lean_lake_config* *b:ale_lean_lake_config* Type: |Dictionary| Default: `{}` Dictionary with configuration settings for lake. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-less.txt ================================================ =============================================================================== ALE Less Integration *ale-less-options* =============================================================================== lessc *ale-less-lessc* *ale-options.less_lessc_executable* *g:ale_less_lessc_executable* *b:ale_less_lessc_executable* less_lessc_executable g:ale_less_lessc_executable Type: |String| Default: `'lessc'` See |ale-integrations-local-executables| *ale-options.less_lessc_options* *g:ale_less_lessc_options* *b:ale_less_lessc_options* less_lessc_options g:ale_less_lessc_options Type: |String| Default: `''` This variable can be set to pass additional options to lessc. *ale-options.less_lessc_use_global* *g:ale_less_lessc_use_global* *b:ale_less_lessc_use_global* less_lessc_use_global g:ale_less_lessc_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== prettier *ale-less-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== stylelint *ale-less-stylelint* *ale-options.less_stylelint_executable* *g:ale_less_stylelint_executable* *b:ale_less_stylelint_executable* less_stylelint_executable g:ale_less_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.less_stylelint_options* *g:ale_less_stylelint_options* *b:ale_less_stylelint_options* less_stylelint_options g:ale_less_stylelint_options Type: |String| Default: `''` This variable can be set to pass additional options to stylelint. *ale-options.less_stylelint_use_global* *g:ale_less_stylelint_use_global* *b:ale_less_stylelint_use_global* less_stylelint_use_global g:ale_less_stylelint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-llvm.txt ================================================ =============================================================================== ALE LLVM Integration *ale-llvm-options* =============================================================================== llc *ale-llvm-llc* *ale-options.llvm_llc_executable* *g:ale_llvm_llc_executable* *b:ale_llvm_llc_executable* llvm_llc_executable g:ale_llvm_llc_executable Type: |String| Default: `"llc"` The command to use for checking. This variable is useful when llc command has suffix like "llc-5.0". =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-lua.txt ================================================ =============================================================================== ALE Lua Integration *ale-lua-options* =============================================================================== cspell *ale-lua-cspell* See |ale-cspell-options| =============================================================================== lua-format *ale-lua-lua-format* *ale-options.lua_lua_format_executable* *g:ale_lua_lua_format_executable* *b:ale_lua_lua_format_executable* lua_lua_format_executable g:ale_lua_lua_format_executable Type: |String| Default: `'lua-format'` This variable can be changed to change the path to lua-format. *ale-options.lua_lua_format_options* *g:ale_lua_lua_format_options* *b:ale_lua_lua_format_options* lua_lua_format_options g:ale_lua_lua_format_options Type: |String| Default: `''` This variable can be set to pass additional options to lua-format. =============================================================================== lua-language-server *ale-lua-lua-language-server* *ale-lua-language-server* *ale-options.lua_language_server_executable* *g:ale_lua_language_server_executable* *b:ale_lua_language_server_executable* lua_language_server_executable g:ale_lua_language_server_executable Type: |String| Default: `'lua-language-server'` This variable can be changed to set the path to lua-language-server. If you have compiled the language server yourself in `/some/path`, the path will be `'/some/path/bin/lua-language-server'`. *ale-options.lua_language_server_config* *g:ale_lua_language_server_config* *b:ale_lua_language_server_config* lua_language_server_config g:ale_lua_language_server_config Type: |Dictionary| Default: `{}` Dictionary containing configuration settings that will be passed to the language server. For available configuration parameters, see `Settings` on the luals wiki: https://luals.github.io/wiki/settings/ =============================================================================== luac *ale-lua-luac* *ale-options.lua_luac_executable* *g:ale_lua_luac_executable* *b:ale_lua_luac_executable* lua_luac_executable g:ale_lua_luac_executable Type: |String| Default: `'luac'` This variable can be changed to change the path to luac. =============================================================================== luacheck *ale-lua-luacheck* *ale-options.lua_luacheck_executable* *g:ale_lua_luacheck_executable* *b:ale_lua_luacheck_executable* lua_luacheck_executable g:ale_lua_luacheck_executable Type: |String| Default: `'luacheck'` This variable can be changed to change the path to luacheck. *ale-options.lua_luacheck_options* *g:ale_lua_luacheck_options* *b:ale_lua_luacheck_options* lua_luacheck_options g:ale_lua_luacheck_options Type: |String| Default: `''` This variable can be set to pass additional options to luacheck. =============================================================================== luafmt *ale-lua-luafmt* *ale-options.lua_luafmt_executable* *g:ale_lua_luafmt_executable* *b:ale_lua_luafmt_executable* lua_luafmt_executable g:ale_lua_luafmt_executable Type: |String| Default: `'luafmt'` This variable can be set to use a different executable for luafmt. *ale-options.lua_luafmt_options* *g:ale_lua_luafmt_options* *b:ale_lua_luafmt_options* lua_luafmt_options g:ale_lua_luafmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the luafmt fixer. =============================================================================== selene *ale-lua-selene* *ale-options.lua_selene_executable* *g:ale_lua_selene_executable* *b:ale_lua_selene_executable* lua_selene_executable g:ale_lua_selene_executable Type: |String| Default: `'selene'` This variable can be set to use a different executable for selene. *ale-options.lua_selene_options* *g:ale_lua_selene_options* *b:ale_lua_selene_options* lua_selene_options g:ale_lua_selene_options Type: |String| Default: `''` This variable can be set to pass additional options to selene. =============================================================================== stylua *ale-lua-stylua* *ale-options.lua_stylua_executable* *g:ale_lua_stylua_executable* *b:ale_lua_stylua_executable* lua_stylua_executable g:ale_lua_stylua_executable Type: |String| Default: `'stylua'` This variable can be set to use a different executable for stylua. *ale-options.lua_stylua_options* *g:ale_lua_stylua_options* *b:ale_lua_stylua_options* lua_stylua_options g:ale_lua_stylua_options Type: |String| Default: `''` This variable can be set to pass additional options to the stylua fixer. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-make.txt ================================================ =============================================================================== ALE Make Integration *ale-make-options* =============================================================================== checkmake *ale-make-checkmake* *ale-options.make_checkmake_config* *g:ale_make_checkmake_config* *b:ale_make_checkmake_config* make_checkmake_config g:ale_make_checkmake_config Type: |String| Default: `''` This variable can be used to set the `--config` option of checkmake command. if the value is empty, the checkmake command will not be invoked with the option. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-markdown.txt ================================================ =============================================================================== ALE Markdown Integration *ale-markdown-options* =============================================================================== cspell *ale-markdown-cspell* See |ale-cspell-options| =============================================================================== dprint *ale-markdown-dprint* See |ale-dprint-options| and https://dprint.dev/plugins/markdown =============================================================================== markdownlint *ale-markdown-markdownlint* *ale-options.markdown_markdownlint_executable* *g:ale_markdown_markdownlint_executable* *b:ale_markdown_markdownlint_executable* markdown_markdownlint_executable g:ale_markdown_markdownlint_executable Type: |String| Default: `'markdownlint'` Override the invoked `markdownlint` binary. You can use other binaries such as `markdownlint-cli2`. *ale-options.markdown_markdownlint_options* *g:ale_markdown_markdownlint_options* *b:ale_markdown_markdownlint_options* markdown_markdownlint_options g:ale_markdown_markdownlint_options Type: |String| Default: `''` This variable can be set to pass additional options to markdownlint. =============================================================================== marksman *ale-markdown-marksman* *ale-options.markdown_marksman_executable* *g:ale_markdown_marksman_executable* *b:ale_markdown_marksman_executable* markdown_marksman_executable g:ale_markdown_marksman_executable Type: |String| Default: `'marksman'` Override the invoked `marksman` binary. =============================================================================== mdl *ale-markdown-mdl* *ale-options.markdown_mdl_executable* *g:ale_markdown_mdl_executable* *b:ale_markdown_mdl_executable* markdown_mdl_executable g:ale_markdown_mdl_executable Type: |String| Default: `'mdl'` Override the invoked mdl binary. This is useful for running mdl from binstubs or a bundle. *ale-options.markdown_mdl_options* *g:ale_markdown_mdl_options* *b:ale_markdown_mdl_options* markdown_mdl_options g:ale_markdown_mdl_options Type: |String| Default: `''` This variable can be set to pass additional options to mdl. =============================================================================== pandoc *ale-markdown-pandoc* *ale-options.markdown_pandoc_executable* *g:ale_markdown_pandoc_executable* *b:ale_markdown_pandoc_executable* markdown_pandoc_executable g:ale_markdown_pandoc_executable Type: |String| Default: `'pandoc'` This variable can be set to specify where to find the pandoc executable *ale-options.markdown_pandoc_options* *g:ale_markdown_pandoc_options* *b:ale_markdown_pandoc_options* markdown_pandoc_options g:ale_markdown_pandoc_options Type: |String| Default: `'-f gfm -t gfm -s -'` This variable can be set to change the default options passed to pandoc =============================================================================== prettier *ale-markdown-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== pymarkdown *ale-markdown-pymarkdown* pymarkdown can be used both as a linter and a fixer for Markdown files. *ale-options.markdown_pymarkdown_executable* *g:ale_markdown_pymarkdown_executable* *b:ale_markdown_pymarkdown_executable* markdown_pymarkdown_executable g:ale_markdown_pymarkdown_executable Type: |String| Default: `'pymarkdown'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pymarkdown'`. Set this to `'poetry'` to invoke `'poetry` `run` `pymarkdown'`. *ale-options.markdown_pymarkdown_options* *g:ale_markdown_pymarkdown_options* *b:ale_markdown_pymarkdown_options* markdown_pymarkdown_options g:ale_markdown_pymarkdown_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pymarkdown invocation. *ale-options.markdown_pymarkdown_use_global* *g:ale_markdown_pymarkdown_use_global* *b:ale_markdown_pymarkdown_use_global* markdown_pymarkdown_use_global g:ale_markdown_pymarkdown_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.markdown_pymarkdown_auto_pipenv* *g:ale_markdown_pymarkdown_auto_pipenv* *b:ale_markdown_pymarkdown_auto_pipenv* markdown_pymarkdown_auto_pipenv g:ale_markdown_pymarkdown_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-options.markdown_pymarkdown_auto_poetry* *g:ale_markdown_pymarkdown_auto_poetry* *b:ale_markdown_pymarkdown_auto_poetry* markdown_pymarkdown_auto_poetry g:ale_markdown_pymarkdown_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.markdown_pymarkdown_auto_uv* *g:ale_markdown_pymarkdown_auto_uv* *b:ale_markdown_pymarkdown_auto_uv* markdown_pymarkdown_auto_uv g:ale_markdown_pymarkdown_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== remark-lint *ale-markdown-remark-lint* *ale-options.markdown_remark_lint_executable* *g:ale_markdown_remark_lint_executable* *b:ale_markdown_remark_lint_executable* markdown_remark_lint_executable g:ale_markdown_remark_lint_executable Type: |String| Default: `'remark'` See |ale-integrations-local-executables| *ale-options.markdown_remark_lint_options* *g:ale_markdown_remark_lint_options* *b:ale_markdown_remark_lint_options* markdown_remark_lint_options g:ale_markdown_remark_lint_options Type: |String| Default: `''` This variable can be set to pass additional options to remark-lint. *ale-options.markdown_remark_lint_use_global* *g:ale_markdown_remark_lint_use_global* *b:ale_markdown_remark_lint_use_global* markdown_remark_lint_use_global g:ale_markdown_remark_lint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== textlint *ale-markdown-textlint* See |ale-text-textlint| =============================================================================== write-good *ale-markdown-write-good* See |ale-write-good-options| =============================================================================== redpen *ale-markdown-redpen* See |ale-redpen-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-mercury.txt ================================================ =============================================================================== ALE Mercury Integration *ale-mercury-options* =============================================================================== mmc *ale-mercury-mmc* *ale-options.mercury_mmc_executable* *g:ale_mercury_mmc_executable* *b:ale_mercury_mmc_executable* mercury_mmc_executable g:ale_mercury_mmc_executable Type: |String| Default: `'mmc'` This variable can be changed to use a different executable for mmc. *ale-options.mercury_mmc_options* *g:ale_mercury_mmc_options* *b:ale_mercury_mmc_options* mercury_mmc_options g:ale_mercury_mmc_options Type: |String| Default: `'--make --output-compile-error-lines 100'` This variable can be set to pass additional options to mmc. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-nasm.txt ================================================ =============================================================================== ALE NASM Integration *ale-nasm-options* =============================================================================== nasm *ale-nasm-nasm* *ale-options.nasm_nasm_executable* *g:ale_nasm_nasm_executable* *b:ale_nasm_nasm_executable* nasm_nasm_executable g:ale_nasm_nasm_executable Type: |String| Default `'nasm'` This variable can be changed to use different executable for NASM. *ale-options.nasm_nasm_options* *g:ale_nasm_nasm_options* *b:ale_nasm_nasm_options* nasm_nasm_options g:ale_nasm_nasm_options Type: |String| Default: `''` This variable can be set to pass additional options to NASM. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-nickel.txt ================================================ =============================================================================== ALE Nickel Integration *ale-nickel-options* =============================================================================== nickel_format *ale-nickel-nickel-format* *ale-options.nickel_nickel_format_executable* *g:ale_nickel_nickel_format_executable* *b:ale_nickel_nickel_format_executable* nickel_nickel_format_executable g:ale_nickel_nickel_format_executable Type: |String| Default: `'nickel'` This option can be changed to change the path for `nickel`. *ale-options.nickel_nickel_format_options* *g:ale_nickel_nickel_format_options* *b:ale_nickel_nickel_format_options* nickel_nickel_format_options g:ale_nickel_nickel_format_options Type: |String| Default: `''` This option can be changed to pass extra options to `'nickel format'` =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-nim.txt ================================================ =============================================================================== ALE Nim Integration *ale-nim-options* =============================================================================== nimcheck *ale-nim-nimcheck* ALE does not provide additional configuration options for `nimcheck` at this point. =============================================================================== nimlsp *ale-nim-nimlsp* *ale-options.nim_nimlsp_nim_sources* *g:ale_nim_nimlsp_nim_sources* *b:ale_nim_nimlsp_nim_sources* g:ale_nim_nimlsp_nim_sources Type: |String| Default: `''` Sets the path to Nim source repository as the first argument to `nimlsp` command. =============================================================================== nimpretty *ale-nim-nimpretty* *ale-options.nim_nimpretty_executable* *g:ale_nim_nimpretty_executable* *b:ale_nim_nimpretty_executable* nim_nimpretty_executable g:ale_nim_nimpretty_executable Type: |String| Default: `'nimpretty'` This variable can be changed to use a different executable for nimpretty. *ale-options.nim_nimpretty_options* *g:ale_nim_nimpretty_options* *b:ale_nim_nimpretty_options* nim_nimpretty_options g:ale_nim_nimpretty_options Type: |String| Default: `'--maxLineLen:80'` This variable can be changed to modify flags given to nimpretty. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-nix.txt ================================================ =============================================================================== ALE Nix Integration *ale-nix-options* =============================================================================== alejandra *ale-nix-alejandra* *ale-options.nix_alejandra_executable* *g:ale_nix_alejandra_executable* *b:ale_nix_alejandra_executable* nix_alejandra_executable g:ale_nix_alejandra_executable Type: |String| Default: `'alejandra'` This variable sets the executable used for alejandra. *ale-options.nix_alejandra_options* *g:ale_nix_alejandra_options* *b:ale_nix_alejandra_options* nix_alejandra_options g:ale_nix_alejandra_options Type: |String| Default: `''` This variable can be set to pass additional options to the alejandra fixer. =============================================================================== nixfmt *ale-nix-nixfmt* *ale-options.nix_nixfmt_executable* *g:ale_nix_nixfmt_executable* *b:ale_nix_nixfmt_executable* nix_nixfmt_executable g:ale_nix_nixfmt_executable Type: |String| Default: `'nixfmt'` This variable sets the executable used for nixfmt. *ale-options.nix_nixfmt_options* *g:ale_nix_nixfmt_options* *b:ale_nix_nixfmt_options* nix_nixfmt_options g:ale_nix_nixfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the nixfmt fixer. =============================================================================== nixpkgs-fmt *ale-nix-nixpkgs-fmt* *ale-options.nix_nixpkgsfmt_executable* *g:ale_nix_nixpkgsfmt_executable* *b:ale_nix_nixpkgsfmt_executable* nix_nixpkgsfmt_executable g:ale_nix_nixpkgsfmt_executable Type: |String| Default: `'nixpkgs-fmt'` This variable sets executable used for nixpkgs-fmt. *ale-options.nix_nixpkgsfmt_options* *g:ale_nix_nixpkgsfmt_options* *b:ale_nix_nixpkgsfmt_options* nix_nixpkgsfmt_options g:ale_nix_nixpkgsfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the nixpkgs-fmt fixer. =============================================================================== statix *ale-nix-statix* *ale-options.nix_statix_check_executable* *g:ale_nix_statix_check_executable* *b:ale_nix_statix_check_executable* nix_statix_check_executable g:ale_nix_statix_check_executable Type: |String| Default: `'statix'` This variable sets the executable used for statix when running it as a linter. *ale-options.nix_statix_check_options* *g:ale_nix_statix_check_options* *b:ale_nix_statix_check_options* nix_statix_check_options g:ale_nix_statix_check_options Type: |String| Default: `''` This variable can be used to pass additional options to statix when running it as a linter. *ale-options.nix_statix_fix_executable* *g:ale_nix_statix_fix_executable* *b:ale_nix_fix_check_executable* nix_statix_fix_executable g:ale_nix_statix_fix_executable Type: |String| Default: `'statix'` This variable sets the executable used for statix when running it as a fixer. *ale-options.nix_statix_fix_options* *g:ale_nix_statix_fix_options* *b:ale_nix_statix_fix_options* nix_statix_fix_options g:ale_nix_statix_fix_options Type: |String| Default: `''` This variable can be used to pass additional options to statix when running it as a fixer. =============================================================================== deadnix *ale-nix-deadnix* *ale-options.nix_deadnix_executable* *g:ale_nix_deadnix_executable* *b:ale_nix_deadnix_executable* nix_deadnix_executable g:ale_nix_deadnix_executable Type: |String| Default: `'deadnix'` This variable sets the executable used for deadnix. *ale-options.nix_deadnix_options* *g:ale_nix_deadnix_options* *b:ale_nix_deadnix_options* nix_deadnix_options g:ale_nix_deadnix_options Type: |String| Default: `''` This variable can be used to pass additional options to deadnix. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-nroff.txt ================================================ =============================================================================== ALE nroff Integration *ale-nroff-options* =============================================================================== write-good *ale-nroff-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-nunjucks.txt ================================================ =============================================================================== ALE Nunjucks Integration *ale-nunjucks-options* =============================================================================== djlint *ale-nunjucks-djlint* See |ale-html-djlint| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-objc.txt ================================================ =============================================================================== ALE Objective-C Integration *ale-objc-options* =============================================================================== ccls *ale-objc-ccls* *ale-options.objc_ccls_executable* *g:ale_objc_ccls_executable* *b:ale_objc_ccls_executable* objc_ccls_executable g:ale_objc_ccls_executable Type: |String| Default: `'ccls'` This variable can be changed to use a different executable for ccls. *ale-options.objc_ccls_init_options* *g:ale_objc_ccls_init_options* *b:ale_objc_ccls_init_options* objc_ccls_init_options g:ale_objc_ccls_init_options Type: |Dictionary| Default: `{}` This variable can be changed to customize ccls initialization options. Example: > let g:ale_objc_ccls_init_options = { \ '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. =============================================================================== clang *ale-objc-clang* *ale-options.objc_clang_options* *g:ale_objc_clang_options* *b:ale_objc_clang_options* objc_clang_options g:ale_objc_clang_options Type: |String| Default: `'-std=c11 -Wall'` This variable can be changed to modify flags given to clang. =============================================================================== clang-format *ale-objc-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for Objective-C. =============================================================================== clangd *ale-objc-clangd* *ale-options.objc_clangd_executable* *g:ale_objc_clangd_executable* *b:ale_objc_clangd_executable* objc_clangd_executable g:ale_objc_clangd_executable Type: |String| Default: `'clangd'` This variable can be changed to use a different executable for clangd. *ale-options.objc_clangd_options* *g:ale_objc_clangd_options* *b:ale_objc_clangd_options* objc_clangd_options g: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. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-objcpp.txt ================================================ =============================================================================== ALE Objective-C++ Integration *ale-objcpp-options* =============================================================================== clang *ale-objcpp-clang* *ale-options.objcpp_clang_options* *g:ale_objcpp_clang_options* *b:ale_objcpp_clang_options* objcpp_clang_options g:ale_objcpp_clang_options Type: |String| Default: `'-std=c++14 -Wall'` This variable can be changed to modify flags given to clang. =============================================================================== clangd *ale-objcpp-clangd* *ale-options.objcpp_clangd_executable* *g:ale_objcpp_clangd_executable* *b:ale_objcpp_clangd_executable* objcpp_clangd_executable g:ale_objcpp_clangd_executable Type: |String| Default: `'clangd'` This variable can be changed to use a different executable for clangd. *ale-options.objcpp_clangd_options* *g:ale_objcpp_clangd_options* *b:ale_objcpp_clangd_options* objcpp_clangd_options g: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: ================================================ FILE: doc/ale-ocaml.txt ================================================ =============================================================================== ALE OCaml Integration *ale-ocaml-options* =============================================================================== dune *ale-ocaml-dune* Dune is a build system for OCaml projects. The `dune format` command is supported for automatically formatting `dune` and `dune-project` files. *ale-options.ocaml_dune_executable* *g:ale_ocaml_dune_executable* *b:ale_ocaml_dune_executable* ocaml_dune_executable g:ale_ocaml_dune_executable Type: |String| Default: `'dune'` This variable can be set to pass the path to dune. *ale-options.ocaml_dune_options* *g:ale_ocaml_dune_options* *b:ale_ocaml_dune_options* ocaml_dune_options g:ale_ocaml_dune_options Type: |String| Default: `''` This variable can be set to pass additional options to the dune fixer. =============================================================================== merlin *ale-ocaml-merlin* To use merlin linter for OCaml source code you need to make sure Merlin for Vim is correctly configured. See the corresponding Merlin wiki page for detailed instructions (https://github.com/the-lambda-church/merlin/wiki/vim-from-scratch). =============================================================================== ocamllsp *ale-ocaml-ocamllsp* The `ocaml-lsp-server` is the official OCaml implementation of the Language Server Protocol. See the installation instructions: https://github.com/ocaml/ocaml-lsp#installation *ale-options.ocaml_ocamllsp_use_opam* *g:ale_ocaml_ocamllsp_use_opam* *b:ale_ocaml_ocamllsp_use_opam* ocaml_ocamllsp_use_opam g:ale_ocaml_ocamllsp_use_opam Type: |Number| Default: `get(g:, 'ale_ocaml_ocamllsp_use_opam', 1)` This variable can be set to change whether or not opam is used to execute the language server. =============================================================================== ols *ale-ocaml-ols* The `ocaml-language-server` is the engine that powers OCaml and ReasonML editor support using the Language Server Protocol. See the installation instructions: https://github.com/freebroccolo/ocaml-language-server#installation *ale-options.ocaml_ols_executable* *g:ale_ocaml_ols_executable* *b:ale_ocaml_ols_executable* ocaml_ols_executable g:ale_ocaml_ols_executable Type: |String| Default: `'ocaml-language-server'` This variable can be set to change the executable path for `ols`. *ale-options.ocaml_ols_use_global* *g:ale_ocaml_ols_use_global* *b:ale_ocaml_ols_use_global* ocaml_ols_use_global g:ale_ocaml_ols_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` This variable can be set to `1` to always use the globally installed executable. See also |ale-integrations-local-executables|. =============================================================================== ocamlformat *ale-ocaml-ocamlformat* *ale-options.ocaml_ocamlformat_executable* *g:ale_ocaml_ocamlformat_executable* *b:ale_ocaml_ocamlformat_executable* ocaml_ocamlformat_executable g:ale_ocaml_ocamlformat_executable Type: |String| Default: `'ocamlformat'` This variable can be set to pass the path of the ocamlformat fixer. *ale-options.ocaml_ocamlformat_options* *g:ale_ocaml_ocamlformat_options* *b:ale_ocaml_ocamlformat_options* ocaml_ocamlformat_options g:ale_ocaml_ocamlformat_options Type: |String| Default: `''` This variable can be set to pass additional options to the ocamlformat fixer. =============================================================================== ocp-indent *ale-ocaml-ocp-indent* *ale-options.ocaml_ocp_indent_executable* *g:ale_ocaml_ocp_indent_executable* *b:ale_ocaml_ocp_indent_executable* ocaml_ocp_indent_executable g:ale_ocaml_ocp_indent_executable Type: |String| Default: `ocp-indent` This variable can be set to pass the path of the ocp-indent. *ale-options.ocaml_ocp_indent_options* *g:ale_ocaml_ocp_indent_options* *b:ale_ocaml_ocp_indent_options* ocaml_ocp_indent_options g:ale_ocaml_ocp_indent_options Type: |String| Default: `''` This variable can be set to pass additional options to the ocp-indent. *ale-options.ocaml_ocp_indent_config* *g:ale_ocaml_ocp_indent_config* *b:ale_ocaml_ocp_indent_config* ocaml_ocp_indent_config g:ale_ocaml_ocp_indent_config Type: |String| Default: `''` This variable can be set to pass additional config to the ocp-indent. Expand after "--config=". "ocp-indent" can also be enabled from ocamlformat config. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-odin.txt ================================================ =============================================================================== ALE Odin Integration *ale-odin-options* *ale-integration-odin* =============================================================================== ols *ale-odin-ols* *ale-options.odin_ols_executable* *g:ale_odin_ols_executable* *b:ale_odin_ols_executable* odin_ols_executable g:ale_odin_ols_executable Type: |String| Default: `'ols'` This variable can be modified to change the executable path for `ols`. *ale-options.odin_ols_config* *g:ale_odin_ols_config* *b:ale_odin_ols_config* odin_ols_config g:ale_odin_ols_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for ols. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-openapi.txt ================================================ =============================================================================== ALE OpenApi Integration *ale-openapi-options* =============================================================================== ibm_validator *ale-openapi-ibm-validator* Website: https://github.com/IBM/openapi-validator ------------------------------------------------------------------------------- Installation Install ibm-openapi-validator either globally or locally: > npm install ibm-openapi-validator -g # global npm install ibm-openapi-validator # local < ------------------------------------------------------------------------------- Configuration OpenAPI files can be written in YAML or JSON so in order for ALE plugins to work with these files we must set the buffer |filetype| to either |openapi.yaml| or |openapi.json| respectively. This causes ALE to lint the file with linters configured for openapi and yaml files or openapi and json files respectively. For example setting filetype to |openapi.yaml| on a buffer and the following |g:ale_linters| configuration will enable linting of openapi files using both |ibm_validator| and |yamlint|: > let g:ale_linters = { \ 'yaml': ['yamllint'], \ 'openapi': ['ibm_validator'] \} < The following plugin will detect openapi files automatically and set the filetype to |openapi.yaml| or |openapi.json|: https://github.com/hsanson/vim-openapi ------------------------------------------------------------------------------- Options *ale-options.openapi_ibm_validator_executable* *g:ale_openapi_ibm_validator_executable* *b:ale_openapi_ibm_validator_executable* openapi_ibm_validator_executable g:ale_openapi_ibm_validator_executable Type: |String| Default: `'lint-openapi'` This variable can be set to change the path to lint-openapi. *ale-options.openapi_ibm_validator_options* *g:ale_openapi_ibm_validator_options* *b:ale_openapi_ibm_validator_options* openapi_ibm_validator_options g:ale_openapi_ibm_validator_options Type: |String| Default: `''` This variable can be set to pass additional options to lint-openapi. =============================================================================== prettier *ale-openapi-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== yamllint *ale-openapi-yamllint* See |ale-yaml-yamllint| for information about the available options. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-openscad.txt ================================================ =============================================================================== ALE OpenSCAD Integration *ale-openscad-options* =============================================================================== sca2d *ale-openscad-sca2d* *ale-options.openscad_sca2d_executable* *g:ale_openscad_sca2d_executable* *b:ale_openscad_sca2d_executable* openscad_sca2d_executable g:ale_openscad_sca2d_executable Type: |String| Default: `'sca2d'` See |ale-integrations-local-executables| *ale-options.openscad_sca2d_options* *g:ale_openscad_sca2d_options* *b:ale_openscad_sca2d_options* openscad_sca2d_options g:ale_openscad_sca2d_options Type: |String| Default: `''` This variable can be set to pass options to sca2d. =============================================================================== scadformat *ale-openscad-scadformat* *ale-options.openscad_scadformat_executable* *g:ale_openscad_scadformat_executable* *b:ale_openscad_scadformat_executable* openscad_scadformat_executable g:ale_openscad_scadformat_executable Type: |String| Default: `'scadformat'` See |ale-integrations-local-executables| *ale-options.openscad_scadformat_options* *g:ale_openscad_scadformat_options* *b:ale_openscad_scadformat_options* openscad_scadformat_options g:ale_openscad_scadformat_options Type: |String| Default: `''` This variable can be set to pass options to scadformat. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-packer.txt ================================================ =============================================================================== ALE Packer Integration *ale-packer-options* =============================================================================== packer-fmt-fixer *ale-packer-fmt-fixer* *ale-options.packer_fmt_executable* *g:ale_packer_fmt_executable* *b:ale_packer_fmt_executable* packer_fmt_executable g:ale_packer_fmt_executable Type: |String| Default: `'packer'` This variable can be changed to use a different executable for packer. *ale-options.packer_fmt_options* *g:ale_packer_fmt_options* *b:ale_packer_fmt_options* packer_fmt_options g:ale_packer_fmt_options Type: |String| Default: `''` This variable can be set to change command lines options for `packer fmt` =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-pascal.txt ================================================ =============================================================================== ALE Pascal Integration *ale-pascal-options* =============================================================================== ptop *ale-pascal-ptop* *ale-options.pascal_ptop_executable* *g:ale_pascal_ptop_executable* *b:ale_pascal_ptop_executable* pascal_ptop_executable g:ale_pascal_ptop_executable Type: |String| Default: `'ptop'` This variable can be changed to specify the ptop executable. *ale-options.pascal_ptop_options* *g:ale_pascal_ptop_options* *b:ale_pascal_ptop_options* pascal_ptop_options g:ale_pascal_ptop_options Type: |String| Default: `''` This variable can be set to pass additional options to the ptop fixer. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-pawn.txt ================================================ =============================================================================== 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: ================================================ FILE: doc/ale-perl.txt ================================================ =============================================================================== ALE Perl Integration *ale-perl-options* ALE offers a few ways to check Perl code. Checking code with `perl` is disabled by default, as `perl` code cannot be checked without executing it. Specifically, we use the `-c` flag to see if `perl` code compiles. This does not execute all of the code in a file, but it does run `BEGIN` and `CHECK` blocks. See `perl --help` and https://stackoverflow.com/a/12908487/406224 See |g:ale_linters|. =============================================================================== perl *ale-perl-perl* *ale-options.perl_perl_executable* *g:ale_perl_perl_executable* *b:ale_perl_perl_executable* perl_perl_executable g:ale_perl_perl_executable Type: |String| Default: `'perl'` This variable can be changed to modify the executable used for linting perl. *ale-options.perl_perl_options* *g:ale_perl_perl_options* *b:ale_perl_perl_options* perl_perl_options g:ale_perl_perl_options Type: |String| Default: `'-c -Mwarnings -Ilib'` This variable can be changed to alter the command-line arguments to the perl invocation. =============================================================================== perl language server *ale-perl-languageserver* perl_perl_executable g:ale_perl_perl_executable Type: |String| Default: `'perl'` The language server will use the same variable as |ale-perl-perl| to launch the perl executable with the Perl::LanguageServer module. *ale-options.perl_languageserver_config* *g:ale_perl_languageserver_config* *b:ale_perl_languageserver_config* perl_languageserver_config g:ale_perl_languageserver_config Type: |Dictionary| Default: `'{}'` This variable can be changed to customize the lsp_config (sent as a workspace/didChangeConfiguration command). For example: > let g:ale_perl_languageserver_config = { \ 'perl': { \ 'fileFilter': [''], \ 'logLevel': 2, \ 'logFile': '/tmp/plls-log.txt', \ 'perlInc': ['/usr/share/perl5/', '/usr/local/share/perl5/' ], \ }, \} < For all available options and explanations, visit https://metacpan.org/pod/Perl::LanguageServer#Extension-Settings =============================================================================== perlcritic *ale-perl-perlcritic* *ale-options.perl_perlcritic_executable* *g:ale_perl_perlcritic_executable* *b:ale_perl_perlcritic_executable* perl_perlcritic_executable g:ale_perl_perlcritic_executable Type: |String| Default: `'perlcritic'` This variable can be changed to modify the perlcritic executable used for linting perl. *ale-options.perl_perlcritic_profile* *g:ale_perl_perlcritic_profile* *b:ale_perl_perlcritic_profile* perl_perlcritic_profile g:ale_perl_perlcritic_profile Type: |String| Default: `'.perlcriticrc'` This variable can be changed to modify the perlcritic profile used for linting perl. The current directory is checked for the file, then the parent directory, etc, until it finds one. If no matching file is found, no profile is passed to perlcritic. Set to an empty string to disable passing a specific profile to perlcritic with the `'--profile'` option. To prevent perlcritic from using any profile, set this variable to an empty string and pass `'--no-profile'`to perlcritic via the |g:ale_perl_perlcritic_options| variable. *ale-options.perl_perlcritic_options* *g:ale_perl_perlcritic_options* *b:ale_perl_perlcritic_options* perl_perlcritic_options g:ale_perl_perlcritic_options Type: |String| Default: `''` This variable can be changed to supply additional command-line arguments to the perlcritic invocation. *ale-options.perl_perlcritic_showrules* *g:ale_perl_perlcritic_showrules* perl_perlcritic_showrules g:ale_perl_perlcritic_showrules Type: |Number| Default: `0` Controls whether perlcritic rule names are shown after the error message. Defaults to off to reduce length of message. =============================================================================== perltidy *ale-perl-perltidy* *ale-options.perl_perltidy_options* *g:ale_perl_perltidy_options* *b:ale_perl_perltidy_options* perl_perltidy_options g:ale_perl_perltidy_options Type: |String| Default: `''` This variable can be changed to alter the command-line arguments to the perltidy invocation. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-perl6.txt ================================================ =============================================================================== 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* *ale-options.perl6_perl6_executable* *g:ale_perl6_perl6_executable* *b:ale_perl6_perl6_executable* perl6_perl6_executable g:ale_perl6_perl6_executable Type: |String| Default: `'perl6'` This variable can be changed to modify the executable used for linting perl6. *ale-options.perl6_perl6_options* *g:ale_perl6_perl6_options* *b:ale_perl6_perl6_options* perl6_perl6_options g: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: ================================================ FILE: doc/ale-php.txt ================================================ =============================================================================== ALE PHP Integration *ale-php-options* =============================================================================== cspell *ale-php-cspell* See |ale-cspell-options| =============================================================================== langserver *ale-php-langserver* *ale-options.php_langserver_executable* *g:ale_php_langserver_executable* *b:ale_php_langserver_executable* php_langserver_executable g:ale_php_langserver_executable Type: |String| Default: `'php-language-server.php'` The variable can be set to configure the executable that will be used for running the PHP language server. `vendor` directory executables will be preferred instead of this setting if |g:ale_php_langserver_use_global| is `0`. See: |ale-integrations-local-executables| *ale-options.php_langserver_use_global* *g:ale_php_langserver_use_global* *b:ale_php_langserver_use_global* php_langserver_use_global g:ale_php_langserver_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable can be set to `1` to force the language server to be run with the executable set for |g:ale_php_langserver_executable|. See: |ale-integrations-local-executables| =============================================================================== phan *ale-php-phan* WARNING: please use the phan_client linter if you have an configuration file for your project because the phan will look into your entirely project and ale will display in the current buffer warnings that may belong to other file. *ale-options.php_phan_minimum_severity* *g:ale_php_phan_minimum_severity* *b:ale_php_phan_minimum_severity* php_phan_minimum_severity g:ale_php_phan_minimum_severity Type: |Number| Default: `0` This variable defines the minimum severity level. *ale-options.php_phan_executable* *g:ale_php_phan_executable* *b:ale_php_phan_executable* php_phan_executable g:ale_php_phan_executable Type: |String| Default: `'phan'` This variable sets executable used for phan or phan_client. *ale-options.php_phan_use_client* *g:ale_php_phan_use_client* *b:ale_php_phan_use_client* php_phan_use_client g:ale_php_phan_use_client Type: |Number| Default: `get(g:, 'ale_php_phan_use_client', 0)` This variable can be set to 1 to use the phan_client with phan daemon mode instead of the phan standalone. =============================================================================== phpactor *ale-php-phpactor* *ale-options.php_phpactor_executable* *g:ale_php_phpactor_executable* *b:ale_php_phpactor_executable* php_phpactor_executable g:ale_php_phpactor_executable Type: |String| Default: `'phpactor'` This variable sets executable used for phpactor. php_phpactor_init_options g:ale_php_phpactor_init_options Type: |Dictionary| Default: `'{}'` This variable can be changed to customize the LSP initialization_options. For example: > let g:ale_php_phpactor_init_options = { \ 'language_server_phpstan.enabled': v:false, \ 'language_server_psalm.enabled': v:false, \ 'worse_reflection.stub_dir': '%application_root%/.php-stubs' \} < For all available options and explanations, visit https://phpactor.readthedocs.io/en/master/reference/configuration.html =============================================================================== phpcbf *ale-php-phpcbf* *ale-options.php_phpcbf_executable* *g:ale_php_phpcbf_executable* *b:ale_php_phpcbf_executable* php_phpcbf_executable g:ale_php_phpcbf_executable Type: |String| Default: `'phpcbf'` See |ale-integrations-local-executables| *ale-options.php_phpcbf_standard* *g:ale_php_phpcbf_standard* *b:ale_php_phpcbf_standard* php_phpcbf_standard g:ale_php_phpcbf_standard Type: |String| Default: `''` This variable can be set to specify the coding standard used by phpcbf. If no coding standard is specified, phpcbf will default to fixing against the PEAR coding standard, or the standard you have set as the default. *ale-options.php_phpcbf_use_global* *g:ale_php_phpcbf_use_global* *b:ale_php_phpcbf_use_global* php_phpcbf_use_global g:ale_php_phpcbf_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.php_phpcbf_options* *g:ale_php_phpcbf_options* *b:ale_php_phpcbf_options* php_phpcbf_options g:ale_php_phpcbf_options Type: |String| Default: `''` This variable can be set to pass additional options to php-cbf =============================================================================== phpcs *ale-php-phpcs* *ale-options.php_phpcs_executable* *g:ale_php_phpcs_executable* *b:ale_php_phpcs_executable* php_phpcs_executable g:ale_php_phpcs_executable Type: |String| Default: `'phpcs'` See |ale-integrations-local-executables| *ale-options.php_phpcs_standard* *g:ale_php_phpcs_standard* *b:ale_php_phpcs_standard* php_phpcs_standard g:ale_php_phpcs_standard Type: |String| Default: `''` This variable can be set to specify the coding standard used by phpcs. If no coding standard is specified, phpcs will default to checking against the PEAR coding standard, or the standard you have set as the default. *ale-options.php_phpcs_use_global* *g:ale_php_phpcs_use_global* *b:ale_php_phpcs_use_global* php_phpcs_use_global g:ale_php_phpcs_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.php_phpcs_options* *g:ale_php_phpcs_options* *b:ale_php_phpcs_options* php_phpcs_options g:ale_php_phpcs_options Type: |String| Default: `''` This variable can be set to pass additional options to php-cs =============================================================================== phpmd *ale-php-phpmd* *ale-options.php_phpmd_executable* *g:ale_php_phpmd_executable* *b:ale_php_phpmd_executable* php_phpmd_executable g:ale_php_phpmd_executable Type: |String| Default: `'phpmd'` This variable sets executable used for phpmd. *ale-options.php_phpmd_ruleset* *g:ale_php_phpmd_ruleset* *b:ale_php_phpmd_ruleset* php_phpmd_ruleset g:ale_php_phpmd_ruleset Type: |String| Default: `'cleancode,codesize,controversial,design,naming,unusedcode'` This variable controls the ruleset used by phpmd. Default is to use all of the available phpmd rulesets =============================================================================== phpstan *ale-php-phpstan* *ale-options.php_phpstan_executable* *g:ale_php_phpstan_executable* *b:ale_php_phpstan_executable* php_phpstan_executable g:ale_php_phpstan_executable Type: |String| Default: `'phpstan'` This variable sets executable used for phpstan. *ale-options.php_phpstan_level* *g:ale_php_phpstan_level* *b:ale_php_phpstan_level* php_phpstan_level g:ale_php_phpstan_level Type: |String| Default: `''` This variable controls the rule levels. 0 is the loosest and 7 is the strictest. If this option isn't set, the rule level will be controlled by the configuration file. If no configuration file can be detected, `'7'` will be used instead. *ale-options.php_phpstan_configuration* *g:ale_php_phpstan_configuration* *b:ale_php_phpstan_configuration* php_phpstan_configuration g:ale_php_phpstan_configuration Type: |String| Default: `''` This variable sets path to phpstan configuration file. *ale-options.php_phpstan_autoload* *g:ale_php_phpstan_autoload* *b:ale_php_phpstan_autoload* php_phpstan_autoload g:ale_php_phpstan_autoload Type: |String| Default: `''` This variable sets path to phpstan autoload file. *ale-options.php_phpstan_memory_limit* *g:ale_php_phpstan_memory_limit* *b:ale_php_phpstan_memory-limit* php_phpstan_memory_limit g:ale_php_phpstan_memory_limit Type: |String| Default: `''` This variable sets the memory limit for phpstan analysis. This is a string in the same format as `php.ini` accepts, e.g. `128M`, `1G`. =============================================================================== psalm *ale-php-psalm* *ale-options.php_psalm_executable* *g:ale_php_psalm_executable* *b:ale_php_psalm_executable* php_psalm_executable g:ale_php_psalm_executable Type: |String| Default: `'psalm'` This variable sets the executable used for psalm. *ale-options.php_psalm_options* *g:ale_php_psalm_options* *b:ale_php_psalm_options* php_psalm_options g:ale_php_psalm_options Type: |String| Default: `''` This variable can be set to pass additional options to psalm. *ale-options.php_psalm_use_global* *g:ale_php_psalm_use_global* *b:ale_php_psalm_use_global* php_psalm_use_global g:ale_php_psalm_use_global Type: |Boolean| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== php-cs-fixer *ale-php-php-cs-fixer* *ale-options.php_cs_fixer_executable* *g:ale_php_cs_fixer_executable* *b:ale_php_cs_fixer_executable* php_cs_fixer_executable g:ale_php_cs_fixer_executable Type: |String| Default: `'php-cs-fixer'` This variable sets executable used for php-cs-fixer. *ale-options.php_cs_fixer_options* *g:ale_php_cs_fixer_options* *b:ale_php_cs_fixer_options* php_cs_fixer_options g:ale_php_cs_fixer_options Type: |String| Default: `''` This variable can be set to pass additional options to php-cs-fixer. *ale-options.php_cs_fixer_use_global* *g:ale_php_cs_fixer_use_global* *b:ale_php_cs_fixer_use_global* php_cs_fixer_use_global g:ale_php_cs_fixer_use_global Type: |Boolean| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== php *ale-php-php* *ale-options.php_php_executable* *g:ale_php_php_executable* *b:ale_php_php_executable* php_php_executable g:ale_php_php_executable Type: |String| Default: `'php'` This variable sets the executable used for php. =============================================================================== pint *ale-php-pint* *ale-options.php_pint_executable* *g:ale_php_pint_executable* *b:ale_php_pint_executable* php_pint_executable g:ale_php_pint_executable Type: |String| Default: `'pint'` This variable sets the executable used for pint. *ale-options.php_pint_options* *g:ale_php_pint_options* *b:ale_php_pint_options* php_pint_options g:ale_php_pint_options Type: |String| Default: `''` This variable can be set to pass additional options to pint. *ale-options.php_pint_use_global* *g:ale_php_pint_use_global* *b:ale_php_pint_use_global* php_pint_use_global g:ale_php_pint_use_global Type: |Boolean| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== tlint *ale-php-tlint* *ale-options.php_tlint_executable* *g:ale_php_tlint_executable* *b:ale_php_tlint_executable* php_tlint_executable g:ale_php_tlint_executable Type: |String| Default: `'tlint'` See |ale-integrations-local-executables| *ale-options.php_tlint_use_global* *g:ale_php_tlint_use_global* *b:ale_php_tlint_use_global* php_tlint_use_global g:ale_php_tlint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.php_tlint_options* *g:ale_php_tlint_options* *b:ale_php_tlint_options* php_tlint_options g:ale_php_tlint_options Type: |String| Default: `''` This variable can be set to pass additional options to tlint =============================================================================== intelephense *ale-php-intelephense* *ale-options.php_intelephense_executable* *g:ale_php_intelephense_executable* *b:ale_php_intelephense_executable* php_intelephense_executable g:ale_php_intelephense_executable Type: |String| Default: `'intelephense'` The variable can be set to configure the executable that will be used for running the intelephense language server. `node_modules` directory executable will be preferred instead of this setting if |g:ale_php_intelephense_use_global| is `0`. See: |ale-integrations-local-executables| *ale-options.php_intelephense_use_global* *g:ale_php_intelephense_use_global* *b:ale_php_intelephense_use_global* php_intelephense_use_global g:ale_php_intelephense_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable can be set to `1` to force the language server to be run with the executable set for |g:ale_php_intelephense_executable|. See: |ale-integrations-local-executables| *ale-options.php_intelephense_config* *g:ale_php_intelephense_config* *b:ale_php_intelephense_config* php_intelephense_config g:ale_php_intelephense_config Type: |Dictionary| Default: `{}` The initialization options config specified by Intelephense. Refer to the installation docs provided by intelephense (github.com/bmewburn/intelephense -docs). =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-po.txt ================================================ =============================================================================== ALE PO Integration *ale-po-options* =============================================================================== write-good *ale-po-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-pod.txt ================================================ =============================================================================== ALE Pod Integration *ale-pod-options* =============================================================================== write-good *ale-pod-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-pony.txt ================================================ =============================================================================== ALE Pony Integration *ale-pony-options* =============================================================================== ponyc *ale-pony-ponyc* *ale-options.pony_ponyc_executable* *g:ale_pony_ponyc_executable* *b:ale_pony_ponyc_executable* pony_ponyc_executable g:ale_pony_ponyc_executable Type: |String| Default: `'ponyc'` See |ale-integrations-local-executables| *ale-options.pony_ponyc_options* *g:ale_pony_ponyc_options* *b:ale_pony_ponyc_options* pony_ponyc_options g:ale_pony_ponyc_options Type: |String| Default: `'--pass paint'` This variable can be set to pass options to ponyc. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-powershell.txt ================================================ =============================================================================== ALE PowerShell Integration *ale-powershell-options* =============================================================================== cspell *ale-powershell-cspell* See |ale-cspell-options| =============================================================================== powershell *ale-powershell-powershell* *ale-options.powershell_powershell_executable* *g:ale_powershell_powershell_executable* *b:ale_powershell_powershell_executable* powershell_powershell_executable g:ale_powershell_powershell_executable Type: |String| Default: `'pwsh'` This variable can be changed to use a different executable for powershell. > " Use powershell.exe rather than the default pwsh let g:ale_powershell_powershell_executable = 'powershell.exe' > =============================================================================== psscriptanalyzer *ale-powershell-psscriptanalyzer* ------------------------------------------------------------------------------- Installation Install PSScriptAnalyzer by any means, so long as it can be automatically imported in PowerShell. ------------------------------------------------------------------------------- Options *ale-options.powershell_psscriptanalyzer_executable* *g:ale_powershell_psscriptanalyzer_executable* *b:ale_powershell_psscriptanalyzer_executable* powershell_psscriptanalyzer_executable g:ale_powershell_psscriptanalyzer_executable Type: |String| Default: `'pwsh'` This variable sets executable used for powershell. For example, on Windows you could set powershell to be Windows Powershell: > let g:ale_powershell_psscriptanalyzer_executable = 'powershell.exe' < *ale-options.powershell_psscriptanalyzer_module* *g:ale_powershell_psscriptanalyzer_module* *b:ale_powershell_psscriptanalyzer_module* powershell_psscriptanalyzer_module g:ale_powershell_psscriptanalyzer_module Type: |String| Default: `'psscriptanalyzer'` This variable sets the name of the psscriptanalyzer module. for psscriptanalyzer invocation. *ale-options.powershell_psscriptanalyzer_exclusions* *g:ale_powershell_psscriptanalyzer_exclusions* *b:ale_powershell_psscriptanalyzer_exclusions* powershell_psscriptanalyzer_exclusions g:ale_powershell_psscriptanalyzer_exclusions Type: |String| Default: `''` Set this variable to exclude test(s) for psscriptanalyzer (-ExcludeRule option). To exclude more than one option, separate them with commas. > " Suppress Write-Host and Global vars warnings let g:ale_powershell_psscriptanalyzer_exclusions = \ 'PSAvoidUsingWriteHost,PSAvoidGlobalVars' < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-prolog.txt ================================================ =============================================================================== ALE Prolog Integration *ale-prolog-options* =============================================================================== swipl *ale-prolog-swipl* *ale-options.prolog_swipl_executable* *g:ale_prolog_swipl_executable* *b:ale_prolog_swipl_executable* prolog_swipl_executable g:ale_prolog_swipl_executable Type: |String| Default: `'swipl'` The executable that will be run for the `swipl` linter. *ale-options.prolog_swipl_load* *g:ale_prolog_swipl_load* *b:ale_prolog_swipl_load* prolog_swipl_load g: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'. *ale-options.prolog_swipl_timeout* *g:ale_prolog_swipl_timeout* *b:ale_prolog_swipl_timeout* prolog_swipl_timeout g: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|. *ale-options.prolog_swipl_alarm* *g:ale_prolog_swipl_alarm* *b:ale_prolog_swipl_alarm* prolog_swipl_alarm g: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|. *ale-options.prolog_swipl_alarm_handler* *g:ale_prolog_swipl_alarm_handler* *b:ale_prolog_swipl_alarm_handler* prolog_swipl_alarm_handler g: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: ================================================ FILE: doc/ale-proto.txt ================================================ =============================================================================== ALE Proto Integration *ale-proto-options* =============================================================================== Integration Information To enable `.proto` file linting, update |g:ale_linters| as appropriate: > " Enable linter for .proto files let g:ale_linters = {'proto': ['buf-lint', 'protoc-gen-lint', 'protolint']} < To enable `.proto` file fixing, update |g:ale_fixers| as appropriate: > " Enable linter for .proto files let b:ale_fixers = {'proto': ['buf-format', 'protolint']} < =============================================================================== buf-format *ale-proto-buf-format* The formatter uses `buf`, a fully-featured Protobuf compiler that doesn't depend on `protoc`. Make sure the `buf` binary is available in the system path, or set ale_proto_buf_format_executable. *ale-options.proto_buf_format_executable* *g:ale_proto_buf_format_executable* proto_buf_format_executable g:ale_proto_buf_format_executable Type: |String| Default: `'buf'` This variable can be changed to modify the executable used for buf. =============================================================================== buf-lint *ale-proto-buf-lint* The linter uses `buf`, a fully-featured Protobuf compiler that doesn't depend on `protoc`. Make sure the `buf` binary is available in the system path, or set ale_proto_buf_lint_executable. *ale-options.proto_buf_lint_executable* *g:ale_proto_buf_lint_executable* proto_buf_lint_executable g:ale_proto_buf_lint_executable Type: |String| Default: `'buf'` This variable can be changed to modify the executable used for buf. *ale-options.proto_buf_lint_config* *g:ale_proto_buf_lint_config* proto_buf_lint_config g:ale_proto_buf_lint_config Type: |String| Default: `''` A path to a buf configuration file. The path to the configuration file can be an absolute path or a relative path. ALE will search for the relative path in parent directories. =============================================================================== clang-format *ale-proto-clangformat* See |ale-c-clangformat| for information about the available options. Note that the C options are also used for Proto. =============================================================================== protoc-gen-lint *ale-proto-protoc-gen-lint* The linter is a plugin for the `protoc` binary. As long as the binary resides in the system path, `protoc` will find it. *ale-options.proto_protoc_gen_lint_options* *g:ale_proto_protoc_gen_lint_options* proto_protoc_gen_lint_options g:ale_proto_protoc_gen_lint_options Type: |String| Default: `''` This variable can be changed to modify flags given to protoc. Note that the directory of the linted file is always passed as an include path with '-I' before any user-supplied options. =============================================================================== protolint *ale-proto-protolint* The linter is a pluggable tool that doesn't depend on the `protoc` binary. This supports both linting and fixing. Make sure the binary is available in the system path, or set ale_proto_protolint_executable. Note that the binary with v0.22.0 or above is supported. *ale-options.proto_protolint_executable* *g:ale_proto_protolint_executable* proto_protolint_executable g:ale_proto_protolint_executable Type: |String| Default: `'protolint'` This variable can be changed to modify the executable used for protolint. *ale-options.proto_protolint_config* *g:ale_proto_protolint_config* proto_protolint_config g:ale_proto_protolint_config Type: |String| Default: `''` A path to a protolint configuration file. The path to the configuration file can be an absolute path or a relative path. ALE will search for the relative path in parent directories. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-pug.txt ================================================ =============================================================================== ALE Pug Integration *ale-pug-options* =============================================================================== puglint *ale-pug-puglint* The puglint linter will detect configuration files based on the path to the filename automatically. Configuration files will be loaded in this order: 1. `.pug-lintrc` 2. `.pug-lintrc.js` 3. `.pug-lintrc.json` 4. `package.json` You might need to create a configuration file for your project to get meaningful results. *ale-options.pug_puglint_executable* *g:ale_pug_puglint_executable* *b:ale_pug_puglint_executable* pug_puglint_executable g:ale_pug_puglint_executable Type: |String| Default: `'pug-lint'` See |ale-integrations-local-executables| *ale-options.pug_puglint_options* *g:ale_pug_puglint_options* *b:ale_pug_puglint_options* pug_puglint_options g:ale_pug_puglint_options Type: |String| Default: `''` This variable can be set to pass additional options to pug-lint. *ale-options.pug_puglint_use_global* *g:ale_pug_puglint_use_global* *b:ale_pug_puglint_use_global* pug_puglint_use_global g:ale_pug_puglint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-puppet.txt ================================================ =============================================================================== ALE Puppet Integration *ale-puppet-options* =============================================================================== puppet *ale-puppet-puppet* *ale-options.puppet_puppet_executable* *g:ale_puppet_puppet_executable* *b:ale_puppet_puppet_executable* puppet_puppet_executable g:ale_puppet_puppet_executable Type: |String| Default: `'puppet'` This variable can be changed to specify the executable used for puppet. *ale-options.puppet_puppet_options* *g:ale_puppet_puppet_options* *b:ale_puppet_puppet_options* puppet_puppet_options g: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* *ale-options.puppet_puppetlint_executable* *g:ale_puppet_puppetlint_executable* *b:ale_puppet_puppetlint_executable* puppet_puppetlint_executable g:ale_puppet_puppetlint_executable Type: |String| Default: `'puppet-lint'` This variable can be changed to specify the executable used for puppet-lint. *ale-options.puppet_puppetlint_options* *g:ale_puppet_puppetlint_options* *b:ale_puppet_puppetlint_options* puppet_puppetlint_options g:ale_puppet_puppetlint_options Type: |String| Default: `'--no-autoloader_layout-check'` This variable can be changed to add command-line arguments to the puppet-lint invocation. =============================================================================== puppet-languageserver *ale-puppet-languageserver* *ale-options.puppet_languageserver_executable* *g:ale_puppet_languageserver_executable* *b:ale_puppet_languageserver_executable* puppet_languageserver_executable g:ale_puppet_languageserver_executable type: |String| Default: `'puppet-languageserver'` This variable can be used to specify the executable used for puppet-languageserver. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-purescript.txt ================================================ =============================================================================== ALE PureScript Integration *ale-purescript-options* =============================================================================== purescript-language-server *ale-purescript-language-server* PureScript Language Server (https://github.com/nwolverson/purescript-language-server) *ale-options.purescript_ls_executable* *g:ale_purescript_ls_executable* *b:ale_purescript_ls_executable* purescript_ls_executable g:ale_purescript_ls_executable Type: |String| Default: `'purescript-language-server'` PureScript language server executable. *ale-options.purescript_ls_config* *g:ale_purescript_ls_config* *b:ale_purescript_ls_config* purescript_ls_config g:ale_purescript_ls_config Type: |Dictionary| Default: `{}` Dictionary containing configuration settings that will be passed to the language server. For example, with a spago project: > let g:ale_purescript_ls_config = { \ 'purescript': { \ 'addSpagoSources': v:true, \ 'addNpmPath': v:true, \ 'buildCommand': 'spago --quiet build --purs-args --json-errors', \ }, \} < =============================================================================== purs-tidy *ale-purescript-tidy* *ale-options.purescript_tidy_executable* *g:ale_purescript_tidy_executable* *b:ale_purescript_tidy_executable* purescript_tidy_executable g:ale_purescript_tidy_executable Type: |String| Default: `'purs-tidy'` This variable can be changed to use a different executable for purs-tidy. *ale-options.purescript_tidy_use_global* *g:ale_purescript_tidy_use_global* *b:ale_purescript_tidy_use_global* purescript_tidy_use_global g:ale_purescript_tidy_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.purescript_tidy_options* *g:ale_purescript_tidy_options* *b:ale_purescript_tidy_options* purescript_tidy_options g:ale_purescript_tidy_options Type: |String| Default: `''` This variable can be set to pass in additional option to the 'purs-tidy' executable. > let g:ale_purescript_options = '--indent 3' < =============================================================================== purty *ale-purescript-purty* *ale-options.purescript_purty_executable* *g:ale_purescript_purty_executable* *b:ale_purescript_purty_executable* purescript_purty_executable g:ale_purescript_purty_executable Type: |String| Default: `'purty'` This variable can be changed to use a different executable for purty. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-pyrex.txt ================================================ =============================================================================== ALE Pyrex (Cython) Integration *ale-pyrex-options* =============================================================================== cython *ale-pyrex-cython* *ale-options.pyrex_cython_executable* *g:ale_pyrex_cython_executable* *b:ale_pyrex_cython_executable* pyrex_cython_executable g:ale_pyrex_cython_executable Type: |String| Default: `'cython'` This variable can be changed to use a different executable for cython. *ale-options.pyrex_cython_options* *g:ale_pyrex_cython_options* *b:ale_pyrex_cython_options* pyrex_cython_options g:ale_pyrex_cython_options Type: |String| Default: `'--warning-extra --warning-errors'` This variable can be changed to modify flags given to cython. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-python.txt ================================================ =============================================================================== ALE Python Integration *ale-python-options* *ale-options.python_auto_pipenv* *g:ale_python_auto_pipenv* *b:ale_python_auto_pipenv* python_auto_pipenv g: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-options.python_auto_poetry* *g:ale_python_auto_poetry* *b:ale_python_auto_poetry* python_auto_poetry g:ale_python_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_auto_uv* *g:ale_python_auto_uv* *b:ale_python_auto_uv* python_auto_uv g:ale_python_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. *ale-options.python_auto_virtualenv* *g:ale_python_auto_virtualenv* *b:ale_python_auto_virtualenv* python_auto_virtualenv g:ale_python_auto_virtualenv Type: |Number| Default: `0` If set to `1`, ALE will automatically set environment variables for commands such as `PATH` to attempt to make the experience of running Python linters via virtualenv easier, without the need for another plugin or some specialised setup. =============================================================================== ALE Python Project Root Behavior *ale-python-root* For some linters, ALE will search for a Python project root by looking at the files in directories on or above where a file being checked is. ALE applies the following methods, in order: 1. Find the first directory containing a common Python configuration file. 2. If no configuration file can be found, use the first directory which does not contain a readable file named `__init__.py`. ALE will look for configuration files with the following filenames. > MANIFEST.in setup.cfg tox.ini .pyre_configuration.local mypy.ini .mypy.ini pycodestyle.cfg .flake8 .flake8rc pylama.ini pylintrc .pylintrc pyrightconfig.json pyrightconfig.toml Pipfile Pipfile.lock poetry.lock pyproject.toml .tool-versions uv.lock < The first directory containing any of the files named above will be used. =============================================================================== autoflake *ale-python-autoflake* *ale-options.python_autoflake_executable* *g:ale_python_autoflake_executable* *b:ale_python_autoflake_executable* python_autoflake_executable g:ale_python_autoflake_executable Type: |String| Default: `'autoflake'` See |ale-integrations-local-executables| *ale-options.python_autoflake_options* *g:ale_python_autoflake_options* *b:ale_python_autoflake_options* python_autoflake_options g:ale_python_autoflake_options Type: |String| Default: `''` This variable can be set to pass extra options to autoflake. *ale-options.python_autoflake_use_global* *g:ale_python_autoflake_use_global* *b:ale_python_autoflake_use_global* python_autoflake_use_global g:ale_python_autoflake_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_autoflake_auto_pipenv* *g:ale_python_autoflake_auto_pipenv* *b:ale_python_autoflake_auto_pipenv* python_autoflake_auto_pipenv g:ale_python_autoflake_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-options.python_autoflake_auto_poetry* *g:ale_python_autoflake_auto_poetry* *b:ale_python_autoflake_auto_poetry* python_autoflake_auto_poetry g:ale_python_autoflake_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_autoflake_auto_uv* *g:ale_python_autoflake_auto_uv* *b:ale_python_autoflake_auto_uv* python_autoflake_auto_uv g:ale_python_autoflake_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== autoimport *ale-python-autoimport* *ale-options.python_autoimport_executable* *g:ale_python_autoimport_executable* *b:ale_python_autoimport_executable* python_autoimport_executable g:ale_python_autoimport_executable Type: |String| Default: `'autoimport'` See |ale-integrations-local-executables| *ale-options.python_autoimport_options* *g:ale_python_autoimport_options* *b:ale_python_autoimport_options* python_autoimport_options g:ale_python_autoimport_options Type: |String| Default: `''` This variable can be set to pass extra options to autoimport. *ale-options.python_autoimport_use_global* *g:ale_python_autoimport_use_global* *b:ale_python_autoimport_use_global* python_autoimport_use_global g:ale_python_autoimport_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_autoimport_auto_pipenv* *g:ale_python_autoimport_auto_pipenv* *b:ale_python_autoimport_auto_pipenv* python_autoimport_auto_pipenv g:ale_python_autoimport_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-options.python_autoimport_auto_poetry* *g:ale_python_autoimport_auto_poetry* *b:ale_python_autoimport_auto_poetry* python_autoimport_auto_poetry g:ale_python_autoimport_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_autoimport_auto_uv* *g:ale_python_autoimport_auto_uv* *b:ale_python_autoimport_auto_uv* python_autoimport_auto_uv g:ale_python_autoimport_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== autopep8 *ale-python-autopep8* *ale-options.python_autopep8_executable* *g:ale_python_autopep8_executable* *b:ale_python_autopep8_executable* python_autopep8_executable g:ale_python_autopep8_executable Type: |String| Default: `'autopep8'` See |ale-integrations-local-executables| *ale-options.python_autopep8_options* *g:ale_python_autopep8_options* *b:ale_python_autopep8_options* python_autopep8_options g:ale_python_autopep8_options Type: |String| Default: `''` This variable can be set to pass extra options to autopep8. *ale-options.python_autopep8_use_global* *g:ale_python_autopep8_use_global* *b:ale_python_autopep8_use_global* python_autopep8_use_global g:ale_python_autopep8_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_autopep8_auto_pipenv* *g:ale_python_autopep8_auto_pipenv* *b:ale_python_autopep8_auto_pipenv* python_autopep8_auto_pipenv g:ale_python_autopep8_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-options.python_autopep8_auto_poetry* *g:ale_python_autopep8_auto_poetry* *b:ale_python_autopep8_auto_poetry* python_autopep8_auto_poetry g:ale_python_autopep8_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_autopep8_auto_uv* *g:ale_python_autopep8_auto_uv* *b:ale_python_autopep8_auto_uv* python_autopep8_auto_uv g:ale_python_autopep8_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== bandit *ale-python-bandit* *ale-options.python_bandit_executable* *g:ale_python_bandit_executable* *b:ale_python_bandit_executable* python_bandit_executable g:ale_python_bandit_executable Type: |String| Default: `'bandit'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `bandit'`. Set this to `'poetry'` to invoke `'poetry` `run` `bandit'`. *ale-options.python_bandit_options* *g:ale_python_bandit_options* *b:ale_python_bandit_options* python_bandit_options g:ale_python_bandit_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the bandit invocation. *ale-options.python_bandit_use_config* *g:ale_python_bandit_use_config* *b:ale_python_bandit_use_config* python_bandit_use_config g:ale_python_bandit_use_config Type: |Number| Default: `1` If this variable is true and a `.bandit` file exists in the directory of the file being checked or a parent directory, an `--ini` option is added to the `bandit` command for the nearest `.bandit` file. Set this variable false to disable adding the `--ini` option automatically. *ale-options.python_bandit_use_global* *g:ale_python_bandit_use_global* *b:ale_python_bandit_use_global* python_bandit_use_global g:ale_python_bandit_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_bandit_auto_pipenv* *g:ale_python_bandit_auto_pipenv* *b:ale_python_bandit_auto_pipenv* python_bandit_auto_pipenv g:ale_python_bandit_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-options.python_bandit_auto_poetry* *g:ale_python_bandit_auto_poetry* *b:ale_python_bandit_auto_poetry* python_bandit_auto_poetry g:ale_python_bandit_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_bandit_auto_uv* *g:ale_python_bandit_auto_uv* *b:ale_python_bandit_auto_uv* python_bandit_auto_uv g:ale_python_bandit_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== black *ale-python-black* *ale-options.python_black_executable* *g:ale_python_black_executable* *b:ale_python_black_executable* python_black_executable g:ale_python_black_executable Type: |String| Default: `'black'` See |ale-integrations-local-executables| *ale-options.python_black_options* *g:ale_python_black_options* *b:ale_python_black_options* python_black_options g:ale_python_black_options Type: |String| Default: `''` This variable can be set to pass extra options to black. *ale-options.python_black_use_global* *g:ale_python_black_use_global* *b:ale_python_black_use_global* python_black_use_global g:ale_python_black_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_black_auto_pipenv* *g:ale_python_black_auto_pipenv* *b:ale_python_black_auto_pipenv* python_black_auto_pipenv g:ale_python_black_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-options.python_black_auto_poetry* *g:ale_python_black_auto_poetry* *b:ale_python_black_auto_poetry* python_black_auto_poetry g:ale_python_black_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_black_auto_uv* *g:ale_python_black_auto_uv* *b:ale_python_black_auto_uv* python_black_auto_uv g:ale_python_black_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. *ale-options.python_black_change_directory* *g:ale_python_black_change_directory* *b:ale_python_black_change_directory* python_black_change_directory g:ale_python_black_change_directory Type: |Number| Default: `1` If set to `1`, ALE will switch to the directory the Python file being checked with `black` is in before checking it. This helps `black` find configuration files more easily. This option can be turned off if you want to control the directory Python is executed from yourself. =============================================================================== cspell *ale-python-cspell* See |ale-cspell-options| =============================================================================== flake8 *ale-python-flake8* *ale-options.python_flake8_change_directory* *g:ale_python_flake8_change_directory* *b:ale_python_flake8_change_directory* python_flake8_change_directory g:ale_python_flake8_change_directory Type: |String| Default: `'project'` If set to `project`, ALE will switch to the project root before checking file. If set to `file`, ALE will first switch to the directory containing the Python file being checked with `flake8` before checking it. You can turn it off with `off` option if you want to control the directory Python is executed from yourself. *ale-options.python_flake8_executable* *g:ale_python_flake8_executable* *b:ale_python_flake8_executable* python_flake8_executable g:ale_python_flake8_executable Type: |String| Default: `'flake8'` This variable can be changed to modify the executable used for flake8. Set this to `'pipenv'` to invoke `'pipenv` `run` `flake8'`. Set this to `'poetry'` to invoke `'poetry` `run` `flake8'`. *ale-options.python_flake8_options* *g:ale_python_flake8_options* *b:ale_python_flake8_options* python_flake8_options g:ale_python_flake8_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the flake8 invocation. For example, to dynamically switch between programs targeting Python 2 and Python 3, you may want to set > let g:ale_python_flake8_executable = 'python3' " or 'python' for Python 2 let g:ale_python_flake8_options = '-m flake8' < after making sure it's installed for the appropriate Python versions (e.g. `python3 -m pip install --user flake8`). *ale-options.python_flake8_use_global* *g:ale_python_flake8_use_global* *b:ale_python_flake8_use_global* python_flake8_use_global g:ale_python_flake8_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable controls whether or not ALE will search for flake8 in a virtualenv directory first. If this variable is set to `1`, then ALE will always use |g:ale_python_flake8_executable| for the executable path. Both variables can be set with `b:` buffer variables instead. *ale-options.python_flake8_auto_pipenv* *g:ale_python_flake8_auto_pipenv* *b:ale_python_flake8_auto_pipenv* python_flake8_auto_pipenv g: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. *ale-options.python_flake8_auto_poetry* *g:ale_python_flake8_auto_poetry* *b:ale_python_flake8_auto_poetry* python_flake8_auto_poetry g:ale_python_flake8_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_flake8_auto_uv* *g:ale_python_flake8_auto_uv* *b:ale_python_flake8_auto_uv* python_flake8_auto_uv g:ale_python_flake8_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== flakehell *ale-python-flakehell* *ale-options.python_flakehell_change_directory* *g:ale_python_flakehell_change_directory* *b:ale_python_flakehell_change_directory* python_flakehell_change_directory g:ale_python_flakehell_change_directory Type: |String| Default: `project` If set to `project`, ALE will switch to the project root before checking file. If set to `file`, ALE will switch to directory the Python file being checked with `flakehell` is in before checking it. You can turn it off with `off` option if you want to control the directory Python is executed from yourself. *ale-options.python_flakehell_executable* *g:ale_python_flakehell_executable* *b:ale_python_flakehell_executable* python_flakehell_executable g:ale_python_flakehell_executable Type: |String| Default: `'flakehell'` This variable can be changed to modify the executable used for flakehell. Set this to `'pipenv'` to invoke `'pipenv` `run` `flakehell'`. Set this to `'poetry'` to invoke `'poetry` `run` `flakehell'`. Set this to `'python'` to invoke `'python` `-m` `flakehell'`. *ale-options.python_flakehell_options* *g:ale_python_flakehell_options* *b:ale_python_flakehell_options* python_flakehell_options g:ale_python_flakehell_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the flakehell lint invocation. *ale-options.python_flakehell_use_global* *g:ale_python_flakehell_use_global* *b:ale_python_flakehell_use_global* python_flakehell_use_global g:ale_python_flakehell_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable controls whether or not ALE will search for flakehell in a virtualenv directory first. If this variable is set to `1`, then ALE will always use |g:ale_python_flakehell_executable| for the executable path. Both variables can be set with `b:` buffer variables instead. *ale-options.python_flakehell_auto_pipenv* *g:ale_python_flakehell_auto_pipenv* *b:ale_python_flakehell_auto_pipenv* python_flakehell_auto_pipenv g:ale_python_flakehell_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-options.python_flakehell_auto_poetry* *g:ale_python_flakehell_auto_poetry* *b:ale_python_flakehell_auto_poetry* python_flakehell_auto_poetry g:ale_python_flakehell_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_flakehell_auto_uv* *g:ale_python_flakehell_auto_uv* *b:ale_python_flakehell_auto_uv* python_flakehell_auto_uv g:ale_python_flakehell_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== isort *ale-python-isort* *ale-options.python_isort_executable* *g:ale_python_isort_executable* *b:ale_python_isort_executable* python_isort_executable g:ale_python_isort_executable Type: |String| Default: `'isort'` See |ale-integrations-local-executables| *ale-options.python_isort_options* *g:ale_python_isort_options* *b:ale_python_isort_options* python_isort_options g:ale_python_isort_options Type: |String| Default: `''` This variable can be set to pass extra options to isort. *ale-options.python_isort_use_global* *g:ale_python_isort_use_global* *b:ale_python_isort_use_global* python_isort_use_global g:ale_python_isort_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_isort_auto_pipenv* *g:ale_python_isort_auto_pipenv* *b:ale_python_isort_auto_pipenv* python_isort_auto_pipenv g:ale_python_isort_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-options.python_isort_auto_poetry* *g:ale_python_isort_auto_poetry* *b:ale_python_isort_auto_poetry* python_isort_auto_poetry g:ale_python_isort_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_isort_auto_uv* *g:ale_python_isort_auto_uv* *b:ale_python_isort_auto_uv* python_isort_auto_uv g:ale_python_isort_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== mypy *ale-python-mypy* The minimum supported version of mypy that ALE supports is v0.4.4. This is the first version containing the `--shadow-file` option ALE needs to be able to check for errors while you type. `mypy` will be run from a detected project root, per |ale-python-root|. *ale-options.python_mypy_auto_pipenv* *g:ale_python_mypy_auto_pipenv* *b:ale_python_mypy_auto_pipenv* python_mypy_auto_pipenv g: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. *ale-options.python_mypy_auto_poetry* *g:ale_python_mypy_auto_poetry* *b:ale_python_mypy_auto_poetry* python_mypy_auto_poetry g:ale_python_mypy_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_mypy_auto_uv* *g:ale_python_mypy_auto_uv* *b:ale_python_mypy_auto_uv* python_mypy_auto_uv g:ale_python_mypy_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. *ale-options.python_mypy_executable* *g:ale_python_mypy_executable* *b:ale_python_mypy_executable* python_mypy_executable g:ale_python_mypy_executable Type: |String| Default: `'mypy'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `mypy'`. Set this to `'poetry'` to invoke `'poetry` `run` `mypy'`. *ale-options.python_mypy_ignore_invalid_syntax* *g:ale_python_mypy_ignore_invalid_syntax* *b:ale_python_mypy_ignore_invalid_syntax* python_mypy_ignore_invalid_syntax g:ale_python_mypy_ignore_invalid_syntax Type: |Number| Default: `0` When set to `1`, syntax error messages for mypy will be ignored. This option can be used when running other Python linters which check for syntax errors, as mypy can take a while to finish executing. *ale-options.python_mypy_options* *g:ale_python_mypy_options* *b:ale_python_mypy_options* python_mypy_options g:ale_python_mypy_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the mypy invocation. *ale-options.python_mypy_show_notes* *g:ale_python_mypy_show_notes* *b:ale_python_mypy_show_notes* python_mypy_show_notes g:ale_python_mypy_show_notes Type: |Number| Default: `1` If enabled, notes on lines will be displayed as 'I' (info) messages. *ale-options.python_mypy_use_global* *g:ale_python_mypy_use_global* *b:ale_python_mypy_use_global* python_mypy_use_global g:ale_python_mypy_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== prospector *ale-python-prospector* *ale-options.python_prospector_executable* *g:ale_python_prospector_executable* *b:ale_python_prospector_executable* python_prospector_executable g:ale_python_prospector_executable Type: |String| Default: `'prospector'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `prospector'`. Set this to `'poetry'` to invoke `'poetry` `run` `prospector'`. *ale-options.python_prospector_options* *g:ale_python_prospector_options* *b:ale_python_prospector_options* python_prospector_options g:ale_python_prospector_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the prospector invocation. For example, to dynamically switch between programs targeting Python 2 and Python 3, you may want to set > let g:ale_python_prospector_executable = 'python3' " or 'python' for Python 2 let g:ale_python_prospector_options = '--rcfile /path/to/.prospector.yaml' " The virtualenv detection needs to be disabled. let g:ale_python_prospector_use_global = 0 after making sure it's installed for the appropriate Python versions (e.g. `python3 -m pip install --user prospector`). < *ale-options.python_prospector_use_global* *g:ale_python_prospector_use_global* *b:ale_python_prospector_use_global* python_prospector_use_global g:ale_python_prospector_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_prospector_auto_pipenv* *g:ale_python_prospector_auto_pipenv* *b:ale_python_prospector_auto_pipenv* python_prospector_auto_pipenv g: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. *ale-options.python_prospector_auto_poetry* *g:ale_python_prospector_auto_poetry* *b:ale_python_prospector_auto_poetry* python_prospector_auto_poetry g:ale_python_prospector_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_prospector_auto_uv* *g:ale_python_prospector_auto_uv* *b:ale_python_prospector_auto_uv* python_prospector_auto_uv g:ale_python_prospector_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pycln *ale-python-pycln* *ale-options.python_pycln_change_directory* *g:ale_python_pycln_change_directory* *b:ale_python_pycln_change_directory* python_pycln_change_directory g:ale_python_pycln_change_directory Type: |Number| Default: `1` If set to `1`, `pycln` will be run from a detected project root, per |ale-python-root|. if set to `0` or no project root detected, `pycln` will be run from the buffer's directory. *ale-options.python_pycln_executable* *g:ale_python_pycln_executable* *b:ale_python_pycln_executable* python_pycln_executable g:ale_python_pycln_executable Type: |String| Default: `'pycln'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pycln'`. Set this to `'poetry'` to invoke `'poetry` `run` `pycln'`. *ale-options.python_pycln_options* *g:ale_python_pycln_options* *b:ale_python_pycln_options* python_pycln_options g:ale_python_pycln_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pycln invocation. For example, to select/enable and/or disable some error codes, you may want to set the following: > let g:ale_python_pycln_options = '--expand-stars' < *ale-options.python_pycln_config_file* *g:ale_python_pycln_config_file* *b:ale_python_pycln_config_file* python_pycln_config_file g:ale_python_pycln_config_file Type: |String| Default: `''` Use this variable to set the configuration file. If `'--config' ` is found in the |g:ale_python_pycln_options|, then that option value will override the value in this variable. *ale-options.python_pycln_use_global* *g:ale_python_pycln_use_global* *b:ale_python_pycln_use_global* python_pycln_use_global g:ale_python_pycln_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pycln_auto_pipenv* *g:ale_python_pycln_auto_pipenv* *b:ale_python_pycln_auto_pipenv* python_pycln_auto_pipenv g:ale_python_pycln_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-options.python_pycln_auto_poetry* *g:ale_python_pycln_auto_poetry* *b:ale_python_pycln_auto_poetry* python_pycln_auto_poetry g:ale_python_pycln_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pycln_auto_uv* *g:ale_python_pycln_auto_uv* *b:ale_python_pycln_auto_uv* python_pycln_auto_uv g:ale_python_pycln_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pycodestyle *ale-python-pycodestyle* *ale-options.python_pycodestyle_executable* *g:ale_python_pycodestyle_executable* *b:ale_python_pycodestyle_executable* python_pycodestyle_executable g:ale_python_pycodestyle_executable Type: |String| Default: `'pycodestyle'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pycodestyle'`. Set this to `'poetry'` to invoke `'poetry` `run` `pycodestyle'`. *ale-options.python_pycodestyle_options* *g:ale_python_pycodestyle_options* *b:ale_python_pycodestyle_options* python_pycodestyle_options g:ale_python_pycodestyle_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pycodestyle invocation. *ale-options.python_pycodestyle_use_global* *g:ale_python_pycodestyle_use_global* *b:ale_python_pycodestyle_use_global* python_pycodestyle_use_global g:ale_python_pycodestyle_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pycodestyle_auto_pipenv* *g:ale_python_pycodestyle_auto_pipenv* *b:ale_python_pycodestyle_auto_pipenv* python_pycodestyle_auto_pipenv g: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. *ale-options.python_pycodestyle_auto_poetry* *g:ale_python_pycodestyle_auto_poetry* *b:ale_python_pycodestyle_auto_poetry* python_pycodestyle_auto_poetry g:ale_python_pycodestyle_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pycodestyle_auto_uv* *g:ale_python_pycodestyle_auto_uv* *b:ale_python_pycodestyle_auto_uv* python_pycodestyle_auto_uv g:ale_python_pycodestyle_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pydocstyle *ale-python-pydocstyle* *ale-options.python_pydocstyle_executable* *g:ale_python_pydocstyle_executable* *b:ale_python_pydocstyle_executable* python_pydocstyle_executable g:ale_python_pydocstyle_executable Type: |String| Default: `'pydocstyle'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pydocstyle'`. Set this to `'poetry'` to invoke `'poetry` `run` `pydocstyle'`. *ale-options.python_pydocstyle_options* *g:ale_python_pydocstyle_options* *b:ale_python_pydocstyle_options* python_pydocstyle_options g:ale_python_pydocstyle_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pydocstyle invocation. *ale-options.python_pydocstyle_use_global* *g:ale_python_pydocstyle_use_global* *b:ale_python_pydocstyle_use_global* python_pydocstyle_use_global g:ale_python_pydocstyle_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pydocstyle_auto_pipenv* *g:ale_python_pydocstyle_auto_pipenv* *b:ale_python_pydocstyle_auto_pipenv* python_pydocstyle_auto_pipenv g:ale_python_pydocstyle_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-options.python_pydocstyle_auto_poetry* *g:ale_python_pydocstyle_auto_poetry* *b:ale_python_pydocstyle_auto_poetry* python_pydocstyle_auto_poetry g:ale_python_pydocstyle_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pydocstyle_auto_uv* *g:ale_python_pydocstyle_auto_uv* *b:ale_python_pydocstyle_auto_uv* python_pydocstyle_auto_uv g:ale_python_pydocstyle_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pyflakes *ale-python-pyflakes* *ale-options.python_pyflakes_executable* *g:ale_python_pyflakes_executable* *b:ale_python_pyflakes_executable* python_pyflakes_executable g:ale_python_pyflakes_executable Type: |String| Default: `'pyflakes'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pyflakes'`. Set this to `'poetry'` to invoke `'poetry` `run` `pyflakes'`. *ale-options.python_pyflakes_auto_pipenv* *g:ale_python_pyflakes_auto_pipenv* *b:ale_python_pyflakes_auto_pipenv* python_pyflakes_auto_pipenv g: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. *ale-options.python_pyflakes_auto_poetry* *g:ale_python_pyflakes_auto_poetry* *b:ale_python_pyflakes_auto_poetry* python_pyflakes_auto_poetry g:ale_python_pyflakes_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pyflakes_auto_uv* *g:ale_python_pyflakes_auto_uv* *b:ale_python_pyflakes_auto_uv* python_pyflakes_auto_uv g:ale_python_pyflakes_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pyflyby *ale-python-pyflyby* *ale-options.python_pyflyby_executable* *g:ale_python_pyflyby_executable* *b:ale_python_pyflyby_executable* python_pyflyby_executable g:ale_python_pyflyby_executable Type: |String| Default: `'tidy-imports'` See |ale-integrations-local-executables| *ale-options.python_pyflyby_options* *g:ale_python_pyflyby_options* *b:ale_python_pyflyby_options* python_pyflyby_options g:ale_python_pyflyby_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pyflyby tidy-imports invocation. *ale-options.python_pyflyby_use_global* *g:ale_python_pyflyby_use_global* *b:ale_python_pyflyby_use_global* python_pyflyby_use_global g:ale_python_pyflyby_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pyflyby_auto_pipenv* *g:ale_python_pyflyby_auto_pipenv* *b:ale_python_pyflyby_auto_pipenv* python_pyflyby_auto_pipenv g:ale_python_pyflyby_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-options.python_pyflyby_auto_poetry* *g:ale_python_pyflyby_auto_poetry* *b:ale_python_pyflyby_auto_poetry* python_pyflyby_auto_poetry g:ale_python_pyflyby_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pyflyby_auto_uv* *g:ale_python_pyflyby_auto_uv* *b:ale_python_pyflyby_auto_uv* python_pyflyby_auto_uv g:ale_python_pyflyby_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pylama *ale-python-pylama* *ale-options.python_pylama_change_directory* *g:ale_python_pylama_change_directory* *b:ale_python_pylama_change_directory* python_pylama_change_directory g:ale_python_pylama_change_directory Type: |Number| Default: `1` If set to `1`, `pylama` will be run from a detected project root, per |ale-python-root|. This is useful because `pylama` only searches for configuration files in its current directory and applies file masks using paths relative to its current directory. This option can be turned off if you want to control the directory in which `pylama` is executed. *ale-options.python_pylama_executable* *g:ale_python_pylama_executable* *b:ale_python_pylama_executable* python_pylama_executable g:ale_python_pylama_executable Type: |String| Default: `'pylama'` This variable can be changed to modify the executable used for pylama. Set this to `'pipenv'` to invoke `'pipenv` `run` `pylama'`. Set this to `'poetry'` to invoke `'poetry` `run` `pylama'`. *ale-options.python_pylama_options* *g:ale_python_pylama_options* *b:ale_python_pylama_options* python_pylama_options g:ale_python_pylama_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pylama invocation. *ale-options.python_pylama_use_global* *g:ale_python_pylama_use_global* *b:ale_python_pylama_use_global* python_pylama_use_global g:ale_python_pylama_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable controls whether or not ALE will search for pylama in a virtualenv directory first. If this variable is set to `1`, then ALE will always use |g:ale_python_pylama_executable| for the executable path. Both variables can be set with `b:` buffer variables instead. *ale-options.python_pylama_auto_pipenv* *g:ale_python_pylama_auto_pipenv* *b:ale_python_pylama_auto_pipenv* python_pylama_auto_pipenv g:ale_python_pylama_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-options.python_pylama_auto_poetry* *g:ale_python_pylama_auto_poetry* *b:ale_python_pylama_auto_poetry* python_pylama_auto_poetry g:ale_python_pylama_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pylama_auto_uv* *g:ale_python_pylama_auto_uv* *b:ale_python_pylama_auto_uv* python_pylama_auto_uv g:ale_python_pylama_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pylint *ale-python-pylint* *ale-options.python_pylint_change_directory* *g:ale_python_pylint_change_directory* *b:ale_python_pylint_change_directory* python_pylint_change_directory g:ale_python_pylint_change_directory Type: |Number| Default: `1` If set to `1`, `pylint` will be run from a detected project root, per |ale-python-root|. Since `pylint` only checks for `pylintrc` in the packages above its current directory before falling back to user and global `pylintrc` files, this is necessary for `pylint` to use a project `pylintrc` file, if present. This option can be turned off if you want to control the directory Python is executed from yourself. *ale-options.python_pylint_executable* *g:ale_python_pylint_executable* *b:ale_python_pylint_executable* python_pylint_executable g:ale_python_pylint_executable Type: |String| Default: `'pylint'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pylint'`. Set this to `'poetry'` to invoke `'poetry` `run` `pylint'`. *ale-options.python_pylint_options* *g:ale_python_pylint_options* *b:ale_python_pylint_options* python_pylint_options g:ale_python_pylint_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pylint invocation. For example, to dynamically switch between programs targeting Python 2 and Python 3, you may want to set > let g:ale_python_pylint_executable = 'python3' " or 'python' for Python 2 let g:ale_python_pylint_options = '--rcfile /path/to/pylint.rc' " The virtualenv detection needs to be disabled. let g:ale_python_pylint_use_global = 0 after making sure it's installed for the appropriate Python versions (e.g. `python3 -m pip install --user pylint`). < *ale-options.python_pylint_use_global* *g:ale_python_pylint_use_global* *b:ale_python_pylint_use_global* python_pylint_use_global g:ale_python_pylint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pylint_auto_pipenv* *g:ale_python_pylint_auto_pipenv* *b:ale_python_pylint_auto_pipenv* python_pylint_auto_pipenv g: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. *ale-options.python_pylint_auto_poetry* *g:ale_python_pylint_auto_poetry* *b:ale_python_pylint_auto_poetry* python_pylint_auto_poetry g:ale_python_pylint_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pylint_auto_uv* *g:ale_python_pylint_auto_uv* *b:ale_python_pylint_auto_uv* python_pylint_auto_uv g:ale_python_pylint_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. *ale-options.python_pylint_use_msg_id* *g:ale_python_pylint_use_msg_id* *b:ale_python_pylint_use_msg_id* python_pylint_use_msg_id g:ale_python_pylint_use_msg_id Type: |Number| Default: `0` Use message for output (e.g. I0011) instead of symbolic name of the message (e.g. locally-disabled). =============================================================================== pylsp *ale-python-pylsp* `pylsp` will be run from a detected project root, per |ale-python-root|. *ale-options.python_pylsp_executable* *g:ale_python_pylsp_executable* *b:ale_python_pylsp_executable* python_pylsp_executable g:ale_python_pylsp_executable Type: |String| Default: `'pylsp'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pylsp'`. Set this to `'poetry'` to invoke `'poetry` `run` `pylsp'`. *ale-options.python_pylsp_use_global* *g:ale_python_pylsp_use_global* *b:ale_python_pylsp_use_global* python_pylsp_use_global g:ale_python_pylsp_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pylsp_auto_pipenv* *g:ale_python_pylsp_auto_pipenv* *b:ale_python_pylsp_auto_pipenv* python_pylsp_auto_pipenv g:ale_python_pylsp_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-options.python_pylsp_auto_poetry* *g:ale_python_pylsp_auto_poetry* *b:ale_python_pylsp_auto_poetry* python_pylsp_auto_poetry g:ale_python_pylsp_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pylsp_auto_uv* *g:ale_python_pylsp_auto_uv* *b:ale_python_pylsp_auto_uv* python_pylsp_auto_uv g:ale_python_pylsp_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. *ale-options.python_pylsp_config* *g:ale_python_pylsp_config* *b:ale_python_pylsp_config* python_pylsp_config g:ale_python_pylsp_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for pylsp. For example, to disable the pycodestyle linter: > let g:ale_python_pylsp_config = { \ 'pylsp': { \ 'plugins': { \ 'pycodestyle': { \ 'enabled': v:false \ } \ } \ }, \} < *ale-options.python_pylsp_options* *g:ale_python_pylsp_options* *b:ale_python_pylsp_options* python_pylsp_options g:ale_python_pylsp_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the pylsp invocation. Note that this is not the same thing as ale_python_pylsp_config, which allows configuration of how pylsp functions; this is intended to provide flexibility in how the pylsp command is invoked. For example, if you had installed `pylsp` but your `pylsp` executable was not on your `PATH` for some reason, an alternative way to run the pylsp server would be: let g:ale_python_pylsp_executable = 'python3' let g:ale_python_pylsp_options = '-m pylsp' An example strategy for installing `pylsp`: `python3 -m pip install --user pylsp` =============================================================================== pyre *ale-python-pyre* `pyre` will be run from a detected project root, per |ale-python-root|. *ale-options.python_pyre_executable* *g:ale_python_pyre_executable* *b:ale_python_pyre_executable* python_pyre_executable g:ale_python_pyre_executable Type: |String| Default: `'pyre'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pyre'`. Set this to `'poetry'` to invoke `'poetry` `run` `pyre'`. *ale-options.python_pyre_use_global* *g:ale_python_pyre_use_global* *b:ale_python_pyre_use_global* python_pyre_use_global g:ale_python_pyre_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pyre_auto_pipenv* *g:ale_python_pyre_auto_pipenv* *b:ale_python_pyre_auto_pipenv* python_pyre_auto_pipenv g: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. *ale-options.python_pyre_auto_poetry* *g:ale_python_pyre_auto_poetry* *b:ale_python_pyre_auto_poetry* python_pyre_auto_poetry g:ale_python_pyre_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pyre_auto_uv* *g:ale_python_pyre_auto_uv* *b:ale_python_pyre_auto_uv* python_pyre_auto_uv g:ale_python_pyre_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pyrefly *ale-python-pyrefly* `pyrefly` will be run from a detected project root, per |ale-python-root|. *ale-options.python_pyrefly_executable* *g:ale_python_pyrefly_executable* *b:ale_python_pyrefly_executable* python_pyrefly_executable g:ale_python_pyrefly_executable Type: |String| Default: `'pyrefly'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `pyrefly'`. Set this to `'poetry'` to invoke `'poetry` `run` `pyrefly'`. Set this to `'uv'` to invoke `'uv` `run` `pyrefly'`. *ale-options.python_pyrefly_use_global* *g:ale_python_pyrefly_use_global* *b:ale_python_pyrefly_use_global* python_pyrefly_use_global g:ale_python_pyrefly_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_pyrefly_auto_pipenv* *g:ale_python_pyrefly_auto_pipenv* *b:ale_python_pyrefly_auto_pipenv* python_pyrefly_auto_pipenv g:ale_python_pyrefly_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-options.python_pyrefly_auto_poetry* *g:ale_python_pyrefly_auto_poetry* *b:ale_python_pyrefly_auto_poetry* python_pyrefly_auto_poetry g:ale_python_pyrefly_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pyrefly_auto_uv* *g:ale_python_pyrefly_auto_uv* *b:ale_python_pyrefly_auto_uv* python_pyrefly_auto_uv g:ale_python_pyrefly_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== pyright *ale-python-pyright* The `pyright` linter requires a recent version of `pyright` which includes the `pyright-langserver` executable. You can install `pyright` on your system through `npm` with `sudo npm install -g pyright` or similar. Refer to their README for installation instructions: https://github.com/Microsoft/pyright `pyright` needs to know the path to your Python executable and probably a virtualenv to run. ALE will try to detect these automatically. See |g:ale_python_pyright_config|. *ale-options.python_pyright_executable* *g:ale_python_pyright_executable* *b:ale_python_pyright_executable* python_pyright_executable g:ale_python_pyright_executable Type: |String| Default: `'pyright-langserver'` The executable for running `pyright`, which is typically installed globally. *ale-options.python_pyright_config* *g:ale_python_pyright_config* *b:ale_python_pyright_config* python_pyright_config g:ale_python_pyright_config Type: |Dictionary| Default: `{}` Settings for configuring the `pyright` language server. See pyright's documentation for a full list of options: https://github.com/microsoft/pyright/blob/master/docs/settings.md ALE will automatically try to set defaults for `venvPath` and `pythonPath` so your project can automatically be checked with the right libraries. You can override these settings with whatever you want in your ftplugin file like so: > let b:ale_python_pyright_config = { \ 'python': { \ 'pythonPath': '/bin/python', \ 'venvPath': '/other/dir', \ }, \} < If `venvPath` is set, but `pythonPath` is not, ALE will use `venvPath . '/bin/python'` or similar as `pythonPath`. A commonly used setting for `pyright` is disabling language services apart from type checking and "hover" (|ale-hover|), you can set this setting like so, or use whatever other settings you want: > let b:ale_python_pyright_config = { \ 'pyright': { \ 'disableLanguageServices': v:true, \ }, \} < *ale-options.python_pyright_auto_pipenv* *g:ale_python_pyright_auto_pipenv* *b:ale_python_pyright_auto_pipenv* python_pyright_auto_pipenv g:ale_python_pyright_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-options.python_pyright_auto_poetry* *g:ale_python_pyright_auto_poetry* *b:ale_python_pyright_auto_poetry* python_pyright_auto_poetry g:ale_python_pyright_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_pyright_auto_uv* *g:ale_python_pyright_auto_uv* *b:ale_python_pyright_auto_uv* python_pyright_auto_uv g:ale_python_pyright_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== refurb *ale-python-refurb* *ale-options.python_refurb_change_directory* *g:ale_python_refurb_change_directory* *b:ale_python_refurb_change_directory* python_refurb_change_directory g:ale_python_refurb_change_directory Type: |Number| Default: `1` If set to `1`, `refurb` will be run from a detected project root, per |ale-python-root|. if set to `0` or no project root detected, `refurb` will be run from the buffer's directory. *ale-options.python_refurb_executable* *g:ale_python_refurb_executable* *b:ale_python_refurb_executable* python_refurb_executable g:ale_python_refurb_executable Type: |String| Default: `'refurb'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `refurb'`. Set this to `'poetry'` to invoke `'poetry` `run` `refurb'`. *ale-options.python_refurb_options* *g:ale_python_refurb_options* *b:ale_python_refurb_options* python_refurb_options g:ale_python_refurb_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the refurb invocation. For example, to select/enable and/or disable some error codes, you may want to set > let g:ale_python_refurb_options = '--ignore 100' < *ale-options.python_refurb_use_global* *g:ale_python_refurb_use_global* *b:ale_python_refurb_use_global* python_refurb_use_global g:ale_python_refurb_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_refurb_auto_pipenv* *g:ale_python_refurb_auto_pipenv* *b:ale_python_refurb_auto_pipenv* python_refurb_auto_pipenv g:ale_python_refurb_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-options.python_refurb_auto_poetry* *g:ale_python_refurb_auto_poetry* *b:ale_python_refurb_auto_poetry* python_refurb_auto_poetry g:ale_python_refurb_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_refurb_auto_uv* *g:ale_python_refurb_auto_uv* *b:ale_python_refurb_auto_uv* python_refurb_auto_uv g:ale_python_refurb_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== reorder-python-imports *ale-python-reorder_python_imports* *ale-options.python_reorder_python_imports_executable* *g:ale_python_reorder_python_imports_executable* *b:ale_python_reorder_python_imports_executable* python_reorder_python_imports_executable g:ale_python_reorder_python_imports_executable Type: |String| Default: `'reorder-python-imports'` See |ale-integrations-local-executables| *ale-options.python_reorder_python_imports_options* *g:ale_python_reorder_python_imports_options* *b:ale_python_reorder_python_imports_options* python_reorder_python_imports_options g:ale_python_reorder_python_imports_options Type: |String| Default: `''` This variable can be set to pass extra options to reorder-python-imports. *ale-options.python_reorder_python_imports_use_global* *g:ale_python_reorder_python_imports_use_global* *b:ale_python_reorder_python_imports_use_global* python_reorder_python_imports_use_global g:ale_python_reorder_python_imports_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_reorder_python_imports_auto_pipenv* *g:ale_python_reorder_python_imports_auto_pipenv* *b:ale_python_reorder_python_imports_auto_pipenv* python_reorder_python_imports_auto_pipenv g:ale_python_reorder_python_imports_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-options.python_reorder_python_imports_auto_poetry* *g:ale_python_reorder_python_imports_auto_poetry* *b:ale_python_reorder_python_imports_auto_poetry* python_reorder_python_imports_auto_poetry g:ale_python_reorder_python_imports_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_reorder_python_imports_auto_uv* *g:ale_python_reorder_python_imports_auto_uv* *b:ale_python_reorder_python_imports_auto_uv* python_reorder_python_imports_auto_uv g:ale_python_reorder_python_imports_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== ruff *ale-python-ruff* *ale-options.python_ruff_change_directory* *g:ale_python_ruff_change_directory* *b:ale_python_ruff_change_directory* python_ruff_change_directory g:ale_python_ruff_change_directory Type: |Number| Default: `1` If set to `1`, `ruff` will be run from a detected project root, per |ale-python-root|. if set to `0` or no project root detected, `ruff` will be run from the buffer's directory. *ale-options.python_ruff_executable* *g:ale_python_ruff_executable* *b:ale_python_ruff_executable* python_ruff_executable g:ale_python_ruff_executable Type: |String| Default: `'ruff'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `ruff'`. Set this to `'poetry'` to invoke `'poetry` `run` `ruff'`. *ale-options.python_ruff_options* *g:ale_python_ruff_options* *b:ale_python_ruff_options* python_ruff_options g:ale_python_ruff_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the ruff invocation. For example, to select/enable and/or disable some error codes, you may want to set: > let g:ale_python_ruff_options = '--ignore F401' < *ale-options.python_ruff_use_global* *g:ale_python_ruff_use_global* *b:ale_python_ruff_use_global* python_ruff_use_global g:ale_python_ruff_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_ruff_auto_pipenv* *g:ale_python_ruff_auto_pipenv* *b:ale_python_ruff_auto_pipenv* python_ruff_auto_pipenv g:ale_python_ruff_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-options.python_ruff_auto_poetry* *g:ale_python_ruff_auto_poetry* *b:ale_python_ruff_auto_poetry* python_ruff_auto_poetry g:ale_python_ruff_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_ruff_auto_uv* *g:ale_python_ruff_auto_uv* *b:ale_python_ruff_auto_uv* python_ruff_auto_uv g:ale_python_ruff_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== ruff-format *ale-python-ruff-format* *ale-options.python_ruff_format_change_directory* *g:ale_python_ruff_format_change_directory* *b:ale_python_ruff_format_change_directory* python_ruff_format_change_directory g:ale_python_ruff_format_change_directory Type: |Number| Default: `1` If set to `1`, `ruff` will be run from a detected project root, per |ale-python-root|. if set to `0` or no project root detected, `ruff` will be run from the buffer's directory. *ale-options.python_ruff_format_executable* *g:ale_python_ruff_format_executable* *b:ale_python_ruff_format_executable* python_ruff_format_executable g:ale_python_ruff_format_executable Type: |String| Default: `'ruff'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `ruff'`. Set this to `'poetry'` to invoke `'poetry` `run` `ruff'`. *ale-options.python_ruff_format_options* *g:ale_python_ruff_format_options* *b:ale_python_ruff_format_options* python_ruff_format_options g:ale_python_ruff_format_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the ruff invocation. For example, to select/enable and/or disable some error codes, you may want to set > let g:ale_python_ruff_format_options = '--ignore F401' < *ale-options.python_ruff_format_use_global* *g:ale_python_ruff_format_use_global* *b:ale_python_ruff_format_use_global* python_ruff_format_use_global g:ale_python_ruff_format_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_ruff_format_auto_pipenv* *g:ale_python_ruff_format_auto_pipenv* *b:ale_python_ruff_format_auto_pipenv* python_ruff_format_auto_pipenv g:ale_python_ruff_format_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-options.python_ruff_format_auto_poetry* *g:ale_python_ruff_format_auto_poetry* *b:ale_python_ruff_format_auto_poetry* python_ruff_format_auto_poetry g:ale_python_ruff_format_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_ruff_format_auto_uv* *g:ale_python_ruff_format_auto_uv* *b:ale_python_ruff_format_auto_uv* python_ruff_format_auto_uv g:ale_python_ruff_format_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== unimport *ale-python-unimport* `unimport` will be run from a detected project root, per |ale-python-root|. *ale-options.python_unimport_auto_pipenv* *g:ale_python_unimport_auto_pipenv* *b:ale_python_unimport_auto_pipenv* python_unimport_auto_pipenv g:ale_python_unimport_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-options.python_unimport_auto_poetry* *g:ale_python_unimport_auto_poetry* *b:ale_python_unimport_auto_poetry* python_unimport_auto_poetry g:ale_python_unimport_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_unimport_auto_uv* *g:ale_python_unimport_auto_uv* *b:ale_python_unimport_auto_uv* python_unimport_auto_uv g:ale_python_unimport_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. *ale-options.python_unimport_executable* *g:ale_python_unimport_executable* *b:ale_python_unimport_executable* python_unimport_executable g:ale_python_unimport_executable Type: |String| Default: `'unimport'` See |ale-integrations-local-executables| Set this to `'pipenv'` to invoke `'pipenv` `run` `unimport'`. Set this to `'poetry'` to invoke `'poetry` `run` `unimport'`. *ale-options.python_unimport_options* *g:ale_python_unimport_options* *b:ale_python_unimport_options* python_unimport_options g:ale_python_unimport_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the unimport invocation. *ale-options.python_unimport_use_global* *g:ale_python_unimport_use_global* *b:ale_python_unimport_use_global* python_unimport_use_global g:ale_python_unimport_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vulture *ale-python-vulture* *ale-options.python_vulture_change_directory* *g:ale_python_vulture_change_directory* *b:ale_python_vulture_change_directory* python_vulture_change_directory g: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. *ale-options.python_vulture_executable* *g:ale_python_vulture_executable* *b:ale_python_vulture_executable* python_vulture_executable g:ale_python_vulture_executable Type: |String| Default: `'vulture'` See |ale-integrations-local-executables| *ale-options.python_vulture_options* *g:ale_python_vulture_options* *b:ale_python_vulture_options* python_vulture_options g:ale_python_vulture_options Type: |String| Default: `''` This variable can be changed to add command-line arguments to the vulture invocation. *ale-options.python_vulture_use_global* *g:ale_python_vulture_use_global* *b:ale_python_vulture_use_global* python_vulture_use_global g:ale_python_vulture_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_vulture_auto_pipenv* *g:ale_python_vulture_auto_pipenv* *b:ale_python_vulture_auto_pipenv* python_vulture_auto_pipenv g:ale_python_vulture_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-options.python_vulture_auto_poetry* *g:ale_python_vulture_auto_poetry* *b:ale_python_vulture_auto_poetry* python_vulture_auto_poetry g:ale_python_vulture_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_vulture_auto_uv* *g:ale_python_vulture_auto_uv* *b:ale_python_vulture_auto_uv* python_vulture_auto_uv g:ale_python_vulture_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== yapf *ale-python-yapf* *ale-options.python_yapf_executable* *g:ale_python_yapf_executable* *b:ale_python_yapf_executable* python_yapf_executable g:ale_python_yapf_executable Type: |String| Default: `'yapf'` See |ale-integrations-local-executables| *ale-options.python_yapf_use_global* *g:ale_python_yapf_use_global* *b:ale_python_yapf_use_global* python_yapf_use_global g:ale_python_yapf_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.python_yapf_auto_pipenv* *g:ale_python_yapf_auto_pipenv* *b:ale_python_yapf_auto_pipenv* python_yapf_auto_pipenv g:ale_python_yapf_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-options.python_yapf_auto_poetry* *g:ale_python_yapf_auto_poetry* *b:ale_python_yapf_auto_poetry* python_yapf_auto_poetry g:ale_python_yapf_auto_poetry Type: |Number| Default: `0` Detect whether the file is inside a poetry, and set the executable to `poetry` if true. This is overridden by a manually-set executable. *ale-options.python_yapf_auto_uv* *g:ale_python_yapf_auto_uv* *b:ale_python_yapf_auto_uv* python_yapf_auto_uv g:ale_python_yapf_auto_uv Type: |Number| Default: `0` Set the executable to `uv` if true. This is overridden by a manually-set executable. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-qml.txt ================================================ =============================================================================== ALE QML Integration *ale-qml-options* =============================================================================== qmlfmt *ale-qml-qmlfmt* *ale-options.qml_qmlfmt_executable* *g:ale_qml_qmlfmt_executable* *b:ale_qml_qmlfmt_executable* qml_qmlfmt_executable g:ale_qml_qmlfmt_executable Type: |String| Default: `'qmlfmt'` This variable can be set to change the path to qmlfmt. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-r.txt ================================================ =============================================================================== ALE R Integration *ale-r-options* =============================================================================== languageserver *ale-r-languageserver* *ale-options.r_languageserver_cmd* *g:ale_r_languageserver_cmd* *b:ale_r_languageserver_cmd* r_languageserver_cmd g:ale_r_languageserver_cmd Type: |String| Default: `'languageserver::run()'` This option can be configured to change the execution command for languageserver. See the languageserver documentation for more options. *ale-options.r_languageserver_config* *g:ale_r_languageserver_config* *b:ale_r_languageserver_config* r_languageserver_config g:ale_r_languageserver_config Type: |Dictionary| Default: `{}` This option can be configured to change settings for languageserver. See the languageserver documentation for more information. =============================================================================== lintr *ale-r-lintr* *ale-options.r_lintr_options* *g:ale_r_lintr_options* *b:ale_r_lintr_options* r_lintr_options g:ale_r_lintr_options Type: |String| Default: `'lintr::with_defaults()'` This option can be configured to change the options for lintr. The value of this option will be run with `eval` for the `lintr::lint` options. Consult the lintr documentation for more information. *ale-options.r_lintr_lint_package* *g:ale_r_lintr_lint_package* *b:ale_r_lintr_lint_package* r_lintr_lint_package g:ale_r_lintr_lint_package Type: |Number| Default: `0` When set to `1`, the file will be checked with `lintr::lint_package` instead of `lintr::lint`. This prevents erroneous namespace warnings when linting package files. =============================================================================== styler *ale-r-styler* *ale-options.r_styler_options* *g:ale_r_styler_options* *b:ale_r_styler_options* r_styler_options g:ale_r_styler_options Type: |String| Default: `'styler::tidyverse_style'` This option can be configured to change the options for styler. The value of this option will be used as the `style` argument for the `styler::style_file` options. Consult the styler documentation for more information. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-racket.txt ================================================ =============================================================================== ALE Racket Integration *ale-racket-options* =============================================================================== racket_langserver *ale-racket-langserver* 1. Install racket-langserver as described here: https://github.com/jeapostrophe/racket-langserver 2. Have `racket` available in the `$PATH` environment variable, currently there is no way to specify path to custom location of `racket`. 3. set `racket_langserver` as a linter for `racket` like: > let g:ale_linters['racket'] += ['racket_langserver'] You should be able to see linter results and use LSP features of `ALE` like `ALEGoToDefinition` with `racket-langserver`. =============================================================================== raco_fmt *ale-racket-raco-fmt* *ale-options.racket_raco_fmt_executable* *g:ale_racket_raco_fmt_executable* *b:ale_racket_raco_fmt_executable* racket_raco_fmt_executable g:ale_racket_raco_fmt_executable Type: |String| Default: `'raco'` If the `raco` excutable is not in the `$PATH` environment variable, or you prefer to use one installed in a custom location, set this option to the path to the specific `raco` executable. *ale-options.racket_raco_fmt_options* *g:ale_racket_raco_fmt_options* *b:ale_racket_raco_fmt_options* racket_raco_fmt_options g:ale_racket_raco_fmt_options Type: |String| Default: `''` Use this variable to pass command-line flags/parameters to `raco_fmt` For example, set the page width limit to 40 > let g:ale_racket_raco_fmt_options = '--width 40' =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-reasonml.txt ================================================ =============================================================================== ALE ReasonML Integration *ale-reasonml-options* =============================================================================== merlin *ale-reasonml-merlin* To use merlin linter for ReasonML source code you need to make sure Merlin for Vim is correctly configured. See the corresponding Merlin wiki page for detailed instructions: https://github.com/the-lambda-church/merlin/wiki/vim-from-scratch =============================================================================== ols *ale-reasonml-ols* The `ocaml-language-server` is the engine that powers OCaml and ReasonML editor support using the Language Server Protocol. See the installation instructions: https://github.com/freebroccolo/ocaml-language-server#installation ------------------------------------------------------------------------------- Options *ale-options.reason_ols_executable* *g:ale_reason_ols_executable* *b:ale_reason_ols_executable* reason_ols_executable g:ale_reason_ols_executable Type: |String| Default: `'ocaml-language-server'` This variable can be set to change the executable path for `ols`. *ale-options.reason_ols_use_global* *g:ale_reason_ols_use_global* *b:ale_reason_ols_use_global* reason_ols_use_global g:ale_reason_ols_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` This variable can be set to `1` to always use the globally installed executable. See also |ale-integrations-local-executables|. =============================================================================== reason-language-server *ale-reasonml-language-server* Note: You must set an executable - there is no 'default' install location. Go to https://github.com/jaredly/reason-language-server and download the latest release. You can place it anywhere, but ensure you set the executable path. *ale-options.reason_ls_executable* *g:ale_reason_ls_executable* *b:ale_reason_ls_executable* reason_ls_executable g:ale_reason_ls_executable Type: |String| This variable defines the standard location of the language server executable. This must be set. =============================================================================== refmt *ale-reasonml-refmt* *ale-options.reasonml_refmt_executable* *g:ale_reasonml_refmt_executable* *b:ale_reasonml_refmt_executable* reasonml_refmt_executable g:ale_reasonml_refmt_executable Type: |String| Default: `'refmt'` This variable can be set to pass the path of the refmt fixer. *ale-options.reasonml_refmt_options* *g:ale_reasonml_refmt_options* *b:ale_reasonml_refmt_options* reasonml_refmt_options g:ale_reasonml_refmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the refmt fixer. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-rego.txt ================================================ =============================================================================== ALE Rego Integration *ale-rego-options* =============================================================================== cspell *ale-rego-cspell* See |ale-cspell-options| =============================================================================== opacheck *ale-rego-opa-check* *ale-options.rego_opacheck_executable* *g:ale_rego_opacheck_executable* *b:ale_rego_opacheck_executable* rego_opacheck_executable g:ale_rego_opacheck_executable Type: |String| Default: `'opa'` This variable can be changed to use a different executable for opa. *ale-options.rego_opacheck_options* *g:rego_opacheck_options* *b:rego_opacheck_options* rego_opacheck_options g:ale_rego_opacheck_options Type: |String| Default: `''` This variable can be changed to pass custom CLI flags to opa check. =============================================================================== opafmt *ale-rego-opa-fmt-fixer* *ale-options.opa_fmt_executable* *g:ale_opa_fmt_executable* *b:ale_opa_fmt_executable* opa_fmt_executable g:ale_opa_fmt_executable Type: |String| Default: `'opa'` This variable can be changed to use a different executable for opa. *ale-options.opa_fmt_options* *g:ale_opa_fmt_options* *b:ale_opa_fmt_options* opa_fmt_options g:ale_opa_fmt_options Type: |String| Default: `''` =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-rescript.txt ================================================ =============================================================================== ALE ReScript Integration *ale-rescript-options* =============================================================================== rescript-language-server *ale-rescript-language-server* *ale-options.rescript_language_server_executable* *g:ale_rescript_language_server_executable* *b:ale_rescript_language_server_executable* ale_rescript_language_server_executable g:ale_rescript_language_server_executable Type: |String| Default: `'rescript-language-server'` See |ale-integrations-local-executables| *ale-options.rescript_language_server_use_global* *g:ale_rescript_language_server_use_global* *b:ale_rescript_language_server_use_global* rescript_language_server_use_global g:ale_rescript_language_server_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', v:true)` See |ale-integrations-local-executables| =============================================================================== rescript_format *ale-rescript-format* *ale-options.rescript_format_executable* *g:ale_rescript_format_executable* *b:ale_rescript_format_executable* rescript_format_executable g:ale_rescript_format_executable Type: |String| Default: `'rescript'` See |ale-integrations-local-executables| *ale-options.rescript_format_use_global* *g:ale_rescript_format_use_global* *b:ale_rescript_format_use_global* rescript_format_use_global g:ale_rescript_format_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', v:false)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-rest.txt ================================================ =============================================================================== ALE REST Integration *ale-rest-options* =============================================================================== kulala_fmt *ale-rest-kulala_fmt* See |ale-http-kulala_fmt| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-restructuredtext.txt ================================================ =============================================================================== ALE reStructuredText Integration *ale-restructuredtext-options* =============================================================================== cspell *ale-restructuredtext-cspell* See |ale-cspell-options| =============================================================================== textlint *ale-restructuredtext-textlint* To use textlint at reStructuredText, please install `textlint-plugin-rst`. https://github.com/jimo1001/textlint-plugin-rst > $ npm install textlint-plugin-rst To install `textlint-plugin-rst`, `docutils-ast-writer` python package must be installed. See: https://github.com/jimo1001/docutils-ast-writer See |ale-text-textlint| =============================================================================== write-good *ale-restructuredtext-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-robot.txt ================================================ =============================================================================== ALE Robot Integration *ale-robot-options* =============================================================================== rflint *ale-robot-rflint* *ale-options.robot_rflint_executable* *g:ale_robot_rflint_executable* *b:ale_robot_rflint_executable* robot_rflint_executable g:ale_robot_rflint_executable Type: |String| Default: `'rflint'` =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-roc.txt ================================================ =============================================================================== ALE Roc Integration *ale-roc-options* *ale-integration-roc* =============================================================================== roc_language_server *ale-roc-roc-language-server* *ale-options.roc_roc_language_server_executable* *g:ale_roc_roc_language_server_executable* *b:ale_roc_roc_language_server_executable* roc_roc_language_server_executable g:ale_roc_roc_language_server_executable Type: |String| Default: `'roc_language_server'` This variable can be modified to change the executable path for `roc_language_server`. *ale-options.roc_roc_language_server_config* *g:ale_roc_roc_language_server_config* *b:ale_roc_roc_language_server_config* roc_roc_language_server_config g:ale_roc_roc_language_server_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for roc_language_server. =============================================================================== roc_format *ale-roc-roc-format* *ale-options.roc_roc_format_executable* *g:ale_roc_roc_format_executable* *b:ale_roc_roc_format_executable* roc_roc_format_executable g:ale_roc_roc_format_executable Type: |String| Default: `'roc'` This variable can be modified to change the executable path for `roc`. *ale-options.roc_roc_format_options* *g:ale_roc_roc_format_options* *b:ale_roc_roc_format_options* roc_roc_format_options g:ale_roc_roc_format_options Type: String Default: `''` Additional flags for `roc format`. =============================================================================== roc_annotate *ale-roc-roc-annotate* *ale-options.roc_roc_annotate_executable* *g:ale_roc_roc_annotate_executable* *b:ale_roc_roc_annotate_executable* roc_roc_annotate_executable g:ale_roc_roc_annotate_executable Type: |String| Default: `'roc'` This variable can be modified to change the executable path for `roc`. *ale-options.roc_roc_annotate_options* *g:ale_roc_roc_annotate_options* *b:ale_roc_roc_annotate_options* roc_roc_annotate_options g:ale_roc_roc_annotate_options Type: String Default: `''` Additional flags for `roc format annotate`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-ruby.txt ================================================ =============================================================================== ALE Ruby Integration *ale-ruby-options* =============================================================================== brakeman *ale-ruby-brakeman* *ale-options.ruby_brakeman_executable* *g:ale_ruby_brakeman_executable* *b:ale_ruby_brakeman_executable* ruby_brakeman_executable g:ale_ruby_brakeman_executable Type: |String| Default: `'brakeman'` Override the invoked brakeman binary. Set this to `'bundle'` to invoke `'bundle` `exec` brakeman'. *ale-options.ruby_brakeman_options* *g:ale_ruby_brakeman_options* *b:ale_ruby_brakeman_options* ruby_brakeman_options g:ale_ruby_brakeman_options Type: |String| Default: `''` The contents of this variable will be passed through to brakeman. =============================================================================== cspell *ale-ruby-cspell* See |ale-cspell-options| =============================================================================== debride *ale-ruby-debride* *ale-options.ruby_debride_executable* *g:ale_ruby_debride_executable* *b:ale_ruby_debride_executable* ruby_debride_executable g:ale_ruby_debride_executable Type: |String| Default: `'debride'` Override the invoked debride binary. Set this to `'bundle'` to invoke `'bundle` `exec` debride'. *ale-options.ruby_debride_options* *g:ale_ruby_debride_options* *b:ale_ruby_debride_options* ruby_debride_options g:ale_ruby_debride_options Type: |String| Default: `''` This variable can be changed to modify flags given to debride. =============================================================================== packwerk *ale-ruby-packwerk* *ale-options.ruby_packwerk_executable* *g:ale_ruby_packwerk_executable* *b:ale_ruby_packwerk_executable* ruby_packwerk_executable g:ale_ruby_packwerk_executable Type: |String| Default: `'packwerk'` Override the invoked packwerk binary. Set this to `'bundle'` to invoke `'bundle` `exec` packwerk'. *ale-options.ruby_packwerk_options* *g:ale_ruby_packwerk_options* *b:ale_ruby_packwerk_options* ruby_packwerk_options g:ale_ruby_packwerk_options Type: |String| Default: `''` This variable can be changed to modify flags given to packwerk. =============================================================================== prettier *ale-ruby-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== rails_best_practices *ale-ruby-rails_best_practices* *ale-options.ruby_rails_best_practices_executable* *g:ale_ruby_rails_best_practices_executable* *b:ale_ruby_rails_best_practices_executable* ruby_rails_best_practices_executable g:ale_ruby_rails_best_practices_executable Type: |String| Default: `'rails_best_practices'` Override the invoked rails_best_practices binary. Set this to `'bundle'` to invoke `'bundle` `exec` rails_best_practices'. *ale-options.ruby_rails_best_practices_options* *g:ale_ruby_rails_best_practices_options* *b:ale_ruby_rails_best_practices_options* ruby_rails_best_practices_options g:ale_ruby_rails_best_practices_options Type: |String| Default: `''` The contents of this variable will be passed through to rails_best_practices. =============================================================================== reek *ale-ruby-reek* *ale-options.ruby_reek_executable* *g:ale_ruby_reek_executable* *b:ale_ruby_reek_executable* ruby_reek_executable g:ale_ruby_reek_executable Type: |String| Default: `'reek'` Override the invoked reek binary. Set this to `'bundle'` to invoke `'bundle` `exec` reek'. *ale-options.ruby_reek_show_context* *g:ale_ruby_reek_show_context* *b:ale_ruby_reek_show_context* ruby_reek_show_context g:ale_ruby_reek_show_context Type: |Number| Default: `0` Controls whether context is included in the linter message. Defaults to off because context is usually obvious while viewing a file. *ale-options.ruby_reek_show_wiki_link* *g:ale_ruby_reek_show_wiki_link* *b:ale_ruby_reek_show_wiki_link* ruby_reek_show_wiki_link g:ale_ruby_reek_show_wiki_link Type: |Number| Default: `0` Controls whether linter messages contain a link to an explanatory wiki page for the type of code smell. Defaults to off to improve readability. =============================================================================== rubocop *ale-ruby-rubocop* *ale-options.ruby_rubocop_executable* *g:ale_ruby_rubocop_executable* *b:ale_ruby_rubocop_executable* ruby_rubocop_executable g:ale_ruby_rubocop_executable Type: |String| Default: `'rubocop'` Override the invoked rubocop binary. Set this to `'bundle'` to invoke `'bundle` `exec` rubocop'. *ale-options.ruby_rubocop_options* *g:ale_ruby_rubocop_options* *b:ale_ruby_rubocop_options* ruby_rubocop_options g:ale_ruby_rubocop_options Type: |String| Default: `''` This variable can be changed to modify flags given to rubocop. *ale-options.ruby_rubocop_auto_correct_all* *g:ale_ruby_rubocop_auto_correct_all* *b:ale_ruby_rubocop_auto_correct_all* ruby_rubocop_auto_correct_all g:ale_ruby_rubocop_auto_correct_all Type: |Number| Default: `0` This variable can be changed to make rubocop to correct all offenses (unsafe). =============================================================================== ruby *ale-ruby-ruby* *ale-options.ruby_ruby_executable* *g:ale_ruby_ruby_executable* *b:ale_ruby_ruby_executable* ruby_ruby_executable g:ale_ruby_ruby_executable Type: |String| Default: `'ruby'` This variable can be changed to use a different executable for ruby. =============================================================================== rufo *ale-ruby-rufo* *ale-options.ruby_rufo_executable* *g:ale_ruby_rufo_executable* *b:ale_ruby_rufo_executable* ruby_rufo_executable g:ale_ruby_rufo_executable Type: |String| Default: `'rufo'` Override the invoked rufo binary. This is useful for running rufo from binstubs or a bundle. =============================================================================== solargraph *ale-ruby-solargraph* *ale-options.ruby_solargraph_executable* *g:ale_ruby_solargraph_executable* *b:ale_ruby_solargraph_executable* ruby_solargraph_executable g:ale_ruby_solargraph_executable Type: |String| Default: `'solargraph'` Override the invoked solargraph binary. Set this to `'bundle'` to invoke `'bundle` `exec` solargraph'. =============================================================================== sorbet *ale-ruby-sorbet* *ale-options.ruby_sorbet_executable* *g:ale_ruby_sorbet_executable* *b:ale_ruby_sorbet_executable* ruby_sorbet_executable g:ale_ruby_sorbet_executable Type: |String| Default: `'srb'` Override the invoked sorbet binary. Set this to `'bundle'` to invoke `'bundle` `exec` srb'. *ale-options.ruby_sorbet_options* *g:ale_ruby_sorbet_options* *b:ale_ruby_sorbet_options* ruby_sorbet_options g:ale_ruby_sorbet_options Type: |String| Default: `''` This variable can be changed to modify flags given to sorbet. *ale-options.ruby_sorbet_enable_watchman* *g:ale_ruby_sorbet_enable_watchman* *b:ale_ruby_sorbet_enable_watchman* ruby_sorbet_enable_watchman g:ale_ruby_sorbet_enable_watchman Type: |Number| Default: `0` Whether or not to use watchman to let the LSP server to know about changes to files from outside of vim. Defaults to disable watchman because it requires watchman to be installed separately from sorbet. *ale-options.ruby_sorbet_initialization_options* *g:ale_ruby_sorbet_initialization_options* *b:ale_ruby_sorbet_initialization_options* ruby_sorbet_initialization_options g:ale_ruby_sorbet_initialization_options Type: |Dictionary| Default: `{ 'highlightUntyped': v:false }` This variable can be changed to modify initialization options provided to the Sorbet language server. By default, a minimal object with defaults is provided to ensure proper LSP initialization. Setting this variable to a an empty object will cause sorbet LSP to fail during initialization. See https://sorbet.org/docs/lsp#initialize-request for available options. =============================================================================== standardrb *ale-ruby-standardrb* *ale-options.ruby_standardrb_executable* *g:ale_ruby_standardrb_executable* *b:ale_ruby_standardrb_executable* ruby_standardrb_executable g:ale_ruby_standardrb_executable Type: |String| Default: `'standardrb'` Override the invoked standardrb binary. Set this to `'bundle'` to invoke `'bundle` `exec` standardrb'. *ale-options.ruby_standardrb_options* *g:ale_ruby_standardrb_options* *b:ale_ruby_standardrb_options* ruby_standardrb_options g:ale_ruby_standardrb_options Type: |String| Default: `''` This variable can be changed to modify flags given to standardrb. =============================================================================== syntax_tree *ale-ruby-syntax_tree* *ale-options.ruby_syntax_tree_executable* *g:ale_ruby_syntax_tree_executable* *b:ale_ruby_syntax_tree_executable* ruby_syntax_tree_executable g:ale_ruby_syntax_tree_executable Type: |String| Default: `'stree'` Override the invoked SyntaxTree binary. Set this to `'bundle'` to invoke `'bundle` `exec` stree'. *ale-options.ruby_syntax_tree_options* *g:ale_ruby_syntax_tree_options* *b:ale_ruby_syntax_tree_options* ruby_syntax_tree_options g:ale_ruby_syntax_tree_options Type: |String| Default: `''` This variable can be changed to modify flags given to SyntaxTree. =============================================================================== rubyfmt *ale-ruby-rubyfmt* *ale-options.ruby_rubyfmt_executable* *g:ale_ruby_rubyfmt_executable* *b:ale_ruby_rubyfmt_executable* ruby_rubyfmt_executable g:ale_ruby_rubyfmt_executable Type: |String| Default: `'rubyfmt'` This option can be changed to change the path for `rubyfmt`. *ale-options.ruby_rubyfmt_options* *g:ale_ruby_rubyfmt_options* *b:ale_ruby_rubyfmt_options* ruby_rubyfmt_options g:ale_ruby_rubyfmt_options Type: |String| Default: `''` This option can be changed to pass extra options to `'rubyfmt'`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-rust.txt ================================================ =============================================================================== ALE Rust Integration *ale-rust-options* *ale-integration-rust* =============================================================================== Integration Information 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 several possible linters and fixers for Rust files: 1. rustc -- The Rust compiler is used to check the currently edited file. So, if your project consists of multiple files, you will get some errors when you use e.g. a struct which is defined in another file. You can use |g:ale_rust_ignore_error_codes| to ignore some of these errors. 2. cargo -- If your project is managed by Cargo, the whole project is checked. That means that all errors are properly shown, but cargo can only operate on the files written on disk, so errors will not be reported while you type. 3. rls -- If you have `rls` installed, you might prefer using this linter over cargo. rls implements the Language Server Protocol for incremental compilation of Rust code, and can check Rust files while you type. `rls` requires Rust files to be contained in Cargo projects. 4. analyzer -- If you have rust-analyzer installed, you might prefer using this linter over cargo and rls. rust-analyzer also implements the Language Server Protocol for incremental compilation of Rust code, and is the next iteration of rls. rust-analyzer either requires Rust files to be contained in Cargo projects or requires the project to be described in the rust-project.json format: https://rust-analyzer.github.io/manual.html#non-cargo-based-projects 5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to consistently reformat your Rust code. Only cargo and rust-analyzer are enabled by default. To switch to using rustc instead of cargo, configure |b:ale_linters| in your ftplugin file appropriately: > " See the help text for the option for more information. let b:ale_linters = ['analyzer', 'rustc'] < Or in Lua: > require("ale").setup.buffer({linters = {"analyzer", "rustc"}}) < Also note that rustc 1.18. or later is needed. =============================================================================== analyzer *ale-rust-analyzer* *ale-options.rust_analyzer_executable* *g:ale_rust_analyzer_executable* *b:ale_rust_analyzer_executable* rust_analyzer_executable g:ale_rust_analyzer_executable Type: |String| Default: `'rust-analyzer'` This variable can be modified to change the executable path for `rust-analyzer`. *ale-options.rust_analyzer_config* *g:ale_rust_analyzer_config* *b:ale_rust_analyzer_config* rust_analyzer_config g:ale_rust_analyzer_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for rust-analyzer. Keys of the dictionary are components of configuration keys. For example: > let g:ale_rust_analyzer_config = { \ 'server': { \ 'extraEnv': { 'RUSTUP_TOOLCHAIN': 'stable' }, \ } \} < corresponds to `rust-analyzer.server.extraEnv = { 'RUSTUP_TOOLCHAIN': 'stable' }` For available configuration parameters, see the `rust-analyzer` manual: https://rust-analyzer.github.io/manual.html#configuration =============================================================================== cargo *ale-rust-cargo* *ale-options.rust_cargo_use_check* *g:ale_rust_cargo_use_check* *b:ale_rust_cargo_use_check* rust_cargo_use_check g:ale_rust_cargo_use_check Type: |Number| Default: `1` When set to `1`, this option will cause ALE to use `cargo check` instead of `cargo build` . `cargo check` is supported since version 1.16.0 of Rust. ALE will never use `cargo check` when the version of `cargo` is less than 0.17.0. *ale-options.rust_cargo_check_all_targets* *g:ale_rust_cargo_check_all_targets* *b:ale_rust_cargo_check_all_targets* rust_cargo_check_all_targets g:ale_rust_cargo_check_all_targets Type: |Number| Default: `0` When set to `1`, ALE will set the `--all-targets` option when `cargo check` is used. See |g:ale_rust_cargo_use_check|, *ale-options.rust_cargo_check_tests* *g:ale_rust_cargo_check_tests* *b:ale_rust_cargo_check_tests* rust_cargo_check_tests g:ale_rust_cargo_check_tests Type: |Number| Default: `0` When set to `1`, ALE will set the `--tests` option when `cargo check` is used. This allows for linting of tests which are normally excluded. See |g:ale_rust_cargo_use_check|, *ale-options.rust_cargo_check_examples* *g:ale_rust_cargo_check_examples* *b:ale_rust_cargo_check_examples* rust_cargo_check_examples g:ale_rust_cargo_check_examples Type: |Number| Default: `0` When set to `1`, ALE will set the `--examples` option when `cargo check` is used. This allows for linting of examples which are normally excluded. See |g:ale_rust_cargo_use_check|, *ale-options.rust_cargo_default_feature_behavior* *g:ale_rust_cargo_default_feature_behavior* *b:ale_rust_cargo_default_feature_behavior* rust_cargo_default_feature_behavior g:ale_rust_cargo_default_feature_behavior Type: |String| Default: `default` When set to `none`, ALE will set the `--no-default-features` option when invoking `cargo`. Only the features specified in |g:ale_rust_cargo_include_features| will be included when performing the lint check. When set to `default`, ALE will instruct `cargo` to build all default features specified in the project's `Cargo.toml` file, in addition to including any additional features defined in |g:ale_rust_cargo_include_features|. When set to `all`, ALE will set the `--all-features` option when invoking `cargo`, which will include all features defined in the project's `Cargo.toml` file when performing the lint check. *ale-options.rust_cargo_include_features* *g:ale_rust_cargo_include_features* *b:ale_rust_cargo_include_features* rust_cargo_include_features g:ale_rust_cargo_include_features Type: |String| Default: `''` When defined, ALE will set the `--features` option when invoking `cargo` to perform the lint check. See |g:ale_rust_cargo_default_feature_behavior|. *ale-options.rust_cargo_avoid_whole_workspace* *g:ale_rust_cargo_avoid_whole_workspace* *b:ale_rust_cargo_avoid_whole_workspace* rust_cargo_avoid_whole_workspace g: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 workspace by invoking `cargo` directly in the crate's directory. Otherwise, behave as usual. *ale-options.rust_cargo_use_clippy* *g:ale_rust_cargo_use_clippy* *b:ale_rust_cargo_use_clippy* rust_cargo_use_clippy g: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') < *ale-options.rust_cargo_clippy_options* *g:ale_rust_cargo_clippy_options* *b:ale_rust_cargo_clippy_options* rust_cargo_clippy_options g: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`). *ale-options.rust_cargo_target_dir* *g:ale_rust_cargo_target_dir* *b:ale_rust_cargo_target_dir* rust_cargo_target_dir g:ale_rust_cargo_target_dir Type: |String| Default: `''` Use a custom target directory when running the commands for ALE. This can help to avoid "waiting for file lock on build directory" messages when running `cargo` commands manually while ALE is performing its checks. =============================================================================== cspell *ale-rust-cspell* See |ale-cspell-options| =============================================================================== rls *ale-rust-rls* *ale-options.rust_rls_executable* *g:ale_rust_rls_executable* *b:ale_rust_rls_executable* rust_rls_executable g:ale_rust_rls_executable Type: |String| Default: `'rls'` This variable can be modified to change the executable path for `rls`. *ale-options.rust_rls_toolchain* *g:ale_rust_rls_toolchain* *b:ale_rust_rls_toolchain* rust_rls_toolchain g:ale_rust_rls_toolchain Type: |String| Default: `''` This option can be set to change the toolchain used for `rls`. Possible values include `'nightly'`, `'beta'`, `'stable'`, and `''`. When using option `''`, rls will automatically find the default toolchain set by rustup. If you want to use `rls` from a specific toolchain version, you may also use values like `'channel-yyyy-mm-dd-arch-target'` as long as `'rls +{toolchain_name} -V'` runs correctly in your command line. The `rls` server will only be started once per executable. *ale-options.rust_rls_config* *g:ale_rust_rls_config* *b:ale_rust_rls_config* rust_rls_config g:ale_rust_rls_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for rls. For example, to force using clippy as linter in your ftplugin file: > let b:ale_rust_rls_config = { \ 'rust': { \ 'clippy_preference': 'on' \ }, \} < Or in Lua: > require("ale").setup.buffer({ rust_rls_config = { rust = { clippy_preference = "on", }, }, }) < =============================================================================== rustc *ale-rust-rustc* *ale-options.rust_rustc_options* *g:ale_rust_rustc_options* *b:ale_rust_rustc_options* rust_rustc_options g:ale_rust_rustc_options Type: |String| Default: `'--emit=mir -o /dev/null'` The variable can be used to change the options passed to `rustc`. Users of nightly builds of Rust might want to use `-Z no-codegen` instead. Be careful when setting the options, as running `rustc` could execute code or generate binary files. *ale-options.rust_ignore_error_codes* *g:ale_rust_ignore_error_codes* *b:ale_rust_ignore_error_codes* rust_ignore_error_codes g:ale_rust_ignore_error_codes Type: |List| of |String|s Default: `[]` This variable can contain error codes which will be ignored. For example, to ignore most errors regarding failed imports, put this in your .vimrc > let g:ale_rust_ignore_error_codes = ['E0432', 'E0433'] < *ale-options.rust_ignore_secondary_spans* *g:ale_rust_ignore_secondary_spans* *b:ale_rust_ignore_secondary_spans* rust_ignore_secondary_spans g:ale_rust_ignore_secondary_spans Type: |Number| Default: `0` When set to 1, instructs the Rust error reporting 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* *ale-options.rust_rustfmt_options* *g:ale_rust_rustfmt_options* *b:ale_rust_rustfmt_options* rust_rustfmt_options g:ale_rust_rustfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the rustfmt fixer. *ale-options.rust_rustfmt_executable* *g:ale_rust_rustfmt_executable* *b:ale_rust_rustfmt_executable* rust_rustfmt_executable g:ale_rust_rustfmt_executable Type: |String| Default: `'rustfmt'` This variable can be modified to change the executable path for `rustfmt`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-salt.tmt ================================================ =============================================================================== ALE SALT Integration *ale-salt-options* =============================================================================== salt-lint *ale-salt-salt-lint* Website: https://github.com/warpnet/salt-lint ------------------------------------------------------------------------------- Installation Install salt-lint in your a virtualenv directory, locally, or globally: > pip install salt-lint # After activating virtualenv pip install --user salt-lint # Install to ~/.local/bin sudo pip install salt-lint # Install globally < See |g:ale_virtualenv_dir_names| for configuring how ALE searches for virtualenv directories. ------------------------------------------------------------------------------- Options *ale-options.salt_salt_lint_executable* *g:ale_salt_salt_lint_executable* *b:ale_salt_salt_lint_executable* salt_salt_lint_executable g:ale_salt_salt_lint_executable Type: |String| Default: `'salt-lint'` This variable can be set to change the path to salt-lint. *ale-options.salt_salt_lint_options* *g:ale_salt_salt_lint_options* *b:ale_salt_salt_lint_options* salt_salt_lint_options g:ale_salt_salt_lint_options Type: |String| Default: `''` This variable can be set to pass additional options to salt-lint. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-sass.txt ================================================ =============================================================================== ALE Sass Integration *ale-sass-options* =============================================================================== sasslint *ale-sass-sasslint* See |ale-scss-sasslint| for information about the available options. =============================================================================== stylelint *ale-sass-stylelint* *ale-options.sass_stylelint_executable* *g:ale_sass_stylelint_executable* *b:ale_sass_stylelint_executable* sass_stylelint_executable g:ale_sass_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.sass_stylelint_use_global* *g:ale_sass_stylelint_use_global* *b:ale_sass_stylelint_use_global* sass_stylelint_use_global g:ale_sass_stylelint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-scala.txt ================================================ =============================================================================== ALE Scala Integration *ale-scala-options* =============================================================================== cspell *ale-scala-cspell* See |ale-cspell-options| =============================================================================== metals *ale-scala-metals* `metals` requires either an SBT project, a Mill project, or a running Bloop server. *ale-options.scala_metals_executable* *g:ale_scala_metals_executable* *b:ale_scala_metals_executable* scala_metals_executable g:ale_scala_metals_executable Type: |String| Default: `'metals-vim'` Override the invoked `metals` binary. *ale-options.scala_metals_project_root* *g:ale_scala_metals_project_root* *b:ale_scala_metals_project_root* scala_metals_project_root g:ale_scala_metals_project_root Type: |String| Default: `''` By default the project root is found by searching upwards for `build.sbt`, `build.sc`, `build.mill`, `.bloop` or `.metals`. If the project root is elsewhere, you can override the project root directory. =============================================================================== 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` *ale-options.scala_sbtserver_address* *g:ale_scala_sbtserver_address* *b:ale_scala_sbtserver_address* scala_sbtserver_address g: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. *ale-options.scala_sbtserver_project_root* *g:ale_scala_sbtserver_project_root* *b:ale_scala_sbtserver_project_root* scala_sbtserver_project_root g: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: > let g:ale_scala_scalafmt_executable = 'ng' < *ale-options.scala_scalafmt_executable* *g:ale_scala_scalafmt_executable* *b:ale_scala_scalafmt_executable* scala_scalafmt_executable g:ale_scala_scalafmt_executable Type: |String| Default: `'scalafmt'` Override the invoked `scalafmt` binary. This is useful for running `scalafmt` with Nailgun. *ale-options.scala_scalafmt_options* *g:ale_scala_scalafmt_options* *b:ale_scala_scalafmt_options* scala_scalafmt_options g:ale_scala_scalafmt_options Type: |String| Default: `''` A string containing additional options to pass to `'scalafmt'`, or `'ng scalafmt'` if Nailgun is used. =============================================================================== scalastyle *ale-scala-scalastyle* `scalastyle` requires a configuration file for a project to run. When no configuration file can be found, ALE will report a problem saying that a configuration file is required at line 1. To disable `scalastyle` globally, use |g:ale_linters| like so: > let g:ale_linters = {'scala': ['scalac']} " Enable only scalac instead < See |g:ale_linters| for more information on disabling linters. *ale-options.scala_scalastyle_config* *g:ale_scala_scalastyle_config* *b:ale_scala_scalastyle_config* scala_scalastyle_config g:ale_scala_scalastyle_config Type: |String| Default: `''` A string containing the location of a global fallback configuration file. By default, ALE will look for a configuration file named `scalastyle_config.xml` or `scalastyle-config.xml` in the current file's directory or parent directories. *ale-options.scala_scalastyle_options* *g:ale_scala_scalastyle_options* *b:ale_scala_scalastyle_options* scala_scalastyle_options g:ale_scala_scalastyle_options Type: |String| Default: `''` A string containing additional options to pass to scalastyle. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-scss.txt ================================================ =============================================================================== ALE SCSS Integration *ale-scss-options* =============================================================================== prettier *ale-scss-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== sasslint *ale-scss-sasslint* *ale-options.scss_sasslint_executable* *g:ale_scss_sasslint_executable* *b:ale_scss_sasslint_executable* scss_sasslint_executable g:ale_scss_sasslint_executable Type: |String| Default: `'sass-lint'` See |ale-integrations-local-executables| *ale-options.scss_sasslint_options* *g:ale_scss_sasslint_options* *b:ale_scss_sasslint_options* scss_sasslint_options g:ale_scss_sasslint_options Type: |String| Default: `''` This variable can be set to pass additional options to sass-lint. *ale-options.scss_sasslint_use_global* *g:ale_scss_sasslint_use_global* *b:ale_scss_sasslint_use_global* scss_sasslint_use_global g:ale_scss_sasslint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== stylelint *ale-scss-stylelint* *ale-options.scss_stylelint_executable* *g:ale_scss_stylelint_executable* *b:ale_scss_stylelint_executable* scss_stylelint_executable g:ale_scss_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.scss_stylelint_options* *g:ale_scss_stylelint_options* *b:ale_scss_stylelint_options* scss_stylelint_options g:ale_scss_stylelint_options Type: |String| Default: `''` This variable can be set to pass additional options to stylelint. *ale-options.scss_stylelint_use_global* *g:ale_scss_stylelint_use_global* *b:ale_scss_stylelint_use_global* scss_stylelint_use_global g:ale_scss_stylelint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-sh.txt ================================================ =============================================================================== ALE Shell Integration *ale-sh-options* =============================================================================== bashate *ale-sh-bashate* *ale-options.sh_bashate_executable* *g:ale_sh_bashate_executable* *b:ale_sh_bashate_executable* sh_bashate_executable g:ale_sh_bashate_executable Type: |String| Default: `'bashate'` This variable sets executable used for bashate. *ale-options.sh_bashate_options* *g:ale_sh_bashate_options* *b:ale_sh_bashate_options* sh_bashate_options g:ale_sh_bashate_options Type: |String| Default: `''` With this variable we are able to pass extra arguments for bashate. For example to ignore the indentation rule: > let g:ale_sh_bashate_options = '-i E003' < =============================================================================== cspell *ale-sh-cspell* See |ale-cspell-options| =============================================================================== sh-language-server *ale-sh-language-server* *ale-options.sh_language_server_executable* *g:ale_sh_language_server_executable* *b:ale_sh_language_server_executable* sh_language_server_executable g:ale_sh_language_server_executable Type: |String| Default: `'bash-language-server'` See |ale-integrations-local-executables| *ale-options.sh_language_server_use_global* *g:ale_sh_language_server_use_global* *b:ale_sh_language_server_use_global* sh_language_server_use_global g:ale_sh_language_server_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== shell *ale-sh-shell* *ale-options.sh_shell_default_shell* *g:ale_sh_shell_default_shell* *b:ale_sh_shell_default_shell* sh_shell_default_shell g:ale_sh_shell_default_shell Type: |String| Default: The current shell (`$SHELL`). Falls back to `'bash'` if that cannot be read or if the current shell is `'fish'`. When ALE runs the linter for shells with the `-n` flag, it will attempt to read the shell from the shebang (`#!`) line from the shell script to determine the shell program to run. When this detection fails, this variable will be used instead. =============================================================================== shellcheck *ale-sh-shellcheck* *ale-options.sh_shellcheck_executable* *g:ale_sh_shellcheck_executable* *b:ale_sh_shellcheck_executable* sh_shellcheck_executable g:ale_sh_shellcheck_executable Type: |String| Default: `'shellcheck'` This variable sets executable used for shellcheck. *ale-options.sh_shellcheck_options* *g:ale_sh_shellcheck_options* *b:ale_sh_shellcheck_options* sh_shellcheck_options g:ale_sh_shellcheck_options Type: |String| Default: `''` With this variable we are able to pass extra arguments for shellcheck for shellcheck invocation. For example, if we want shellcheck to follow external sources (`see SC1091`) we can set the variable as such: > let g:ale_sh_shellcheck_options = '-x' < *ale-options.sh_shellcheck_change_directory* *g:ale_sh_shellcheck_change_directory* *b:ale_sh_shellcheck_change_directory* sh_shellcheck_change_directory g:ale_sh_shellcheck_change_directory Type: |Number| Default: `1` If set to `1`, ALE will switch to the directory the shell file being checked with `shellcheck` is in before checking it. This helps `shellcheck` determine the path to sourced files more easily. This option can be turned off if you want to control the directory `shellcheck` is executed from yourself. *ale-options.sh_shellcheck_dialect* *g:ale_sh_shellcheck_dialect* *b:ale_sh_shellcheck_dialect* sh_shellcheck_dialect g:ale_sh_shellcheck_dialect Type: |String| Default: `'auto'` This variable specifies the shellcheck dialect (`-s` option). The value `'auto'` causes ALE to detect the dialect automatically, based on the shebang line (if present) or the value of `b:is_bash`, `b:is_sh`, or `b:is_kornshell` (set and used by |sh.vim|). *ale-options.sh_shellcheck_exclusions* *g:ale_sh_shellcheck_exclusions* *b:ale_sh_shellcheck_exclusions* sh_shellcheck_exclusions g:ale_sh_shellcheck_exclusions Type: |String| Default: `''` Set this variable to exclude test(s) for shellcheck (-e/--exclude option). To exclude more than one option, separate them with commas. For example, to ignore some warnings that aren't applicable to files that will be sourced by other scripts, use the buffer-local variant: > autocmd BufEnter PKGBUILD,.env \ let b:ale_sh_shellcheck_exclusions = 'SC2034,SC2154,SC2164' < =============================================================================== shfmt *ale-sh-shfmt* *ale-options.sh_shfmt_options* *g:ale_sh_shfmt_options* *b:ale_sh_shfmt_options* sh_shfmt_options g:ale_sh_shfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the shfmt fixer. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-sml.txt ================================================ =============================================================================== ALE SML Integration *ale-sml-options* =============================================================================== smlnj *ale-sml-smlnj* *ale-sml-smlnj-cm* There are two SML/NJ powered checkers: - one using Compilation Manager that works on whole projects, but requires you to save before errors show up - one using the SML/NJ REPL that works as you change the text, but might fail if your project can only be built with CM. We dynamically select which one to use based whether we find a `*.cm` file at or above the directory of the file being checked. Only one checker (`smlnj`, `smlnj-cm`) will be enabled at a time. ------------------------------------------------------------------------------- Options *ale-options.sml_smlnj_cm_file* *g:ale_sml_smlnj_cm_file* *b:ale_sml_smlnj_cm_file* sml_smlnj_cm_file g:ale_sml_smlnj_cm_file Type: |String| Default: `'*.cm'` By default, ALE will look for a `*.cm` file in your current directory, searching upwards. It stops when it finds at least one `*.cm` file (taking the first file if there are more than one). Change this option (in the buffer or global scope) to control how ALE finds CM files. For example, to always search for a CM file named `sandbox.cm`: > let g:ale_sml_smlnj_cm_file = 'sandbox.cm' < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-solidity.txt ================================================ =============================================================================== ALE Solidity Integration *ale-solidity-options* =============================================================================== solc *ale-solidity-solc* *ale-options.solidity_solc_executable* *g:ale_solidity_solc_executable* *b:ale_solidity_solc_executable* solidity_solc_executable g:ale_solidity_solc_executable Type: |String| Default: `'solc'` Override the invoked solc binary. For truffle/hardhat binaries. *ale-options.solidity_solc_options* *g:ale_solidity_solc_options* *b:ale_solidity_solc_options* solidity_solc_options g:ale_solidity_solc_options Type: |String| Default: `''` This variable can be set to pass extra options to solc. =============================================================================== solhint *ale-solidity-solhint* Solhint should work out-of-the-box. You can further configure it using a `.solihint.json` file. See https://github.com/protofire/solhint for more information. =============================================================================== solium *ale-solidity-solium* Use of Solium linter for Solidity source code requires a .soliumrc.json file in project root. This file can be generated by running `solium --init`. See the corresponding solium usage for detailed instructions (https://github.com/duaraghav8/Solium#usage). =============================================================================== forge *ale-solidity-forge* `forge fmt` is not a linter, only a formatter. It should be used only as a fixer. `forge fmt` should work out-of-the-box. You can further configure it using `foundry.toml`. See the corresponding documentation for detailed instructions (https://book.getfoundry.sh/reference/config/formatter). =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-spec.txt ================================================ =============================================================================== ALE Spec Integration *ale-spec-options* *ale-integration-spec* =============================================================================== Integration Information The rpmlint linter is disabled by default, because running rpmlint can result in the execution of code embedded in the spec file and rpmlint makes no distinction between checks which are safe to run on untrusted files and those which are not. Currently linters must be enabled globally. The rpmlint linter can be enabled with: > let g:ale_linters = {'spec': ['rpmlint']} < =============================================================================== rpmlint *ale-spec-rpmlint* *ale-options.spec_rpmlint_executable* *g:ale_spec_rpmlint_executable* *b:ale_spec_rpmlint_executable* spec_rpmlint_executable g:ale_spec_rpmlint_executable Type: |String| Default: `'rpmlint'` This variable sets executable used for rpmlint. *ale-options.spec_rpmlint_options* *g:ale_spec_rpmlint_options* *b:ale_spec_rpmlint_options* spec_rpmlint_options g:ale_spec_rpmlint_options Type: |String| Default: `''` Set this to pass extra arguments to rpmlint. For example, to instruct rpmlint to use a specific configuration file: > let g:ale_spec_rpmlint_options = '-f custom.cf' < =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-sql.txt ================================================ =============================================================================== ALE SQL Integration *ale-sql-options* =============================================================================== dprint *ale-sql-dprint* See |ale-dprint-options| and https://github.com/dprint/dprint-plugin-sql/releases =============================================================================== pgformatter *ale-sql-pgformatter* *ale-options.sql_pgformatter_executable* *g:ale_sql_pgformatter_executable* *b:ale_sql_pgformatter_executable* sql_pgformatter_executable g:ale_sql_pgformatter_executable Type: |String| Default: `'pg_format'` This variable sets executable used for pgformatter. *ale-options.sql_pgformatter_options* *g:ale_sql_pgformatter_options* *b:ale_sql_pgformatter_options* sql_pgformatter_options g:ale_sql_pgformatter_options Type: |String| Default: `''` This variable can be set to pass additional options to the pgformatter fixer. =============================================================================== sqlfluff *ale-sql-sqlfluff* *ale-options.sql_sqlfluff_executable* *g:ale_sql_sqlfluff_executable* *b:ale_sql_sqlfluff_executable* sql_sqlfluff_executable g:ale_sql_sqlfluff_executable Type: |String| Default: `'sqlfluff'` This variable sets executable used for sqlfluff. *ale-options.sql_sqlfluff_options* *g:ale_sql_sqlfluff_options* *b:ale_sql_sqlfluff_options* sql_sqlfluff_options g:ale_sql_sqlfluff_options Type: |String| Default: `''` This variable can be set to pass additional options to the sqlfluff linter. =============================================================================== sqlfmt *ale-sql-sqlfmt* *ale-options.sql_sqlfmt_executable* *g:ale_sql_sqlfmt_executable* *b:ale_sql_sqlfmt_executable* sql_sqlfmt_executable g:ale_sql_sqlfmt_executable Type: |String| Default: `'sqlfmt'` This variable sets executable used for sqlfmt. *ale-options.sql_sqlfmt_options* *g:ale_sql_sqlfmt_options* *b:ale_sql_sqlfmt_options* sql_sqlfmt_options g: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. =============================================================================== sqlformat *ale-sql-sqlformat* *ale-options.sql_sqlformat_executable* *g:ale_sql_sqlformat_executable* *b:ale_sql_sqlformat_executable* sql_sqlformat_executable g:ale_sql_sqlformat_executable Type: |String| Default: `'sqlformat'` This variable sets executable used for sqlformat. *ale-options.sql_sqlformat_options* *g:ale_sql_sqlformat_options* *b:ale_sql_sqlformat_options* sql_sqlformat_options g:ale_sql_sqlformat_options Type: |String| Default: `''` This variable can be set to pass additional options to the sqlformat fixer. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-stylus.txt ================================================ =============================================================================== ALE Stylus Integration *ale-stylus-options* =============================================================================== stylelint *ale-stylus-stylelint* *ale-options.stylus_stylelint_executable* *g:ale_stylus_stylelint_executable* *b:ale_stylus_stylelint_executable* stylus_stylelint_executable g:ale_stylus_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.stylus_stylelint_options* *g:ale_stylus_stylelint_options* *b:ale_stylus_stylelint_options* stylus_stylelint_options g:ale_stylus_stylelint_options Type: |String| Default: `''` This variable can be set to pass additional options to stylelint. *ale-options.stylus_stylelint_use_global* *g:ale_stylus_stylelint_use_global* *b:ale_stylus_stylelint_use_global* stylus_stylelint_use_global g:ale_stylus_stylelint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-sugarss.txt ================================================ =============================================================================== ALE SugarSS Integration *ale-sugarss-options* =============================================================================== stylelint *ale-sugarss-stylelint* *ale-options.sugarss_stylelint_executable* *g:ale_sugarss_stylelint_executable* *b:ale_sugarss_stylelint_executable* sugarss_stylelint_executable g:ale_sugarss_stylelint_executable Type: |String| Default: `'stylelint'` See |ale-integrations-local-executables| *ale-options.sugarss_stylelint_options* *g:ale_sugarss_stylelint_options* *b:ale_sugarss_stylelint_options* sugarss_stylelint_options g:ale_sugarss_stylelint_options Type: |String| Default: `''` This variable can be set to pass additional options to stylelint. *ale-options.sugarss_stylelint_use_global* *g:ale_sugarss_stylelint_use_global* *b:ale_sugarss_stylelint_use_global* sugarss_stylelint_use_global g:ale_sugarss_stylelint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-supported-languages-and-tools.txt ================================================ *ale-supported-languages-and-tools.txt* For Vim version 8.0. *ale-supported-list* ALE Supported Languages and Tools =============================================================================== The following languages and tools are supported by ALE. 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 * `ada_language_server` * `cspell` * `gcc` * `gnatpp` * Ansible * `ansible-language-server` * `ansible-lint`!! * API Blueprint * `drafter` * APKBUILD * `apkbuild-fixer` * `apkbuild-lint` * `secfixes-check` * AsciiDoc * `alex` * `cspell` * `languagetool`!! * `proselint` * `redpen` * `textlint` * `vale` * `write-good` * ASM * `gcc` * `llvm-mc` * Astro * `eslint` * `prettier` * AVRA * `avra` * Awk * `gawk` * Bash * `bashate` * `cspell` * `language-server` * `shell` (-n flag) * `shellcheck` * `shfmt` * Bats * `shellcheck` * Bazel * `buildifier` * BibTeX * `bibclean` * Bicep * `bicep` * Bindzone * `checkzone` (named-checkzone) * BitBake * `oelint-adv` * Bourne Shell * `shell` (-n flag) * `shellcheck` * `shfmt` * C * `astyle` * `ccls` * `clang` (`cc`) * `clang-format` * `clangcheck`!! * `clangd` * `clangtidy`!! * `cppcheck` * `cpplint`!! * `cquery` * `cspell` * `flawfinder` * `gcc` (`cc`) * `uncrustify` * C# * `clang-format` * `csc`!! * `cspell` * `dotnet-format` * `mcs` * `mcsc`!! * `uncrustify` * C++ (filetype cpp) * `astyle` * `ccls` * `clang` (`cc`) * `clang-format` * `clangcheck`!! * `clangd` * `clangtidy`!! * `clazy`!! * `cppcheck` * `cpplint`!! * `cquery` * `cspell` * `flawfinder` * `gcc` (`cc`) * `uncrustify` * C3 * `c3lsp` * Cairo * `scarb`!! * `starknet` * Chef * `cookstyle` * `foodcritic`!! * Clojure * `clj-kondo` * `cljfmt` * `joker` * CloudFormation * `cfn-python-lint` * `checkov` * CMake * `cmake-format` * `cmake-lint` * `cmakelint` * CoffeeScript * `coffee` * `coffeelint` * Crystal * `ameba`!! * `crystal`!! * CSS * `VSCode CSS language server` * `cspell` * `css-beautify` * `csslint` * `fecs` * `prettier` * `stylelint` * Cucumber * `cucumber` * CUDA * `clang-format` * `clangd` * `nvcc`!! * Cypher * `cypher-lint` * Cython (pyrex filetype) * `cython` * D * `dfmt` * `dls` * `dmd` * `uncrustify` * Dafny * `dafny`!! * Dart * `analysis_server` * `dart-analyze`!! * `dart-format`!! * `dartfmt`!! * `language_server` * desktop * `desktop-file-validate` * Dhall * `dhall-format` * `dhall-freeze` * `dhall-lint` * Dockerfile * `dockerfile_lint` * `dockerlinter` * `dprint` * `hadolint` * Elixir * `credo` * `cspell` * `dialyxir` * `dogma`!! * `elixir-ls` * `expert` * `lexical` * `mix`!! * Elm * `elm-format` * `elm-ls` * `elm-make` * Erb * `erb` * `erb-formatter` * `erblint` * `erubi` * `erubis` * `htmlbeautifier` * `ruumba` * Erlang * `SyntaxErl` * `dialyzer`!! * `elvis`!! * `erlang-mode` (The Erlang mode for Emacs) * `erlang_ls` * `erlc` * `erlfmt` * Fish * `fish` (-n flag) * `fish_indent` * Fortran * `fortitude` * `gcc` * `language_server` * Fountain * `proselint` * FusionScript * `fusion-lint` * Git Commit Messages * `gitlint` * Gleam * `gleam_format` * `gleamlsp` * GLSL * `glslang` * `glslls` * Go * `bingo` * `cspell` * `go build`!! * `go mod`!! * `go vet`!! * `gofmt` * `gofumpt` * `goimports` * `golangci-lint`!! * `golangserver` * `golines` * `gopls` * `gosimple`!! * `gotype`!! * `revive`!! * `staticcheck`!! * Go HTML Templates * djlint * GraphQL * `eslint` * `gqlint` * `prettier` * Groovy * `npm-groovy-lint` * Hack * `hack` * `hackfmt` * `hhast` * Haml * `haml-lint` * Handlebars * djlint * `ember-template-lint` * Haskell * `brittany` * `cabal-ghc` * `cspell` * `floskell` * `fourmolu` * `ghc` * `ghc-mod` * `hdevtools` * `hfmt` * `hie` * `hindent` * `hlint` * `hls` * `ormolu` * `stack-build`!! * `stack-ghc` * `stylish-haskell` * HCL * `packer-fmt` * `terraform-fmt` * HTML * `VSCode HTML language server` * `alex` * `angular` * `cspell` * djlint * `eslint` * `fecs` * `html-beautify` * `htmlhint` * `prettier` * `proselint` * `rustywind` * `superhtml` * `tidy` * `write-good` * HTML Angular * djlint * HTML Django * djlint * HTTP * kulala_fmt * Hurl * `hurlfmt` * Idris * `idris` * Ink * `ink-language-server` * Inko * `inko` !! * ISPC * `ispc`!! * Java * `PMD` * `checkstyle`!! * `clang-format` * `cspell` * `eclipselsp` * `google-java-format` * `javac` * `javalsp` * `uncrustify` * JavaScript * `biome` * `clang-format` * `cspell` * `deno` * `dprint` * `eslint` * `fecs` * `flow` * `jscs` * `jshint` * `prettier` * `prettier-eslint` * `prettier-standard` * `standard` * `tsserver` * `xo` * Jinja * djlint * j2lint * JSON * `VSCode JSON language server` * `biome` * `clang-format` * `cspell` * `dprint` * `eslint` * `fixjson` * `jq` * `json.tool` * `jsonlint` * `prettier` * `spectral` * JSON5 * `eslint` * JSONC * `biome` * `eslint` * Jsonnet * `jsonnet-lint` * `jsonnetfmt` * Julia * `languageserver` * Kotlin * `kotlinc`!! * `ktlint` * `languageserver` * LaTeX (tex) * `alex` * `chktex` * `cspell` * `lacheck` * `proselint` * `redpen` * `texlab` * `textlint` * `vale` * `write-good` * Lean 4 * `lake` * Less * `lessc` * `prettier` * `stylelint` * LLVM * `llc` * Lua * `cspell` * `lua-format` * `lua-language-server` * `luac` * `luacheck` * `luafmt` * `selene` * `stylua` * Mail * `alex` * `languagetool`!! * `proselint` * `vale` * Make * `checkmake` * Markdown * `alex` * `cspell` * `languagetool`!! * `markdownlint`!! * `marksman` * `mdl` * `pandoc` * `prettier` * `proselint` * `pymarkdown` * `redpen` * `remark-lint` * `textlint` * `vale` * `write-good` * MATLAB * `mlint` * Mercury * `mmc`!! * NASM * `nasm`!! * Nickel * `nickel_format` * Nim * `nim check`!! * `nimlsp` * `nimpretty` * nix * `alejandra` * `deadnix` * `nix-instantiate` * `nixfmt` * `nixpkgs-fmt` * `rnix-lsp` * `statix` * nroff * `alex` * `proselint` * `write-good` * Nunjucks * djlint * Objective-C * `ccls` * `clang` * `clang-format` * `clangd` * `uncrustify` * Objective-C++ * `clang` * `clangd` * `uncrustify` * OCaml * `dune` * `merlin` (see |ale-ocaml-merlin|) * `ocamlformat` * `ocamllsp` * `ocp-indent` * `ols` * Odin * `ols` * OpenApi * `ibm_validator` * `prettier` * `yamllint` * OpenSCAD * `SCA2D` * `scadformat` * Packer * `packer-fmt-fixer` * Pascal * `ptop` * Pawn * `uncrustify` * Perl * `languageserver` * `perl -c` * `perl-critic` * `perltidy` * Perl6 * `perl6 -c` * PHP * `cspell` * `intelephense` * `langserver` * `phan` * `php -l` * `php-cs-fixer` * `phpactor` * `phpcbf` * `phpcs` * `phpmd` * `phpstan` * `pint` * `psalm`!! * `tlint` * PO * `alex` * `msgfmt` * `proselint` * `write-good` * Pod * `alex` * `proselint` * `write-good` * Pony * `ponyc` * PowerShell * `cspell` * `powershell` * `psscriptanalyzer` * Prolog * `swipl` * proto * `buf-format`!! * `buf-lint`!! * `clang-format` * `protoc-gen-lint`!! * `protolint`!! * Pug * `pug-lint` * Puppet * `languageserver` * `puppet` * `puppet-lint` * PureScript * `purescript-language-server` * `purs-tidy` * `purty` * Python * `autoflake`!! * `autoimport` * `autopep8` * `bandit` * `black` * `cspell` * `flake8` * `flakehell` * `isort` * `mypy` * `prospector`!! * `pycln` * `pycodestyle` * `pydocstyle` * `pyflakes` * `pyflyby` * `pylama`!! * `pylint`!! * `pylsp` * `pyre` * `pyrefly` * `pyright` * `refurb` * `reorder-python-imports` * ruff * ruff-format * `unimport` * `vulture`!! * `yapf` * QML * `qmlfmt` * `qmllint` * R * `languageserver` * `lintr` * `styler` * Racket * `racket-langserver` * `raco` * `raco_fmt` * Re:VIEW * `redpen` * ReasonML * `merlin` * `ols` * `reason-language-server` * `refmt` * Rego * `cspell` * `opacheck` * `opafmt` * ReScript * `rescript-language-server` * `rescript_format` * REST * kulala_fmt * reStructuredText * `alex` * `cspell` * `proselint` * `redpen` * `rstcheck` * `textlint` * `vale` * `write-good` * Robot * `rflint` * Roc * roc_annotate * roc_format * roc_language_server * RPM spec * `rpmlint` * Ruby * `brakeman`!! * `cspell` * `debride` * `packwerk`!! * `prettier` * `rails_best_practices`!! * `reek` * `rubocop` * `ruby` * `rubyfmt` * `rufo` * `solargraph` * `sorbet` * `standardrb` * `steep` * `syntax_tree` * Rust * `cargo`!! * `cspell` * `rls` * `rust-analyzer` * `rustc` (see |ale-integration-rust|) * `rustfmt` * Salt * `salt-lint` * Sass * `sass-lint` * `stylelint` * Scala * `cspell` * `fsc` * `metals` * `sbtserver` * `scalac` * `scalafmt` * `scalastyle` * SCSS * `prettier` * `sass-lint` * `scss-lint` * `stylelint` * Slim * `slim-lint` * SML * `smlnj` * Solidity * `forge` * `solc` * `solhint` * `solium` * SQL * `dprint` * `pgformatter` * `sql-lint` * `sqlfluff` * `sqlfmt` * `sqlformat` * `sqlint` * Stylus * `stylelint` * SugarSS * `stylelint` * Svelte * `prettier` * `svelteserver` * Swift * Apple `swift-format` * `cspell` * `sourcekit-lsp` * `swiftformat` * `swiftlint` * systemd * `systemd-analyze`!! * Tcl * `nagelfar`!! * Terraform * `checkov` * `terraform` * `terraform-fmt-fixer` * `terraform-ls` * `terraform-lsp` * `tflint` * `tfsec` * Texinfo * `alex` * `cspell` * `proselint` * `write-good` * Text^ * `alex` * `cspell` * `languagetool`!! * `proselint` * `redpen` * `textlint` * `vale` * `write-good` * Thrift * `thrift` * `thriftcheck` * TOML * `dprint` * `tombi` * TypeScript * `biome` * `cspell` * `deno` * `dprint` * `eslint` * `fecs` * `prettier` * `standard` * `tslint` * `tsserver` * `typecheck` * Typst * `typstyle` * V * `v`!! * `vfmt` * VALA * `uncrustify` * `vala_lint`!! * Verilog * `hdl-checker` * `iverilog` * slang * `verible` * `verilator` * `vlog` * `xvlog` * `yosys`!! * VHDL * `ghdl` * `vcom` * `xvhdl` * Vim * `vimls` * `vint` * Vim help^ * `alex` * `proselint` * `write-good` * Vue * `cspell` * `prettier` * `vls` * `volar` * WGSL * `naga` * XHTML * `alex` * `cspell` * `proselint` * `write-good` * XML * `xmllint` * YAML * `actionlint` * `circleci`!! * `gitlablint` * `prettier` * `spectral` * `swaglint` * `yaml-language-server` * `yamlfix` * `yamlfmt` * `yamllint` * `yq` * YANG * `yang-lsp` * Yara * `yls` * Zeek * `zeek`!! * Zig * `zigfmt` * `zlint` * `zls` =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-svelte.txt ================================================ =============================================================================== ALE Svelte Integration *ale-svelte-options* =============================================================================== prettier *ale-svelte-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== svelteserver *ale-svelte-svelteserver* *ale-options.svelte_svelteserver_executable* *g:ale_svelte_svelteserver_executable* *b:ale_svelte_svelteserver_executable* svelte_svelteserver_executable g:ale_svelte_svelteserver_executable Type: |String| Default: `'svelteserver'` See |ale-integrations-local-executables| *ale-options.svelte_svelteserver_use_global* *g:ale_svelte_svelteserver_use_global* *b:ale_svelte_svelteserver_use_global* svelte_svelteserver_use_global g:ale_svelte_svelteserver_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-swift.txt ================================================ =============================================================================== ALE Swift Integration *ale-swift-options* =============================================================================== apple-swift-format *ale-swift-apple-swift-format* There are 3 options to enable linting and fixing with Apple's swift-format: 1. Install the local executable in your path, as described here: https://github.com/apple/swift-format 2. Install the executable via your OS package manager, for instance via Homebrew with `brew install swift-format` 3. Your Swift project has a dependency on the swift-format package, so it can be run with `swift run swift-format lint ...` In this case, you need to set a variable, see |g:ale_swift_appleswiftformat_use_swiftpm|. Additionally, ALE tries to locate and use the nearest existing `.swift-format` configuration file. *ale-options.swift_appleswiftformat_executable* *g:ale_swift_appleswiftformat_executable* *b:ale_swift_appleswiftformat_executable* swift_appleswiftformat_executable g:ale_swift_appleswiftformat_executable Type: |String| Default: `'swift-format'` This variable can be modified to change the executable path for `swift-format`. *ale-options.swift_appleswiftformat_use_swiftpm* *g:ale_swift_appleswiftformat_use_swiftpm* *b:ale_swift_appleswiftformat_use_swiftpm* swift_appleswiftformat_use_swiftpm g:ale_swift_appleswiftformat_use_swiftpm Type: |Number| Default: `0` When set to `1`, this option will cause ALE to use `swift run swift-format lint ...` instead of the global executable. Use this option if your Swift project has a dependency on the swift-format package. See |ale-integrations-local-executables| =============================================================================== cspell *ale-swift-cspell* See |ale-cspell-options| =============================================================================== sourcekitlsp *ale-swift-sourcekitlsp* To enable the SourceKit-LSP you need to install and build the executable as described here: https://github.com/apple/sourcekit-lsp#building-sourcekit-lsp *ale-options.sourcekit_lsp_executable* *g:ale_sourcekit_lsp_executable* *b:ale_sourcekit_lsp_executable* sourcekit_lsp_executable g:ale_sourcekit_lsp_executable Type: |String| Default: `'sourcekit-lsp'` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-systemd.txt ================================================ =============================================================================== ALE systemd Integration *ale-systemd-options* =============================================================================== systemd-analyze *ale-systemd-analyze* ALE supports checking user systemd units with `systemd-analyze --user verify` Checks will only work with user unit files in their proper location. There aren't any options, and checks can only run after saving the file. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-tcl.txt ================================================ =============================================================================== ALE Tcl Integration *ale-tcl-options* =============================================================================== nagelfar *ale-tcl-nagelfar* *ale-options.tcl_nagelfar_executable* *g:ale_tcl_nagelfar_executable* *b:ale_tcl_nagelfar_executable* tcl_nagelfar_executable g:ale_tcl_nagelfar_executable Type: |String| Default: `'nagelfar.tcl'` This variable can be changed to change the path to nagelfar. *ale-options.tcl_nagelfar_options* *g:ale_tcl_nagelfar_options* *b:ale_tcl_nagelfar_options* tcl_nagelfar_options g:ale_tcl_nagelfar_options Type: |String| Default: `''` This variable can be changed to modify flags given to nagelfar. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-terraform.txt ================================================ =============================================================================== ALE Terraform Integration *ale-terraform-options* =============================================================================== checkov *ale-terraform-checkov* *ale-options.terraform_checkov_executable* *g:ale_terraform_checkov_executable* *b:ale_terraform_checkov_executable* terraform_checkov_executable g:ale_terraform_checkov_executable Type: |String| Default: `'checkov'` This variable can be changed to use a different executable for checkov. *ale-options.terraform_checkov_options* *g:ale_terraform_checkov_options* *b:ale_terraform_checkov_options* terraform_checkov_options g:ale_terraform_checkov_options Type: |String| Default: `''` This variable can be changed to set additional options for checkov. =============================================================================== terraform-fmt-fixer *ale-terraform-fmt-fixer* *ale-options.terraform_fmt_executable* *g:ale_terraform_fmt_executable* *b:ale_terraform_fmt_executable* terraform_fmt_executable g:ale_terraform_fmt_executable Type: |String| Default: `'terraform'` This variable can be changed to use a different executable for terraform. *ale-options.terraform_fmt_options* *g:ale_terraform_fmt_options* *b:ale_terraform_fmt_options* terraform_fmt_options g:ale_terraform_fmt_options Type: |String| Default: `''` =============================================================================== terraform *ale-terraform-terraform* *ale-options.terraform_terraform_executable* *g:ale_terraform_terraform_executable* *b:ale_terraform_terraform_executable* terraform_terraform_executable g:ale_terraform_terraform_executable Type: |String| Default: `'terraform'` This variable can be changed to use a different executable for terraform. =============================================================================== terraform-ls *ale-terraform-terraform-ls* Official terraform language server. More stable than *terraform-lsp* but currently has less features. *ale-options.terraform_ls_executable* *g:ale_terraform_ls_executable* *b:ale_terraform_ls_executable* terraform_ls_executable g:ale_terraform_ls_executable Type: |String| Default: `'terraform-ls'` This variable can be changed to use a different executable for terraform-ls. *ale-options.terraform_ls_options* *g:ale_terraform_ls_options* *b:ale_terraform_ls_options* terraform_ls_options g:ale_terraform_ls_options Type: |String| Default: `''` This variable can be changed to pass custom CLI flags to terraform-ls. =============================================================================== terraform-lsp *ale-terraform-terraform-lsp* *ale-options.terraform_langserver_executable* *g:ale_terraform_langserver_executable* *b:ale_terraform_langserver_executable* terraform_langserver_executable g:ale_terraform_langserver_executable Type: |String| Default: `'terraform-lsp'` This variable can be changed to use a different executable for terraform-lsp. *ale-options.terraform_langserver_options* *g:ale_terraform_langserver_options* *b:ale_terraform_langserver_options* terraform_langserver_options g:ale_terraform_langserver_options Type: |String| Default: `''` This variable can be changed to pass custom CLI flags to terraform-lsp. =============================================================================== tflint *ale-terraform-tflint* *ale-options.terraform_tflint_executable* *g:ale_terraform_tflint_executable* *b:ale_terraform_tflint_executable* terraform_tflint_executable g:ale_terraform_tflint_executable Type: |String| Default: `'tflint'` This variable can be changed to use a different executable for tflint. *ale-options.terraform_tflint_options* *g:ale_terraform_tflint_options* *b:ale_terraform_tflint_options* terraform_tflint_options g:ale_terraform_tflint_options Type: |String| Default: `'-f json'` This variable can be changed to pass different options to tflint. Ale does expect json output from tflint, so if you change this, you'll probably want to include '-f json' in your new value. =============================================================================== tfsec *ale-terraform-tfsec* *ale-options.terraform_tfsec_executable* *g:ale_terraform_tfsec_executable* *b:ale_terraform_tfsec_executable* terraform_tfsec_executable g:ale_terraform_tfsec_executable Type: |String| Default: `'tfsec'` This variable can be changed to use a different executable for tfsec. *ale-options.terraform_tfsec_options* *g:ale_terraform_tfsec_options* *b:ale_terraform_tfsec_options* terraform_tfsec_options g:ale_terraform_tfsec_options Type: |String| Default: `''` This variable can be changed to pass custom CLI flags to tfsec. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-tex.txt ================================================ =============================================================================== ALE TeX Integration *ale-tex-options* =============================================================================== chktex *ale-tex-chktex* *ale-options.tex_chktex_executable* *g:ale_tex_chktex_executable* *b:ale_tex_chktex_executable* tex_chktex_executable g:ale_tex_chktex_executable Type: |String| Default: `'chktex'` This variable can be changed to change the path to chktex. *ale-options.tex_chktex_options* *g:ale_tex_chktex_options* *b:ale_tex_chktex_options* tex_chktex_options g:ale_tex_chktex_options Type: |String| Default: `'-I'` This variable can be changed to modify flags given to chktex. =============================================================================== cspell *ale-tex-cspell* See |ale-cspell-options| =============================================================================== lacheck *ale-tex-lacheck* *ale-options.lacheck_executable* *g:ale_lacheck_executable* *b:ale_lacheck_executable* lacheck_executable g:ale_lacheck_executable Type: |String| Default: `'lacheck'` This variable can be changed to change the path to lacheck. =============================================================================== latexindent *ale-tex-latexindent* *ale-options.tex_latexindent_executable* *g:ale_tex_latexindent_executable* *b:ale_tex_latexindent_executable* tex_latexindent_executable g:ale_tex_latexindent_executable Type: |String| Default: `'latexindent'` This variable can be changed to change the path to latexindent. *ale-options.tex_latexindent_options* *g:ale_tex_latexindent_options* *b:ale_tex_latexindent_options* tex_latexindent_options g:ale_tex_latexindent_options Type: |String| Default: `''` This variable can be changed to modify flags given to latexindent. =============================================================================== texlab *ale-tex-texlab* *ale-options.tex_texlab_executable* *g:ale_tex_texlab_executable* *b:ale_tex_texlab_executable* tex_texlab_executable g:ale_tex_texlab_executable Type: |String| Default: `'texlab'` This variable can be changed to change the path to texlab. *ale-options.tex_texlab_options* *g:ale_tex_texlab_options* *b:ale_tex_texlab_options* tex_texlab_options g:ale_tex_texlab_options Type: |String| Default: `''` This variable can be changed to modify flags given to texlab command. *ale-options.tex_texlab_config* *g:ale_tex_texlab_config* *b:ale_tex_texlab_config* tex_texlab_config g:ale_tex_texlab_config Type: |Dictionary| Default: `{}` Dictionary containing LSP configuration settings used to initialize texlab language server. Refer to texlab documentation for possible settings: https://github.com/latex-lsp/texlab/blob/master/docs/options.md For example to set build onSave initialization setting: > let g:ale_tex_texlab_config = {"build":{"onSave":v:true}} < =============================================================================== redpen *ale-tex-redpen* See |ale-redpen-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-texinfo.txt ================================================ =============================================================================== ALE Texinfo Integration *ale-texinfo-options* =============================================================================== cspell *ale-texinfo-cspell* See |ale-cspell-options| =============================================================================== write-good *ale-texinfo-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-text.txt ================================================ =============================================================================== ALE Text Integration *ale-text-options* ============================================================================== cspell *ale-text-cspell* See |ale-cspell-options| =============================================================================== textlint *ale-text-textlint* The options for the textlint linter are global because it does not make sense to have them specified on a per-language basis. *ale-options.textlint_executable* *g:ale_textlint_executable* *b:ale_textlint_executable* textlint_executable g:ale_textlint_executable Type: |String| Default: `'textlint'` See |ale-integrations-local-executables| *ale-options.textlint_options* *g:ale_textlint_options* *b:ale_textlint_options* textlint_options g:ale_textlint_options Type: |String| Default: `''` This variable can be set to pass additional options to textlint. *ale-options.textlint_use_global* *g:ale_textlint_use_global* *b:ale_textlint_use_global* textlint_use_global g:ale_textlint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== write-good *ale-text-write-good* See |ale-write-good-options| =============================================================================== redpen *ale-text-redpen* See |ale-redpen-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-thrift.txt ================================================ =============================================================================== ALE Thrift Integration *ale-thrift-options* =============================================================================== thrift *ale-thrift-thrift* The `thrift` linter works by compiling the buffer's contents and reporting any errors reported by the parser and the configured code generator(s). ------------------------------------------------------------------------------- Options *ale-options.thrift_thrift_executable* *g:ale_thrift_thrift_executable* *b:ale_thrift_thrift_executable* thrift_thrift_executable g:ale_thrift_thrift_executable Type: |String| Default: `'thrift'` See |ale-integrations-local-executables| *ale-options.thrift_thrift_generators* *g:ale_thrift_thrift_generators* *b:ale_thrift_thrift_generators* thrift_thrift_generators g:ale_thrift_thrift_generators Type: |List| Default: `['cpp']` This list must contain one or more named code generators. Generator options can be included as part of each string, e.g. `['py:dynamic']`. *ale-options.thrift_thrift_includes* *g:ale_thrift_thrift_includes* *b:ale_thrift_thrift_includes* thrift_thrift_includes g:ale_thrift_thrift_includes Type: |List| Default: `['.']` This list contains paths that will be searched for thrift `include` directives. *ale-options.thrift_thrift_options* *g:ale_thrift_thrift_options* *b:ale_thrift_thrift_options* thrift_thrift_options g:ale_thrift_thrift_options Type: |String| Default: `'-strict'` This variable can be changed to customize the additional command-line arguments that are passed to the thrift compiler. =============================================================================== thriftcheck *ale-thrift-thriftcheck* *ale-options.thrift_thriftcheck_executable* *g:ale_thrift_thriftcheck_executable* *b:ale_thrift_thriftcheck_executable* thrift_thriftcheck_executable g:ale_thrift_thriftcheck_executable Type: |String| Default: `'thriftcheck'` See |ale-integrations-local-executables| *ale-options.thrift_thriftcheck_options* *g:ale_thrift_thriftcheck_options* *b:ale_thrift_thriftcheck_options* thrift_thriftcheck_options g:ale_thrift_thriftcheck_options Type: |String| Default: `''` This variable can be changed to customize the additional command-line arguments that are passed to thriftcheck. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-toml.txt ================================================ =============================================================================== ALE TOML Integration *ale-toml-options* =============================================================================== dprint *ale-toml-dprint* See |ale-dprint-options| and https://dprint.dev/plugins/toml =============================================================================== tombi *ale-toml-tombi* `'tombi'` is a TOML formatter, linter, and language server. *ale-options.toml_tombi_executable* *g:ale_toml_tombi_executable* *b:ale_toml_tombi_executable* toml_tombi_executable g:ale_toml_tombi_executable Type: |String| Default: `'tombi'` This variable can be modified to change the executable path for `tombi`. *ale-options.toml_tombi_online* *g:ale_toml_tombi_online* *b:ale_toml_tombi_online* toml_tombi_online g:ale_toml_tombi_online Type: |Boolean| Default: `1` This variable can be modified allow fetching remote schemas when using `tombi`. *ale-options.toml_tombi_lsp_options* *g:ale_toml_tombi_lsp_options* *b:ale_toml_tombi_lsp_options* toml_tombi_lsp_options g:ale_toml_tombi_lsp_options Type: |String| Default: `''` This variable can be modified to provide options when using `tombi` as an LSP server. *ale-options.toml_tombi_format_options* *g:ale_toml_tombi_format_options* *b:ale_toml_tombi_format_options* toml_tombi_format_options g:ale_toml_tombi_format_options Type: |String| Default: `''` This variable can be modified to provide options when using `tombi` as a formatter. *ale-options.toml_tombi_lint_options* *g:ale_toml_tombi_lint_options* *b:ale_toml_tombi_lint_options* toml_tombi_lint_options g:ale_toml_tombi_lint_options Type: |String| Default: `''` This variable can be modified to provide options when using `tombi` as a linter. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-typescript.txt ================================================ =============================================================================== ALE TypeScript Integration *ale-typescript-options* =============================================================================== biome *ale-typescript-biome* *ale-options.biome_executable* *g:ale_biome_executable* *b:ale_biome_executable* biome_executable g:ale_biome_executable Type: |String| Default: `'biome'` *ale-options.biome_options* *g:ale_biome_options* *b:ale_biome_options* biome_options g:ale_biome_options Type: |String| Default: `''` This variable can be set to pass additional options to `biome check` when applying fixes. *ale-options.biome_use_global* *g:ale_biome_use_global* *b:ale_biome_use_global* biome_use_global g:ale_biome_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| *ale-options.biome_fixer_apply_unsafe* *g:ale_biome_fixer_apply_unsafe* *b:ale_biome_fixer_apply_unsafe* biome_fixer_apply_unsafe g:ale_biome_fixer_apply_unsafe Type: |Number| Default: `0` If set to `1`, biome will apply unsafe fixes along with safe fixes. *ale-options.biome_lsp_project_root* *g:ale_biome_lsp_project_root* *b:ale_biome_lsp_project_root* biome_lsp_project_root g:ale_biome_lsp_project_root Type: |String| Default: `''` If this variable is left unset, ALE will try to find the project root by executing the following steps in the given order: 1. Find an ancestor directory containing a biome.json. 2. Find an ancestor directory containing a biome.jsonc. 3. Find an ancestor directory containing a package.json. 4. Find an ancestor directory containing a .git folder. 5. Use the directory of the current buffer (if the buffer was opened from a file). =============================================================================== cspell *ale-typescript-cspell* See |ale-cspell-options| =============================================================================== deno *ale-typescript-deno* Starting from version 1.6.0, Deno comes with its own language server. Earlier versions are not supported. ------------------------------------------------------------------------------- Options *ale-options.deno_executable* *g:ale_deno_executable* *b:ale_deno_executable* deno_executable g:ale_deno_executable Type: |String| Default: `'deno'` *ale-options.deno_lsp_project_root* *g:ale_deno_lsp_project_root* *b:ale_deno_lsp_project_root* deno_lsp_project_root g:ale_deno_lsp_project_root Type: |String| Default: `''` If this variable is left unset, ALE will try to find the project root by executing the following steps in the given order: 1. Find an ancestor directory containing a tsconfig.json. 2. Find an ancestor directory containing a .git folder. 3. Use the directory of the current buffer (if the buffer was opened from a file). *ale-options.deno_unstable* *g:ale_deno_unstable* *b:ale_deno_unstable* deno_unstable g:ale_deno_unstable Type: |Number| Default: `0` Enable or disable unstable Deno features and APIs. *ale-options.deno_import_map* *g:ale_deno_import_map* *b:ale_deno_import_map* deno_import_map g:ale_deno_import_map Type: |String| Default: `'import_map.json'` Specify the import map filename to load url maps in a deno project. =============================================================================== dprint *ale-typescript-dprint* See |ale-dprint-options| and https://dprint.dev/plugins/typescript =============================================================================== eslint *ale-typescript-eslint* Because of how TypeScript compiles code to JavaScript and how interrelated the two languages are, the `eslint` linter for TypeScript uses the JavaScript options for `eslint` too. See: |ale-javascript-eslint|. =============================================================================== prettier *ale-typescript-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== standard *ale-typescript-standard* *ale-options.typescript_standard_executable* *g:ale_typescript_standard_executable* *b:ale_typescript_standard_executable* typescript_standard_executable g:ale_typescript_standard_executable Type: |String| Default: `'standard'` See |ale-integrations-local-executables| *ale-options.typescript_standard_options* *g:ale_typescript_standard_options* *b:ale_typescript_standard_options* typescript_standard_options g:ale_typescript_standard_options Type: |String| Default: `''` This variable can be set to pass additional options to standard. *ale-options.typescript_standard_use_global* *g:ale_typescript_standard_use_global* *b:ale_typescript_standard_use_global* typescript_standard_use_global g:ale_typescript_standard_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== 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 your typescript ftplugin file. > let b:ale_linters_ignore = ['tslint'] < Or in Lua: > require("ale").setup.buffer({linters_ignore={"tslint"}}) < ------------------------------------------------------------------------------- Options *ale-options.typescript_tslint_executable* *g:ale_typescript_tslint_executable* *b:ale_typescript_tslint_executable* typescript_tslint_executable g:ale_typescript_tslint_executable Type: |String| Default: `'tslint'` See |ale-integrations-local-executables| *ale-options.typescript_tslint_config_path* *g:ale_typescript_tslint_config_path* *b:ale_typescript_tslint_config_path* typescript_tslint_config_path g:ale_typescript_tslint_config_path Type: |String| Default: `''` ALE will first discover the tslint.json path in an ancestor directory. If no such path exists, this variable will be used instead. *ale-options.typescript_tslint_ignore_empty_files* *g:ale_typescript_tslint_ignore_empty_files* *b:ale_typescript_tslint_ignore_empty_files* typescript_tslint_ignore_empty_files g:ale_typescript_tslint_ignore_empty_files Type: |Number| Default: `0` When set to `1`, ALE will not report any problems for empty files with TSLint. ALE will still execute TSLint for the files, but ignore any problems reported. This stops ALE from complaining about newly created files, and files where lines have been added and then removed. *ale-options.typescript_tslint_rules_dir* *g:ale_typescript_tslint_rules_dir* *b:ale_typescript_tslint_rules_dir* typescript_tslint_rules_dir g:ale_typescript_tslint_rules_dir Type: |String| Default: `''` If this variable is set, ALE will use it as the rules directory for tslint. *ale-options.typescript_tslint_use_global* *g:ale_typescript_tslint_use_global* *b:ale_typescript_tslint_use_global* typescript_tslint_use_global g:ale_typescript_tslint_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== tsserver *ale-typescript-tsserver* *ale-options.typescript_tsserver_executable* *g:ale_typescript_tsserver_executable* *b:ale_typescript_tsserver_executable* typescript_tsserver_executable g:ale_typescript_tsserver_executable Type: |String| Default: `'tsserver'` ALE will first discover the tsserver path in an ancestor node_modules directory. If no such path exists, this variable will be used instead. If you wish to use only a globally installed version of tsserver, set |g:ale_typescript_tsserver_use_global| to `1`. *ale-options.typescript_tsserver_config_path* *g:ale_typescript_tsserver_config_path* *b:ale_typescript_tsserver_config_path* typescript_tsserver_config_path g:ale_typescript_tsserver_config_path Type: |String| Default: `''` ALE will first discover the tsserver.json path in an ancestor directory. If no such path exists, this variable will be used instead. *ale-options.typescript_tsserver_use_global* *g:ale_typescript_tsserver_use_global* *b:ale_typescript_tsserver_use_global* typescript_tsserver_use_global g:ale_typescript_tsserver_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` This variable controls whether or not ALE will search for a local path for tsserver first. If this variable is set to `1`, then ALE will always use the global version of tsserver, in preference to locally installed versions of tsserver in node_modules. =============================================================================== xo *ale-typescript-xo* *ale-options.typescript_xo_executable* *g:ale_typescript_xo_executable* *b:ale_typescript_xo_executable* typescript_xo_executable g:ale_typescript_xo_executable Type: |String| Default: `'xo'` See |ale-integrations-local-executables| *ale-options.typescript_xo_options* *g:ale_typescript_xo_options* *b:ale_typescript_xo_options* typescript_xo_options g:ale_typescript_xo_options Type: |String| Default: `''` This variable can be set to pass additional options to xo. *ale-options.typescript_xo_use_global* *g:ale_typescript_xo_use_global* *b:ale_typescript_xo_use_global* typescript_xo_use_global g:ale_typescript_xo_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-typst.html ================================================ =============================================================================== ALE Typst Integration *ale-typst-options* =============================================================================== typstyle *ale-typst-typstyle* *ale-options.typst_typstyle_executable* *g:ale_typst_typstyle_executable* *b:ale_typst_typstyle_executable* typst_typstyle_executable g:ale_typst_typstyle_executable Type: |String| Default: `'typstyle'` See |ale-integrations-local-executables| *ale-options.typst_typstyle_options* *g:ale_typst_typstyle_options* *b:ale_typst_typstyle_options* typst_typstyle_options g:ale_typst_typstyle_options Type: |String| Default: `''` This variable can be changed to modify flags given to typstyle. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-v.txt ================================================ =============================================================================== ALE V Integration *ale-v-options* =============================================================================== Integration Information `v` is V's build tool. `vfmt` (called as `v fmt` from the same executable that does the builds) is the autoformatter/fixer. *ale-options.v_v_executable* *g:ale_v_v_executable* *b:ale_v_v_executable* v_v_executable g:ale_v_v_executable Type: |String| Default: `'v'` The executable that will be run for the `v` linter and the `vfmt` fixer. =============================================================================== v *ale-v-v* *ale-options.v_v_options* *g:ale_v_v_options* *b:ale_v_v_options* v_v_options g:ale_v_v_options Type: |String| Default: `''` This variable can be set to pass additional options to the v linter. They are injected directly after "v .". =============================================================================== vfmt *ale-v-vfmt* *ale-options.v_vfmt_options* *g:ale_v_vfmt_options* *b:ale_v_vfmt_options* v_vfmt_options g:ale_v_vfmt_options Type: |String| Default: `''` This variable can be set to pass additional options to the vfmt fixer. They are injected directly after "v fmt". =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-vala.txt ================================================ =============================================================================== ALE VALA Integration *ale-vala-options* =============================================================================== uncrustify *ale-vala-uncrustify* See |ale-c-uncrustify| for information about the available options. =============================================================================== Vala-Lint *ale-vala-vala-lint* *ale-options.vala_vala_lint_executable* *g:ale_vala_vala_lint_executable* *b:ale_vala_vala_lint_executable* g:ale_vala_vala_lint_executable Type: |String| Default: `'io.elementary.vala-lint'` This variable can be set to specify a Vala-Lint executable file. *ale-options.vala_vala_lint_config_filename* *g:ale_vala_vala_lint_config_filename* *b:ale_vala_vala_lint_config_filename* g:ale_vala_vala_lint_config_filename Type: |String| Default: `'vala-lint.conf'` This variable can be set to specify a Vala-Lint config filename. When a file with the specified name was not found or this variable was set to empty, Vala-Lint will be executed without specifying a config filename. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-verilog.txt ================================================ =============================================================================== ALE Verilog/SystemVerilog Integration *ale-verilog-options* =============================================================================== ALE can use eight different linters for Verilog HDL: HDL Checker Using `hdl_checker --lsp` iverilog: Using `iverilog -t null -Wall` slang: Using `slang -Weverything` verible_ls Using `verible-verilog-ls` verilator Using `verilator --lint-only -Wall` ModelSim/Questa Using `vlog -quiet -lint` Vivado Using `xvlog` Yosys Using `yosys -Q -T -p 'read_verilog'` By default, both 'verilog' and 'systemverilog' filetypes are checked. You can limit 'systemverilog' files to be checked using only 'verilator' by defining 'g:ale_linters' variable: > au FileType systemverilog \ let g:ale_linters = {'systemverilog' : ['verilator'],} < =============================================================================== ALE can use one fixer for Verilog HDL: verible_fomat Using `verible-verilog-format` =============================================================================== General notes Linters/compilers that utilize a "work" directory for analyzing designs- such as ModelSim and Vivado- can be passed the location of these directories as part of their respective option strings listed below. This is useful for holistic analysis of a file (e.g. a design with components, packages, or other code defined external to the current file as part of a larger project) or when wanting to simply pass an alternative location for the auto-generated work directories (such as '/tmp') so as to not muddle the current directory. Since these type of linters often use this work directory for holding compiled design data as part of a single build process, they sometimes cannot handle the frequent, asynchronous application launches when linting while text is changing. This can happen in the form of hangs or crashes. To help prevent this when using these linters, it may help to run linting less frequently; for example, only when a file is saved. HDL Checker is an alternative for some of the issues described above. It wraps around ghdl, Vivado and ModelSim/Questa and, when using the latter, it can handle mixed language (VHDL, Verilog, SystemVerilog) designs. =============================================================================== hdl-checker *ale-verilog-hdl-checker* See |ale-vhdl-hdl-checker| =============================================================================== iverilog *ale-verilog-iverilog* No additional options =============================================================================== slang *ale-verilog-slang* *ale-options.verilog_slang_options* *g:ale_verilog_slang_options* *b:ale_verilog_slang_options* verilog_slang_options g:ale_verilog_slang_options Type: |String| Default: `''` This variable can be changed to modify 'slang' command arguments. =============================================================================== verible_ls *ale-verilog-verible-ls* *ale-config.verilog_verible_ls_executable* *g:ale_verilog_verible_ls_executable* *b:ale_verilog_verible_ls_executable* verilog_verible_ls_executable g:ale_verilog_verible_ls_executable Type: |String| Default: `'verible-verilog-ls'` This variable can be modifies to change the executable path for `verible_ls` *ale-config.verilog_verible_ls_config* *g:ale_verilog_verible_ls_config* *b:ale_verilog_verible_ls_config* verilog_verible_ls_config g:ale_verilog_verible_ls_config Type: |Dictionary| Default: `{}` Dictionary with configuration settings for `verible_ls` *ale-config.verilog_verible_ls_options* *g:ale_verilog_verible_ls_options* *b:ale_verilog_verible_ls_options* verilog_verible_ls_options g:ale_verilog_verible_ls_options Type: |String| Default: `'--rules_config_search'` Additional flags for `verible_ls` *ale-config.verilog_verible_ls_rules* *g:ale_verilog_verible_ls_rules* *b:ale_verilog_verible_ls_rules* verilog_verible_ls_rules g:ale_verilog_verible_ls_rules Type: |String| Default: `''` Additional rules applied by `verible_ls` =============================================================================== verible_format *ale-verilog-verible-format* *ale-config.verilog_verible_format_executable* *g:ale_verilog_verible_format_executable* *b:ale_verilog_verible_format_executable* verilog_verible_format_executable g:ale_verilog_verible_format_executable Type: |String| Default: `'verible-verilog-format'` This variable can be modifies to change the executable path for `verible_format` *ale-config.verilog_verible_format_options* *g:ale_verilog_verible_format_options* *b:ale_verilog_verible_format_options* verilog_verible_format_options g:ale_verilog_verible_format_options Type: |String| Default: `''` Additional flags for `verible_format` =============================================================================== verilator *ale-verilog-verilator* *ale-options.verilog_verilator_options* *g:ale_verilog_verilator_options* *b:ale_verilog_verilator_options* verilog_verilator_options g:ale_verilog_verilator_options Type: |String| Default: `''` This variable can be changed to modify 'verilator' command arguments. For example `'-sv --default-language "1800-2012"'` if you want to enable SystemVerilog parsing and select the 2012 version of the language. =============================================================================== vlog *ale-verilog-vlog* *ale-options.verilog_vlog_executable* *g:ale_verilog_vlog_executable* *b:ale_verilog_vlog_executable* verilog_vlog_executable g:ale_verilog_vlog_executable Type: |String| Default: `'vlog'` This variable can be changed to the path to the 'vlog' executable. *ale-options.verilog_vlog_options* *g:ale_verilog_vlog_options* *b:ale_verilog_vlog_options* verilog_vlog_options g:ale_verilog_vlog_options Type: |String| Default: `'-quiet -lint'` This variable can be changed to modify the flags/options passed to 'vlog'. =============================================================================== xvlog *ale-verilog-xvlog* *ale-options.verilog_xvlog_executable* *g:ale_verilog_xvlog_executable* *b:ale_verilog_xvlog_executable* verilog_xvlog_executable g:ale_verilog_xvlog_executable Type: |String| Default: `'xvlog'` This variable can be changed to the path to the 'xvlog' executable. *ale-options.verilog_xvlog_options* *g:ale_verilog_xvlog_options* *b:ale_verilog_xvlog_options* verilog_xvlog_options g:ale_verilog_xvlog_options Type: |String| Default: `''` This variable can be changed to modify the flags/options passed to 'xvlog'. =============================================================================== yosys *ale-verilog-yosys* *ale-options.verilog_yosys_executable* *g:ale_verilog_yosys_executable* *b:ale_verilog_yosys_executable* verilog_yosys_executable g:ale_verilog_yosys_executable Type: |String| Default: `'yosys'` This variable can be changed to the path to the 'yosys' executable. *ale-options.verilog_yosys_options* *g:ale_verilog_yosys_options* *b:ale_verilog_yosys_options* verilog_yosys_options g:ale_verilog_yosys_options Type: |String| Default: `'-Q -T -p ''read_verilog %s'''` This variable can be changed to modify the flags/options passed to 'yosys'. By default, Yosys is an interactive program. To obtain linting functionality, the `'read_verilog'` command is used. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-vhdl.txt ================================================ =============================================================================== ALE VHDL Integration *ale-vhdl-options* =============================================================================== ALE can use four different linters for VHDL: ghdl: Using `ghdl --std=08` ModelSim/Questa Using `vcom -2008 -quiet -lint` Vivado Using `xvhdl --2008` HDL Checker Using `hdl_checker --lsp` =============================================================================== General notes ghdl, ModelSim/Questa and Vivado linters default to VHDL-2008 support. This, and other options, can be changed with each linter's respective option variable. Linters/compilers that utilize a "work" directory for analyzing designs- such as ModelSim and Vivado- can be passed the location of these directories as part of their respective option strings listed below. This is useful for holistic analysis of a file (e.g. a design with components, packages, or other code defined external to the current file as part of a larger project) or when wanting to simply pass an alternative location for the auto-generated work directories (such as '/tmp') so as to not muddle the current directory. Since these type of linters often use this work directory for holding compiled design data as part of a single build process, they sometimes cannot handle the frequent, asynchronous application launches when linting while text is changing. This can happen in the form of hangs or crashes. To help prevent this when using these linters, it may help to run linting less frequently; for example, only when a file is saved. HDL Checker is an alternative for some of the issues described above. It wraps around ghdl, Vivado and ModelSim/Questa and, when using the latter, it can handle mixed language (VHDL, Verilog, SystemVerilog) designs. =============================================================================== ghdl *ale-vhdl-ghdl* *ale-options.vhdl_ghdl_executable* *g:ale_vhdl_ghdl_executable* *b:ale_vhdl_ghdl_executable* vhdl_ghdl_executable g:ale_vhdl_ghdl_executable Type: |String| Default: `'ghdl'` This variable can be changed to the path to the 'ghdl' executable. *ale-options.vhdl_ghdl_options* *g:ale_vhdl_ghdl_options* *b:ale_vhdl_ghdl_options* vhdl_ghdl_options g:ale_vhdl_ghdl_options Type: |String| Default: `'--std=08'` This variable can be changed to modify the flags/options passed to 'ghdl'. =============================================================================== hdl-checker *ale-vhdl-hdl-checker* HDL Checker is a wrapper for VHDL/Verilg/SystemVerilog tools that aims to reduce the boilerplate code needed to set things up. It can automatically infer libraries for VHDL sources, determine the compilation order and provide some static checks. You can install it using pip: > $ pip install hdl-checker `hdl-checker` will be run from a detected project root, determined by the following methods, in order: 1. Find the first directory containing a configuration file (see |g:ale_hdl_checker_config_file|) 2. If no configuration file can be found, find the first directory containing a folder named `'.git' 3. If no such folder is found, use the directory of the current buffer *ale-options.hdl_checker_executable* *g:ale_hdl_checker_executable* *b:ale_hdl_checker_executable* hdl_checker_executable g:ale_hdl_checker_executable Type: |String| Default: `'hdl_checker'` This variable can be changed to the path to the 'hdl_checker' executable. *ale-options.hdl_checker_options* *g:ale_hdl_checker_options* *b:ale_hdl_checker_options* hdl_checker_options g:ale_hdl_checker_options Type: |String| Default: `''` This variable can be changed to modify the flags/options passed to the 'hdl_checker' server startup command. *ale-options.hdl_checker_config_file* *g:ale_hdl_checker_config_file* *b:ale_hdl_checker_config_file* hdl_checker_config_file g:ale_hdl_checker_config_file Type: |String| Default: `'.hdl_checker.config'` (Unix), `'_hdl_checker.config'` (Windows) This variable can be changed to modify the config file HDL Checker will try to look for. It will also affect how the project's root directory is determined (see |ale-vhdl-hdl-checker|). More info on the configuration file format can be found at: https://github.com/suoto/hdl_checker/wiki/Setting-up-a-project =============================================================================== vcom *ale-vhdl-vcom* *ale-options.vhdl_vcom_executable* *g:ale_vhdl_vcom_executable* *b:ale_vhdl_vcom_executable* vhdl_vcom_executable g:ale_vhdl_vcom_executable Type: |String| Default: `'vcom'` This variable can be changed to the path to the 'vcom' executable. *ale-options.vhdl_vcom_options* *g:ale_vhdl_vcom_options* *b:ale_vhdl_vcom_options* vhdl_vcom_options g:ale_vhdl_vcom_options Type: |String| Default: `'-2008 -quiet -lint'` This variable can be changed to modify the flags/options passed to 'vcom'. =============================================================================== xvhdl *ale-vhdl-xvhdl* *ale-options.vhdl_xvhdl_executable* *g:ale_vhdl_xvhdl_executable* *b:ale_vhdl_xvhdl_executable* vhdl_xvhdl_executable g:ale_vhdl_xvhdl_executable Type: |String| Default: `'xvhdl'` This variable can be changed to the path to the 'xvhdl' executable. *ale-options.vhdl_xvhdl_options* *g:ale_vhdl_xvhdl_options* *b:ale_vhdl_xvhdl_options* vhdl_xvhdl_options g:ale_vhdl_xvhdl_options Type: |String| Default: `'--2008'` This variable can be changed to modify the flags/options passed to 'xvhdl'. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-vim-help.txt ================================================ =============================================================================== ALE Vim help Integration *ale-vim-help-options* =============================================================================== write-good *ale-vim-help-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-vim.txt ================================================ =============================================================================== ALE Vim Integration *ale-vim-options* =============================================================================== vimls *ale-vim-vimls* The `vim-language-server` is the engine that powers VimL editor support using the Language Server Protocol. See the installation instructions: https://github.com/iamcco/vim-language-server#install *ale-options.vim_vimls_executable* *g:ale_vim_vimls_executable* *b:ale_vim_vimls_executable* vim_vimls_executable g:ale_vim_vimls_executable Type: |String| Default: `'vim-language-server'` This option can be set to change the executable path for vimls. *ale-options.vim_vimls_config* *g:ale_vim_vimls_config* *b:ale_vim_vimls_config* vim_vimls_config g:ale_vim_vimls_config Type: |Dictionary| Default: `{}` Dictionary containing configuration settings that will be passed to the language server. For example: > let g:ale_vim_vimls_config = { \ 'vim': { \ 'iskeyword': '@,48-57,_,192-255,-#', \ 'vimruntime': '', \ 'runtimepath': '', \ 'diagnostic': {'enable': v:true}, \ 'indexes': { \ 'runtimepath': v:true, \ 'gap': 100, \ 'count': 3, \ 'projectRootPatterns': ['.git', 'autoload', 'plugin'], \ }, \ 'suggest': { \ 'fromVimruntime': v:true, \ 'fromRuntimepath': v:false, \ }, \ }, \} < Consult the vim-language-server documentation for more information about settings. *ale-options.vim_vimls_use_global* *g:ale_vim_vimls_use_global* *b:ale_vim_vimls_use_global* vim_vimls_use_global g:ale_vim_vimls_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== vint *ale-vim-vint* *ale-options.vim_vint_executable* *g:ale_vim_vint_executable* *b:ale_vim_vint_executable* vim_vint_executable g:ale_vim_vint_executable Type: |String| Default: `'vint'` This option can be set to change the executable path for Vint. *ale-options.vim_vint_show_style_issues* *g:ale_vim_vint_show_style_issues* *b:ale_vim_vint_show_style_issues* vim_vint_show_style_issues g:ale_vim_vint_show_style_issues Type: |Number| Default: `1` This variable will enable/disable style issues for Vint. When this option is disabled, only warnings and errors which are not purely style issues will be reported. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-vue.txt ================================================ =============================================================================== ALE Vue Integration *ale-vue-options* =============================================================================== cspell *ale-vue-cspell* See |ale-cspell-options| =============================================================================== prettier *ale-vue-prettier* See |ale-javascript-prettier| for information about the available options. =============================================================================== vls *ale-vue-vls* *ale-options.vue_vls_executable* *g:ale_vue_vls_executable* *b:ale_vue_vls_executable* vue_vls_executable g:ale_vue_vls_executable Type: |String| Default: `'vls'` See |ale-integrations-local-executables| *ale-options.vue_vls_use_global* *g:ale_vue_vls_use_global* *b:ale_vue_vls_use_global* vue_vls_use_global g:ale_vue_vls_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== volar *ale-vue-volar* It is required to have typescript installed in your project as your dev dependency: `npm i -D typescript` *ale-options.vue_volar_executable* *g:ale_vue_volar_executable* *b:ale_vue_volar_executable* vue_volar_executable g:ale_vue_volar_executable Type: |String| Default: `'vue-language-server'` See |ale-integrations-local-executables| *ale-options.vue_volar_use_global* *g:ale_vue_volar_use_global* *b:ale_vue_volar_use_global* vue_volar_use_global g:ale_vue_volar_use_global Type: |Number| Default: `1` See |ale-integrations-local-executables| *ale-options.vue_volar_init_options* *g:ale_vue_volar_init_options* *b:ale_vue_volar_init_options* vue_volar_init_options g:ale_vue_volar_init_options Type: |Dictionary| Default: `{'typescript': 'tsdk': ''}` This option can be configured to set the initialization options for volar. ALE will automatically replace `tsdk` with local detected path to the typescript library. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-wgsl.txt ================================================ =============================================================================== ALE WGSL Integration *ale-wgsl-options* =============================================================================== naga *ale-wgsl-naga* *ale-options.wgsl_naga_executable* *g:ale_wgsl_naga_executable* *b:ale_wgsl_naga_executable* wgsl_naga_executable g:ale_wgsl_naga_executable Type: |String| Default: `'naga'` The executable that will be run for the `naga` linter. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-xhtml.txt ================================================ =============================================================================== ALE XHTML Integration *ale-xhtml-options* =============================================================================== cspell *ale-xhtml-cspell* See |ale-cspell-options| =============================================================================== write-good *ale-xhtml-write-good* See |ale-write-good-options| =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-xml.txt ================================================ =============================================================================== ALE XML Integration *ale-xml-options* =============================================================================== xmllint *ale-xml-xmllint* *ale-options.xml_xmllint_executable* *g:ale_xml_xmllint_executable* *b:ale_xml_xmllint_executable* xml_xmllint_executable g:ale_xml_xmllint_executable Type: |String| Default: `'xmllint'` This variable can be set to change the path to xmllint. *ale-options.xml_xmllint_options* *g:ale_xml_xmllint_options* *b:ale_xml_xmllint_options* xml_xmllint_options g:ale_xml_xmllint_options Type: |String| Default: `''` This variable can be set to pass additional options to xmllint. *ale-options.xml_xmllint_indentsize* *g:ale_xml_xmllint_indentsize* *b:ale_xml_xmllint_indentsize* xml_xmllint_indentsize g: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: ================================================ FILE: doc/ale-yaml.txt ================================================ =============================================================================== ALE YAML Integration *ale-yaml-options* =============================================================================== actionlint *ale-yaml-actionlint* Website: https://github.com/rhysd/actionlint Installation ------------------------------------------------------------------------------- See installation guide: https://github.com/rhysd/actionlint#quick-start This linter is disabled by default and must be enabled by setting `g:ale_linters`. To enable it only for Github Action YAML files a configuration like this is better: > au BufRead,BufNewFile */.github/*/*.y{,a}ml \ let b:ale_linters = {'yaml': ['actionlint']} < ------------------------------------------------------------------------------- Options *ale-options.yaml_actionlint_executable* *g:ale_yaml_actionlint_executable* *b:ale_yaml_actionlint_executable* yaml_actionlint_executable g:ale_yaml_actionlint_executable Type: |String| Default: `'actionlint'` This variable can be set to change the path to actionlint. *ale-options.yaml_actionlint_options* *g:ale_yaml_actionlint_options* *b:ale_yaml_actionlint_options* yaml_actionlint_options g:ale_yaml_actionlint_options Type: |String| Default: `''` This variable can be set to add extra options to actionlint executable. For example, to disable running `shellcheck` and `pyflakes` external commands, you may want to set: > let g:ale_yaml_actionlint_options = '-shellcheck= -pyflakes=' < Please note that passing `-format` as option is not supported at the moment. =============================================================================== circleci *ale-yaml-circleci* Website: https://circleci.com/docs/2.0/local-cli Installation ------------------------------------------------------------------------------- Follow the instructions on the website, and make sure to test that you can validate configuration files with: > circleci config validate - < .circleci/config.yml < As long as the validator runs correctly, you should be able to see errors when you save the configuration file. The validator doesn't run as you type because it sends network requests, and running too often would overload the circleci servers. =============================================================================== 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 < =============================================================================== spectral *ale-yaml-spectral* Website: https://github.com/stoplightio/spectral Installation ------------------------------------------------------------------------------- Install spectral either globally or locally: > npm install @stoplight/spectral -g # global npm install @stoplight/spectral # local < ------------------------------------------------------------------------------- Options *ale-options.yaml_spectral_executable* *g:ale_yaml_spectral_executable* *b:ale_yaml_spectral_executable* yaml_spectral_executable g:ale_yaml_spectral_executable Type: |String| Default: `'spectral'` This variable can be set to change the path to spectral. *ale-options.yaml_spectral_use_global* *g:ale_yaml_spectral_use_global* *b:ale_yaml_spectral_use_global* yaml_spectral_use_global g:ale_yaml_spectral_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== swaglint *ale-yaml-swaglint* Website: https://github.com/byCedric/swaglint Installation ------------------------------------------------------------------------------- Install swaglint either globally or locally: > npm install swaglint -g # global npm install swaglint # local < ------------------------------------------------------------------------------- Options *ale-options.yaml_swaglint_executable* *g:ale_yaml_swaglint_executable* *b:ale_yaml_swaglint_executable* yaml_swaglint_executable g:ale_yaml_swaglint_executable Type: |String| Default: `'swaglint'` This variable can be set to change the path to swaglint. *ale-options.yaml_swaglint_use_global* *g:ale_yaml_swaglint_use_global* *b:ale_yaml_swaglint_use_global* yaml_swaglint_use_global g:ale_yaml_swaglint_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== yaml-language-server *ale-yaml-language-server* Website: https://github.com/redhat-developer/yaml-language-server Installation ------------------------------------------------------------------------------- Install yaml-language-server either globally or locally: > npm install yaml-language-server -g # global npm install yaml-language-server # local ------------------------------------------------------------------------------- Options *ale-options.yaml_ls_executable* *g:ale_yaml_ls_executable* *b:ale_yaml_ls_executable* yaml_ls_executable g:ale_yaml_ls_executable Type: |String| Default: `'yaml-language-server'` This variable can be set to change the path to yaml-language-server. *ale-options.yaml_ls_config* *g:ale_yaml_ls_config* *b:ale_yaml_ls_config* yaml_ls_config g:ale_yaml_ls_config Type: |Dictionary| Default: `{}` A Dictionary for settings to pass to the language server. For example, to enable the schema store, you can do use the following in your yaml ftplugin file: > let b:ale_yaml_ls_config = { \ 'yaml': { \ 'schemaStore': { \ 'enable': v:true, \ }, \ }, \} < Or in Lua: > require("ale").setup.buffer({ yaml_ls_config = { yaml = { schemaStore = { enable = true, }, }, }, }) < Consult the yaml-language-server documentation for more information about settings. *ale-options.yaml_ls_use_global* *g:ale_yaml_ls_use_global* *b:ale_yaml_ls_use_global* yaml_ls_use_global g:ale_yaml_ls_use_global Type: |String| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== yamlfix *ale-yaml-yamlfix* Website: https://lyz-code.github.io/yamlfix Installation ------------------------------------------------------------------------------- Install yamlfix: > pip install yamlfix < ------------------------------------------------------------------------------- Options *ale-options.yaml_yamlfix_executable* *g:ale_yaml_yamlfix_executable* *b:ale_yaml_yamlfix_executable* yaml_yamlfix_executable g:ale_yaml_yamlfix_executable Type: |String| Default: `'yamlfix'` See |ale-integrations-local-executables| *ale-options.yaml_yamlfix_options* *g:ale_yaml_yamlfix_options* *b:ale_yaml_yamlfix_options* yaml_yamlfix_options g:ale_yaml_yamlfix_options Type: |String| Default: `''` This variable can be set to pass extra options to yamlfix. *ale-options.yaml_yamlfix_use_global* *g:ale_yaml_yamlfix_use_global* *b:ale_yaml_yamlfix_use_global* yaml_yamlfix_use_global g:ale_yaml_yamlfix_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== yamlfmt *ale-yaml-yamlfmt* Website: https://github.com/google/yamlfmt ------------------------------------------------------------------------------- Installation Install yamlfmt: See the website. ------------------------------------------------------------------------------- Options *ale-options.yaml_yamlfmt_executable* *g:ale_yaml_yamlfmt_executable* *b:ale_yaml_yamlfmt_executable* yaml_yamlfmt_executable g:ale_yaml_yamlfmt_executable Type: |String| Default: `'yamlfmt'` See |ale-integrations-local-executables| *ale-options.yaml_yamlfmt_options* *g:ale_yaml_yamlfmt_options* *b:ale_yaml_yamlfmt_options* yaml_yamlfmt_options g:ale_yaml_yamlfmt_options Type: |String| Default: `''` This variable can be set to pass extra options to yamlfmt. *ale-options.yaml_yamlfmt_use_global* *g:ale_yaml_yamlfmt_use_global* *b:ale_yaml_yamlfmt_use_global* yaml_yamlfmt_use_global g:ale_yaml_yamlfmt_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| =============================================================================== yamllint *ale-yaml-yamllint* Website: https://github.com/adrienverge/yamllint ------------------------------------------------------------------------------- Installation Install yamllint in your a virtualenv directory, locally, or globally: > pip install yamllint # After activating virtualenv pip install --user yamllint # Install to ~/.local/bin sudo pip install yamllint # Install globally See |g:ale_virtualenv_dir_names| for configuring how ALE searches for virtualenv directories. ------------------------------------------------------------------------------- Options *ale-options.yaml_yamllint_executable* *g:ale_yaml_yamllint_executable* *b:ale_yaml_yamllint_executable* yaml_yamllint_executable g:ale_yaml_yamllint_executable Type: |String| Default: `'yamllint'` This variable can be set to change the path to yamllint. *ale-options.yaml_yamllint_options* *g:ale_yaml_yamllint_options* *b:ale_yaml_yamllint_options* yaml_yamllint_options g:ale_yaml_yamllint_options Type: |String| Default: `''` This variable can be set to pass additional options to yamllint. =============================================================================== gitlablint *ale-yaml-gitlablint* Website: https://github.com/elijah-roberts/gitlab-lint ------------------------------------------------------------------------------- Installation Install yamllint in your a virtualenv directory, locally, or globally: > pip3 install gitlab_lint # After activating virtualenv pip3 install --user gitlab_lint # Install to ~/.local/bin sudo pip3 install gitlab_lint # Install globally See |g:ale_virtualenv_dir_names| for configuring how ALE searches for virtualenv directories. Is recommended to use |g:ale_pattern_options| to enable this linter so it only applies to 'gitlab-ci.yml' files and not all yaml files: > let g:ale_pattern_options = { \ '.gitlab-ci\.yml$': { \ 'ale_linters': ['gitlablint'], \ }, \} < ------------------------------------------------------------------------------- Options *ale-options.yaml_gitlablint_executable* *g:ale_yaml_gitlablint_executable* *b:ale_yaml_gitlablint_executable* yaml_gitlablint_executable g:ale_yaml_gitlablint_executable Type: |String| Default: `'gll'` This variable can be set to change the path to gll. *ale-options.yaml_gitlablint_options* *g:ale_yaml_gitlablint_options* *b:ale_yaml_gitlablint_options* yaml_gitlablint_options g:ale_yaml_gitlablint_options Type: |String| Default: `''` This variable can be set to pass additional options to gll. =============================================================================== yq *ale-yaml-yq* Website: https://github.com/mikefarah/yq ------------------------------------------------------------------------------- Installation Install yq: > wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - | tar xz && mv ${BINARY} /usr/bin/yq ------------------------------------------------------------------------------- Options *ale-options.yaml_yq_executable* *g:ale_yaml_yq_executable* *b:ale_yaml_yq_executable* yaml_yq_executable g:ale_yaml_yq_executable Type: |String| Default: `'yq'` This variable can be set to change the path to yq. *ale-options.yaml_yq_options* *g:ale_yaml_yq_options* *b:ale_yaml_yq_options* yaml_yq_options g:ale_yaml_yq_options Type: |String| Default: `''` This variable can be set to pass additional options to yq. *ale-options.yaml_yq_filters* *g:ale_yaml_yq_filters* *b:ale_yaml_yq_filters* yaml_yq_filters g:ale_yaml_yq_filters Type: |String| Default: `'.'` This option can be changed to pass additional filters to yq =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-yang.txt ================================================ =============================================================================== ALE YANG Integration *ale-yang-options* =============================================================================== yang-lsp *ale-yang-lsp* *ale-options.yang_lsp_executable* *g:ale_yang_lsp_executable* *b:ale_yang_lsp_executable* yang_lsp_executable g: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: ================================================ FILE: doc/ale-yara.txt ================================================ =============================================================================== ALE Yara Integration *ale-yara-options* *ale-integration-yara* =============================================================================== Integration Information Currently, the only supported linter for yara is yls. =============================================================================== yls *ale-yara-yls* *ale-options.yara_yls_executable* *g:ale_yara_yls_executable* *b:ale_yara_yls_executable* yara_yls_executable g:ale_yara_yls_executable Type: |String| Default: `'yls'` This variable can be modified to change the executable path for `yls`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-zeek.txt ================================================ =============================================================================== ALE Zeek Integration *ale-zeek-options* *ale-integration-zeek* =============================================================================== Integration Information Currently, the only supported linter for Zeek is zeek. =============================================================================== zeek *ale-zeek-zeek* *ale-options.zeek_zeek_executable* *g:ale_zeek_zeek_executable* *b:ale_zeek_zeek_executable* zeek_zeek_executable g:ale_zeek_zeek_executable Type: |String| Default: `'zeek'` This variable can be modified to change the executable path for `zeek`. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale-zig.txt ================================================ =============================================================================== ALE Zig Integration *ale-zig-options* *ale-integration-zig* =============================================================================== Integration Information The following linters are supported for Zig: * zlint (https://github.com/DonIsaac/zlint) * zls (https://github.com/zigtools/zls) =============================================================================== zigfmt *ale-zig-zigfmt* *ale-options.zig_zigfmt_executable* *g:ale_zig_zigfmt_executable* *b:ale_zig_zigfmt_executable* zig_zigfmt_executable g:ale_zig_zigfmt_executable Type: |String| Default: `'zig'` The executable that will be run for the `zig fmt` fixer. =============================================================================== zlint *ale-zig-zlint* *ale-options.zig_zlint_executable* *g:ale_zig_zlint_executable* *b:ale_zig_zlint_executable* zig_zlint_executable g:ale_zig_zlint_executable Type: |String| Default: `'zlint'` This variable can be modified to change the executable path for `zlint`. =============================================================================== zls *ale-zig-zls* *ale-options.zig_zls_executable* *g:ale_zig_zls_executable* *b:ale_zig_zls_executable* zig_zls_executable g:ale_zig_zls_executable Type: |String| Default: `'zls'` This variable can be modified to change the executable path for `zls`. *ale-options.zig_zls_config* *g:ale_zig_zls_config* *b:ale_zig_zls_config* zig_zls_config g:ale_zig_zls_config Type: |Dictionary| Default: `{}` WARNING: As of writing, zls does not support receiving configuration from the client. This variable is a PLACEHOLDER until it does. Dictionary with configuration settings for zls. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: doc/ale.txt ================================================ *ale.txt* Plugin to lint and fix files asynchronously *ale* ALE - Asynchronous Lint Engine =============================================================================== CONTENTS *ale-contents* 1. Introduction.........................|ale-introduction| 2. Supported Languages & Tools..........|ale-support| 3. Linting..............................|ale-lint| 3.1 Linting On Other Machines.........|ale-lint-other-machines| 3.2 Adding Language Servers...........|ale-lint-language-servers| 3.3 Other Sources.....................|ale-lint-other-sources| 4. Fixing Problems......................|ale-fix| 5. Language Server Protocol Support.....|ale-lsp| 5.1 LSP Neovim Integration............|ale-lsp-neovim| 5.2 Completion........................|ale-completion| 5.3 Go To Definition..................|ale-go-to-definition| 5.4 Go To Type Definition.............|ale-go-to-type-definition| 5.5 Go To Implementation..............|ale-go-to-implementation| 5.6 Find References...................|ale-find-references| 5.7 Hovering..........................|ale-hover| 5.8 Symbol Search.....................|ale-symbol-search| 5.9 Refactoring: Rename, Actions......|ale-refactor| 6. Global Options.......................|ale-options| 6.1 Highlights........................|ale-highlights| 7. Linter/Fixer Options.................|ale-integration-options| 7.1 Options for alex..................|ale-alex-options| 7.2 Options for cspell................|ale-cspell-options| 7.3 Options for dprint................|ale-dprint-options| 7.4 Options for languagetool..........|ale-languagetool-options| 7.5 Options for write-good............|ale-write-good-options| 7.6 Options for redpen................|ale-redpen-options| 7.7 Options for vale..................|ale-vale-options| 7.8 Other Linter/Fixer Options........|ale-other-integration-options| 8. Commands/Keybinds....................|ale-commands| 9. API..................................|ale-api| 10. Special Thanks......................|ale-special-thanks| 11. Contact.............................|ale-contact| =============================================================================== 1. Introduction *ale-introduction* ALE provides the means to run linters asynchronously in Vim in a variety of languages and tools. ALE sends the contents of buffers to linter programs using the |job-control| features available in Vim 8 and NeoVim. For Vim 8, Vim must be compiled with the |+job| and |+channel| and |+timers| features as a minimum. ALE supports the following key features for linting: 1. Running linters when text is changed. 2. Running linters when files are opened. 3. Running linters when files are saved. (When a global flag is set.) 4. Populating the |location-list| with warning and errors. 5. Setting |signs| with warnings and errors for error markers. 6. Using `:echo` to show error messages when the cursor moves. 7. Setting syntax highlights for errors. ALE can fix problems with files with the `:ALEFix` command, using the same job control functionality used for checking for problems. Try using the `:ALEFixSuggest` command for browsing tools that can be used to fix problems for the current buffer. If you are interested in contributing to the development of ALE, read the developer documentation. See |ale-development| For configuring ALE in Neovim, you can use the |ale.setup| function to configure ALE globally in `init.vim`. > require("ale").setup({ completion_enabled = true, maximum_file_size = 1024 * 1024, warn_about_trailing_whitespace = false, }) < In |ftplugin| files you can customise behavior for different filetypes by using the |ale.setup.buffer| function. > -- In ftplugin/python.lua in &runtimepath require("ale").setup.buffer({ linters = {"ruff", "pyright"}, fixers = {"ruff"} }) < Buffer local settings override global settings for that buffer. =============================================================================== 2. Supported Languages & Tools *ale-support* ALE supports a wide variety of languages and tools. See |ale-supported-list| for the full list. =============================================================================== 3. Linting *ale-lint* ALE's primary focus is on checking for problems with your code with various programs via some Vim code for integrating with those programs, referred to as 'linters.' ALE supports a wide array of programs for linting by default, but additional programs can be added easily by defining files in |runtimepath| with the filename pattern `ale_linters//.vim`. For more information on defining new linters, see the extensive documentation for |ale#linter#Define()|. Without any configuration, ALE will attempt to check all of the code for every file you open in Vim with all available tools by default. To see what ALE is doing, and what options have been set, try using the `:ALEInfo` command. Most of the linters ALE runs will check the Vim buffer you are editing instead of the file on disk. This allows you to check your code for errors before you have even saved your changes. ALE will check your code in the following circumstances, which can be configured with the associated options. * When you modify a buffer - |g:ale_lint_on_text_changed| * On leaving insert mode - |g:ale_lint_on_insert_leave| * When you open a new or modified buffer - |g:ale_lint_on_enter| * When you save a buffer - |g:ale_lint_on_save| * When the filetype changes for a buffer - |g:ale_lint_on_filetype_changed| * If ALE is used to check code manually - |:ALELint| *ale-lint-settings-on-startup* It is worth reading the documentation for every option. You should configure which events ALE will use before ALE is loaded, so it can optimize which autocmd commands to run. You can force autocmd commands to be reloaded with `:ALEDisable | ALEEnable` This also applies to the autocmd commands used for |g:ale_echo_cursor|. *ale-lint-file-linters* Some programs must be run against files which have been saved to disk, and simply do not support reading temporary files or stdin, either of which are required for ALE to be able to check for errors as you type. The programs which behave this way are documented in the lists and tables of supported programs. ALE will only lint files with these programs in the following circumstances. * When you open a new or modified buffer - |g:ale_lint_on_enter| * When you save a buffer - |g:ale_lint_on_save| * When the filetype changes for a buffer - |g:ale_lint_on_filetype_changed| * If ALE is used to check code manually - |:ALELint| ALE will report problems with your code in the following ways, listed with their relevant options. * Via Neovim diagnostics (On in Neovim 0.7+) - |g:ale_use_neovim_diagnostics_api| * 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 virtual text at your cursor - |g:ale_virtualtext_cursor| * By previewing details at 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 behavior of each way of displaying problems. You can disable or enable whichever options you prefer. Most settings can be configured for each buffer. (|b:| instead of |g:|), including disabling ALE for certain buffers with |b:ale_enabled|. The |g:ale_pattern_options| setting can be used to configure files differently based on regular expressions for filenames. For configuring entire projects, the buffer-local options can be used with external plugins for reading Vim project configuration files. Buffer-local settings can also be used in ftplugin files for different filetypes. ALE offers several options for controlling which linters are run. * Selecting linters to run. - |g:ale_linters| * Aliasing filetypes for linters - |g:ale_linter_aliases| * Only running linters you asked for. - |g:ale_linters_explicit| * Disabling only a subset of linters. - |g:ale_linters_ignore| * Disabling LSP linters and `tsserver`. - |g:ale_disable_lsp| You can stop ALE any currently running linters with the `:ALELintStop` command. Any existing problems will be kept. ------------------------------------------------------------------------------- 3.1 Linting On Other Machines *ale-lint-other-machines* ALE offers support for running linters or fixers on files you are editing locally on other machines, so long as the other machine has access to the file you are editing. This could be a linter or fixer run inside of a Docker image, running in a virtual machine, running on a remote server, etc. In order to run tools on other machines, you will need to configure your tools to run via scripts that execute commands on those machines, such as by setting the ALE `_executable` options for those tools to a path for a script to run, or by using |g:ale_command_wrapper| to specify a script to wrap all commands that are run by ALE, before they are executed. For tools that ALE runs where ALE looks for locally installed executables first, you may need to set the `_use_global` options for those tools to `1`, or you can set |g:ale_use_global_executables| to `1` before ALE is loaded to only use global executables for all tools. In order for ALE to properly lint or fix files which are running on another file system, you must provide ALE with |List|s of strings for mapping paths to and from your local file system and the remote file system, such as the file system of your Docker container. See |g:ale_filename_mappings| for all of the different ways these filename mappings can be configured. For example, you might configure `pylint` to run via Docker by creating a script like so. > #!/usr/bin/env bash exec docker run -i --rm -v "$(pwd):/data" cytopia/pylint "$@" < You will want to run Docker commands with `-i` in order to read from stdin. With the above script in mind, you might configure ALE to lint your Python project with `pylint` by providing the path to the script to execute, and mappings which describe how to change between the two file systems in your `python.vim` |ftplugin| file, like so: > if expand('%:p') =~# '^/home/w0rp/git/test-pylint/' let b:ale_linters = ['pylint'] let b:ale_python_pylint_use_global = 1 " This is the path to the script above. let b:ale_python_pylint_executable = '/home/w0rp/git/test-pylint/pylint.sh' " /data matches the path in Docker. let b:ale_filename_mappings = { \ 'pylint': [ \ ['/home/w0rp/git/test-pylint', '/data'], \ ], \} endif < You might consider using a Vim plugin for loading Vim configuration files specific to each project, if you have a lot of projects to manage. ------------------------------------------------------------------------------- 3.2 Adding Language Servers *ale-lint-language-servers* ALE comes with many default configurations for language servers, so they can be detected and run automatically. ALE can connect to other language servers by defining a new linter for a filetype. New linters can be defined in |vimrc|, in plugin files, or `ale_linters` directories in 'runtimepath'. See |ale-linter-loading-behavior| for more information on loading linters. A minimal configuration for a language server linter might look so. > call ale#linter#Define('filetype_here', { \ 'name': 'any_name_you_want', \ 'lsp': 'stdio', \ 'executable': '/path/to/executable', \ 'command': '%e run', \ 'project_root': '/path/to/root_of_project', \}) < For language servers that use a TCP or named pipe socket connection, you should define the address to connect to instead. > call ale#linter#Define('filetype_here', { \ 'name': 'any_name_you_want', \ 'lsp': 'socket', \ 'address': 'servername:1234', \ 'project_root': '/path/to/root_of_project', \}) < Most of the options for a language server can be replaced with a |Funcref| for a function accepting a buffer number for dynamically computing values such as the executable path, the project path, the server address, etc, most of which can also be determined based on executing some other asynchronous task. See |ale#command#Run()| for computing linter options based on asynchronous results. See |ale#linter#Define()| for a detailed explanation of all of the options for configuring linters. ------------------------------------------------------------------------------- 3.3 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. |ale#other_source#ShowResults()| must not be called synchronously before ALE's engine executes its code after the |ALEWantResults| event runs. If there are immediate results to provide to ALE, a 0 millisecond timer with |timer_start()| can be set instead up to call |ale#other_source#ShowResults()| after ALE has first executed its engine code for its own sources. 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(a:buffer, 'some-name', a:results) endfunction < =============================================================================== 4. Fixing Problems *ale-fix* ALE can fix problems with files with the `:ALEFix` command. `:ALEFix` accepts names of fixers to be applied as arguments. Alternatively, when no arguments are provided, the variable |g:ale_fixers| will be read for getting a |List| of commands for filetypes, split on `.`, and the functions named in |g:ale_fixers| will be executed for fixing the errors. The `:ALEFixSuggest` command can be used to suggest tools that be used to fix problems for the current buffer. The values for `g:ale_fixers` can be a list of |String|, |Funcref|, or |lambda| values. String values must either name a function, or a short name for a function set in the ALE fixer registry. Each function for fixing errors must accept either one argument `(buffer)` or two arguments `(buffer, lines)`, representing the buffer being fixed and the lines to fix. The functions must return either `0`, for changing nothing, a |List| for new lines to set, a |Dictionary| for describing a command to be run in the background, or the result of |ale#command#Run()|. Functions receiving a variable number of arguments will not receive the second argument `lines`. Functions should name two arguments if the `lines` argument is desired. This is required to avoid unnecessary copying of the lines of the buffers being checked. When a |Dictionary| is returned for an `:ALEFix` callback, the following keys are supported for running the commands. `cwd` An optional |String| for setting the working directory for the command. If not set, or `v:null`, the `cwd` of the last command that spawn this one will be used. `command` A |String| for the command to run. This key is required. When `%t` is included in a command string, a temporary file will be created, containing the lines from the file after previous adjustment have been done. See |ale-command-format-strings| for formatting options. `read_temporary_file` When set to `1`, ALE will read the contents of the temporary file created for `%t`. This option can be used for commands which need to modify some file on disk in order to fix files. `process_with` An optional callback for post-processing. The callback must accept arguments `(bufnr, output)`: the buffer number undergoing fixing and the fixer's output as a |List| of |String|s. It must return a |List| of |String|s that will be the new contents of the buffer. This callback is useful to remove excess lines from the command's output or apply additional changes to the output. `read_buffer` An optional key for disabling reading the buffer. When set to `0`, ALE will not pipe the buffer's data into the command via stdin. This option is ignored and the buffer is not read when `read_temporary_file` is `1`. This option defaults to `1`. *ale-fix-configuration* Synchronous functions and asynchronous jobs will be run in a sequence for fixing files, and can be combined. For example: > let g:ale_fixers = { \ 'javascript': [ \ 'DoSomething', \ 'eslint', \ {buffer, lines -> filter(lines, 'v:val !=~ ''^\s*//''')}, \ ], \} ALEFix < The above example will call a function called `DoSomething` which could act upon some lines immediately, then run `eslint` from the ALE registry, and then call a lambda function which will remove every single line comment from the file. For buffer-local settings, such as in |g:ale_pattern_options| or in ftplugin files, a |List| may be used for configuring the fixers instead. > " Same as the above, only a List can be used instead of a Dictionary. let b:ale_fixers = [ \ 'DoSomething', \ 'eslint', \ {buffer, lines -> filter(lines, 'v:val !=~ ''^\s*//''')}, \] ALEFix < For convenience, a plug mapping is defined for `:ALEFix`, so you can set up a keybind easily for fixing files. > " Bind F8 to fixing problems with ALE nmap (ale_fix) < Files can be fixed automatically with the following options, which are all off by default. |g:ale_fix_on_save| - Fix files when they are saved. Fixers can be disabled on save with |g:ale_fix_on_save_ignore|. They will still be run when you manually run `:ALEFix`. Fixers can be run on another machines, just like linters, such as fixers run from a Docker container, running in a virtual machine, running a remote server, etc. See |ale-lint-other-machines|. =============================================================================== 5. Language Server Protocol Support *ale-lsp* ALE integrates with Language Server Protocol (LSP) 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. If you want to use another plugin for LSP features and tsserver, you can use the |g:ale_disable_lsp| setting to disable ALE's own LSP integrations, or ignore particular linters with |g:ale_linters_ignore|. In ALE's default configuration ALE will attempt to avoid conflicting with `nvim-lspconfig`. ALE will integrate with Neovim's LSP client by default in Neovim 0.8+. This functionality can be controlled with the |g:ale_use_neovim_lsp_api| setting. See |ale-lsp-neovim| below for information about ALE's integration with Neovim's LSP client. If for any reason you want to stop a language server ALE starts, such as when a project configuration has significantly changed, or new files have been added the language server isn't aware of, use either `:ALEStopLSP` or `:ALEStopAllLSPs` to stop the server until ALE automatically starts it again. ------------------------------------------------------------------------------- 5.1 LSP Neovim Integration *ale-lsp-neovim* In Neovim 0.8+ ALE will integrate with Neovim's native LSP client by default, unless disabled by setting |g:ale_use_neovim_lsp_api| to `0`. All built in functionality for Neovim's LSP client should work as expected, and this ensures ALE integrates well with other plugins that rely on Neovim's LSP client. NOTE: Neovim versions below `0.11.0` do not support socket connections to language servers when the `address` defined in ALE uses a hostname instead of an IP address. To work around this, configure language clients with an IP address instead of a hostname, or revert back to ALE's custom LSP client. See |lsp| for information on Neovim's built in LSP client. For diagnostics, for computing problems to show via ALE, ALE overrides the diagnostics handler for the LSP client launched by ALE, so all of the functionality in ALE will work as expected. By default ALE will send diagnostics back to Neovim's diagnostics API, which can be configured with the |g:ale_use_neovim_diagnostics_api| setting. This ensures that all of the functionality ALE adds on top for diagnostics will function, and that problems from linters that don't use LSP can be combined with LSP servers. See the diagram below. > +-------------------+ | Language Server | (Sends diagnostics) +-------------------+ | +-------------------+ | Neovim LSP Client | (Receives diagnostics) +-------------------+ | +-------------------+ | ALE Processing | (Intercepts and processes diagnostics) +-------------------+ | +-------------------+ | Diagnostic engine | (Either Neovim's diagnostics or ALE's custom code) +-------------------+ | +-------------------+ | Neovim | (User sees formatted diagnostics) +-------------------+ < For LSP functionality executed via ALE's own functions, commands, and keybinds, ALE will intercept requests and handle them in an entirely custom way, ensuring ALE functionality should work largely the same between different Vim versions. See the diagram below. > +-------------------+ | Neovim | (User triggers LSP request via ALE) +-------------------+ | +-------------------+ | ALE | (ALE sends request to Neovim client) +-------------------+ | +-------------------+ | Neovim LSP Client | (Forwards request to language server) +-------------------+ | +-------------------+ | Language Server | (Processes request and sends response) +-------------------+ | +-------------------+ | Neovim LSP Client | (Receives response) +-------------------+ | +-------------------+ | ALE | (ALE Handles "raw" LSP response) +-------------------+ | +-------------------+ | Neovim | (User sees result) +-------------------+ < For LSP functionality built-in to Neovim, such as the |gd| keybind for jumping to a definition, Neovim will bypass ALE entirely, ensuring that ALE does not interfere with LSP functionality as expected by built-in Neovim tools or other plugins. See the diagram below. > +-------------------+ | Neovim | (User triggers LSP request) +-------------------+ | +-------------------+ | Neovim LSP Client | (Directly handles the request) +-------------------+ | +-------------------+ | Language Server | (Processes request and sends response) +-------------------+ | +-------------------+ | Neovim LSP Client | (Receives response and shows result) +-------------------+ | +-------------------+ | Neovim | (User sees result) +-------------------+ < ------------------------------------------------------------------------------- 5.2 Completion *ale-completion* In Neovim 0.8+ ALE's integration with its native LSP client will make it possible to use other plugins that rely on Neovim's LSP client as a basis. `nvim-cmp` is recommended as a completion plugin worth trying in Neovim. See: https://github.com/hrsh7th/nvim-cmp ALE offers support for automatic completion of code while you type. Completion is only supported while at least one LSP linter is enabled. ALE will only suggest symbols provided by the LSP servers. *ale-deoplete-integration* ALE integrates with Deoplete for offering automatic completion data. ALE's completion source for Deoplete is named `'ale'`, and should enabled automatically if Deoplete is enabled and configured correctly. Deoplete integration should not be combined with ALE's own implementation. *ale-asyncomplete-integration* ALE additionally integrates with asyncomplete.vim for offering automatic completion data. ALE's asyncomplete source requires registration with defaults provided by the |asyncomplete#sources#ale#get_source_options| function > " Use ALE's function for asyncomplete defaults " Provide your own overrides here. au User asyncomplete_setup call asyncomplete#register_source( \ asyncomplete#sources#ale#get_source_options({ \ 'priority': 10, \ }) \) > ALE also offers its own completion implementation, which does not require any other plugins. Suggestions will be made while you type after completion is enabled. ALE's own completion implementation can be enabled by setting |g:ale_completion_enabled| to `true` or `1`. This setting must be set to `true` or `1` before ALE is loaded. The delay for completion can be configured with |g:ale_completion_delay|. This setting should not be enabled if you wish to use ALE as a completion source for other plugins. ALE automatic completion will not work when 'paste' is active. Only set 'paste' when you are copy and pasting text into your buffers. ALE automatic completion will interfere with default insert completion with `CTRL-N` and so on (|compl-vim|). You can write your own keybinds and a function in your |vimrc| file to force insert completion instead, like so: > function! SmartInsertCompletion() abort " Use the default CTRL-N in completion menus if pumvisible() return "\" endif " Exit and re-enter insert mode, and use insert completion return "\a\" endfunction inoremap =SmartInsertCompletion() < ALE provides an 'omnifunc' function |ale#completion#OmniFunc| for triggering completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| > " Use ALE's function for omnicompletion. set omnifunc=ale#completion#OmniFunc < *ale-completion-fallback* You can write your own completion function and fallback on other methods of completion by checking if there are no results that ALE can determine. For example, for Python code, you could fall back on the `python3complete` function. > function! TestCompletionFunc(findstart, base) abort let l:result = ale#completion#OmniFunc(a:findstart, a:base) " Check if ALE couldn't find anything. if (a:findstart && l:result is -3) \|| (!a:findstart && empty(l:result)) " Defer to another omnifunc if ALE couldn't find anything. return python3complete#Complete(a:findstart, a:base) endif return l:result endfunction set omnifunc=TestCompletionFunc < See |complete-functions| for documentation on how to write completion functions. 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|. The `:ALEComplete` command can be used to show completion suggestions manually, even when |g:ale_completion_enabled| is set to `0`. For manually requesting completion information with Deoplete, consult Deoplete's documentation. ALE supports automatic imports from external modules. This behavior can be disabled by setting the |g:ale_completion_autoimport| variable to `0`. Disabling automatic imports can drop some or all completion items from some LSP servers (e.g. eclipselsp). You can manually request imports for symbols at the cursor with the `:ALEImport` command. The word at the cursor must be an exact match for some potential completion result which includes additional text to insert into the current buffer, which ALE will assume is code for an import line. This command can be useful when your code already contains something you need to import. You can execute other commands whenever ALE inserts some completion text with the |ALECompletePost| event. When working with TypeScript files, ALE can remove warnings from your completions by setting the |g:ale_completion_tsserver_remove_warnings| variable to 1. *ale-completion-completeopt-bug* ALE Automatic completion implementation replaces |completeopt| before opening the omnicomplete menu with . 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 < Or alternatively, if you want to show documentation in popups: > set completeopt=menu,menuone,popup,noselect,noinsert < *ale-symbols* ALE provides a set of basic completion symbols. If you want to replace those symbols with others, you can set the variable |g:ale_completion_symbols| with a mapping of the type of completion to the symbol or other string that you would like to use. An example here shows the available options for symbols > let g:ale_completion_symbols = { \ 'text': '', \ 'method': '', \ 'function': '', \ 'constructor': '', \ 'field': '', \ 'variable': '', \ 'class': '', \ 'interface': '', \ 'module': '', \ 'property': '', \ 'unit': 'unit', \ 'value': 'val', \ 'enum': '', \ 'keyword': 'keyword', \ 'snippet': '', \ 'color': 'color', \ 'file': '', \ 'reference': 'ref', \ 'folder': '', \ 'enum member': '', \ 'constant': '', \ 'struct': '', \ 'event': 'event', \ 'operator': '', \ 'type_parameter': 'type param', \ '': 'v' \ } < ------------------------------------------------------------------------------- 5.3 Go To Definition *ale-go-to-definition* ALE supports jumping to the files and locations where symbols are defined through any enabled LSP linters. The locations ALE will jump to depend on the information returned by LSP servers. The `:ALEGoToDefinition` command will jump to the definition of symbols under the cursor. See the documentation for the command for configuring how the location will be displayed. ALE will update Vim's |tagstack| automatically unless |g:ale_update_tagstack| is set to `0`. ------------------------------------------------------------------------------- 5.4 Go To Type Definition *ale-go-to-type-definition* ALE supports jumping to the files and locations where symbols' types are defined through any enabled LSP linters. The locations ALE will jump to depend on the information returned by LSP servers. The `:ALEGoToTypeDefinition` command will jump to the definition of symbols under the cursor. See the documentation for the command for configuring how the location will be displayed. ------------------------------------------------------------------------------- 5.5 Go To Implementation *ale-go-to-implementation* ALE supports jumping to the files and locations where symbols are implemented through any enabled LSP linters. The locations ALE will jump to depend on the information returned by LSP servers. The `:ALEGoToImplementation` command will jump to the implementation of symbols under the cursor. See the documentation for the command for configuring how the location will be displayed. ------------------------------------------------------------------------------- 5.6 Find References *ale-find-references* ALE supports finding references for symbols though any enabled LSP linters with the `:ALEFindReferences` command. See the documentation for the command for a full list of options. ------------------------------------------------------------------------------- 5.7 Hovering *ale-hover* ALE supports "hover" information for printing brief information about symbols at the cursor taken from LSP linters. The following commands are supported: `:ALEHover` - Print information about the symbol at the cursor. Truncated information will be displayed when the cursor rests on a symbol by default, as long as there are no problems on the same line. You can disable this behavior by setting |g:ale_hover_cursor| to `0`. If |g:ale_set_balloons| is set to `true` or `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. Hover information can be displayed in the preview window instead by setting |g:ale_hover_to_preview| to `true` or `1`. When using Neovim or Vim with |popupwin|, if |g:ale_hover_to_floating_preview| or |g:ale_floating_preview| is set to `true` or `1`, the hover information will show in a floating window. The borders of the floating preview window can be customized by setting |g:ale_floating_window_border|. 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 `true` or `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 < Documentation for symbols at the cursor can be retrieved using the `:ALEDocumentation` command. This command is only available for `tsserver`. ------------------------------------------------------------------------------- 5.8 Symbol Search *ale-symbol-search* ALE supports searching for workspace symbols via LSP linters with the `:ALESymbolSearch` command. See the documentation for the command for a full list of options. ------------------------------------------------------------------------------- 5.9 Refactoring: Rename, Actions *ale-refactor* ALE supports renaming symbols in code such as variables or class names with the `:ALERename` command. `:ALEFileRename` will rename file and fix import paths (tsserver only). `:ALECodeAction` will execute actions on the cursor or applied to a visual range selection, such as automatically fixing errors. Actions will appear in the right click mouse menu by default for GUI versions of Vim, unless disabled by setting |g:ale_popup_menu_enabled| to `0`. Make sure to set your Vim to move the cursor position whenever you right click, and enable the mouse menu: > set mouse=a set mousemodel=popup_setpos < You may wish to remove some other menu items you don't want to see: > silent! aunmenu PopUp.Select\ Word silent! aunmenu PopUp.Select\ Sentence silent! aunmenu PopUp.Select\ Paragraph silent! aunmenu PopUp.Select\ Line silent! aunmenu PopUp.Select\ Block silent! aunmenu PopUp.Select\ Blockwise silent! aunmenu PopUp.Select\ All < =============================================================================== 6. Global Options *ale-options* Options documented here can be configured either Vim variables, or via the |ale.setup| and |ale.setup.buffer| functions in Lua. When configuring via the Lua functions in Lua scripts, ALE will bridge types to Vim script in the following ways. 1. Strings, numbers, booleans, and `nil` will be represented exactly. 2. Tables with no or only number keys will become a |List| in Vim. 3. Keys other than strings and numbers in tables cannot be represented. 4. Tables with special |metatable| properties cannot be represented. 5. Options accepting functions as values will automatically have Vim functions created that bridge the function calls to and from Lua code. *g:airline#extensions#ale#enabled* g:airline#extensions#ale#enabled Type: |Number| Default: `1` Enables or disables the |airline|'s native extension for ale, which displays warnings and errors in the status line, prefixed by |airline#extensions#ale#error_symbol| and |airline#extensions#ale#warning_symbol|. *ale-options.cache_executable_check_failures* *g:ale_cache_executable_check_failures* cache_executable_check_failures g:ale_cache_executable_check_failures Type: |Boolean| or |Number| Default: `nil` When set to `true` or `1`, ALE will cache failing executable checks for linters. By default, only executable checks which succeed will be cached. When this option is set to `true` or `1`, Vim will have to be restarted after new executables are installed for ALE to be able to run linters for those executables. *ale-options.change_sign_column_color* *g:ale_change_sign_column_color* change_sign_column_color g:ale_change_sign_column_color Type: |Boolean| or |Number| Default: `false` When set to `true` or `1`, this option will set different highlights for the sign column itself when ALE reports problems with a file. This option can be combined with |g:ale_sign_column_always|. ALE uses the following highlight groups for highlighting the sign column: `:ALESignColumnWithErrors` - Links to `Error` by default. `:ALESignColumnWithoutErrors` - Uses the value for `SignColumn` by default. The sign column color can only be changed globally in Vim. The sign column might produce unexpected results if editing different files in split windows. *ale-options.close_preview_on_insert* *g:ale_close_preview_on_insert* close_preview_on_insert g:ale_close_preview_on_insert Type: |Boolean| or |Number| Default: `false` When this option is set to `true` or `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 `true` or `1` before ALE is loaded for this behavior to be enabled. See |ale-lint-settings-on-startup|. *ale-options.command_wrapper* *g:ale_command_wrapper* *b:ale_command_wrapper* command_wrapper g:ale_command_wrapper Type: |String| Default: `''` An option for wrapping all commands that ALE runs, for linters, fixers, and LSP commands. This option can be set globally, or for specific buffers. This option can be used to apply nice to all commands. For example: > " Prefix all commands with nice. let g:ale_command_wrapper = 'nice -n5' < Use the `:ALEInfo` command to view the commands that are run. All of the arguments for commands will be put on the end of the wrapped command by default. A `%*` marker can be used to spread the arguments in the wrapped command. > " Has the same effect as the above. let g:ale_command_wrapper = 'nice -n5 %*' < For passing all of the arguments for a command as one argument to a wrapper, `%@` can be used instead. > " Will result in say: /bin/bash -c 'other-wrapper -c "some command" -x' let g:ale_command_wrapper = 'other-wrapper -c %@ -x' < For commands including `&&` or `;`, only the last command in the list will be passed to the wrapper. `&&` is most commonly used in ALE to change the working directory before running a command. *ale-options.completion_delay* *g:ale_completion_delay* completion_delay g:ale_completion_delay Type: |Number| Default: `100` The number of milliseconds before ALE will send a request to a language server for completions after you have finished typing. See |ale-completion| *ale-options.completion_enabled* *g:ale_completion_enabled* *b:ale_completion_enabled* completion_enabled g:ale_completion_enabled Type: |Boolean| or |Number| Default: `false` When this option is set to `true` or `1`, completion support will be enabled. This setting must be set to `true` or `1` before ALE is loaded for this behavior to be enabled. This setting should not be enabled if you wish to use ALE as a completion source for other completion plugins. ALE automatic completion will not work when 'paste' is active. Only set 'paste' when you are copy and pasting text into your buffers. A buffer-local version of this setting `b:ale_completion_enabled` can be set to `0` to disable ALE's automatic completion support for a single buffer. ALE's completion support must be enabled globally to be enabled locally. See |ale-completion| *ale-options.completion_tsserver_remove_warnings* *g:ale_completion_tsserver_remove_warnings* completion_tsserver_remove_warnings g:ale_completion_tsserver_remove_warnings Type: |Boolean| or |Number| Default: `false` When this option is set to `false` or `0`, ALE will return all completion items from its built in completion engine, including those that are a warning. Warnings can be excluded from completed items by setting it to `true` or `1`. *ale-options.completion_autoimport* *g:ale_completion_autoimport* completion_autoimport g:ale_completion_autoimport Type: |Boolean| or |Number| Default: `true` When this option is set to `1`, ALE will try to automatically import completion results from external modules. It can be disabled by setting it to `0`. Some LSP servers include auto imports on every completion item so disabling automatic imports may drop some or all completion items returned by it (e.g. eclipselsp). *ale-options.completion_excluded_words* *g:ale_completion_excluded_words* *b:ale_completion_excluded_words* completion_excluded_words g:ale_completion_excluded_words Type: |List| Default: `[]` This option can be set to a list of |String| values for "words" to exclude from completion results, as in the words for |complete-items|. The strings will be matched exactly in a case-sensitive manner. (|==#|) This setting can be configured in ftplugin files with buffer variables, so that different lists can be used for different filetypes. For example: > " In ~/.vim/ftplugin/typescript.vim " Don't suggest `it` or `describe` so we can use snippets for those words. let b:ale_completion_excluded_words = ['it', 'describe'] < *ale-options.completion_symbols* *g:ale_completion_symbols* completion_symbols g:ale_completion_symbols Type: |Dictionary| Default: See `autoload/ale/completion.vim` A mapping from completion types to symbols for completions. See |ale-symbols| for more information. By default, this mapping only uses built in Vim completion kinds, but it can be updated to use any Unicode character for the completion kind. For example: > let g:ale_completion_symbols = { \ 'text': '', \ 'method': '', \ 'function': '', \ 'constructor': '', \ 'field': '', \ 'variable': '', \ 'class': '', \ 'interface': '', \ 'module': '', \ 'property': '', \ 'unit': 'v', \ 'value': 'v', \ 'enum': 't', \ 'keyword': 'v', \ 'snippet': 'v', \ 'color': 'v', \ 'file': 'v', \ 'reference': 'v', \ 'folder': 'v', \ 'enum_member': 'm', \ 'constant': 'm', \ 'struct': 't', \ 'event': 'v', \ 'operator': 'f', \ 'type_parameter': 'p', \ '': 'v' \ }) < *ale-options.completion_max_suggestions* *g:ale_completion_max_suggestions* completion_max_suggestions g:ale_completion_max_suggestions Type: |Number| Default: `50` The maximum number of items ALE will suggest in completion menus for automatic completion. Setting this number higher will require more processing time, and may suggest too much noise. Setting this number lower will require less processing time, but some suggestions will not be included, so you might not be able to see the suggestions you want. Adjust this option as needed, depending on the complexity of your codebase and your available processing power. *ale-options.cursor_detail* *g:ale_cursor_detail* cursor_detail g:ale_cursor_detail Type: |Number| Default: `false` When this option is set to `true` or `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 `true` or `1`. Either this setting or |g:ale_echo_cursor| must be set to `true` or `1` before ALE is loaded for messages to be displayed. See |ale-lint-settings-on-startup|. *ale-options.default_navigation* *g:ale_default_navigation* *b:ale_default_navigation* default_navigation g:ale_default_navigation Type: |String| Default: `'buffer'` The default method for navigating away from the current buffer to another buffer, such as for `:ALEFindReferences` or `:ALEGoToDefinition`. *ale-options.detail_to_floating_preview* *g:ale_detail_to_floating_preview* *b:ale_detail_to_floating_preview* detail_to_floating_preview g:ale_detail_to_floating_preview Type: |Number| Default: `0` When this option is set to `1`, Neovim or Vim with |popupwin| will use a floating window for ALEDetail output. *ale-options.disable_lsp* *g:ale_disable_lsp* *b:ale_disable_lsp* disable_lsp g:ale_disable_lsp Type: |Boolean| OR |Number| OR |String| Default: `'auto'` When this option is set to `'auto'`, ALE will automatically disable linters that it detects as having already been configured with the `nvim-lspconfig` plugin. When this option is set to `true` or `1`, ALE ignores all linters powered by LSP, and also `tsserver`. Any linters that are disabled will also not be usable for LSP functionality other than just linting. Please see also |ale-lsp|. *ale-options.echo_cursor* *g:ale_echo_cursor* echo_cursor g:ale_echo_cursor Type: |Number| Default: `1` When this option is set to `1`, a truncated message will be echoed 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_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 `true` or `1` before ALE is loaded for messages to be displayed. See |ale-lint-settings-on-startup|. *ale-options.echo_delay* *g:ale_echo_delay* *b:ale_echo_delay* echo_delay g:ale_echo_delay Type: |Number| Default: `10` Given any integer, this option controls the number of milliseconds before 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. *ale-options.echo_msg_error_str* *g:ale_echo_msg_error_str* echo_msg_error_str g:ale_echo_msg_error_str Type: |String| Default: `'Error'` The string used for `%severity%` for errors. See |g:ale_echo_msg_format| *ale-options.echo_msg_format* *g:ale_echo_msg_format* *b:ale_echo_msg_format* echo_msg_format g:ale_echo_msg_format Type: |String| Default: `'%code: %%s'` This variable defines a message format for echoed messages. The following sequences of characters will be replaced. `%s` - replaced with the text for the problem `%...code...% `- replaced with the error code `%linter%` - replaced with the name of the linter `%severity%` - replaced with the severity of the problem (e.g. `Error`) `%type%` - replaced with the type of the problem (e.g. `E`) The strings for `%severity%` can be configured with the following options. |g:ale_echo_msg_error_str| - Defaults to `'Error'` |g:ale_echo_msg_info_str| - Defaults to `'Info'` |g:ale_echo_msg_warning_str| - Defaults to `'Warning'` `%code%` is replaced with the error code, and replaced with an empty string when there is no error code. Any extra characters between the percent signs will be printed when an error code is present. For example, a message like `(error code): message` will be printed for `'%(code): %%s'` and simply the message will be printed when there is no code. |g:ale_echo_cursor| needs to be set to 1 for messages to be displayed. The echo message format can also be configured separately for each buffer, so different formats can be used for different languages. (Say in ftplugin files.) *ale-options.echo_msg_info_str* *g:ale_echo_msg_info_str* echo_msg_info_str g:ale_echo_msg_info_str Type: |String| Default: `'Info'` The string used for `%severity%` for info. See |g:ale_echo_msg_format| *ale-options.echo_msg_log_str* *g:ale_echo_msg_log_str* echo_msg_log_str g:ale_echo_msg_log_str Type: |String| Default: `'Log'` The string used for `%severity%` for log, used only for handling LSP show message requests. See |g:ale_lsp_show_message_format| *ale-options.echo_msg_warning_str* *g:ale_echo_msg_warning_str* echo_msg_warning_str g:ale_echo_msg_warning_str Type: |String| Default: `'Warning'` The string used for `%severity%` for warnings. See |g:ale_echo_msg_format| *ale-options.enabled* *g:ale_enabled* *b:ale_enabled* enabled g:ale_enabled Type: |Number| Default: `1` When set to `0`, this option will completely disable ALE, such that no error checking will be performed, etc. ALE can be toggled on and off with the `:ALEToggle` command, which changes this option. ALE can be disabled in each buffer by setting `let b:ale_enabled = 0` Disabling ALE based on filename patterns can be accomplished by setting a regular expression for |g:ale_pattern_options|. For example: > " Disable linting for all minified JS files. let g:ale_pattern_options = {'\.min.js$': {'ale_enabled': 0}} < See |g:ale_pattern_options| for more information on that option. *ale-options.exclude_highlights* *g:ale_exclude_highlights* *b:ale_exclude_highlights* exclude_highlights g:ale_exclude_highlights Type: |List| Default: `[]` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. A list of regular expressions for matching against highlight messages to remove. For example: > " Do not highlight messages matching strings like these. let b:ale_exclude_highlights = ['line too long', 'foo.*bar'] < See also: |g:ale_set_highlights| *ale-options.fixers* *g:ale_fixers* *b:ale_fixers* fixers g:ale_fixers Type: |Dictionary| Default: `{}` A mapping from filetypes to |List| values for functions for fixing errors. See |ale-fix| for more information. This variable can be overridden with variables in each buffer. `b:ale_fixers` can be set to a |List| of callbacks instead, which can be more convenient. A special `'*'` key be used as a wildcard filetype for configuring fixers for every other type of file. For example: > " Fix Python files with 'bar'. " Don't fix 'html' files. " Fix everything else with 'foo'. let g:ale_fixers = {'python': ['bar'], 'html': [], '*': ['foo']} < *ale-options.fix_on_save* *g:ale_fix_on_save* *b:ale_fix_on_save* fix_on_save g:ale_fix_on_save Type: |Number| Default: `0` When set to 1, ALE will fix files when they are saved. If |g:ale_lint_on_save| is set to 1, files will be checked with linters 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`. Some fixers can be excluded from being run automatically when you save files with the |g:ale_fix_on_save_ignore| setting. *ale-options.fix_on_save_ignore* *g:ale_fix_on_save_ignore* *b:ale_fix_on_save_ignore* fix_on_save_ignore g:ale_fix_on_save_ignore Type: |Dictionary| or |List| Default: `{}` Given a |Dictionary| mapping filetypes to |Lists| of fixers to ignore, or just a |List| of fixers to ignore, exclude those fixers from being run automatically when files are saved. You can disable some fixers in your ftplugin file: > " Disable fixers 'b' and 'c' when fixing on safe for this buffer. let b:ale_fix_on_save_ignore = ['b', 'c'] " Alternatively, define ignore lists for different filetypes. let b:ale_fix_on_save_ignore = {'foo': ['b'], 'bar': ['c']} < You can disable some fixers globally per filetype like so: > let g:ale_fixers = {'foo': ['a', 'b'], 'bar': ['c', 'd']} let g:ale_fix_on_save = 1 " For filetype `foo.bar`, only fixers 'b' and 'd' will be run on save. let g:ale_fix_on_save_ignore = {'foo': ['a'], 'bar': ['c']} " Alternatively, disable these fixers on save for all filetypes. let g:ale_fix_on_save_ignore = ['a', 'c'] < You can ignore fixers based on matching |Funcref| values too: > let g:AddBar = {buffer, lines -> lines + ['bar']} let g:ale_fixers = {'foo': g:AddBar} " The lambda fixer will be ignored, as it will be found in the ignore list. let g:ale_fix_on_save_ignore = [g:AddBar] < *ale-options.floating_preview* *g:ale_floating_preview* floating_preview g:ale_floating_preview Type: |Number| Default: `0` When set to `1`, Neovim or Vim with |popupwin| will use a floating window for ale's preview window. This is equivalent to setting |g:ale_hover_to_floating_preview| and |g:ale_detail_to_floating_preview| to `1`. *ale-options.floating_preview_popup_opts* *g:ale_floating_preview_popup_opts* floating_preview_popup_opts g:ale_floating_preview_popup_opts Type: |String| or |Dictionary| Default: `''` Either a dictionary of options or the string name of a function that returns a dictionary of options. This will be used as an argument to |popup_create| for Vim users or |nvim_open_win| for NeoVim users. In either case, the resulting dictionary is merged with ALE defaults rather than explicitly overriding them. This only takes effect if |g:ale_floating_preview| is enabled. NOTE: for Vim users see |popup_create-arguments|, for NeoVim users see |nvim_open_win| for argument details For example, to enhance popups with a title: > function! CustomOpts() abort let [l:info, l:loc] = ale#util#FindItemAtCursor(bufnr('')) return {'title': ' ALE: ' . (l:loc.linter_name) . ' '} endfunction let g:ale_floating_preview_popup_opts = 'g:CustomOpts' < *ale-options.floating_window_border* *g:ale_floating_window_border* floating_window_border g:ale_floating_window_border Type: |List| Default: `['|', '-', '+', '+', '+', '+', '|', '-']` When set to `[]`, window borders are disabled. The elements in the list set the characters for the left side, top, top-left corner, top-right corner, bottom-right corner, bottom-left corner, right side, and bottom of the floating window, respectively. If the terminal supports Unicode, you might try setting the value to ` ['│', '─', '╭', '╮', '╯', '╰', '│', '─']`, to make it look nicer. NOTE: For compatibility with previous versions, if the list does not have elements for the right side and bottom, the left side and top will be used instead. *ale-options.history_enabled* *g:ale_history_enabled* history_enabled g:ale_history_enabled Type: |Number| Default: `1` When set to `1`, ALE will remember the last few commands which were run for every buffer which is open. This information can be viewed with the `:ALEInfo` command. The size of the buffer can be controlled with the |g:ale_max_buffer_history_size| option. This option can be disabled if storing a command history is not desired. *ale-options.history_log_output* *g:ale_history_log_output* history_log_output g:ale_history_log_output Type: |Number| Default: `1` When set to `1`, ALE will store the output of commands which have completed successfully in the command history, and the output will be displayed when using `:ALEInfo`. |g:ale_history_enabled| must be set to `1` for this output to be stored or printed. Some memory will be consumed by this option. It is very useful for figuring out what went wrong with linters, and for bug reports. Turn this option off if you want to save on some memory usage. *ale-options.hover_cursor* *g:ale_hover_cursor* hover_cursor g:ale_hover_cursor Type: |Number| Default: `1` If set to `1`, ALE will show truncated information in the echo line about the symbol at the cursor automatically when the |CursorHold| event is fired. The delay before requesting hover information is based on 'updatetime', as with all |CursorHold| events. If there's a problem on the line where the cursor is resting, ALE will not show any hover information. See |ale-hover| for more information on hover information. This setting must be set to `1` before ALE is loaded for this behavior to be enabled. See |ale-lint-settings-on-startup|. *ale-options.hover_to_preview* *g:ale_hover_to_preview* *b:ale_hover_to_preview* hover_to_preview g:ale_hover_to_preview Type: |Number| Default: `0` If set to `1`, hover messages will be displayed in the preview window, instead of in balloons or the message line. *ale-options.hover_to_floating_preview* *g:ale_hover_to_floating_preview* *b:ale_hover_to_floating_preview* hover_to_floating_preview g:ale_hover_to_floating_preview Type: |Number| Default: `0` If set to `1`, Neovim or Vim with |popupwin| will use floating windows for hover messages. *ale-options.info_default_mode* *g:ale_info_default_mode* *b:ale_info_default_mode* info_default_mode g:ale_info_default_mode Type: |String| Default: `'preview'` Changes the default mode used for `:ALEInfo`. See documentation for `:ALEInfo` for more information. *ale-options.keep_list_window_open* *g:ale_keep_list_window_open* *b:ale_keep_list_window_open* keep_list_window_open g:ale_keep_list_window_open Type: |Number| Default: `0` When set to `1`, this option will keep the loclist or quickfix windows event after all warnings/errors have been removed for files. By default the loclist or quickfix windows will be closed automatically when there are no warnings or errors. See |g:ale_open_list| *ale-options.list_window_size* *g:ale_list_window_size* *b:ale_list_window_size* list_window_size g:ale_list_window_size Type: |Number| Default: `10` This number configures the number of lines to set for the height of windows opened automatically for ALE problems. The default of `10` matches the Vim default height. See |g:ale_open_list| for information on automatically opening windows for quickfix or the loclist. *ale-options.lint_delay* *g:ale_lint_delay* *b:ale_lint_delay* lint_delay g:ale_lint_delay Type: |Number| Default: `200` This variable controls the milliseconds delay after which the linters will be run after text is changed. This option is only meaningful with the |g:ale_lint_on_text_changed| variable set to `always`, `insert`, or `normal`. A buffer-local option, `b:ale_lint_delay`, can be set to change the delay for different buffers, such as in |ftplugin| files. *ale-options.ale_lint_diff* *g:ale_lint_diff* g:ale_lint_diff Type: |Number| Default: `0` When this option is set to `1`, ALE will lint buffers where `&diff` is set. *ale-options.lint_on_enter* *g:ale_lint_on_enter* lint_on_enter g:ale_lint_on_enter Type: |Number| Default: `1` When this option is set to `1`, the |BufWinEnter| event will be used to apply linters when buffers are first opened. If this is not desired, this variable can be set to `0` in your vimrc file to disable this behavior. The |FileChangedShellPost| and |BufEnter| events will be used to check if files have been changed outside of Vim. If a file is changed outside of Vim, it will be checked when it is next opened. 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|. *ale-options.lint_on_filetype_changed* *g:ale_lint_on_filetype_changed* lint_on_filetype_changed g:ale_lint_on_filetype_changed Type: |Number| Default: `1` This option will cause ALE to run when the filetype for a file is changed after a buffer has first been loaded. A short delay will be used before linting will be done, so the filetype can be changed quickly several times in a row, but resulting in only one lint cycle. 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|. *ale-options.lint_on_save* *g:ale_lint_on_save* lint_on_save g:ale_lint_on_save Type: |Number| Default: `1` This option will make ALE run the linters whenever a file is saved when it it set to `1` in your vimrc file. This option can be used in combination with the |g:ale_lint_on_enter| and |g:ale_lint_on_text_changed| options to make ALE only check files after that have been saved, if that is what is desired. *ale-options.lint_on_text_changed* *g:ale_lint_on_text_changed* lint_on_text_changed g:ale_lint_on_text_changed Type: |Boolean| or |Number| or |String| Default: `'normal'` This option controls how ALE will check your files as you make changes. The following values can be used. `'always'`, `'1'`, `true`, or `1` - Check buffers on |TextChanged| or |TextChangedI|. `'normal'` - Check buffers only on |TextChanged|. `'insert'` - Check buffers only on |TextChangedI|. `'never'`, `'0'`, `false`, or `0` - Never check buffers on changes. 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|. *ale-options.lint_on_insert_leave* *g:ale_lint_on_insert_leave* *b:ale_lint_on_insert_leave* lint_on_insert_leave g:ale_lint_on_insert_leave Type: |Boolean| or |Number| Default: `true` When set to `1` in your vimrc file, this option will cause ALE to run linters when you leave insert mode. 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 mapping. > " Make using Ctrl+C do the same as Escape, to trigger autocmd commands inoremap < A buffer-local version of this setting `b:ale_lint_on_insert_leave` can be set to `0` to disable linting when leaving insert mode. The setting must be enabled globally to be enabled locally. 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|. *ale-options.linter_aliases* *g:ale_linter_aliases* *b:ale_linter_aliases* linter_aliases g:ale_linter_aliases Type: |Dictionary| or |List| or |String| Default: `{}` The |g:ale_linter_aliases| option can be used to set aliases from one filetype to another. A given filetype can be mapped to use the linters run for another given filetype. This |Dictionary| will be merged with a default dictionary containing the following values: > { \ 'Dockerfile': 'dockerfile', \ 'bash': 'sh', \ 'csh': 'sh', \ 'javascriptreact': ['javascript', 'jsx'], \ 'plaintex': 'tex', \ 'ps1': 'powershell', \ 'rmarkdown': 'r', \ 'rmd': 'r', \ 'systemverilog': 'verilog', \ 'typescriptreact': ['typescript', 'tsx'], \ 'vader': ['vim', 'vader'], \ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'], \ 'vimwiki': 'markdown', \ 'vue': ['vue', 'javascript'], \ 'xsd': ['xsd', 'xml'], \ 'xslt': ['xslt', 'xml'], \ 'zsh': 'sh', \} < For example, if you wish to map a new filetype `'foobar'` to run the `'php'` linters, you could set the following: > let g:ale_linter_aliases = {'foobar': 'php'} < Or in Lua: > require("ale").setup({linter_aliases = {foobar = "php"}}) < When combined with the |g:ale_linters| option, the original filetype (`'foobar'`) will be used for determining which linters to run, not the aliased type (`'php'`). This allows an aliased type to run a different set of linters from the type it is being mapped to. Passing a list of filetypes is also supported. Say you want to lint javascript and css embedded in HTML (using linters that support that). You could alias `html` like so: > `let g:ale_linter_aliases = {'html': ['html', 'javascript', 'css']}` < Or in Lua: > require("ale").setup({linter_aliases = {html = {"html", "javascript", "css"}}) < Note that `html` itself was included as an alias. That is because aliases will override the original linters for the aliased filetype. Linter aliases can be configured in each buffer with buffer-local variables. 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| 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' < Or in Lua: > require("ale").setup.buffer({linter_aliases = {"html", "javascript", "css"}}) -- OR, Alias a filetype to only a single filetype with a String. require("ale").setup.buffer({linter_aliases = "javascript"}) < No linters will be loaded when the buffer's filetype is empty. *ale-options.filename_mappings* *g:ale_filename_mappings* *b:ale_filename_mappings* filename_mappings g:ale_filename_mappings Type: |Dictionary| or |List| Default: `{}` Either a |Dictionary| mapping a linter or fixer name, as displayed in `:ALEInfo`, to a |List| of two-item |List|s for filename mappings, or just a |List| of two-item |List|s. When given some paths to files, the value of this setting will be used to convert filenames on a local file system to filenames on some remote file system, such as paths in a Docker image, virtual machine, or network drive. For example: > let g:ale_filename_mappings = { \ 'pylint': [ \ ['/home/john/proj', '/data'], \ ], \} < Or in Lua: > require("ale").setup({ filename_mappings = { pylint = { {"/home/john/proj", "/data"}, }, }, }) < With the above configuration, a filename such as `/home/john/proj/foo.py` will be provided to the linter/fixer as `/data/foo.py`, and paths parsed from linter results such as `/data/foo.py` will be converted back to `/home/john/proj/foo.py`. You can use `*` as to apply a |List| of filename mappings to all other linters or fixers not otherwise matched. > " Use one List of paths for pylint. " Use another List of paths for everything else. let g:ale_filename_mappings = { \ 'pylint': [ \ ['/home/john/proj', '/data'], \ ], \ '*': [ \ ['/home/john/proj', '/other-data'], \ ], \} < If you just want every single linter or fixer to use the same filename mapping, you can just use a |List|. > " Same as above, but for ALL linters and fixers. let g:ale_filename_mappings = [ \ ['/home/john/proj', '/data'], \] < Or in Lua: > require("ale").setup({ filename_mappings = { {"/home/john/proj", "/data"}, }, }) < You can provide many such filename paths for multiple projects. Paths are matched by checking if the start of a file path matches the given strings, in a case-sensitive manner. Earlier entries in the |List| will be tried before later entries when mapping to a given file system. Buffer-local options can be set to the same values to override the global options, such as in |ftplugin| files. NOTE: Only fixers registered with a short name can support filename mapping by their fixer names. See |ale-fix|. Filename mappings set for all tools by using only a |List| for the setting will also be applied to fixers not in the registry. NOTE: In order for this filename mapping to work correctly, linters and fixers must exclusively determine paths to files to lint or fix via ALE command formatting as per |ale-command-format-strings|, and paths parsed from linter files must be provided in `filename` keys if a linter returns results for more than one file at a time, as per |ale-loclist-format|. If you discover a linter or fixer which does not behave properly, please report it as an issue. If you are running a linter or fixer through Docker or another remote file system, you may have to mount your temporary directory, which you can discover with the following command: > :echo fnamemodify(tempname(), ':h:h') < You should provide a mapping from this temporary directory to whatever you mount this directory to in Docker, or whatever remote file system you are working with. You can inspect the filename mappings ALE will use with the |ale#GetFilenameMappings()| function. *ale-options.linters* *g:ale_linters* *b:ale_linters* linters g:ale_linters Type: |Dictionary| or |List| Default: `{}` The |g:ale_linters| option sets a |Dictionary| mapping a filetype to a |List| of linter programs to be run when checking particular filetypes. This |Dictionary| will be merged with a default dictionary containing the following values: > { \ 'apkbuild': ['apkbuild_lint', 'secfixes_check'], \ 'csh': ['shell'], \ 'elixir': ['credo', 'dialyxir', 'dogma'], \ 'go': ['gofmt', 'golangci-lint', 'gopls', 'govet'], \ 'groovy': ['npm-groovy-lint'], \ 'hack': ['hack'], \ 'help': [], \ 'inko': ['inko'], \ 'json': ['jsonlint', 'spectral'], \ 'json': ['jsonlint', 'spectral', 'vscodejson'], \ 'json5': [], \ 'jsonc': [], \ 'perl': ['perlcritic'], \ 'perl6': [], \ 'python': ['flake8', 'mypy', 'pylint', 'pyright', 'ruff'], \ 'rust': ['analyzer', 'cargo'], \ 'spec': [], \ 'text': [], \ 'vader': ['vimls'], \ 'vue': ['eslint', 'vls'], \ 'zsh': ['shell'], \ 'v': ['v'], \ 'yaml': ['actionlint', 'spectral', 'yaml-language-server', 'yamllint'], \} < This option can be used to enable only a particular set of linters for a file. For example, you can enable only `eslint` for JavaScript files: > let g:ale_linters = {'javascript': ['eslint']} < Or in Lua: > require("ale").setup({linters = {javascript = {"eslint"}}}) < If you want to disable all linters for a particular filetype, you can pass an empty list of linters as the value: > let g:ale_linters = {'javascript': []} < Or in Lua: > require("ale").setup({linters = {javascript = {}}}) < All linters will be run for unspecified filetypes. All available linters can be enabled explicitly for a given filetype by passing the string `'all'`, instead of a List. > let g:ale_linters = {'c': 'all'} < Or in Lua: > require("ale").setup({linters = {c = "all"}}) < Linters can be configured in each buffer with buffer-local variables. ALE will first look for linters for filetypes in the `b:ale_linters` variable, then `g:ale_linters`, and then the default Dictionary mentioned above. `b:ale_linters` can be set to a List, or the string `'all'`. When linters for two different filetypes share the same name, the first linter loaded will be used. Any ambiguity can be resolved by using a Dictionary specifying which linter to run for which filetype instead. > " Use ESLint for the buffer if the filetype includes 'javascript'. let b:ale_linters = {'javascript': ['eslint'], 'html': ['tidy']} " Use a List for the same setting. This will work in most cases. let b:ale_linters = ['eslint', 'tidy'] " Disable all linters for the buffer. let b:ale_linters = [] " Explicitly enable all available linters for the filetype. let b:ale_linters = 'all' < In Lua: > require("ale").setup.buffer({ linters = {javascript = {"eslint"}, html = {"tidy"}}, }) require("ale").setup.buffer({linters = {"eslint", "tidy"}}) require("ale").setup.buffer({linters = {}}) require("ale").setup.buffer({linters = "all"}) < ALE can be configured to disable all linters unless otherwise specified with `g:ale_enabled` or `b:ale_enabled` with the option |g:ale_linters_explicit|. *ale-options.linters_explicit* *g:ale_linters_explicit* linters_explicit g:ale_linters_explicit Type: |Boolean| or |Number| Default: `false` When set to `true` or `1`, only the linters from |g:ale_linters| and |b:ale_linters| will be enabled. The default behavior for ALE is to enable as many linters as possible, unless otherwise specified. *ale-options.linters_ignore* *g:ale_linters_ignore* *b:ale_linters_ignore* linters_ignore g:ale_linters_ignore Type: |Dictionary| or |List| Default: `{}` Linters to ignore. Commands for ignored linters will not be run, and diagnostics for LSP linters will be ignored. (See |ale-lsp|) This setting can be set to a |Dictionary| mapping filetypes to linter names, just like |g:ale_linters|, to list linters to ignore. Ignore lists will be applied after everything else. > " Select flake8 and pylint, and ignore pylint, so only flake8 is run. let g:ale_linters = {'python': ['flake8', 'pylint']} let g:ale_linters_ignore = {'python': ['pylint']} < Or in Lua: > require("ale").setup({ linters = {"python": {"flake8", "pylint"}}, linters_ignore = {"python": {"pylint"}}, }) < This setting can be set to simply a |List| of linter names, which is especially more convenient when using the setting in ftplugin files for particular buffers. > " The same as above, in a ftplugin/python.vim. let b:ale_linters = ['flake8', 'pylint'] let b:ale_linters_ignore = ['pylint'] < Or in Lua: > require("ale").setup.buffer({ linters = {"flake8", "pylint"}, linters_ignore = {"pylint"}, }) < *ale-options.list_vertical* *g:ale_list_vertical* *b:ale_list_vertical* list_vertical g:ale_list_vertical Type: |Boolean| or |Number| Default: `false` When set to `true` or `1`, this will cause ALE to open any windows (loclist or quickfix) vertically instead of horizontally (|vert| |lopen|) or (|vert| |copen|) *ale-options.loclist_msg_format* *g:ale_loclist_msg_format* *b:ale_loclist_msg_format* loclist_msg_format g:ale_loclist_msg_format Type: |String| Default: `g:ale_echo_msg_format` (`echo_msg_format`) This option is the same as |g:ale_echo_msg_format|, but for formatting the message used for the loclist and the quickfix list. The strings for configuring `%severity%` are also used for this option. *ale-options.lsp_show_message_format* *g:ale_lsp_show_message_format* lsp_show_message_format g:ale_lsp_show_message_format Type: |String| Default: `'%severity%:%linter%: %s'` This variable defines the format that messages received from an LSP will have when echoed. The following sequences of characters will be replaced. `%s` - replaced with the message text `%linter%` - replaced with the name of the linter `%severity%` - replaced with the severity of the message The strings for `%severity%` levels "error", "info" and "warning" are shared with |g:ale_echo_msg_format|. Severity "log" is unique to |g:ale_lsp_show_message_format| and it can be configured via |g:ale_echo_msg_log_str| - Defaults to `'Log'` Please note that |g:ale_lsp_show_message_format| *can not* be configured separately for each buffer like |g:ale_echo_msg_format| can. *ale-options.lsp_show_message_severity* *g:ale_lsp_show_message_severity* lsp_show_message_severity g:ale_lsp_show_message_severity Type: |String| Default: `'error'` This variable defines the minimum severity level an LSP message needs to be displayed. Messages below this level are discarded; please note that messages with `Log` severity level are always discarded. Possible values follow the LSP spec `MessageType` definition: `'error'` - Displays only errors. `'warning'` - Displays errors and warnings. `'information'` - Displays errors, warnings and infos `'log'` - Same as `'information'` `'disabled'` - Doesn't display any information at all. *ale-options.lsp_suggestions* *g:ale_lsp_suggestions* lsp_suggestions g:ale_lsp_suggestions Type: |Boolean| or |Number| Default: `false` If set to `true` or ``1`, show suggestions from LSP servers or tsserver, in addition to warnings and errors. *ale-options.max_buffer_history_size* *g:ale_max_buffer_history_size* max_buffer_history_size g:ale_max_buffer_history_size Type: |Number| Default: `20` This setting controls the maximum number of commands which will be stored in the command history used for `:ALEInfo`. Command history will be rotated in a FIFO manner. If set to a number <= 0, then the history will be continuously set to an empty |List|. History can be disabled completely with |g:ale_history_enabled|. *ale-options.max_signs* *g:ale_max_signs* *b:ale_max_signs* max_signs g:ale_max_signs Type: |Number| Default: `-1` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. When set to any positive integer, ALE will not render any more than the given number of signs for any one buffer. When set to `0`, no signs will be set, but sign processing will still be done, so existing signs can be removed. When set to any other value, no limit will be imposed on the number of signs set. For disabling sign processing, see |g:ale_set_signs|. *ale-options.maximum_file_size* *g:ale_maximum_file_size* *b:ale_maximum_file_size* maximum_file_size g:ale_maximum_file_size Type: |Number| Default: `nil` A maximum file size in bytes for ALE to check. If set to any positive number, ALE will skip checking files larger than the given size. *ale-options.open_list* *g:ale_open_list* *b:ale_open_list* open_list g:ale_open_list Type: |Boolean| |Number| or |String| Default: `false` When set to `true` or `1`, this will cause ALE to automatically open a window for the loclist (|lopen|) or for the quickfix list instead if |g:ale_set_quickfix| is `true` or `1`. (|copen|) When set to any higher numerical value, ALE will only open the window when the number of warnings or errors are at least that many. When set to `'on_save'`, ALE will only open the loclist after buffers have been saved. The list will be opened some time after buffers are saved and any linter for a buffer returns results. The window will be kept open until all warnings or errors are cleared, including those not set by ALE, unless |g:ale_keep_list_window_open| is set to `true` or `1`, in which case the window will be kept open when no problems are found. The window size can be configured with |g:ale_list_window_size|. Windows can be opened vertically with |g:ale_list_vertical|. If you want to close the loclist window automatically when the buffer is closed, you can set up the following |autocmd| command: > augroup CloseLoclistWindowGroup autocmd! autocmd QuitPre * if empty(&buftype) | lclose | endif augroup END < *g:ale_pattern_options* g:ale_pattern_options Type: |Dictionary| Default: `nil` NOTE: This option is not available through |ale.setup| in Lua as the options named here would require separate translation to the equivalent Vim options. You should instead use conditions in ftplugin files to configure options based on filename patterns. This option maps regular expression patterns to |Dictionary| values for buffer variables. This option can be set to automatically configure different settings for different files. For example: > " Use just ESLint for linting and fixing files which end in '.foo.js' let g:ale_pattern_options = { \ '\.foo\.js$': { \ 'ale_linters': ['eslint'], \ 'ale_fixers': ['eslint'], \ }, \} < See |b:ale_linters| and |b:ale_fixers| for information for those options. Filenames are matched with |match()|, and patterns depend on the |magic| setting, unless prefixed with the special escape sequences like `'\v'`, etc. The patterns can match any part of a filename. The absolute path of the filename will be used for matching, taken from `expand('%:p')`. The options for every match for the filename will be applied, with the pattern keys sorted in alphabetical order. Options for `'zebra'` will override the options for `'alpha'` for a filename `alpha-zebra`. *ale-options.pattern_options_enabled* *g:ale_pattern_options_enabled* pattern_options_enabled g:ale_pattern_options_enabled Type: |Boolean| or |Number| Default: `nil` This option can be used for disabling pattern options. If set to `0`, ALE will not set buffer variables per |g:ale_pattern_options|. *ale-options.popup_menu_enabled* *g:ale_popup_menu_enabled* popup_menu_enabled g:ale_popup_menu_enabled Type: |Boolean| or |Number| Default: `has('gui_running')` When this option is set to `true` or `1`, ALE will show code actions and rename capabilities in the right click mouse menu when there's a LSP server or tsserver available. See |ale-refactor|. This feature is only supported in GUI versions of Vim. This setting must be set to `true` or `1` before ALE is loaded for this behavior to be enabled. See |ale-lint-settings-on-startup|. *ale-options.references_show_contents* *g:ale_references_show_contents* references_show_contents g:ale_references_show_contents Type: |Boolean| or |Number| Default: true If set to `true` or `1`, matches found by `:ALEFindReferences` will be shown with a preview of the matching line. *ale-options.references_use_fzf* *g:ale_references_use_fzf* references_use_fzf g:ale_references_use_fzf Type: |Boolean| or |Number| Default: `false` If set to `true` or `1`, matches found by `:ALEFindReferences` will be always shown using |fzf-vim| (https://github.com/junegunn/fzf.vim). *ale-options.rename_tsserver_find_in_comments* *g:ale_rename_tsserver_find_in_comments* rename_tsserver_find_in_comments g:ale_rename_tsserver_find_in_comments Type: |Boolean| or |Number| Default: `false` If set to `true` or `1`, this option will tell tsserver to find and replace text in comments when calling `:ALERename`. *ale-options.rename_tsserver_find_in_strings* *g:ale_rename_tsserver_find_in_strings* rename_tsserver_find_in_strings g:ale_rename_tsserver_find_in_strings Type: |Boolean| or |Number| Default: `false` If set to `true` or `1`, this option will tell tsserver to find and replace text in strings when calling `:ALERename`. *ale-options.root* *g:ale_root* *b:ale_root* root g:ale_root Type: |Dictionary| or |String| Default: `{}` This option is used to determine the project root for a linter. If the value is a |Dictionary|, it maps a linter to either a |String| containing the project root or a |Funcref| to call to look up the root. The |Funcref| is provided the buffer number as its argument. The buffer-specific variable may additionally be a string containing the project root itself. If neither variable yields a result, a linter-specific function is invoked to detect a project root. If this, too, yields no result, and the linter is an LSP linter, it will not run. *ale-options.save_hidden* *g:ale_save_hidden* save_hidden g:ale_save_hidden Type: |Boolean| or |Number| Default: `false` When set to `true` or `1`, save buffers when 'hidden' is set when applying code actions or rename operations, such as through `:ALERename` or `:ALEOrganizeImports`. *ale-options.set_balloons* *g:ale_set_balloons* *b:ale_set_balloons* set_balloons g:ale_set_balloons Type: |Boolean| or |Number| or |String| Default: `has('balloon_eval') && has('gui_running')` When this option is set to `true` or `1`, balloon messages will be displayed for problems or hover information if available. Problems nearest to the line the mouse cursor is over will be displayed. If there are no problems to show, and one of the linters is an LSP linter supporting "Hover" information, per |ale-hover|, then brief information about the symbol under the cursor will be displayed in a balloon. This option can be set to `'hover'` to only enable balloons for hover message, so diagnostics are never shown in balloons. You may wish to configure use this setting only in GUI Vim like so: > let g:ale_set_balloons = has('gui_running') ? 'hover' : 0 < Balloons can be enabled for terminal versions of Vim that support balloons, but some versions of Vim will produce strange mouse behavior when balloons are enabled. To configure balloons for your terminal, you should first configure your |ttymouse| setting, and then consider setting `g:ale_set_balloons` to `1` before ALE is loaded. `b:ale_set_balloons` can be set to `0` to disable balloons for a buffer. Balloons cannot be enabled for a specific buffer when not initially enabled globally. Balloons will not be shown when |g:ale_enabled| or |b:ale_enabled| is not `true` or `1`. *ale-options.set_balloons_legacy_echo* *g:ale_set_balloons_legacy_echo* *b:ale_set_balloons_legacy_echo* set_balloons_legacy_echo g:ale_set_balloons_legacy_echo Type: |Boolean| or |Number| Default: `nil` If set to `true` or `1`, moving your mouse over documents in Vim will make ALE ask `tsserver` or `LSP` servers for information about the symbol where the mouse cursor is, and print that information into Vim's echo line. This is an option for supporting older versions of Vim which do not properly support balloons in an asynchronous manner. If your version of Vim supports the |balloon_show| function, then this option does nothing meaningful. *ale-options.set_highlights* *g:ale_set_highlights* set_highlights g:ale_set_highlights Type: |Boolean| or |Number| Default: `has('syntax')` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. ALE's highlight groups will not be used when setting highlights through Neovim's diagnostics API. See |diagnostic-highlights| for how to configure Neovim diagnostic highlighting. When this option is set to `true` or `1`, highlights will be presented. ALE will use the following highlight groups for problems: ALEError items with `'type': 'E'` |hl-ALEError| ALEWarning items with `'type': 'W'` |hl-ALEWarning| ALEInfo items with `'type': 'I'` |hl-ALEInfo| ALEStyleError items with `'type': 'E'` and `'sub_type': 'style'` |hl-ALEStyleError| ALEStyleWarning items with `'type': 'W'` and `'sub_type': 'style'` |hl-ALEStyleWarning| When |g:ale_set_signs| is not set to `true` or `1`, the following highlights for entire lines will be set. ALEErrorLine all items with `'type': 'E'` |hl-ALEErrorLine| ALEWarningLine all items with `'type': 'W'` |hl-ALEWarningLine| ALEInfoLine all items with `'type': 'I'` |hl-ALEInfoLine| Vim can only highlight the characters up to the last column in a buffer for match highlights, whereas the line highlights when signs are enabled will run to the edge of the screen. Highlights can be excluded with the |g:ale_exclude_highlights| option. *ale-options.set_loclist* *g:ale_set_loclist* set_loclist g:ale_set_loclist Type: |Boolean| or |Number| Default: `true` When this option is set to `true` or `1`, the |location-list| will be populated with any warnings and errors which are found by ALE. This feature can be used to implement jumping between errors through typical use of `:lnext` and `:lprev`. *ale-options.set_quickfix* *g:ale_set_quickfix* set_quickfix g:ale_set_quickfix Type: |Boolean| or |Number| Default: `false` When this option is set to `true` or `1`, the |quickfix| list will be populated with any problems which are found by ALE, instead of the |location-list|. The loclist will never be populated when this option is enabled. Problems from every buffer ALE has checked will be included in the quickfix list, which can be checked with `:copen`. Problems will be de-duplicated. This feature should not be used in combination with tools for searching for matches and commands like `:cfdo`, as ALE will replace the quickfix list pretty frequently. If you wish to use such tools, you should populate the loclist or use `:ALEPopulateQuickfix` instead. *ale-options.set_signs* *g:ale_set_signs* set_signs g:ale_set_signs Type: |Boolean| or |Number| Default: `has('signs')` When this option is set to `true` or `1`, the |sign| column will be populated with signs marking where problems appear in the file. When |g:ale_use_neovim_diagnostics_api| is `1`, the only other setting that will be respected for signs is |g:ale_sign_priority|. ALE's highlight groups will and other sign settings will not apply when setting signs through Neovim's diagnostics API. See |diagnostic-signs| for how to configure signs in Neovim. ALE will use the following highlight groups for problems: ALEErrorSign items with `'type': 'E'` |hl-ALEErrorSign| ALEWarningSign items with `'type': 'W'` |hl-ALEWarningSign| ALEInfoSign items with `'type': 'I'` |hl-ALEInfoSign| ALEStyleErrorSign items with `'type': 'E'` and `'sub_type': 'style'` |hl-ALEStyleErrorSign| ALEStyleWarningSign items with `'type': 'W'` and `'sub_type': 'style'` |hl-ALEStyleWarningSign| In addition to the style of the signs, the style of lines where signs appear can be configured with the following highlights: ALEErrorLine all items with `'type': 'E'` |hl-ALEErrorLine| ALEWarningLine all items with `'type': 'W'` |hl-ALEWarningLine| ALEInfoLine all items with `'type': 'I'` |hl-ALEInfoLine| With Neovim 0.3.2 or higher, ALE can use the `numhl` option to highlight the 'number' column. It uses the following highlight groups. ALEErrorSignLineNr items with `'type': 'E'` |hl-ALEErrorSignLineNr| ALEWarningSignLineNr items with `'type': 'W'` |hl-ALEWarningSignLineNr| ALEInfoSignLineNr items with `'type': 'I'` |hl-ALEInfoSignLineNr| ALEStyleErrorSignLineNr items with `'type': 'E'` and `'sub_type': 'style'` |hl-ALEStyleErrorSignLineNr| ALEStyleWarningSignLineNr items with `'type': 'W'` and `'sub_type': 'style'` |hl-ALEStyleWarningSignLineNr| To enable line number highlighting |g:ale_sign_highlight_linenrs| must be set to `true` or `1` before ALE is loaded. The markers for the highlights can be customized with the following options: |g:ale_sign_error| |g:ale_sign_warning| |g:ale_sign_info| |g:ale_sign_style_error| |g:ale_sign_style_warning| When multiple problems exist on the same line, the signs will take precedence in the order above, from highest to lowest. To limit the number of signs ALE will set, see |g:ale_max_signs|. *ale-options.sign_priority* *g:ale_sign_priority* sign_priority g:ale_sign_priority Type: |Number| Default: `30` From Neovim 0.4.0 and Vim 8.1, ALE can set sign priority to all signs. The larger this value is, the higher priority ALE signs have over other plugin signs. See |sign-priority| for further details on how priority works. *ale-options.shell* *g:ale_shell* *b:ale_shell* shell g:ale_shell Type: |String| Default: `nil` Override the shell used by ALE for executing commands. ALE uses 'shell' by default, but falls back in `/bin/sh` if the default shell looks like `fish` or `pwsh`, which are not compatible with all of the commands run by ALE. The shell specified with this option will be used even if it might not work in all cases. For Windows, ALE uses `cmd` when this option isn't set. Setting this option will apply shell escaping to the command string, even on Windows. NOTE: Consider setting |g:ale_shell_arguments| if this option is defined. *ale-options.shell_arguments* *g:ale_shell_arguments* *b:ale_shell_arguments* shell_arguments g:ale_shell_arguments Type: |String| Default: `nil` This option specifies the arguments to use for executing a command with a custom shell, per |g:ale_shell|. If this option is not set, 'shellcmdflag' will be used instead. *ale-options.sign_column_always* *g:ale_sign_column_always* sign_column_always g:ale_sign_column_always Type: |Boolean| or |Number| Default: `v:false` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. By default, the sign gutter will disappear when all warnings and errors have been fixed for a file. When this option is set to `1`, the sign column will remain open. This can be preferable if you don't want the text in your file to move around as you edit a file. *ale-options.sign_error* *g:ale_sign_error* sign_error g:ale_sign_error Type: |String| Default: `'E'` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. The sign for errors in the sign gutter. *ale-options.sign_info* *g:ale_sign_info* sign_info g:ale_sign_info Type: |String| Default: `'I'` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. The sign for "info" markers in the sign gutter. *ale-options.sign_style_error* *g:ale_sign_style_error* sign_style_error g:ale_sign_style_error Type: |String| Default: `g:ale_sign_error` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. The sign for style errors in the sign gutter. *ale-options.sign_style_warning* *g:ale_sign_style_warning* sign_style_warning g:ale_sign_style_warning Type: |String| Default: `g:ale_sign_warning` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. The sign for style warnings in the sign gutter. *ale-options.sign_offset* *g:ale_sign_offset* sign_offset g:ale_sign_offset Type: |Number| Default: `1000000` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. This variable controls offset from which numeric IDs will be generated for new signs. Signs cannot share the same ID values, so when two Vim plugins set signs at the same time, the IDs have to be configured such that they do not conflict with one another. If the IDs used by ALE are found to conflict with some other plugin, this offset value can be changed, and hopefully both plugins will work together. See |sign-place| for more information on how signs are set. *ale-options.sign_warning* *g:ale_sign_warning* sign_warning g:ale_sign_warning Type: |String| Default: `'W'` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. The sign for warnings in the sign gutter. *ale-options.sign_highlight_linenrs* *g:ale_sign_highlight_linenrs* sign_highlight_linenrs g:ale_sign_highlight_linenrs Type: |Boolean| or |Number| Default: `false` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. When set to `true` or `1`, this option enables highlighting problems on the 'number' column in Vim versions that support `numhl` highlights. This option must be configured before ALE is loaded. *ale-options.update_tagstack* *g:ale_update_tagstack* *b:ale_update_tagstack* update_tagstack g:ale_update_tagstack Type: |Boolean| or |Number| Default: `v:true` When set to `true` or `1`, ALE will update Vims |tagstack| automatically when jumping to a location through ALE's commands, so users can jump back to where they came from. *ale-options.type_map* *g:ale_type_map* *b:ale_type_map* type_map g:ale_type_map Type: |Dictionary| Default: `{}` This option can be set re-map problem types for linters. Each key in the |Dictionary| should be the name of a linter, and each value must be a |Dictionary| mapping problem types from one type to another. The following types are supported: `'E'` - `{'type': 'E'}` `'ES'` - `{'type': 'E', 'sub_type': 'style'}` `'W'` - `{'type': 'W'}` `'WS'` - `{'type': 'W', 'sub_type': 'style'}` `'I'` - `{'type': 'I'}` For example, if you want to turn flake8 errors into warnings, you can write the following: > let g:ale_type_map = {'flake8': {'ES': 'WS', 'E': 'W'}} < Or in Lua: > require("ale").setup(type_map = {flake8 = {ES = "WS", E = "W"}}) < If you wanted to turn style errors and warnings into regular errors and warnings, you can write the following: > let g:ale_type_map = {'flake8': {'ES': 'E', 'WS': 'W'}} < Or in Lua: > require("ale").setup(type_map = {flake8 = {ES = "E", WS = "W"}}) < Type maps can be set per-buffer with `b:ale_type_map`, or in Lua with |ale.setup.buffer|. *ale-options.use_global_executables* *g:ale_use_global_executables* use_global_executables g:ale_use_global_executables Type: |Number| Default: `nil` This option can be set to change the default for all `_use_global` options. This option must be set before ALE is loaded, preferably in a vimrc file. See |ale-integrations-local-executables| for more information on those options. *ale-options.use_neovim_diagnostics_api* *g:ale_use_neovim_diagnostics_api* use_neovim_diagnostics_api g:ale_use_neovim_diagnostics_api Type: |Boolean| or |Number| Default: `has('nvim-0.7')` If set to `true` or `1`, disable ALE's standard UI, and instead send all linter output to Neovim's diagnostics API. This allows you to collect problems using ALE and other plugins together all in one place. Many options for configuring how problems appear on the screen will not apply when the API is enabled. This option requires Neovim 0.7+, as that version introduces the diagnostics API. *ale-options.use_neovim_lsp_api* *g:ale_use_neovim_lsp_api* use_neovim_lsp_api g:ale_use_neovim_lsp_api Type: |Boolean| or |Number| Default: `has('nvim-0.8')` If set to `true` or `1`, ALE will use Neovim's native LSP client API for LSP functionality. This makes it possible to use Neovim's built in LSP commands and keybinds, and improves integration with other Neovim plugins that integrate with Neovim's LSP client. See |ale-lsp-neovim| for more information about ALE's integration with Neovim's LSP client. This option requires Neovim 0.8+. *ale-options.virtualtext_cursor* *g:ale_virtualtext_cursor* virtualtext_cursor g:ale_virtualtext_cursor Type: |Number| or |String| Default: `'all'` (if supported, otherwise `'disabled'`) This option controls how ALE will display problems using |virtual-text|. The following values can be used. `'all'`, `'2'`, or `2` - Show problems for all lines. `'current'`, `'1'`, or `1` - Show problems for the current line. `'disabled'`, `'0'`, or `0` - Do not show problems with virtual-text. When |g:ale_use_neovim_diagnostics_api| is `1`, `'current'` will behave the same as `'all'`. Messages are only displayed after a short delay. See |g:ale_virtualtext_delay|. Messages can be prefixed with a string if not using Neovim's diagnostics API. See |g:ale_virtualtext_prefix|. If and only if not displaying problems via Neovim's diagnostics API, highlights for configuring ALE's virtualtext messages can be configured with custom highlight groups: ALEVirtualTextError items with `'type': 'E'` |hl-ALEVirtualTextError| ALEVirtualTextWarning items with `'type': 'W'` |hl-ALEVirtualTextWarning| ALEVirtualTextInfo items with `'type': 'I'` |hl-ALEVirtualTextInfo| ALEVirtualTextStyleError items with `'type': 'E'` and `'sub_type': 'style'` |hl-ALEVirtualTextStyleError| ALEVirtualTextStyleWarning items with `'type': 'W'` and `'sub_type': 'style'` |hl-ALEVirtualTextStyleWarning| *ale-options.virtualtext_delay* *g:ale_virtualtext_delay* *b:ale_virtualtext_delay* virtualtext_delay g:ale_virtualtext_delay Type: |Number| Default: `10` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. 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. *ale-options.virtualtext_prefix* *g:ale_virtualtext_prefix* *b:ale_virtualtext_prefix* virtualtext_prefix g:ale_virtualtext_prefix Type: |String| Default: `'%comment% %type%: '` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. Prefix to be used with |g:ale_virtualtext_cursor|. This setting can be changed in each buffer with |b:ale_virtualtext_prefix||. All of the same format markers used for |g:ale_echo_msg_format| can be used for defining the prefix, including some additional sequences of characters. `%comment%` - replaced with comment characters in the current language ALE will read the comment characters from 'commentstring', reading only the part before `%s`, with whitespace trimmed. If comment syntax cannot be pulled from 'commentstring', ALE will default to `'#'`. *ale-options.virtualtext_column* *g:ale_virtualtext_column* *b:ale_virtualtext_column* *ale-options.virtualtext_maxcolumn* *g:ale_virtualtext_maxcolumn* *b:ale_virtualtext_maxcolumn* virtualtext_column virtualtext_maxcolumn g:ale_virtualtext_column g:ale_virtualtext_maxcolumn Type: |String| or |Number| Default: `0` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. Virtualtext column range, from `column` to `maxcolumn`. If a line is `column` or less characters long, the virtualtext message is shifted right to `column`. Where the line is greater than `column` characters long, but less than `maxcolumn`, the virtualtext message is placed at the end of the line. Where the line is greater than `maxcolumn` the virtualtext message is omitted. A |Number| greater than `0` is used as the fixed column position, however a |String| ending in `%` represents a percentage of the window width. When `column` is set to zero, column positioning is disabled, when `maxcolumn` is set to zero, no maximum line length is enforced. *ale-options.virtualtext_single* *g:ale_virtualtext_single* *b:ale_virtualtext_single* virtualtext_single g:ale_virtualtext_single Type: |Boolean| or |Number| Default: `true` This has no effect when |g:ale_use_neovim_diagnostics_api| is `true` or `1`. Enable or disable concatenation of multiple virtual text messages on a single line. By default, if a line has multiple errors or warnings, each will be appended in turn. With `single` set to a non-zero value, only the first problem on a line will be printed with virtual text. The most severe problem on a line will be printed. If two problems exist on a line of equal severity, the problem at the left-most position will be printed. *ale-options.virtualenv_dir_names* *g:ale_virtualenv_dir_names* *b:ale_virtualenv_dir_names* virtualenv_dir_names g:ale_virtualenv_dir_names Type: |List| Default: `['.venv', 'env', 've', 'venv', 'virtualenv', '.env']` A list of directory names to be used when searching upwards from Python files to discover virtualenv directories with. For directory named `'foo'`, ALE will search for `'foo/bin/activate'` (`foo\Scripts\activate\` on Windows) in all directories on and above the directory containing the Python file to find virtualenv paths. *ale-options.warn_about_trailing_blank_lines* *g:ale_warn_about_trailing_blank_lines* *b:ale_warn_about_trailing_blank_lines* warn_about_trailing_blank_lines g:ale_warn_about_trailing_blank_lines Type: |Number| Default: `1` When this option is set to `1`, warnings about trailing blank lines will be shown. This option behaves similarly to |g:ale_warn_about_trailing_whitespace|. *ale-options.warn_about_trailing_whitespace* *g:ale_warn_about_trailing_whitespace* *b:ale_warn_about_trailing_whitespace* warn_about_trailing_whitespace g:ale_warn_about_trailing_whitespace Type: |Number| Default: `1` When this option is set to `1`, warnings relating to trailing whitespace on lines will be shown. If warnings are too irritating while editing buffers, and you have configured Vim to automatically remove trailing whitespace, you can disable these warnings by setting this option to `0`. Not all linters may respect this option. If a linter does not, please file a bug report, and it may be possible to add such support. This option may be configured on a per buffer basis. *ale-options.windows_node_executable_path* *g:ale_windows_node_executable_path* *b:ale_windows_node_executable_path* windows_node_executable_path g:ale_windows_node_executable_path Type: |String| Default: `'node.exe'` This variable is used as the path to the executable to use for executing scripts with Node.js on Windows. For Windows, any file with a `.js` file extension needs to be executed with the node executable explicitly. Otherwise, Windows could try and open the scripts with other applications, like a text editor. Therefore, these scripts are executed with whatever executable is configured with this setting. ------------------------------------------------------------------------------- 6.1. Highlights *ale-highlights* ALEError *hl-ALEError* Default: `highlight link ALEError SpellBad` The highlight for highlighted errors. See |g:ale_set_highlights|. ALEErrorLine *hl-ALEErrorLine* Default: Undefined The highlight for an entire line where errors appear. Only the first line for a problem will be highlighted. See |g:ale_set_signs| and |g:ale_set_highlights|. ALEErrorSign *hl-ALEErrorSign* Default: `highlight link ALEErrorSign error` The highlight for error signs. See |g:ale_set_signs|. ALEErrorSignLineNr *hl-ALEErrorSignLineNr* Default: `highlight link ALEErrorSignLineNr CursorLineNr` The highlight for error signs. See |g:ale_set_signs|. NOTE: This highlight is only available on Neovim 0.3.2 or higher. ALEInfo *hl-ALEInfo* *ALEInfo-highlight* Default: `highlight link ALEInfo ALEWarning` The highlight for highlighted info messages. See |g:ale_set_highlights|. ALEInfoSign *hl-ALEInfoSign* Default: `highlight link ALEInfoSign ALEWarningSign` The highlight for info message signs. See |g:ale_set_signs|. ALEInfoLine *hl-ALEInfoLine* Default: Undefined The highlight for entire lines where info messages appear. Only the first line for a problem will be highlighted. See |g:ale_set_signs| and |g:ale_set_highlights|. ALEInfoSignLineNr *hl-ALEInfoSignLineNr* Default: `highlight link ALEInfoSignLineNr CursorLineNr` The highlight for error signs. See |g:ale_set_signs|. NOTE: This highlight is only available on Neovim 0.3.2 or higher. ALEStyleError *hl-ALEStyleError* Default: `highlight link ALEStyleError ALEError` The highlight for highlighted style errors. See |g:ale_set_highlights|. ALEStyleErrorSign *hl-ALEStyleErrorSign* Default: `highlight link ALEStyleErrorSign ALEErrorSign` The highlight for style error signs. See |g:ale_set_signs|. ALEStyleErrorSignLineNr *hl-ALEStyleErrorSignLineNr* Default: `highlight link ALEStyleErrorSignLineNr CursorLineNr` The highlight for error signs. See |g:ale_set_signs|. NOTE: This highlight is only available on Neovim 0.3.2 or higher. ALEStyleWarning *hl-ALEStyleWarning* Default: `highlight link ALEStyleWarning ALEError` The highlight for highlighted style warnings. See |g:ale_set_highlights|. ALEStyleWarningSign *hl-ALEStyleWarningSign* Default: `highlight link ALEStyleWarningSign ALEWarningSign` The highlight for style warning signs. See |g:ale_set_signs|. ALEStyleWarningSignLineNr *hl-ALEStyleWarningSignLineNr* Default: `highlight link ALEStyleWarningSignLineNr CursorLineNr` The highlight for error signs. See |g:ale_set_signs|. NOTE: This highlight is only available on Neovim 0.3.2 or higher. ALEVirtualTextError *hl-ALEVirtualTextError* Default: `highlight link ALEVirtualTextError Comment` The highlight for virtualtext errors. See |g:ale_virtualtext_cursor|. ALEVirtualTextInfo *hl-ALEVirtualTextInfo* Default: `highlight link ALEVirtualTextInfo ALEVirtualTextWarning` The highlight for virtualtext info. See |g:ale_virtualtext_cursor|. ALEVirtualTextStyleError *hl-ALEVirtualTextStyleError* Default: `highlight link ALEVirtualTextStyleError ALEVirtualTextError` The highlight for virtualtext style errors. See |g:ale_virtualtext_cursor|. ALEVirtualTextStyleWarning *hl-ALEVirtualTextStyleWarning* Default: `highlight link ALEVirtualTextStyleWarning ALEVirtualTextWarning` The highlight for virtualtext style warnings. See |g:ale_virtualtext_cursor|. ALEVirtualTextWarning *hl-ALEVirtualTextWarning* Default: `highlight link ALEVirtualTextWarning Comment` The highlight for virtualtext errors. See |g:ale_virtualtext_cursor|. ALEWarning *hl-ALEWarning* Default: `highlight link ALEWarning SpellCap` The highlight for highlighted warnings. See |g:ale_set_highlights|. ALEWarningLine *hl-ALEWarningLine* Default: Undefined The highlight for entire lines where warnings appear. Only the first line for a problem will be highlighted. See |g:ale_set_signs| and |g:ale_set_highlights|. ALEWarningSign *hl-ALEWarningSign* Default: `highlight link ALEWarningSign todo` The highlight for warning signs. See |g:ale_set_signs|. ALEWarningSignLineNr *hl-ALEWarningSignLineNr* Default: `highlight link ALEWarningSignLineNr CursorLineNr` The highlight for error signs. See |g:ale_set_signs|. NOTE: This highlight is only available on Neovim 0.3.2 or higher. =============================================================================== 7. Linter/Fixer Options *ale-integration-options* Linter and fixer options are documented below and in individual help files. Every option for programs can be set globally, or individually for each buffer. For example, |b:ale_python_flake8_executable| will override any values set for |g:ale_python_flake8_executable|. *ale-integrations-local-executables* Some tools will prefer to search for locally-installed executables, unless configured otherwise. For example, the `eslint` linter will search for various executable paths in `node_modules`. The `flake8` linter will search for virtualenv directories. If you prefer to use global executables for those tools, set the relevant `_use_global` and `_executable` options for those linters. > " Use the global executable with a special name for eslint. let g:ale_javascript_eslint_executable = 'special-eslint' let g:ale_javascript_eslint_use_global = 1 " Use the global executable with a special name for flake8. let g:ale_python_flake8_executable = '/foo/bar/flake8' let g:ale_python_flake8_use_global = 1 < |g:ale_use_global_executables| can be set to `true` or `1` in your init or vimrc file to make ALE use global executables for all linters by default. The option |g:ale_virtualenv_dir_names| controls the local virtualenv paths ALE will use to search for Python executables. ------------------------------------------------------------------------------- 7.1. Options for alex *ale-alex-options* The options for `alex` are shared between all filetypes, so options can be configured once. *ale-options.alex_executable* *g:ale_alex_executable* *b:ale_alex_executable* alex_executable g:ale_alex_executable Type: |String| Default: `'alex'` See |ale-integrations-local-executables| *ale-options.alex_use_global* *g:ale_alex_use_global* *b:ale_alex_use_global* alex_use_global g:ale_alex_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| ------------------------------------------------------------------------------- 7.2. Options for cspell *ale-cspell-options* The options for `cspell` are shared between all filetypes, so options can be configured only once. *ale-options.cspell_executable* *g:ale_cspell_executable* *b:ale_cspell_executable* cspell_executable g:ale_cspell_executable Type: |String| Default: `'cspell'` See |ale-integrations-local-executables| *ale-options.cspell_options* *g:ale_cspell_options* *b:ale_cspell_options* cspell_options g:ale_cspell_options Type: |String| Default: `''` This variable can be set to pass additional options to `cspell`. *ale-options.cspell_use_global* *g:ale_cspell_use_global* *b:ale_cspell_use_global* cspell_use_global g:ale_cspell_use_global Type: |Number| Default: `get(g: 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| ------------------------------------------------------------------------------- 7.3. Options for dprint *ale-dprint-options* `dprint` is a fixer for many file types, including: (java|type)script, json(c?), markdown, and more. See https://dprint.dev/plugins for an up-to-date list of supported plugins and their configuration options. *ale-options.dprint_executable* *g:ale_dprint_executable* *b:ale_dprint_executable* dprint_executable g:ale_dprint_executable Type: |String| Default: `'dprint'` See |ale-integrations-local-executables| *ale-options.dprint_config* *g:ale_dprint_config* *b:ale_dprint_config* dprint_config g:ale_dprint_config Type: |String| Default: `'dprint.json'` This variable can be changed to provide a config file to `dprint`. The default is the nearest `dprint.json` searching upward from the current buffer. See https://dprint.dev/config and https://plugins.dprint.dev *ale-options.dprint_options* *g:ale_dprint_options* *b:ale_dprint_options* dprint_options g:ale_dprint_options Type: |String| Default: `''` This variable can be set to pass additional options to `dprint`. *ale-options.dprint_use_global* *g:ale_dprint_use_global* *b:ale_dprint_use_global* dprint_use_global g:ale_dprint_use_global Type: |Number| Default: `get(g: 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| ------------------------------------------------------------------------------- 7.4. Options for languagetool *ale-languagetool-options* *ale-options.languagetool_executable* *g:ale_languagetool_executable* *b:ale_languagetool_executable* languagetool_executable g:ale_languagetool_executable Type: |String| Default: `'languagetool'` The executable to run for languagetool. *ale-options.languagetool_options* *g:ale_languagetool_options* *b:ale_languagetool_options* languagetool_options g:ale_languagetool_options Type: |String| Default: `'--autoDetect'` This variable can be set to pass additional options to languagetool. ------------------------------------------------------------------------------- 7.5. Options for write-good *ale-write-good-options* The options for `write-good` are shared between all filetypes, so options can be configured once. *ale-options.writegood_executable* *g:ale_writegood_executable* *b:ale_writegood_executable* writegood_executable g:ale_writegood_executable Type: |String| Default: `'writegood'` See |ale-integrations-local-executables| *ale-options.writegood_options* *g:ale_writegood_options* *b:ale_writegood_options* writegood_options g:ale_writegood_options Type: |String| Default: `''` This variable can be set to pass additional options to writegood. *ale-options.writegood_use_global* *g:ale_writegood_use_global* *b:ale_writegood_use_global* writegood_use_global g:ale_writegood_use_global Type: |Number| Default: `get(g:, 'ale_use_global_executables', 0)` See |ale-integrations-local-executables| ------------------------------------------------------------------------------- 7.6. Options for redpen *ale-redpen-options* The options for `redpen` are shared between all filetypes, so options can be configured once. *ale-options.redpen_options* *g:ale_redpen_options* *b:ale_redpen_options* redpen_options g:ale_redpen_options Type: |String| Default: `''` This variable can be set to pass additional options to redpen. ------------------------------------------------------------------------------- 7.7. Options for vale *ale-vale-options* The following options can be used to configure the `vale` linter for text files. g:ale_text_vale_executable *g:ale_text_vale_executable* Type: String Default: 'vale' This option controls which executable is used for running Vale. Set it to an absolute path or a different command name if needed. g:ale_text_vale_options *g:ale_text_vale_options* Type: String Default: '' Extra command-line options to pass to the Vale executable. Example: let g:ale_text_vale_options = '--minAlertLevel=warning' ------------------------------------------------------------------------------- 7.8. Other Linter/Fixer Options *ale-other-integration-options* ALE supports a very wide variety of tools. Other linter or fixer options are documented in additional help files. ada.....................................|ale-ada-options| cspell................................|ale-ada-cspell| gcc...................................|ale-ada-gcc| gnatpp................................|ale-ada-gnatpp| ada-language-server...................|ale-ada-language-server| ansible.................................|ale-ansible-options| ansible-language-server...............|ale-ansible-language-server| ansible-lint..........................|ale-ansible-ansible-lint| apkbuild................................|ale-apkbuild-options| apkbuild-fixer........................|ale-apkbuild-apkbuild-fixer| apkbuild-lint.........................|ale-apkbuild-apkbuild-lint| secfixes-check........................|ale-apkbuild-secfixes-check| asciidoc................................|ale-asciidoc-options| cspell................................|ale-asciidoc-cspell| write-good............................|ale-asciidoc-write-good| textlint..............................|ale-asciidoc-textlint| redpen................................|ale-asciidoc-redpen| asm.....................................|ale-asm-options| gcc...................................|ale-asm-gcc| llvm_mc...............................|ale-asm-llvm_mc| astro...................................|ale-astro-options| eslint................................|ale-astro-eslint| prettier..............................|ale-astro-prettier| avra....................................|ale-avra-options| avra..................................|ale-avra-avra| awk.....................................|ale-awk-options| gawk..................................|ale-awk-gawk| bats....................................|ale-bats-options| shellcheck............................|ale-bats-shellcheck| bazel...................................|ale-bazel-options| buildifier............................|ale-bazel-buildifier| bib.....................................|ale-bib-options| bibclean..............................|ale-bib-bibclean| bicep...................................|ale-bicep-options| bicep.................................|ale-bicep-bicep| az_bicep..............................|ale-bicep-az_bicep| bindzone................................|ale-bindzone-options| checkzone.............................|ale-bindzone-checkzone| bitbake.................................|ale-bitbake-options| oelint-adv............................|ale-bitbake-oelint_adv| c.......................................|ale-c-options| astyle................................|ale-c-astyle| cc....................................|ale-c-cc| ccls..................................|ale-c-ccls| clangcheck............................|ale-c-clangcheck| clangd................................|ale-c-clangd| clang-format..........................|ale-c-clangformat| clangtidy.............................|ale-c-clangtidy| cppcheck..............................|ale-c-cppcheck| cquery................................|ale-c-cquery| cspell................................|ale-c-cspell| flawfinder............................|ale-c-flawfinder| uncrustify............................|ale-c-uncrustify| cairo...................................|ale-cairo-options| scarb.................................|ale-cairo-scarb| starknet..............................|ale-cairo-starknet| chef....................................|ale-chef-options| cookstyle.............................|ale-chef-cookstyle| foodcritic............................|ale-chef-foodcritic| clojure.................................|ale-clojure-options| clj-kondo.............................|ale-clojure-clj-kondo| cljfmt................................|ale-clojure-cljfmt| joker.................................|ale-clojure-joker| cloudformation..........................|ale-cloudformation-options| cfn-python-lint.......................|ale-cloudformation-cfn-python-lint| checkov...............................|ale-cloudformation-checkov| cmake...................................|ale-cmake-options| cmakelint.............................|ale-cmake-cmakelint| cmake-lint............................|ale-cmake-cmake-lint| cmake-format..........................|ale-cmake-cmakeformat| cpp.....................................|ale-cpp-options| astyle................................|ale-cpp-astyle| cc....................................|ale-cpp-cc| ccls..................................|ale-cpp-ccls| clangcheck............................|ale-cpp-clangcheck| clangd................................|ale-cpp-clangd| 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| cspell................................|ale-cpp-cspell| flawfinder............................|ale-cpp-flawfinder| uncrustify............................|ale-cpp-uncrustify| c#......................................|ale-cs-options| clang-format..........................|ale-cs-clangformat| csc...................................|ale-cs-csc| cspell................................|ale-cs-cspell| dotnet-format.........................|ale-cs-dotnet-format| mcs...................................|ale-cs-mcs| mcsc..................................|ale-cs-mcsc| uncrustify............................|ale-cs-uncrustify| css.....................................|ale-css-options| cspell................................|ale-css-cspell| css-beautify..........................|ale-css-css-beautify| fecs..................................|ale-css-fecs| prettier..............................|ale-css-prettier| stylelint.............................|ale-css-stylelint| vscodecss.............................|ale-css-vscode| cuda....................................|ale-cuda-options| clang-format..........................|ale-cuda-clangformat| clangd................................|ale-cuda-clangd| nvcc..................................|ale-cuda-nvcc| c3......................................|ale-c3-options| c3lsp.................................|ale-c3-c3lsp| d.......................................|ale-d-options| dfmt..................................|ale-d-dfmt| dls...................................|ale-d-dls| uncrustify............................|ale-d-uncrustify| dafny...................................|ale-dafny-options| dafny.................................|ale-dafny-dafny| dart....................................|ale-dart-options| analysis_server.......................|ale-dart-analysis_server| dart-analyze..........................|ale-dart-analyze| dart-format...........................|ale-dart-format| dartfmt...............................|ale-dart-dartfmt| desktop.................................|ale-desktop-options| desktop-file-validate.................|ale-desktop-desktop-file-validate| dhall...................................|ale-dhall-options| dhall-format..........................|ale-dhall-format| dhall-freeze..........................|ale-dhall-freeze| dhall-lint............................|ale-dhall-lint| dockerfile..............................|ale-dockerfile-options| dockerfile_lint.......................|ale-dockerfile-dockerfile_lint| dockerlinter..........................|ale-dockerfile-dockerlinter| dprint................................|ale-dockerfile-dprint| 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| credo.................................|ale-elixir-credo| cspell................................|ale-elixir-cspell| lexical...............................|ale-elixir-lexical| expert................................|ale-elixir-expert| elm.....................................|ale-elm-options| elm-format............................|ale-elm-elm-format| elm-ls................................|ale-elm-elm-ls| elm-make..............................|ale-elm-elm-make| erlang..................................|ale-erlang-options| dialyzer..............................|ale-erlang-dialyzer| elvis.................................|ale-erlang-elvis| erlang-mode...........................|ale-erlang-erlang-mode| erlang_ls.............................|ale-erlang-erlang_ls| erlc..................................|ale-erlang-erlc| erlfmt................................|ale-erlang-erlfmt| syntaxerl.............................|ale-erlang-syntaxerl| eruby...................................|ale-eruby-options| erb-formatter.........................|ale-eruby-erbformatter| erblint...............................|ale-eruby-erblint| htmlbeautifier........................|ale-eruby-htmlbeautifier| ruumba................................|ale-eruby-ruumba| fish....................................|ale-fish-options| fish_indent...........................|ale-fish-fish_indent| fortran.................................|ale-fortran-options| fortitude.............................|ale-fortran-fortitude| gcc...................................|ale-fortran-gcc| language_server.......................|ale-fortran-language-server| fountain................................|ale-fountain-options| fusionscript............................|ale-fuse-options| fusion-lint...........................|ale-fuse-fusionlint| git commit..............................|ale-gitcommit-options| gitlint...............................|ale-gitcommit-gitlint| gleam...................................|ale-gleam-options| gleam_format..........................|ale-gleam-gleam_format| gleamlsp..............................|ale-gleam-gleamlsp| glsl....................................|ale-glsl-options| glslang...............................|ale-glsl-glslang| glslls................................|ale-glsl-glslls| go......................................|ale-go-options| bingo.................................|ale-go-bingo| cspell................................|ale-go-cspell| gobuild...............................|ale-go-gobuild| gofmt.................................|ale-go-gofmt| gofumpt...............................|ale-go-gofumpt| goimports.............................|ale-go-goimports| golangci-lint.........................|ale-go-golangci-lint| golangserver..........................|ale-go-golangserver| golines...............................|ale-go-golines| gopls.................................|ale-go-gopls| govet.................................|ale-go-govet| revive................................|ale-go-revive| staticcheck...........................|ale-go-staticcheck| go html template........................|ale-gohtmltmpl-options| djlint................................|ale-gohtmltmpl-djlint| graphql.................................|ale-graphql-options| eslint................................|ale-graphql-eslint| gqlint................................|ale-graphql-gqlint| prettier..............................|ale-graphql-prettier| groovy..................................|ale-groovy-options| npm-groovy-lint.......................|ale-groovy-npm-groovy-lint| hack....................................|ale-hack-options| hack..................................|ale-hack-hack| hackfmt...............................|ale-hack-hackfmt| hhast.................................|ale-hack-hhast| handlebars..............................|ale-handlebars-options| djlint................................|ale-handlebars-djlint| prettier..............................|ale-handlebars-prettier| ember-template-lint...................|ale-handlebars-embertemplatelint| haskell.................................|ale-haskell-options| brittany..............................|ale-haskell-brittany| cspell................................|ale-haskell-cspell| floskell..............................|ale-haskell-floskell| ghc...................................|ale-haskell-ghc| ghc-mod...............................|ale-haskell-ghc-mod| cabal-ghc.............................|ale-haskell-cabal-ghc| hdevtools.............................|ale-haskell-hdevtools| hfmt..................................|ale-haskell-hfmt| hindent...............................|ale-haskell-hindent| hlint.................................|ale-haskell-hlint| hls...................................|ale-haskell-hls| stack-build...........................|ale-haskell-stack-build| stack-ghc.............................|ale-haskell-stack-ghc| stylish-haskell.......................|ale-haskell-stylish-haskell| hie...................................|ale-haskell-hie| ormolu................................|ale-haskell-ormolu| fourmolu..............................|ale-haskell-fourmolu| hcl.....................................|ale-hcl-options| packer-fmt............................|ale-hcl-packer-fmt| terraform-fmt.........................|ale-hcl-terraform-fmt| help....................................|ale-help-options| cspell................................|ale-help-cspell| html....................................|ale-html-options| angular...............................|ale-html-angular| cspell................................|ale-html-cspell| djlint................................|ale-html-djlint| fecs..................................|ale-html-fecs| html-beautify.........................|ale-html-beautify| htmlhint..............................|ale-html-htmlhint| prettier..............................|ale-html-prettier| rustywind.............................|ale-html-rustywind| stylelint.............................|ale-html-stylelint| superhtml.............................|ale-html-superhtml| tidy..................................|ale-html-tidy| vscodehtml............................|ale-html-vscode| write-good............................|ale-html-write-good| html angular template...................|ale-htmlangular-options| djlint................................|ale-htmlangular-djlint| html django template....................|ale-htmldjango-options| djlint................................|ale-htmldjango-djlint| http....................................|ale-http-options| kulala_fmt............................|ale-http-kulala_fmt| hurl....................................|ale-hurl-options| hurlfmt...............................|ale-hurl-hurlfmt| idris...................................|ale-idris-options| idris.................................|ale-idris-idris| ink.....................................|ale-ink-options| ink-language-server...................|ale-ink-language-server| inko....................................|ale-inko-options| inko..................................|ale-inko-inko| ispc....................................|ale-ispc-options| ispc..................................|ale-ispc-ispc| java....................................|ale-java-options| checkstyle............................|ale-java-checkstyle| clang-format..........................|ale-java-clangformat| cspell................................|ale-java-cspell| javac.................................|ale-java-javac| google-java-format....................|ale-java-google-java-format| pmd...................................|ale-java-pmd| javalsp...............................|ale-java-javalsp| eclipselsp............................|ale-java-eclipselsp| uncrustify............................|ale-java-uncrustify| javascript..............................|ale-javascript-options| biome.................................|ale-javascript-biome| clang-format..........................|ale-javascript-clangformat| cspell................................|ale-javascript-cspell| deno..................................|ale-javascript-deno| dprint................................|ale-javascript-dprint| eslint................................|ale-javascript-eslint| fecs..................................|ale-javascript-fecs| flow..................................|ale-javascript-flow| importjs..............................|ale-javascript-importjs| jscs..................................|ale-javascript-jscs| jshint................................|ale-javascript-jshint| prettier..............................|ale-javascript-prettier| prettier-eslint.......................|ale-javascript-prettier-eslint| prettier-standard.....................|ale-javascript-prettier-standard| standard..............................|ale-javascript-standard| xo....................................|ale-javascript-xo| jinja...................................|ale-jinja-options| djlint................................|ale-jinja-djlint| j2lint................................|ale-jinja-j2lint| json....................................|ale-json-options| biome.................................|ale-json-biome| clang-format..........................|ale-json-clangformat| cspell................................|ale-json-cspell| dprint................................|ale-json-dprint| eslint................................|ale-json-eslint| fixjson...............................|ale-json-fixjson| pytool................................|ale-json-pytool| jsonlint..............................|ale-json-jsonlint| jq....................................|ale-json-jq| prettier..............................|ale-json-prettier| spectral..............................|ale-json-spectral| vscodejson............................|ale-json-vscode| jsonc...................................|ale-jsonc-options| biome.................................|ale-jsonc-biome| eslint................................|ale-jsonc-eslint| jsonnet.................................|ale-jsonnet-options| jsonnetfmt............................|ale-jsonnet-jsonnetfmt| jsonnet-lint..........................|ale-jsonnet-jsonnet-lint| json5...................................|ale-json5-options| eslint................................|ale-json5-eslint| julia...................................|ale-julia-options| languageserver........................|ale-julia-languageserver| kotlin..................................|ale-kotlin-options| kotlinc...............................|ale-kotlin-kotlinc| ktlint................................|ale-kotlin-ktlint| languageserver........................|ale-kotlin-languageserver| latex...................................|ale-latex-options| cspell................................|ale-latex-cspell| write-good............................|ale-latex-write-good| textlint..............................|ale-latex-textlint| lean....................................|ale-lean-options| lake..................................|ale-lean-lake| less....................................|ale-less-options| lessc.................................|ale-less-lessc| prettier..............................|ale-less-prettier| stylelint.............................|ale-less-stylelint| llvm....................................|ale-llvm-options| llc...................................|ale-llvm-llc| lua.....................................|ale-lua-options| cspell................................|ale-lua-cspell| lua-format............................|ale-lua-lua-format| lua-language-server...................|ale-lua-lua-language-server| luac..................................|ale-lua-luac| luacheck..............................|ale-lua-luacheck| luafmt................................|ale-lua-luafmt| selene................................|ale-lua-selene| stylua................................|ale-lua-stylua| make....................................|ale-make-options| checkmake.............................|ale-make-checkmake| markdown................................|ale-markdown-options| cspell................................|ale-markdown-cspell| dprint................................|ale-markdown-dprint| markdownlint..........................|ale-markdown-markdownlint| marksman..............................|ale-markdown-marksman| mdl...................................|ale-markdown-mdl| pandoc................................|ale-markdown-pandoc| prettier..............................|ale-markdown-prettier| pymarkdown............................|ale-markdown-pymarkdown| remark-lint...........................|ale-markdown-remark-lint| textlint..............................|ale-markdown-textlint| write-good............................|ale-markdown-write-good| redpen................................|ale-markdown-redpen| mercury.................................|ale-mercury-options| mmc...................................|ale-mercury-mmc| nasm....................................|ale-nasm-options| nasm..................................|ale-nasm-nasm| nickel..................................|ale-nickel-options| nickel_format.........................|ale-nickel-nickel-format| nim.....................................|ale-nim-options| nimcheck..............................|ale-nim-nimcheck| nimlsp................................|ale-nim-nimlsp| nimpretty.............................|ale-nim-nimpretty| nix.....................................|ale-nix-options| alejandra.............................|ale-nix-alejandra| nixfmt................................|ale-nix-nixfmt| nixpkgs-fmt...........................|ale-nix-nixpkgs-fmt| statix................................|ale-nix-statix| deadnix...............................|ale-nix-deadnix| nroff...................................|ale-nroff-options| write-good............................|ale-nroff-write-good| nunjucks................................|ale-nunjucks-options| djlint................................|ale-nunjucks-djlint| objc....................................|ale-objc-options| ccls..................................|ale-objc-ccls| clang.................................|ale-objc-clang| clang-format..........................|ale-objc-clangformat| clangd................................|ale-objc-clangd| uncrustify............................|ale-objc-uncrustify| objcpp..................................|ale-objcpp-options| clang.................................|ale-objcpp-clang| clangd................................|ale-objcpp-clangd| uncrustify............................|ale-objcpp-uncrustify| ocaml...................................|ale-ocaml-options| dune..................................|ale-ocaml-dune| merlin................................|ale-ocaml-merlin| ocamllsp..............................|ale-ocaml-ocamllsp| ols...................................|ale-ocaml-ols| ocamlformat...........................|ale-ocaml-ocamlformat| ocp-indent............................|ale-ocaml-ocp-indent| odin....................................|ale-odin-options| ols...................................|ale-odin-ols| openapi.................................|ale-openapi-options| ibm_validator.........................|ale-openapi-ibm-validator| prettier..............................|ale-openapi-prettier| yamllint..............................|ale-openapi-yamllint| openscad................................|ale-openscad-options| sca2d.................................|ale-openscad-sca2d| scadformat............................|ale-openscad-scadformat| packer..................................|ale-packer-options| packer-fmt-fixer......................|ale-packer-fmt-fixer| pascal..................................|ale-pascal-options| ptop..................................|ale-pascal-ptop| pawn....................................|ale-pawn-options| uncrustify............................|ale-pawn-uncrustify| perl....................................|ale-perl-options| perl..................................|ale-perl-perl| perl language server..................|ale-perl-languageserver| perlcritic............................|ale-perl-perlcritic| perltidy..............................|ale-perl-perltidy| perl6...................................|ale-perl6-options| perl6.................................|ale-perl6-perl6| php.....................................|ale-php-options| cspell................................|ale-php-cspell| langserver............................|ale-php-langserver| phan..................................|ale-php-phan| phpactor..............................|ale-php-phpactor| 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| pint..................................|ale-php-pint| tlint.................................|ale-php-tlint| intelephense..........................|ale-php-intelephense| 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| powershell..............................|ale-powershell-options| cspell................................|ale-powershell-cspell| powershell............................|ale-powershell-powershell| psscriptanalyzer......................|ale-powershell-psscriptanalyzer| prolog..................................|ale-prolog-options| swipl.................................|ale-prolog-swipl| proto...................................|ale-proto-options| buf-format............................|ale-proto-buf-format| buf-lint..............................|ale-proto-buf-lint| clang-format..........................|ale-proto-clangformat| protoc-gen-lint.......................|ale-proto-protoc-gen-lint| protolint.............................|ale-proto-protolint| 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| purescript..............................|ale-purescript-options| purescript-language-server............|ale-purescript-language-server| purs-tidy.............................|ale-purescript-tidy| purty.................................|ale-purescript-purty| pyrex (cython)..........................|ale-pyrex-options| cython................................|ale-pyrex-cython| python..................................|ale-python-options| autoflake.............................|ale-python-autoflake| autoimport............................|ale-python-autoimport| autopep8..............................|ale-python-autopep8| bandit................................|ale-python-bandit| black.................................|ale-python-black| cspell................................|ale-python-cspell| flake8................................|ale-python-flake8| flakehell.............................|ale-python-flakehell| isort.................................|ale-python-isort| mypy..................................|ale-python-mypy| prospector............................|ale-python-prospector| pycln.................................|ale-python-pycln| pycodestyle...........................|ale-python-pycodestyle| pydocstyle............................|ale-python-pydocstyle| pyflakes..............................|ale-python-pyflakes| pyflyby...............................|ale-python-pyflyby| pylama................................|ale-python-pylama| pylint................................|ale-python-pylint| pylsp.................................|ale-python-pylsp| pyre..................................|ale-python-pyre| pyrefly...............................|ale-python-pyrefly| pyright...............................|ale-python-pyright| refurb................................|ale-python-refurb| reorder-python-imports................|ale-python-reorder_python_imports| ruff..................................|ale-python-ruff| ruff-format...........................|ale-python-ruff-format| unimport..............................|ale-python-unimport| vulture...............................|ale-python-vulture| yapf..................................|ale-python-yapf| qml.....................................|ale-qml-options| qmlfmt................................|ale-qml-qmlfmt| r.......................................|ale-r-options| languageserver........................|ale-r-languageserver| lintr.................................|ale-r-lintr| styler................................|ale-r-styler| racket..................................|ale-racket-options| racket_langserver.....................|ale-racket-langserver| raco_fmt..............................|ale-racket-raco-fmt| reasonml................................|ale-reasonml-options| merlin................................|ale-reasonml-merlin| ols...................................|ale-reasonml-ols| reason-language-server................|ale-reasonml-language-server| refmt.................................|ale-reasonml-refmt| rego....................................|ale-rego-options| cspell................................|ale-rego-cspell| opacheck..............................|ale-rego-opa-check| opafmt................................|ale-rego-opa-fmt-fixer| rescript................................|ale-rescript-options| rescript-language-server..............|ale-rescript-language-server| rescript_format.......................|ale-rescript-format| rest....................................|ale-rest-options| kulala_fmt............................|ale-rest-kulala_fmt| restructuredtext........................|ale-restructuredtext-options| cspell................................|ale-restructuredtext-cspell| textlint..............................|ale-restructuredtext-textlint| write-good............................|ale-restructuredtext-write-good| robot...................................|ale-robot-options| rflint................................|ale-robot-rflint| roc.....................................|ale-roc-options| roc_language_server...................|ale-roc-roc-language-server| roc_format............................|ale-roc-roc-format| roc_annotate..........................|ale-roc-roc-annotate| ruby....................................|ale-ruby-options| brakeman..............................|ale-ruby-brakeman| cspell................................|ale-ruby-cspell| debride...............................|ale-ruby-debride| packwerk..............................|ale-ruby-packwerk| prettier..............................|ale-ruby-prettier| rails_best_practices..................|ale-ruby-rails_best_practices| reek..................................|ale-ruby-reek| rubocop...............................|ale-ruby-rubocop| ruby..................................|ale-ruby-ruby| rufo..................................|ale-ruby-rufo| solargraph............................|ale-ruby-solargraph| sorbet................................|ale-ruby-sorbet| standardrb............................|ale-ruby-standardrb| syntax_tree...........................|ale-ruby-syntax_tree| rubyfmt...............................|ale-ruby-rubyfmt| rust....................................|ale-rust-options| analyzer..............................|ale-rust-analyzer| cargo.................................|ale-rust-cargo| cspell................................|ale-rust-cspell| rls...................................|ale-rust-rls| rustc.................................|ale-rust-rustc| rustfmt...............................|ale-rust-rustfmt| salt....................................|ale-salt-options| salt-lint.............................|ale-salt-salt-lint| sass....................................|ale-sass-options| sasslint..............................|ale-sass-sasslint| stylelint.............................|ale-sass-stylelint| scala...................................|ale-scala-options| cspell................................|ale-scala-cspell| metals................................|ale-scala-metals| sbtserver.............................|ale-scala-sbtserver| scalafmt..............................|ale-scala-scalafmt| scalastyle............................|ale-scala-scalastyle| scss....................................|ale-scss-options| prettier..............................|ale-scss-prettier| sasslint..............................|ale-scss-sasslint| stylelint.............................|ale-scss-stylelint| sh......................................|ale-sh-options| bashate...............................|ale-sh-bashate| cspell................................|ale-sh-cspell| sh-language-server....................|ale-sh-language-server| shell.................................|ale-sh-shell| shellcheck............................|ale-sh-shellcheck| shfmt.................................|ale-sh-shfmt| sml.....................................|ale-sml-options| smlnj.................................|ale-sml-smlnj| solidity................................|ale-solidity-options| solc..................................|ale-solidity-solc| solhint...............................|ale-solidity-solhint| solium................................|ale-solidity-solium| forge.................................|ale-solidity-forge| spec....................................|ale-spec-options| rpmlint...............................|ale-spec-rpmlint| sql.....................................|ale-sql-options| dprint................................|ale-sql-dprint| pgformatter...........................|ale-sql-pgformatter| sqlfluff..............................|ale-sql-sqlfluff| sqlfmt................................|ale-sql-sqlfmt| sqlformat.............................|ale-sql-sqlformat| stylus..................................|ale-stylus-options| stylelint.............................|ale-stylus-stylelint| sugarss.................................|ale-sugarss-options| stylelint.............................|ale-sugarss-stylelint| svelte..................................|ale-svelte-options| prettier..............................|ale-svelte-prettier| svelteserver..........................|ale-svelte-svelteserver| swift...................................|ale-swift-options| apple-swift-format....................|ale-swift-apple-swift-format| cspell................................|ale-swift-cspell| sourcekitlsp..........................|ale-swift-sourcekitlsp| systemd.................................|ale-systemd-options| systemd-analyze.......................|ale-systemd-analyze| tcl.....................................|ale-tcl-options| nagelfar..............................|ale-tcl-nagelfar| terraform...............................|ale-terraform-options| checkov...............................|ale-terraform-checkov| terraform-fmt-fixer...................|ale-terraform-fmt-fixer| terraform.............................|ale-terraform-terraform| terraform-ls..........................|ale-terraform-terraform-ls| terraform-lsp.........................|ale-terraform-terraform-lsp| tflint................................|ale-terraform-tflint| tfsec.................................|ale-terraform-tfsec| tex.....................................|ale-tex-options| chktex................................|ale-tex-chktex| cspell................................|ale-tex-cspell| lacheck...............................|ale-tex-lacheck| latexindent...........................|ale-tex-latexindent| texlab................................|ale-tex-texlab| redpen................................|ale-tex-redpen| texinfo.................................|ale-texinfo-options| cspell................................|ale-texinfo-cspell| write-good............................|ale-texinfo-write-good| text....................................|ale-text-options| cspell................................|ale-text-cspell| textlint..............................|ale-text-textlint| write-good............................|ale-text-write-good| redpen................................|ale-text-redpen| thrift..................................|ale-thrift-options| thrift................................|ale-thrift-thrift| thriftcheck...........................|ale-thrift-thriftcheck| toml....................................|ale-toml-options| dprint................................|ale-toml-dprint| tombi.................................|ale-toml-tombi| typescript..............................|ale-typescript-options| biome.................................|ale-typescript-biome| cspell................................|ale-typescript-cspell| deno..................................|ale-typescript-deno| dprint................................|ale-typescript-dprint| eslint................................|ale-typescript-eslint| prettier..............................|ale-typescript-prettier| standard..............................|ale-typescript-standard| tslint................................|ale-typescript-tslint| tsserver..............................|ale-typescript-tsserver| xo....................................|ale-typescript-xo| typst...................................|ale-typst-options| typstyle..............................|ale-typst-typstyle| v.......................................|ale-v-options| v.....................................|ale-v-v| vfmt..................................|ale-v-vfmt| vala....................................|ale-vala-options| uncrustify............................|ale-vala-uncrustify| verilog/systemverilog...................|ale-verilog-options| hdl-checker...........................|ale-verilog-hdl-checker| iverilog..............................|ale-verilog-iverilog| slang.................................|ale-verilog-slang| verible_ls............................|ale-verilog-verible-ls| verible_format........................|ale-verilog-verible-format| verilator.............................|ale-verilog-verilator| vlog..................................|ale-verilog-vlog| xvlog.................................|ale-verilog-xvlog| yosys.................................|ale-verilog-yosys| vhdl....................................|ale-vhdl-options| ghdl..................................|ale-vhdl-ghdl| hdl-checker...........................|ale-vhdl-hdl-checker| vcom..................................|ale-vhdl-vcom| xvhdl.................................|ale-vhdl-xvhdl| vim help................................|ale-vim-help-options| write-good............................|ale-vim-help-write-good| vim.....................................|ale-vim-options| vimls.................................|ale-vim-vimls| vint..................................|ale-vim-vint| vue.....................................|ale-vue-options| cspell................................|ale-vue-cspell| prettier..............................|ale-vue-prettier| vls...................................|ale-vue-vls| volar.................................|ale-vue-volar| wgsl....................................|ale-wgsl-options| naga..................................|ale-wgsl-naga| xhtml...................................|ale-xhtml-options| cspell................................|ale-xhtml-cspell| write-good............................|ale-xhtml-write-good| xml.....................................|ale-xml-options| xmllint...............................|ale-xml-xmllint| yaml....................................|ale-yaml-options| actionlint............................|ale-yaml-actionlint| circleci..............................|ale-yaml-circleci| prettier..............................|ale-yaml-prettier| spectral..............................|ale-yaml-spectral| swaglint..............................|ale-yaml-swaglint| yaml-language-server..................|ale-yaml-language-server| yamlfix...............................|ale-yaml-yamlfix| yamlfmt...............................|ale-yaml-yamlfmt| yamllint..............................|ale-yaml-yamllint| gitlablint............................|ale-yaml-gitlablint| yq....................................|ale-yaml-yq| yang....................................|ale-yang-options| yang-lsp..............................|ale-yang-lsp| yara....................................|ale-yara-options| yls...................................|ale-yara-yls| zeek....................................|ale-zeek-options| zeek..................................|ale-zeek-zeek| zig.....................................|ale-zig-options| zigfmt................................|ale-zig-zigfmt| zlint.................................|ale-zig-zlint| zls...................................|ale-zig-zls| =============================================================================== 8. Commands/Keybinds *ale-commands* :ALEComplete *:ALEComplete* Manually trigger LSP autocomplete and show the menu. Works only when called from insert mode. > inoremap :ALEComplete < A plug mapping `(ale_complete)` is defined for this command. > imap (ale_complete) < :ALEDocumentation *:ALEDocumentation* Similar to the `:ALEHover` command, retrieve documentation information for the symbol at the cursor. Documentation data will always be shown in a preview window, no matter how small the documentation content is. NOTE: This command is only available for `tsserver`. A plug mapping `(ale_documentation)` is defined for this command. :ALEFindReferences *:ALEFindReferences* Find references in the codebase for the symbol under the cursor using the enabled LSP linters for the buffer. ALE will display a preview window containing the results if some references are found. The window can be navigated using the usual Vim navigation commands. The Enter key () can be used to jump to a referencing location, or the `t` key can be used to jump to the location in a new tab. The locations opened in different ways using the following variations. `:ALEFindReferences -tab` - Open the location in a new tab. `:ALEFindReferences -split` - Open the location in a horizontal split. `:ALEFindReferences -vsplit` - Open the location in a vertical split. `:ALEFindReferences -quickfix` - Put the locations into quickfix list. `:ALEFindReferences -contents` - Show line contents for matches. `:ALEFindReferences -fzf` - Show matches/previews using |fzf-vim|. The default method used for navigating to a new location can be changed by modifying |g:ale_default_navigation|. The default behaviour on whether to show line content for matches can be changed by modifying |g:ale_references_show_contents|. The default behaviour on whether to use `fzf` to show matches/file previews can be changed by modifying |g:ale_references_use_fzf|. `-fzf` can be combined with `-tab`, `-split`, `-vsplit`, `-quickfix` and `-relative`, while line contents/file previews are always shown. You can add `-relative` to the command to view results with relatives paths, instead of absolute paths. This option has no effect if `-quickfix` is used. The selection can be opened again with the `:ALERepeatSelection` command. You can jump back to the position you were at before going to a reference of something with jump motions like CTRL-O. See |jump-motions|. A plug mapping `(ale_find_references)` is defined for this command. You can define additional plug mapping with any additional options you want like so: > nnoremap (my_mapping) :ALEFindReferences -relative < :ALEFix [linter] *:ALEFix* Fix problems with the current buffer. See |ale-fix| for more information. If the command is run with a bang (`:ALEFix!`), all warnings will be suppressed, including warnings about no fixers being defined, and warnings about not being able to apply fixes to a file because it has been changed. A plug mapping `(ale_fix)` is defined for this command. :ALEFixSuggest *:ALEFixSuggest* Suggest tools that can be used to fix problems in the current buffer. See |ale-fix| for more information. :ALEGoToDefinition [options] *:ALEGoToDefinition* Jump to the definition of a symbol under the cursor using the enabled LSP linters for the buffer. ALE will jump to a definition if an LSP server provides a location to jump to. Otherwise, ALE will do nothing. The locations opened in different ways using the following variations. `:ALEGoToDefinition -tab` - Open the location in a new tab. `:ALEGoToDefinition -split` - Open the location in a horizontal split. `:ALEGoToDefinition -vsplit` - Open the location in a vertical split. The default method used for navigating to a new location can be changed by modifying |g:ale_default_navigation|. You can jump back to the position you were at before going to the definition of something with jump motions like CTRL-O. See |jump-motions|. You should consider using the 'hidden' option in combination with this command. Otherwise, Vim will refuse to leave the buffer you're jumping from unless you have saved your edits. The following Plug mappings are defined for this command, which correspond to the following commands. `(ale_go_to_definition)` - `:ALEGoToDefinition` `(ale_go_to_definition_in_tab)` - `:ALEGoToDefinition -tab` `(ale_go_to_definition_in_split)` - `:ALEGoToDefinition -split` `(ale_go_to_definition_in_vsplit)` - `:ALEGoToDefinition -vsplit` :ALEGoToTypeDefinition [options] *:ALEGoToTypeDefinition* This works similar to `:ALEGoToDefinition` but instead jumps to the definition of a type of a symbol under the cursor. ALE will jump to a definition if an LSP server provides a location to jump to. Otherwise, ALE will do nothing. The locations opened in different ways using the following variations. `:ALEGoToTypeDefinition -tab` - Open the location in a new tab. `:ALEGoToTypeDefinition -split` - Open the location in a horizontal split. `:ALEGoToTypeDefinition -vsplit` - Open the location in a vertical split. The default method used for navigating to a new location can be changed by modifying |g:ale_default_navigation|. You can jump back to the position you were at before going to the definition of something with jump motions like CTRL-O. See |jump-motions|. The following Plug mappings are defined for this command, which correspond to the following commands. `(ale_go_to_type_definition)` - `:ALEGoToTypeDefinition` `(ale_go_to_type_definition_in_tab)` - `:ALEGoToTypeDefinition -tab` `(ale_go_to_type_definition_in_split)` - `:ALEGoToTypeDefinition -split` `(ale_go_to_type_definition_in_vsplit)` - `:ALEGoToTypeDefinition -vsplit` :ALEGoToImplementation [options] *:ALEGoToImplementation* This works similar to `:ALEGoToDefinition` but instead jumps to the implementation of symbol under the cursor. ALE will jump to a definition if an LSP server provides a location to jump to. Otherwise, ALE will do nothing. The locations opened in different ways using the following variations. `:ALEGoToImplementation -tab` - Open the location in a new tab. `:ALEGoToImplementation -split` - Open the location in a horizontal split. `:ALEGoToImplementation -vsplit` - Open the location in a vertical split. The default method used for navigating to a new location can be changed by modifying |g:ale_default_navigation|. You can jump back to the position you were at before going to the definition of something with jump motions like CTRL-O. See |jump-motions|. The following Plug mappings are defined for this command, which correspond to the following commands. `(ale_go_to_implementation)` - `:ALEGoToImplementation` `(ale_go_to_implementation_in_tab)` - `:ALEGoToImplementation -tab` `(ale_go_to_implementation_in_split)` - `:ALEGoToImplementation -split` `(ale_go_to_implementation_in_vsplit)` - `:ALEGoToImplementation -vsplit` :ALEHover *:ALEHover* Print brief information about the symbol under the cursor, taken from any available LSP linters. There may be a small non-blocking delay before information is printed. NOTE: In Vim 8, long messages will be shown in a preview window, as Vim 8 does not support showing a prompt to press enter to continue for long messages from asynchronous callbacks. A plug mapping `(ale_hover)` is defined for this command. :ALEImport *:ALEImport* Try to import a symbol using `tsserver` or a Language Server. ALE will look for completions for the word at the cursor which contain additional text edits that possible insert lines to import the symbol. The first match with additional text edits will be used, and may add other code to the current buffer other than import lines. If linting is enabled, and |g:ale_lint_on_text_changed| is set to ever check buffers when text is changed, the buffer will be checked again after changes are made. A Plug mapping `(ale_import)` is defined for this command. This mapping should only be bound for normal mode. :ALEOrganizeImports *:ALEOrganizeImports* Organize imports using tsserver. Currently not implemented for LSPs. :ALERename *:ALERename* Rename a symbol using `tsserver` or a Language Server. The symbol where the cursor is resting will be the symbol renamed, and a prompt will open to request a new name. The rename operation will not save modified buffers when 'hidden' is on unless |g:ale_save_hidden| is `true` or `1`. :ALEFileRename *:ALEFileRename* Rename a file and fix imports using `tsserver`. :ALECodeAction *:ALECodeAction* Apply a code action via LSP servers or `tsserver`. If there is an error present on a line that can be fixed, ALE will automatically fix a line, unless there are multiple possible code fixes to apply. This command can be run in visual mode apply actions, such as applicable refactors. A menu will be shown to select code action to apply. :ALERepeatSelection *:ALERepeatSelection* Repeat the last selection displayed in the preview window. :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. You can add `-relative` to the command to view results with relatives paths, instead of absolute paths. :ALELint *:ALELint* Run ALE once for the current buffer. This command can be used to run ALE manually, instead of automatically, if desired. This command will also run linters where `lint_file` is evaluates to `1`, meaning linters which check the file instead of the Vim buffer. A plug mapping `(ale_lint)` is defined for this command. :ALELintStop *:ALELintStop* Stop any currently running jobs for checking the current buffer. Any problems from previous linter results will continue to be shown. :ALEPopulateQuickfix *:ALEPopulateQuickfix* :ALEPopulateLocList *:ALEPopulateLocList* Manually populate the |quickfix| or |location-list| and show the corresponding list. Useful when you have other uses for both the |quickfix| and |location-list| and don't want them automatically populated. Be sure to disable auto populating: > let g:ale_set_quickfix = 0 let g:ale_set_loclist = 0 < With these settings, ALE will still run checking and display it with signs, highlighting, and other output described in |ale-lint-file-linters|. :ALEPrevious *:ALEPrevious* :ALEPreviousWrap *:ALEPreviousWrap* :ALENext *:ALENext* :ALENextWrap *:ALENextWrap* :ALEFirst *:ALEFirst* :ALELast *:ALELast* *ale-navigation-commands* Move between warnings or errors in a buffer. ALE will only navigate between the errors or warnings it generated, even if both |g:ale_set_quickfix| and |g:ale_set_loclist| are set to `0`. `:ALEPrevious` and `:ALENext` will stop at the top and bottom of a file, while `:ALEPreviousWrap` and `:ALENextWrap` will wrap around the file to find the last or first warning or error in the file, respectively. `:ALEPrevious` and `:ALENext` take optional flags arguments to custom their behavior : `-wrap` enable wrapping around the file `-error`, `-warning` and `-info` enable jumping to errors, warnings or infos respectively, ignoring anything else. They are mutually exclusive and if several are provided the priority is the following: error > warning > info. `-style` and `-nostyle` allow you to jump respectively to style error or warning and to not style error or warning. They also are mutually exclusive and nostyle has priority over style. Flags can be combined to create create custom jumping. Thus you can use ":ALENext -wrap -error -nosyle" to jump to the next error which is not a style error while going back to the beginning of the file if needed. `:ALEFirst` goes to the first error or warning in the buffer, while `:ALELast` goes to the last one. The following || mappings are defined for the commands: > (ale_previous) - ALEPrevious (ale_previous_wrap) - ALEPreviousWrap (ale_previous_error) - ALEPrevious -error (ale_previous_wrap_error) - ALEPrevious -wrap -error (ale_previous_warning) - ALEPrevious -warning (ale_previous_wrap_warning) - ALEPrevious -wrap -warning (ale_next) - ALENext (ale_next_wrap) - ALENextWrap (ale_next_error) - ALENext -error (ale_next_wrap_error) - ALENext -wrap -error (ale_next_warning) - ALENext -warning (ale_next_wrap_warning) - ALENext -wrap -warning (ale_first) - ALEFirst (ale_last) - ALELast < For example, these commands could be bound to the keys CTRL-j and CTRL-k: > " Map movement through errors without wrapping. nmap (ale_previous) nmap (ale_next) " OR map keys to use wrapping. nmap (ale_previous_wrap) nmap (ale_next_wrap) < :ALEToggle *:ALEToggle* :ALEEnable *:ALEEnable* :ALEDisable *:ALEDisable* :ALEToggleBuffer *:ALEToggleBuffer* :ALEEnableBuffer *:ALEEnableBuffer* :ALEDisableBuffer *:ALEDisableBuffer* `:ALEToggle`, `:ALEEnable`, and `:ALEDisable` enable or disable ALE linting, including all of its autocmd events, loclist items, quickfix items, signs, current jobs, etc., globally. Executing any of these commands will change the |g:ale_enabled| variable. ALE can be disabled or enabled for only a single buffer with `:ALEToggleBuffer`, `:ALEEnableBuffer`, and `:ALEDisableBuffer`. Disabling ALE for a buffer will not remove autocmd events, but will prevent ALE from checking for problems and reporting problems for whatever buffer the `:ALEDisableBuffer` or `:ALEToggleBuffer` command is executed from. These commands can be used for temporarily disabling ALE for a buffer. These commands will modify the |b:ale_enabled| variable. ALE linting cannot be enabled for a single buffer when it is disabled globally, as disabling ALE globally removes the autocmd events needed to perform linting with. The following plug mappings are defined, for conveniently defining keybinds: `:ALEToggle` - `(ale_toggle)` `:ALEEnable` - `(ale_enable)` `:ALEDisable` - `(ale_disable)` `:ALEToggleBuffer` - `(ale_toggle_buffer)` `:ALEEnableBuffer` - `(ale_enable_buffer)` `:ALEDisableBuffer` - `(ale_disable_buffer)` For removing problems reported by ALE, but leaving ALE enabled, see `:ALEReset` and `:ALEResetBuffer`. :ALEDetail *:ALEDetail* Show the full linter message for the problem nearest to the cursor on the given line in the preview window. The preview window can be easily closed with the `q` key. If there is no message to show, the window will not be opened. If a loclist item has a `detail` key set, the message for that key will be preferred over `text`. See |ale-loclist-format|. A plug mapping `(ale_detail)` is defined for this command. :ALEInfo *:ALEInfo* *:ALEInfoToFile* Print runtime information about ALE, including the values of global and buffer-local settings for ALE, the linters that are enabled, the commands that have been run, and the output of commands. ALE will log the commands that are run by default. If you wish to disable this, set |g:ale_history_enabled| to `0`. Because it could be expensive, ALE does not remember the output of recent commands by default. Set |g:ale_history_log_output| to `1` to enable logging of output for commands. ALE will only log the output captured for parsing problems, etc. You can pass options to the command to control how ALE displays the information, such as `:ALEInfo -echo`, etc. > -preview Show the info in a preview window. -clip OR -clipboard Copy the information to your clipboard. -echo echo all of the information with :echo < The default mode can be configured with |g:ale_info_default_mode|. When shown in a preview window, syntax highlights can be defined for the `ale-info` filetype. `:ALEInfoToFile` will write the ALE runtime information to a given filename. The filename works just like `:write`. :ALEReset *:ALEReset* :ALEResetBuffer *:ALEResetBuffer* `:ALEReset` will remove all problems reported by ALE for all buffers. `:ALEResetBuffer` will remove all problems reported for a single buffer. Either command will leave ALE linting enabled, so ALE will report problems when linting is performed again. See |ale-lint| for more information. The following plug mappings are defined, for conveniently defining keybinds: `:ALEReset` - `(ale_reset)` `:ALEResetBuffer` - `(ale_reset_buffer)` ALE can be disabled globally or for a buffer with `:ALEDisable` or `:ALEDisableBuffer`. :ALEStopAllLSPs *:ALEStopAllLSPs* `:ALEStopAllLSPs` will close and stop all channels and jobs for all LSP-like clients, including tsserver, remove all of the data stored for them, and delete all of the problems found for them, updating every linted buffer. This command can be used when LSP clients mess up and need to be restarted. :ALEStopLSP [linter] *:ALEStopLSP* `:ALEStopLSP` will stop a specific language server with a given linter name. Completion is supported for currently running language servers. All language servers with the given name will be stopped across all buffers for all projects. If the command is run with a bang (`:ALEStopLSP!`), all warnings will be suppressed. =============================================================================== 9. API *ale-api* ALE offers a number of functions for running linters or fixers, or defining them. The following functions are part of the publicly documented part of that API, and should be expected to continue to work. Functions documented with Vim autocmd names `ale#Foo` are available in the Vim context, and functions documented with dot names `ale.foo` are available in Lua scripts. ale.env(variable_name, value) *ale.env()* ale#Env(variable_name, value) *ale#Env()* Given a variable name and a string value, produce a string for including in a command for setting environment variables. This function can be used for building a command like so. > :echo string(ale#Env('VAR', 'some value') . 'command') 'VAR=''some value'' command' # On Linux or Mac OSX 'set VAR="some value" && command' # On Windows ale.escape(str) *ale.escape()* ale#Escape(str) *ale#Escape()* Given a string, escape that string so it is ready for shell execution. If the shell is detected to be `cmd.exe`, ALE will apply its own escaping that tries to avoid escaping strings unless absolutely necessary to avoid issues with Windows programs that do not properly handle quoted arguments. In all other cases, ALE will call |shellescape|. ale.get_filename_mappings(buffer, name) *ale.get_filename_mappings()* ale#GetFilenameMappings(buffer, name) *ale#GetFilenameMappings()* Given a `buffer` and the `name` of either a linter for fixer, return a |List| of two-item |List|s that describe mapping to and from the local and foreign file systems for running a particular linter or fixer. See |g:ale_filename_mappings| for details on filename mapping. ale.has(feature) *ale.has()* ale#Has(feature) *ale#Has()* In Vim, `ale#Has` returns `1` if ALE supports a given feature, like |has()| for Vim features. In Lua `ale.has` returns `true` instead, and `false` if a feature is not supported. ALE versions can be checked with version strings in the format `ale#Has('ale-x.y.z')`, such as `ale#Has('ale-2.4.0')`. ale.pad(str) *ale.pad()* ale#Pad(str) *ale#Pad()* Given a string or any |empty()| value, return either the string prefixed with a single space, or an empty string. This function can be used to build parts of a command from variables. ale.queue(delay, [linting_flag, buffer]) *ale.queue()* ale#Queue(delay, [linting_flag, buffer]) *ale#Queue()* Run linters for the current buffer, based on the filetype of the buffer, with a given `delay`. A `delay` of `0` will run the linters immediately. The linters will always be run in the background. Calling this function several times will reset an internal timer so ALE doesn't check buffers too often. An optional `linting_flag` argument can be given. If `linting_flag` is `'lint_file'`, then linters where the `lint_file` option evaluates to `1` will be run. Otherwise, those linters will not be run. An optional `buffer` argument can be given for specifying the buffer to check. The active buffer (`bufnr('')`) will be checked by default. *ale-cool-down* If an exception is thrown when queuing/running ALE linters, ALE will enter a cool down period where it will stop checking anything for a short period of time. This is to prevent ALE from seriously annoying users if a linter is broken, or when developing ALE itself. ale.setup(config) *ale.setup()* Configure ALE global settings, which are documented in |ale-options|. For example: > require("ale").setup({ completion_enabled = true, maximum_file_size = 1024 * 1024, warn_about_trailing_whitespace = false, }) < You can also call this function with `ale.setup.global` to make what context ALE is being configured in less ambiguous if you like. ale.setup.buffer(config) *ale.setup.buffer()* Configure ALE buffer-local settings, which are documented in |ale-options|. For example: > require("ale").setup.buffer({ linters = {"ruff", "pyright"}, fixers = {"ruff"} }) < ale.var(buffer, variable_name) *ale.var()* ale#Var(buffer, variable_name) *ale#Var()* Given a buffer number and an ALE variable name return the value of that if defined in the buffer, and if not defined in the buffer return the global value. The `ale_` prefix will be added to the Vim variable name. The `ale#Var` Vim function will return errors if the variable is not defined in either the buffer or globally. The `ale.var` Lua function will return `nil` if the variable is not defined in either the buffer or globally. ale#command#CreateDirectory(buffer) *ale#command#CreateDirectory()* Create a new temporary directory with a unique name, and manage that directory with |ale#command#ManageDirectory()|, so it will be removed as soon as possible. It is advised to only call this function from a callback function for returning a linter command to run. ale#command#CreateFile(buffer) *ale#command#CreateFile()* Create a new temporary file with a unique name, and manage that file with |ale#command#ManageFile()|, so it will be removed as soon as possible. It is advised to only call this function from a callback function for returning a linter command to run. ale#command#Run(buffer, command, callback, [options]) *ale#command#Run()* Start running a job in the background, and pass the results to the given callback later. This function can be used for computing the results of ALE linter or fixer functions asynchronously with jobs. `buffer` must match the buffer being linted or fixed, `command` must be a |String| for a shell command to execute, `callback` must be defined as a |Funcref| to call later with the results, and an optional |Dictionary| of `options` can be provided. The `callback` will receive the arguments `(buffer, output, metadata)`, where the `buffer` will match the buffer given to the function, the `output` will be a `List` of lines of output from the job that was run, and the `metadata` will be a |Dictionary| with additional information about the job that was run, including: `exit_code` - A |Number| with the exit code for the program that was run. The result of this function is either a special |Dictionary| ALE will use for waiting for the command to finish, or `0` if the job is not started. The The return value of the `callback` will be used as the eventual result for whatever value is being given to ALE. For example: > function! s:GetCommand(buffer, output, meta) abort " Do something with a:output here, from the foo command. " This is used as the command to run for linting. return 'final command' endfunction " ... 'command': {b -> ale#command#Run(b, 'foo', function('s:GetCommand'))} < The result of a callback can also be the result of another call to this function, so that several commands can be arbitrarily chained together. For example: > function! s:GetAnotherCommand(buffer, output, meta) abort " We can finally return this command. return 'last command' endfunction function! s:GetCommand(buffer, output, meta) abort " We can return another deferred result. return ale#command#Run( \ a:buffer, \ 'second command', \ function('s:GetAnotherCommand') \) endfunction " ... 'command': {b -> ale#command#Run(b, 'foo', function('s:GetCommand'))} < The following `options` can be provided. `cwd` - An optional |String| for setting the working directory for the command, just as per |ale#linter#Define|. If not set, or `v:null`, the `cwd` of the last command that spawned this one will be used. `output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or `'none`' for selecting which output streams to read lines from. The default is `'stdout'` `executable` - An executable for formatting into `%e` in the command. If this option is not provided, formatting commands with `%e` will not work. `read_buffer` - If set to `1`, the buffer will be piped into the command. The default is `0`. `input` - When creating temporary files with `%t` or piping text into a command `input` can be set to a |List| of text to use instead of the buffer's text. `filename_mappings` - A |List| of two-item |List|s describing filename mappings to apply for formatted filenames in the command string, as per |g:ale_filename_mappings|. If the call to this function is being used for a linter or fixer, the mappings should be provided with this option, and can be retrieved easily with |ale#GetFilenameMappings()|. The default is `[]`. ale#command#EscapeCommandPart(command_part) *ale#command#EscapeCommandPart()* Given a |String|, return a |String| with all `%` characters replaced with `%%` instead. This function can be used to escape strings which are dynamically generated for commands before handing them over to ALE, so that ALE doesn't treat any strings with `%` formatting sequences specially. ale#command#ManageDirectory(buffer, directory) *ale#command#ManageDirectory()* Like |ale#command#ManageFile()|, but directories and all of their contents will be deleted, akin to `rm -rf directory`, which could lead to loss of data if mistakes are made. This command will also delete any temporary filenames given to it. It is advised to use |ale#command#ManageFile()| instead for deleting single files. ale#command#ManageFile(buffer, filename) *ale#command#ManageFile()* Given a buffer number for a buffer currently running some linting or fixing tasks and a filename, register a filename with ALE for automatic deletion after linting or fixing is complete, or when Vim exits. If Vim exits suddenly, ALE will try its best to remove temporary files, but ALE cannot guarantee with absolute certainty that the files will be removed. It is advised to create temporary files in the operating system's managed temporary file directory, such as with |tempname()|. Directory names should not be given to this function. ALE will only delete files and symlinks given to this function. This is to prevent entire directories from being accidentally deleted, say in cases of writing `dir . '/' . filename` where `filename` is actually `''`, etc. ALE instead manages directories separately with the |ale#command#ManageDirectory| function. ale#completion#OmniFunc(findstart, base) *ale#completion#OmniFunc()* A completion function to use with 'omnifunc'. See |ale-completion|. ale#engine#GetLoclist(buffer) *ale#engine#GetLoclist()* Given a buffer number, this function will return the list of problems reported by ALE for a given buffer in the format accepted by |setqflist()|. A reference to the buffer's list of problems will be returned. The list must be copied before applying |map()| or |filter()|. ale#engine#IsCheckingBuffer(buffer) *ale#engine#IsCheckingBuffer()* Given a buffer number, returns `1` when ALE is busy checking that buffer. This function can be used for status lines, tab names, etc. *ale#fix#registry#Add()* ale#fix#registry#Add(name, func, filetypes, desc, [aliases]) Given a |String| `name` for a name to add to the registry, a |String| `func` for a function name, a |List| `filetypes` for a list of filetypes to set for suggestions, and a |String| `desc` for a short description of the fixer, register a fixer in the registry. The `name` can then be used for |g:ale_fixers| in place of the function name, and suggested for fixing files. An optional |List| of |String|s for aliases can be passed as the `aliases` argument. These aliases can also be used for looking up a fixer function. ALE will search for fixers in the registry first by `name`, then by their `aliases`. For example to register a custom fixer for `luafmt`: > function! FormatLua(buffer) abort return { \ 'command': 'luafmt --stdin' \} endfunction execute ale#fix#registry#Add('luafmt', 'FormatLua', ['lua'], 'luafmt for lua') " You can now use it in g:ale_fixers let g:ale_fixers = { \ 'lua': ['luafmt'] } < ale#linter#Define(filetype, linter) *ale#linter#Define()* Given a |String| for a filetype and a |Dictionary| Describing a linter configuration, add a linter for the given filetype. The dictionaries each offer the following options: `name` The name of the linter. These names will be used by |g:ale_linters| option for enabling/disabling particular linters. This argument is required. `callback` A |String| or |Funcref| for a callback function accepting two arguments (buffer, lines), for a buffer number the output is for, and the lines of output from a linter. This callback function should return a |List| of |Dictionary| objects in the format accepted by |setqflist()|. The |List| will be sorted by line and then column order so it can be searched with a binary search by in future before being passed on to the |location-list|, etc. This argument is required, unless the linter is an LSP linter. In which case, this argument must not be defined, as LSP linters handle diagnostics automatically. See |ale-lsp-linters|. If the function named does not exist, including if the function is later deleted, ALE will behave as if the callback returned an empty list. The keys for each item in the List will be handled in the following manner: *ale-loclist-format* `text` - This error message is required. `detail` - An optional, more descriptive message. This message can be displayed with the `:ALEDetail` command instead of the message for `text`, if set. `lnum` - The line number is required. Any strings will be automatically converted to numbers by using |str2nr()|. Line 0 will be moved to line 1, and lines beyond the end of the file will be moved to the end. `col` - The column number is optional and will default to `0`. Any strings will be automatically converted to number using |str2nr()|. `end_col` - An optional end column number. This key can be set to specify the column problems end on, for improved highlighting. `end_lnum` - An optional end line number. This key can set along with `end_col` for highlighting multi-line problems. `bufnr` - This key represents the buffer number the problems are for. This value will default to the buffer number being checked. The `filename` key can be set instead of this key, and then the eventual `bufnr` value in the final list will either represent the number for an open buffer or `-1` for a file not open in any buffer. `filename` - An optional filename for the file the problems are for. This should be an absolute path to a file. Problems for files which have not yet been opened will be set in those files after they are opened and have been checked at least once. Temporary files in directories used for Vim temporary files with |tempname()| will be assumed to be the buffer being checked, unless the `bufnr` key is also set with a valid number for some other buffer. `vcol` - Defaults to `0`. If set to `1`, ALE will convert virtual column positions for `col` and `end_col` to byte column positions. If the buffer is changed in-between checking it and displaying the results, the calculated byte column positions will probably be wrong. `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, or a |Funcref| for a function to call for computing the executable, accepting a buffer number. The result can be computed with |ale#command#Run()|. This value will be used to check if the program requested is installed or not. If an `executable` is not defined, the command will be run without checking if a program is executable first. Defining an executable path is recommended to avoid starting too many processes. `command` A |String| for a command to run asynchronously, or a |Funcref| for a function to call for computing the command, accepting a buffer number. The result can be computed with |ale#command#Run()|. The command string can be formatted with format markers. See |ale-command-format-strings|. This command will be fed the lines from the buffer to check, and will produce the lines of output given to the `callback`. `cwd` An optional |String| for setting the working directory for the command, or a |Funcref| for a function to call for computing the command, accepting a buffer number. The working directory can be specified as a format string for determining the path dynamically. See |ale-command-format-strings|. To set the working directory to the directory containing the file you're checking, you should probably use `'%s:h'` as the option value. If this option is absent or the string is empty, the `command` will be run with no determined working directory in particular. The directory specified with this option will be used as the default working directory for all commands run in a chain with |ale#command#Run()|, unless otherwise specified. `output_stream` A |String| for the output stream the lines of output should be read from for the command which is run. The accepted values are `'stdout'`, `'stderr'`, and `'both'`. This argument defaults to `'stdout'`. This argument can be set for linter programs which output their errors and warnings to the stderr stream instead of stdout. The option `'both'` will read from both stder and stdout at the same time. `read_buffer` A |Number| (`0` or `1`) indicating whether a command should read the Vim buffer as input via stdin. This option is set to `1` by default, and can be disabled if a command manually reads from a temporary file instead, etc. This option behaves as if it was set to `0` when the `lint_file` option evaluates to `1`. *ale-lint-file* `lint_file` A |Number| (`0` or `1`), or a |Funcref| for a function accepting a buffer number for computing either `0` or `1`, indicating whether a command should read the file instead of the Vim buffer. This option can be used for linters which must check the file on disk, and which cannot check a Vim buffer instead. The result can be computed with |ale#command#Run()|. Linters where the eventual value of this option evaluates to `1` will not be run as a user types, per |g:ale_lint_on_text_changed|. Linters will instead be run only when events occur against the file on disk, including |g:ale_lint_on_enter| and |g:ale_lint_on_save|. Linters where this option evaluates to `1` will also be run when the `:ALELint` command is run. When this option is evaluates to `1`, ALE will behave as if `read_buffer` was set to `0`. *ale-lsp-linters* `lsp` A |String| for defining LSP (Language Server Protocol) linters. This argument may be omitted or `''` when a linter does not represent an LSP linter. When this argument is set to `'stdio'`, then the linter will be defined as an LSP linter which keeps a process for a language server running, and communicates with it directly via a |channel|. `executable` and `command` must be set. When this argument is set to `'socket'`, then the linter will be defined as an LSP linter via a TCP or named pipe socket connection. `address` must be set. ALE will not start a server automatically. When this argument is not empty `project_root` must be defined. `language` can be defined to describe the language for a file. The filetype will be used as the language by default. LSP linters handle diagnostics automatically, so the `callback` argument must not be defined. An optional `completion_filter` callback may be defined for filtering completion results. `initialization_options` may be defined to pass initialization options to the LSP. `lsp_config` may be defined to pass configuration settings to the LSP. `address` A |String| representing an address to connect to, or a |Funcref| accepting a buffer number and returning the |String|. If the value contains a colon, it is interpreted as referring to a TCP socket; otherwise it is interpreted as the path of a named pipe. The result can be computed with |ale#command#Run()|. This argument must only be set if the `lsp` argument is set to `'socket'`. `project_root` A |String| representing a path to the project for the file being checked with the language server, or a |Funcref| accepting a buffer number and returning the |String|. If an empty string is returned, the file will not be checked at all. This argument must only be set if the `lsp` argument is also set to a non-empty string. `language` A |String| representing the name of the language being checked, or a |Funcref| accepting a buffer number and returning the |String|. This string will be sent to the LSP to tell it what type of language is being checked. If a language isn't provided, the language will default to the value of the filetype given to |ale#linter#Define|. `completion_filter` A |String| or |Funcref| for a callback function accepting a buffer number and a completion item. The completion item will be a |Dictionary| following the Language Server Protocol `CompletionItem` interface as described in the specification, available online here: https://microsoft.github.io/language-server-protocol `aliases` A |List| of aliases for the linter name. This argument can be set with alternative names for selecting the linter with |g:ale_linters|. This setting can make it easier to guess the linter name by offering a few alternatives. `initialization_options` A |Dictionary| of initialization options for LSPs, or a |Funcref| for a callback function accepting a buffer number and returning the |Dictionary|. This will be fed (as JSON) to the LSP in the initialize command. `lsp_config` A |Dictionary| for configuring a language server, or a |Funcref| for a callback function accepting a buffer number and returning the |Dictionary|. This will be fed (as JSON) to the LSP in the workspace/didChangeConfiguration command. If temporary files or directories are created for commands run with `command`, then these temporary files or directories can be managed by ALE, for automatic deletion. See |ale#command#ManageFile()| and |ale#command#ManageDirectory| for more information. *ale-command-format-strings* All command strings will be formatted for special character sequences. Any substring `%s` will be replaced with the full path to the current file being edited. This format option can be used to pass the exact filename being edited to a program. For example: > 'command': 'eslint -f unix --stdin --stdin-filename %s' < Any substring `%t` will be replaced with a path to a temporary file. Merely adding `%t` will cause ALE to create a temporary file containing the contents of the buffer being checked. All occurrences of `%t` in command strings will reference the one temporary file. The temporary file will be created inside a temporary directory, and the entire temporary directory will be automatically deleted, following the behavior of |ale#command#ManageDirectory|. This option can be used for some linters which do not support reading from stdin. For example: > 'command': 'ghc -fno-code -v0 %t', < Any substring `%e` will be replaced with the escaped executable supplied with `executable`. This provides a convenient way to define a command string which needs to include a dynamic executable name, but which is otherwise static. For example: > 'command': '%e --some-argument', < The character sequence `%%` can be used to emit a literal `%` into a command, so literal character sequences `%s` and `%t` can be escaped by using `%%s` and `%%t` instead, etc. Some |filename-modifiers| can be applied to `%s` and `%t`. Only `:h`, `:t`, `:r`, and `:e` may be applied, other modifiers will be ignored. Filename modifiers can be applied to the format markers by placing them after them. For example: > 'command': '%s:h %s:e %s:h:t', < Given a path `/foo/baz/bar.txt`, the above command string will generate something akin to `'/foo/baz' 'txt' 'baz'` If a callback for a command generates part of a command string which might possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting behavior is not desired, the |ale#command#EscapeCommandPart()| function can be used to replace those characters to avoid formatting issues. *ale-linter-loading-behavior* Linters for ALE will be loaded by searching |runtimepath| in the following format: > ale_linters//.vim < Any linters which exist anywhere in 'runtimepath' with that directory structure will be automatically loaded for the matching |filetype|. Filetypes containing `.` characters will be split into individual parts, and files will be loaded for each filetype between the `.` characters. Linters can be defined from vimrc and other files as long as this function is loaded first. For example, the following code will define a Hello World linter in vimrc in Vim 8: > " Plugins have to be loaded first. " If you are using a plugin manager, run that first. packloadall call ale#linter#Define('vim', { \ 'name': 'echo-test', \ 'executable': 'echo', \ 'command': 'echo hello world', \ 'callback': {buffer, lines -> map(lines, '{"text": v:val, "lnum": 1}')}, \}) < ale#linter#Get(filetype) *ale#linter#Get()* Return all of linters configured for a given filetype as a |List| of |Dictionary| values in the format specified by |ale#linter#Define()|. Filetypes may be dot-separated to invoke linters for multiple filetypes: for instance, the filetype `javascript.jsx` will return linters for both the `javascript` and `jsx` filetype. Aliases may be defined in as described in |g:ale_linter_aliases|. Aliases are applied after dot-separated filetypes are broken up into their components. ale#linter#PreventLoading(filetype) *ale#linter#PreventLoading()* Given a `filetype`, prevent any more linters from being loaded from |runtimepath| for that filetype. This function can be called from vimrc or similar to prevent ALE from loading linters. *ale#lsp_linter#SendRequest()* ale#lsp_linter#SendRequest(buffer, linter_name, message, [Handler]) Send a custom request to an LSP linter. The arguments are defined as follows: `buffer` A valid buffer number. `linter_name` A |String| identifying an LSP linter that is available and enabled for the |filetype| of `buffer`. `message` A |List| in the form `[is_notification, method, parameters]`, containing three elements: `is_notification` - an |Integer| that has value 1 if the request is a notification, 0 otherwise; `method` - a |String|, identifying an LSP method supported by `linter`; `parameters` - a |dictionary| of LSP parameters that are applicable to `method`. `Handler` Optional argument, meaningful only when `message[0]` is 0. A |Funcref| that is called when a response to the request is received, and takes as unique argument a dictionary representing the response obtained from the server. *ale#other_source#ShowResults()* ale#other_source#ShowResults(buffer, linter_name, loclist) 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()* ale#other_source#StartChecking(buffer, linter_name) 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()* Given the number of a buffer which may have problems, return a |Dictionary| containing information about the number of problems detected by ALE. The following keys are supported: `error` -> The number of problems with type `E` and `sub_type != 'style'` `warning` -> The number of problems with type `W` and `sub_type != 'style'` `info` -> The number of problems with type `I` `style_error` -> The number of problems with type `E` and `sub_type == 'style'` `style_warning` -> The number of problems with type `W` and `sub_type == 'style'` `total` -> The total number of problems. ale#statusline#FirstProblem(buffer, type) *ale#statusline#FirstProblem()* Returns a copy of the first entry in the `loclist` that matches the supplied buffer number and problem type. If there is no such entry, an empty dictionary is returned. Problem type should be one of the strings listed below: `error` -> Returns the first `loclist` item with type `E` and `sub_type != 'style'` `warning` -> First item with type `W` and `sub_type != 'style'` `info` -> First item with type `I` `style_error` -> First item with type `E` and `sub_type == 'style'` `style_warning` -> First item with type `W` and `sub_type == 'style'` b:ale_linted *b:ale_linted* `b:ale_linted` is set to the number of times a buffer has been checked by ALE after all linters for one lint cycle have finished checking a buffer. This variable may not be defined until ALE first checks a buffer, so it should be accessed with |get()| or |getbufvar()|. For example: > " Print a message indicating how many times ALE has checked this buffer. echo 'ALE has checked this buffer ' . get(b:, 'ale_linted') . ' time(s).' " Print 'checked' using getbufvar() if a buffer has been checked. 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. This variable can be read in Lua scripts in the usual way via `vim.g.ale_want_results_buffer`. *ALECompletePost-autocmd* ALECompletePost *ALECompletePost* This |User| autocmd is triggered after ALE inserts an item on |CompleteDone|. This event can be used to run commands after a buffer is changed by ALE as the result of completion. For example, `:ALEFix` can be configured to run automatically when completion is done: > augroup FixAfterComplete autocmd! " Run ALEFix when completion items are added. autocmd User ALECompletePost ALEFix! " If ALE starts fixing a file, stop linters running for now. autocmd User ALEFixPre ALELintStop augroup END < *ALELintPre-autocmd* ALELintPre *ALELintPre* *ALELintPost-autocmd* ALELintPost *ALELintPost* *ALEFixPre-autocmd* ALEFixPre *ALEFixPre* *ALEFixPost-autocmd* ALEFixPost *ALEFixPost* These |User| autocommands are triggered before and after every lint or fix cycle. They can be used to update statuslines, send notifications, etc. The autocmd commands are run with |:silent|, so |:unsilent| is required for echoing messages. For example to change the color of the statusline while the linter is running: > augroup ALEProgress autocmd! autocmd User ALELintPre hi Statusline ctermfg=darkgrey autocmd User ALELintPost hi Statusline ctermfg=NONE augroup END < Or to display the progress in the statusline: > let s:ale_running = 0 let l:stl .= '%{s:ale_running ? "[linting]" : ""}' augroup ALEProgress autocmd! autocmd User ALELintPre let s:ale_running = 1 | redrawstatus autocmd User ALELintPost let s:ale_running = 0 | redrawstatus augroup END < *ALEJobStarted-autocmd* ALEJobStarted *ALEJobStarted* This |User| autocommand is triggered immediately after a job is successfully run. This provides better accuracy for checking linter status with |ale#engine#IsCheckingBuffer()| over |ALELintPre-autocmd|, which is actually triggered before any linters are executed. *ALELSPStarted-autocmd* ALELSPStarted *ALELSPStarted* This |User| autocommand is triggered immediately after an LSP connection is successfully initialized. This provides a way to perform any additional initialization work, such as setting up buffer-level mappings. *ALEWantResults-autocmd* ALEWantResults *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* Special thanks to Mark Grealish (https://www.bhalash.com/) for providing ALE's snazzy looking ale glass logo. Cheers, Mark! =============================================================================== 11. Contact *ale-contact* If you like this plugin, and wish to get in touch, check out the GitHub page for issues and more at https://github.com/dense-analysis/ale If you wish to contact the author of this plugin directly, please feel free to send an email to devw0rp@gmail.com. Please drink responsibly, or not at all, which is ironically the preference of w0rp, who is teetotal. =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: ================================================ FILE: ftplugin/ale-fix-suggest.vim ================================================ " Close the ALEFixSuggest window with the q key. noremap q :q! let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'execute') let b:undo_ftplugin .= ' | execute "silent! unmap q"' ================================================ FILE: ftplugin/ale-info.vim ================================================ " Close the ALEInfo preview window with the q key. noremap q :q! " Explicitly use the default synmaxcol for ale-info. setlocal synmaxcol=3000 function! ALEInfoOpenHelp() abort let l:variable = matchstr(getline('.'), '\v[gb]:ale_[a-z0-9_]+') if !empty(l:variable) execute('help ' . l:variable) endif endfunction " Press space to open :help for an ALE Variable nnoremap :call ALEInfoOpenHelp() let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'execute') let b:undo_ftplugin .= ' | setlocal synmaxcol<' let b:undo_ftplugin .= ' | execute "silent! unmap q"' let b:undo_ftplugin .= ' | execute "silent! nunmap "' let b:undo_ftplugin .= ' | if exists(''*ALEInfoOpenHelp'') | delfunction ALEInfoOpenHelp | endif' ================================================ FILE: ftplugin/ale-preview-selection.vim ================================================ " Close the ALEPreviewWindow window with the q key. noremap q :q! " Disable some keybinds for the selection window. noremap v noremap i noremap I noremap noremap noremap noremap a noremap A noremap o noremap O " Keybinds for opening selection items. noremap :call ale#preview#OpenSelection() noremap t :call ale#preview#OpenSelectionInTab() let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'execute') let b:undo_ftplugin .= ' | execute "silent! unmap q"' let b:undo_ftplugin .= ' | execute "silent! unmap v"' let b:undo_ftplugin .= ' | execute "silent! unmap i"' let b:undo_ftplugin .= ' | execute "silent! unmap I"' let b:undo_ftplugin .= ' | execute "silent! unmap "' let b:undo_ftplugin .= ' | execute "silent! unmap "' let b:undo_ftplugin .= ' | execute "silent! unmap "' let b:undo_ftplugin .= ' | execute "silent! unmap a"' let b:undo_ftplugin .= ' | execute "silent! unmap A"' let b:undo_ftplugin .= ' | execute "silent! unmap o"' let b:undo_ftplugin .= ' | execute "silent! unmap O"' let b:undo_ftplugin .= ' | execute "silent! unmap "' let b:undo_ftplugin .= ' | execute "silent! unmap t"' ================================================ FILE: ftplugin/ale-preview.vim ================================================ " Close the ALEPreviewWindow window with the q key. noremap q :q! let b:undo_ftplugin = get(b:, 'undo_ftplugin', 'execute') let b:undo_ftplugin .= ' | execute "silent! unmap q"' ================================================ FILE: lspconfig.vim ================================================ if get(g:, 'lspconfig', 0) " lspconfig is installed. endif ================================================ FILE: lua/ale/diagnostics.lua ================================================ local ale = require("ale") local module = {} local diagnostic_severity_map = { E = vim.diagnostic.severity.ERROR, W = vim.diagnostic.severity.WARN, I = vim.diagnostic.severity.INFO } -- A map of all possible values that we can consider virtualtext enabled for -- from ALE's setting. local virtualtext_enabled_set = { ["all"] = true, ["2"] = true, [2] = true, ["current"] = true, ["1"] = true, [1] = true, [true] = true, } ---Send diagnostics to the Neovim diagnostics API ---@param buffer number The buffer number to retreive the variable for. ---@param loclist table The loclist array to report as diagnostics. ---@return nil module.send = function(buffer, loclist) local diagnostics = {} -- Convert all the ALE loclist items to the shape that Neovim's diagnostic -- API is expecting. for _, location in ipairs(loclist) do if location.bufnr == buffer then table.insert( diagnostics, -- All line numbers from ALE are 1-indexed, but all line -- numbers in the diagnostics API are 0-indexed, so we have to -- subtract 1 to make this work. { lnum = location.lnum - 1, -- Ending line number, or if we don't have one, just make -- it the same as the starting line number end_lnum = (location.end_lnum or location.lnum) - 1, -- Which column does the error start on? col = math.max((location.col or 1) - 1, 0), -- end_col does not appear to need 1 subtracted. end_col = location.end_col, -- Which severity: error, warning, or info? severity = diagnostic_severity_map[location.type] or "E", -- An error code code = location.code, -- The error message message = location.text, -- e.g. "rubocop" source = location.linter_name, } ) end end local set_signs = ale.var(buffer, "set_signs") local sign_priority = ale.var(buffer, "sign_priority") local signs if (set_signs == 1 or set_signs == true) and sign_priority then -- If signs are enabled, set the priority for them. local local_cfg = { priority = sign_priority } local global_cfg = vim.diagnostic.config().signs if global_cfg == false or global_cfg == true or global_cfg == nil then signs = local_cfg elseif type(global_cfg) == "table" then signs = vim.tbl_extend("force", global_cfg, local_cfg) else -- If a global function is defined, then define a function -- that calls that function when Neovim calls our function. signs = function(...) return vim.tbl_extend("force", global_cfg(...), local_cfg) end end end vim.diagnostic.set( vim.api.nvim_create_namespace("ale"), buffer, diagnostics, { virtual_text = virtualtext_enabled_set[vim.g.ale_virtualtext_cursor] ~= nil, signs = signs, } ) end return module ================================================ FILE: lua/ale/init.lua ================================================ local ale = {} local global_settings = setmetatable({}, { __index = function(_, key) return vim.g['ale_' .. key] end, __newindex = function(_, key, value) vim.g['ale_' .. key] = value end }) local buffer_settings = setmetatable({}, { __index = function(_, key) return vim.b['ale_' .. key] end, __newindex = function(_, key, value) vim.b['ale_' .. key] = value end }) ale.set_global = function(c) for key, value in pairs(c) do global_settings[key] = value end end ale.set_buffer = function(c) for key, value in pairs(c) do buffer_settings[key] = value end end ---(when called) Set global ALE settings, just like ale.setup.global. ---@class ALESetup ---@field global fun(c: table): nil -- Set global ALE settings. ---@field buffer fun(c: table): nil -- Set buffer-local ALE settings. ---@overload fun(c: table): nil ---@type ALESetup ale.setup = setmetatable({ ---Set global ALE settings. ---@param c table The table of ALE settings to set. ---@return nil global = function(c) ale.set_global(c) end, ---Set buffer-local ALE settings. ---@param c table The table of ALE settings to set. ---@return nil buffer = function(c) ale.set_buffer(c) end, }, { __call = function(self, c) self.global(c) end, }) ---Run ALE linters on a buffer after a delay. --- ---If a delay in milliseconds multiple times, the internal timer used by ALE ---will be reset, so ALE doesn't lint too often. --- ---If the `linting_flag` is not 'lint_file' then linters that require files to ---be saved will no be run. ---@param delay number Milliseconds to wait for. A delay of 0 lints immediately. ---@param linting_flag string|nil If set to 'lint_file', run all linters. ---@param buffer number|nil The buffer to check. Defaults to the current buffer. ---@return nil ale.queue = function(delay, linting_flag, buffer) vim.fn["ale#Queue"](delay, linting_flag, buffer) end ---Check if ALE supports a given feature. --- ---The ALE version can be checked with ale.has("ale-1.0.0"), etc. ---@param feature string The feature to test for. ---@return boolean supported If the feature is supported. ale.has = function(feature) return vim.fn["ale#Has"](feature) == 1 end ---Prefix a string with a single space if it is not empty. ---nil will be treated the same as an empty string. --- ---This function is a convenience for chaining options for commands together ---without adding redundant whitespace. ---@param str string|nil A value to pad with whitespace. ---@return string padded A value padded with whitespace. ale.pad = function(str) if str == nil or str == "" then return "" end return " " .. str end ---Get an ALE variable for a buffer (first) or globally (second) ---@param buffer number The buffer number to retreive the variable for. ---@param variable_name string The variable to retrieve. ---@return any value The value for the ALE variable ale.var = function(buffer, variable_name) variable_name = "ale_" .. variable_name local exists, value = pcall(vim.api.nvim_buf_get_var, buffer, variable_name) if exists then return value end return vim.g[variable_name] end ---Escape a string for use in a shell command ---@param str string The string to escape. ---@return string escaped The escaped string. ale.escape = function(str) local shell = vim.fn.fnamemodify(vim.o.shell, ":t") if shell:lower() == "cmd.exe" then local step1 if str:find(" ") then step1 = '"' .. str:gsub('"', '""') .. '"' else step1 = str:gsub("([&|<>^])", "^%1") end local percent_subbed = step1:gsub("%%", "%%%%") return percent_subbed end return vim.fn.shellescape(str) end ---Create a prefix for a shell command for adding environment variables. ---@param variable_name string The environment variable name. ---@param value string The value to set for the environment variable. ---@return string prefix The shell code for prefixing a command. ale.env = function(variable_name, value) if vim.fn.has("win32") then return "set " .. ale.escape(variable_name .. "=" .. value) .. " && " end return variable_name .. "=" .. ale.escape(value) .. " " end ---Get an array of arrays for mapping paths to and from filesystems for an ALE ---linter, as configured in the `filename_mappings` setting. --- ---The result can be used to instruct ALE how to map between filesystems. ---@param buffer number The buffer number. ---@param name string The linter name. ---@return table mappings An array of arrays for mapping filenames. ale.get_filename_mappings = function(buffer, name) local linter_mappings = ale.var(buffer, "filename_mappings") if linter_mappings[1] ~= nil then return linter_mappings end if linter_mappings[name] == nil then name = "*" end return linter_mappings[name] or {} end return ale ================================================ FILE: lua/ale/lsp.lua ================================================ local module = {} module.start = function(config) -- Neovim's luaeval sometimes adds a Boolean key to table we need to remove. if type(config.init_options) == "table" and config.init_options[true] ~= nil then config.init_options[true] = nil end -- ensure init_options uses empty_dict if empty if type(config.init_options) == "table" and next(config.init_options) == nil and getmetatable(config.init_options) == nil then config.init_options = vim.empty_dict() end -- If configuring LSP via a socket connection, then generate the cmd -- using vim.lsp.rpc.connect(), as defined in Neovim documentation. if config.host then local cmd_func = vim.lsp.rpc.connect(config.host, config.port) config.host = nil config.port = nil -- Wrap the cmd function so we don't throw errors back to the user -- if the connection to an address fails to start. -- -- We will separately log in ALE that we failed to start a connection. -- -- In older Neovim versions TCP connections do not function if supplied -- a hostname instead of an address. config.cmd = function(dispatch) local success, result = pcall(cmd_func, dispatch) if success then return result end return nil end end config.handlers = { -- Override Neovim's handling of diagnostics to run through ALE's -- functions so all of the functionality in ALE works. ["textDocument/publishDiagnostics"] = function(err, result, _, _) if err == nil then vim.fn["ale#lsp_linter#HandleLSPDiagnostics"]( config.name, result.uri, result.diagnostics ) end end, -- Handle pull model diagnostic data. ["textDocument/diagnostic"] = function(err, result, request, _) if err == nil then local diagnostics if result.kind == "unchanged" then diagnostics = "unchanged" else diagnostics = result.items end vim.fn["ale#lsp_linter#HandleLSPDiagnostics"]( config.name, request.params.textDocument.uri, diagnostics ) end end, -- When the pull model is enabled we have to handle and return -- some kind of data for a server diagnostic refresh request. ["workspace/diagnostic/refresh"] = function() return {} end, } config.on_init = function(client, _) -- Tell ALE about server capabilities as soon as we can. -- This will inform ALE commands what can be done with each server, -- such as "go to definition" support, etc. vim.fn["ale#lsp#UpdateCapabilities"]( config.name, client.server_capabilities ) -- Neovim calls `on_init` before marking a client as active, meaning -- we can't get a client via get_client_by_id until after `on_init` is -- called. By deferring execution of calling the init callbacks we -- can only call them after the client becomes available, which -- will make notifications for configuration changes work, etc. vim.defer_fn(function() vim.fn["ale#lsp#CallInitCallbacks"](config.name) end, 0) end config.get_language_id = function(bufnr, _) return vim.fn["ale#lsp#GetLanguage"](config.name, bufnr) end local capabilities = vim.lsp.protocol.make_client_capabilities() -- Language servers like Pyright do not enable the diagnostics pull model -- unless dynamicRegistration is enabled for diagnostics. if capabilities.textDocument.diagnostic ~= nil then capabilities.textDocument.diagnostic.dynamicRegistration = true config.capabilities = capabilities end ---@diagnostic disable-next-line: missing-fields return vim.lsp.start(config, { attach = false, silent = true, }) end module.buf_attach = function(args) return vim.lsp.buf_attach_client(args.bufnr, args.client_id) end module.buf_detach = function(args) return vim.lsp.buf_detach_client(args.bufnr, args.client_id) end -- Send a message to an LSP server. -- Notifications do not need to be handled. -- -- 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. module.send_message = function(args) local client = vim.lsp.get_client_by_id(args.client_id) if client == nil then return 0 end if args.is_notification then local success if vim.version().minor >= 11 then -- Supporting Neovim 0.11+ ---@diagnostic disable-next-line success = client.notify(client, args.method, args.params) else -- Supporting Neovim 0.10 and below ---@diagnostic disable-next-line success = client.notify(args.method, args.params) end -- For notifications we send a request and expect no direct response. if success then return -1 end return 0 end local success, request_id local handle_func = function(_, result, _, _) vim.fn["ale#lsp#HandleResponse"](client.name, { id = request_id, result = result, }) end if vim.version().minor >= 11 then -- Supporting Neovim 0.11+ -- We send a request and handle the response. -- -- We set the bufnr to -1 to prevent Neovim from flushing anything, as ALE -- already flushes changes to files before sending requests. ---@diagnostic disable-next-line success, request_id = client.request(client, args.method, args.params, handle_func, -1) else -- Supporting Neovim 0.10 and below ---@diagnostic disable-next-line success, request_id = client.request(args.method, args.params, handle_func, -1) end if success then return request_id end return 0 end return module ================================================ FILE: lua/ale/util.lua ================================================ local M = {} function M.configured_lspconfig_servers() local configs = require 'lspconfig.configs' local keys = {} for key, _ in pairs(configs) do table.insert(keys, key) end return keys end return M ================================================ FILE: plugin/ale.vim ================================================ " Author: w0rp " Description: Main entry point for the plugin: sets up prefs and autocommands " Preferences can be set in vimrc files and so on to configure ale " Sanity Checks if exists('g:loaded_ale_dont_use_this_in_other_plugins_please') finish endif " Set a special flag used only by this plugin for preventing doubly " loading the script. 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') " We check for Neovim 0.2.0+, but we only officially support NeoVim 0.7.0 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. let s:has_features = has('timers') && exists('*job_start') && exists('*ch_close_in') endif if !s:has_features " Only output a warning if editing some special files. if index(['', 'gitcommit'], &filetype) == -1 " no-custom-checks echoerr 'ALE requires NeoVim >= 0.7.0 or Vim 8 with +timers +job +channel' " no-custom-checks echoerr 'Please update your editor appropriately.' endif " Stop here, as it won't work. finish endif " Set this flag so that other plugins can use it, like airline. let g:loaded_ale = 1 " This global variable is used internally by ALE for tracking information for " each buffer which linters are being run against. let g:ale_buffer_info = {} " This global Dictionary tracks data for fixing code. Don't mess with it. let g:ale_fix_buffer_data = {} " User Configuration " This option prevents ALE autocmd commands from being run for particular " filetypes which can cause issues. let g:ale_filetype_blacklist = [ \ 'dirvish', \ 'nerdtree', \ 'qf', \ 'tags', \ 'unite', \] " This Dictionary configures which linters are enabled for which languages. let g:ale_linters = get(g:, 'ale_linters', {}) " This option can be changed to only enable explicitly selected linters. let g:ale_linters_explicit = get(g:, 'ale_linters_explicit', v:false) " Ignoring linters, for disabling some, or ignoring LSP diagnostics. let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {}) " Disabling all language server functionality. let g:ale_disable_lsp = get(g:, 'ale_disable_lsp', 'auto') " This Dictionary configures which functions will be used for fixing problems. let g:ale_fixers = get(g:, 'ale_fixers', {}) " This Dictionary allows users to set up filetype aliases for new filetypes. let g:ale_linter_aliases = get(g:, 'ale_linter_aliases', {}) " This flag can be set with a number of milliseconds for delaying the " execution of a linter when text is changed. The timeout will be set and " cleared each time text is changed, so repeated edits won't trigger the " jobs for linting until enough time has passed after editing is done. let g:ale_lint_delay = get(g:, 'ale_lint_delay', 200) " This flag can be set to 'never' to disable linting when text is changed. " This flag can also be set to 'always' or 'insert' to lint when text is " changed in both normal and insert mode, or only in insert mode respectively. let g:ale_lint_on_text_changed = get(g:, 'ale_lint_on_text_changed', 'normal') " This flag can be set to true or 1 to enable linting when leaving insert mode. let g:ale_lint_on_insert_leave = get(g:, 'ale_lint_on_insert_leave', v:true) " When true or 1 linting is done when a buffer is entered. let g:ale_lint_on_enter = get(g:, 'ale_lint_on_enter', v:true) " When true or 1 linting is done when a buffer is written. let g:ale_lint_on_save = get(g:, 'ale_lint_on_save', v:true) " When true or 1 linting is done when the filetype changes. let g:ale_lint_on_filetype_changed = get(g:, 'ale_lint_on_filetype_changed', v:true) " If set to true or 1, suggestions from LSP servers and tsserver will be shown. let g:ale_lsp_suggestions = get(g:, 'ale_lsp_suggestions', v:false) " When true or 1 files are automatically fixed on save. let g:ale_fix_on_save = get(g:, 'ale_fix_on_save', v:false) " When true or 1 ALE linting is enabled. " Disabling ALE linting does not disable fixing of files. let g:ale_enabled = get(g:, 'ale_enabled', 1) " A Dictionary mapping linter or fixer names to Arrays of two-item Arrays " mapping filename paths from one system to another. let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {}) " This Dictionary configures the default project roots for various linters. let g:ale_root = get(g:, 'ale_root', {}) " These flags dictates if ale uses the quickfix or the loclist (loclist is the " default, quickfix overrides loclist). let g:ale_set_loclist = get(g:, 'ale_set_loclist', v:true) let g:ale_set_quickfix = get(g:, 'ale_set_quickfix', v:false) " This flag can be set to 0 to disable setting signs. " This is enabled by default only if the 'signs' feature exists. let g:ale_set_signs = get(g:, 'ale_set_signs', has('signs') ? v:true : v:false) " This flag can be set to 0 to disable setting error highlights. let g:ale_set_highlights = get(g:, 'ale_set_highlights', has('syntax') ? v:true : v:false) " This List can be configured to exclude particular highlights. let g:ale_exclude_highlights = get(g:, 'ale_exclude_highlights', []) " When set to true or 1 problems on lines are echoed when the cursor moves. let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', v:true) " If set to true or 1 automatically show errors in the preview window. let g:ale_cursor_detail = get(g:, 'ale_cursor_detail', v:false) " This flag can be changed to disable/enable virtual text. let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', (has('nvim-0.3.2') || has('patch-9.0.0297') && has('textprop') && has('popupwin')) ? 'all' : 'disabled') " When set to true or 1 LSP hover messages are shown at the cursor. let g:ale_hover_cursor = get(g:, 'ale_hover_cursor', v:true) " When true or 1 to close the preview window on entering Insert Mode. let g:ale_close_preview_on_insert = get(g:, 'ale_close_preview_on_insert', v:false) " When set to true or 1 balloon support is enabled. let g:ale_set_balloons = get(g:, 'ale_set_balloons', (has('balloon_eval') && has('gui_running')) ? v:true : v:false) " When set to true or 1 use the preview window for showing hover messages. let g:ale_hover_to_preview = get(g:, 'ale_hover_to_preview', v:false) " When set to true or 1 use floating preview windows in Neovim. let g:ale_floating_preview = get(g:, 'ale_floating_preview', v:false) " When set to true or 1 show hove messages in floating windows in Neovim. let g:ale_hover_to_floating_preview = get(g:, 'ale_hover_to_floating_preview', v:false) " When set to true or 1 details are shown in floating windows in Neovim. let g:ale_detail_to_floating_preview = get(g:, 'ale_detail_to_floating_preview', v:false) " Border setting for floating preview windows " " The elements in the list set the characters for the left, top, top-left, " top-right, bottom-right, bottom-left, right, and bottom of the border " respectively let g:ale_floating_window_border = get(g:, 'ale_floating_window_border', ['|', '-', '+', '+', '+', '+', '|', '-']) " When set to true or 1 warnings for trailing whitespace are shown. let g:ale_warn_about_trailing_whitespace = get(g:, 'ale_warn_about_trailing_whitespace', v:true) " When set to true or 1 warnings for trailing blank lines are shown. let g:ale_warn_about_trailing_blank_lines = get(g:, 'ale_warn_about_trailing_blank_lines', v:true) " When set to true or 1 the command history is logged. let g:ale_history_enabled = get(g:, 'ale_history_enabled', v:true) " When set to true or 1 the full output of commands is logged. let g:ale_history_log_output = get(g:, 'ale_history_log_output', v:true) " When set to true or 1 enable ALE's built-in autocompletion functionality. let g:ale_completion_enabled = get(g:, 'ale_completion_enabled', v:false) " When set to true or 1 enable automatic detection of pipenv for Python. let g:ale_python_auto_pipenv = get(g:, 'ale_python_auto_pipenv', v:false) " When set to true or 1 enable automatic detection of poetry for Python. let g:ale_python_auto_poetry = get(g:, 'ale_python_auto_poetry', v:false) " When set to true or 1 enable automatic detection of uv for Python. let g:ale_python_auto_uv = get(g:, 'ale_python_auto_uv', v:false) " When set to true or 1 enable automatically updating environment variables " for running Python linters from virtualenv directories. " " The variables are set based on ALE's virtualenv detection. let g:ale_python_auto_virtualenv = get(g:, 'ale_python_auto_virtualenv', v:false) " This variable can be overridden to set the GO111MODULE environment variable. let g:ale_go_go111module = get(g:, 'ale_go_go111module', '') " The default executable for deno. Must be set before ALE lints any buffers. let g:ale_deno_executable = get(g:, 'ale_deno_executable', 'deno') " If true or 1, enable a popup menu for commands. let g:ale_popup_menu_enabled = get(g:, 'ale_popup_menu_enabled', has('gui_running') ? v:true : v:false) " If true or 1, save hidden files when code actions are applied. let g:ale_save_hidden = get(g:, 'ale_save_hidden', v:false) " If true or 1, disables ALE's built in error display. " " Instead, all errors are piped to the Neovim diagnostics API. let g:ale_use_neovim_diagnostics_api = get(g:, 'ale_use_neovim_diagnostics_api', has('nvim-0.7') ? v:true : v:false) if g:ale_use_neovim_diagnostics_api && !has('nvim-0.7') " no-custom-checks echoerr('Setting g:ale_use_neovim_diagnostics_api to true or 1 requires Neovim 0.7+.') endif " If true or 1, uses Neovim's built-in LSP client to integrate with LSP, which " improves ALE's integration with built-in Neovim tools and other plugins. let g:ale_use_neovim_lsp_api = get(g:, 'ale_use_neovim_lsp_api', has('nvim-0.8') ? v:true : v:false) " If 1, replaces ALE's use of jobs and channels to connect to language " servers, plus the custom code, and instead hooks ALE into Neovim's built-in " language server tools. if g:ale_use_neovim_lsp_api && !has('nvim-0.8') " no-custom-checks echoerr('Setting g:ale_use_neovim_lsp_api to true or 1 requires Neovim 0.8+.') endif if g:ale_set_balloons || g:ale_set_balloons is# 'hover' call ale#balloon#Enable() endif if g:ale_completion_enabled call ale#completion#Enable() endif if g:ale_popup_menu_enabled call ale#code_action#EnablePopUpMenu() endif " Define commands for moving through warnings and errors. command! -bar -nargs=* ALEPrevious \ :call ale#loclist_jumping#WrapJump('before', ) command! -bar -nargs=* ALENext \ :call ale#loclist_jumping#WrapJump('after', ) command! -bar ALEPreviousWrap :call ale#loclist_jumping#Jump('before', 1) command! -bar ALENextWrap :call ale#loclist_jumping#Jump('after', 1) command! -bar ALEFirst :call ale#loclist_jumping#JumpToIndex(0) command! -bar ALELast :call ale#loclist_jumping#JumpToIndex(-1) " A command for showing error details. command! -bar ALEDetail :call ale#cursor#ShowCursorDetail() " Define commands for turning ALE on or off. command! -bar ALEToggle :call ale#toggle#Toggle() command! -bar ALEEnable :call ale#toggle#Enable() command! -bar ALEDisable :call ale#toggle#Disable() command! -bar ALEReset :call ale#toggle#Reset() " Commands for turning ALE on or off for a buffer. command! -bar ALEToggleBuffer :call ale#toggle#ToggleBuffer(bufnr('')) command! -bar ALEEnableBuffer :call ale#toggle#EnableBuffer(bufnr('')) command! -bar ALEDisableBuffer :call ale#toggle#DisableBuffer(bufnr('')) command! -bar ALEResetBuffer :call ale#toggle#ResetBuffer(bufnr('')) " A command to stop all LSP-like clients, including tsserver. command! -bar ALEStopAllLSPs :call ale#lsp#reset#StopAllLSPs() " A command to stop a specific language server, or tsseserver. command! -bar -bang -nargs=1 -complete=customlist,ale#lsp#reset#Complete ALEStopLSP :call ale#lsp#reset#StopLSP(, '') " A command for linting manually. command! -bar ALELint :call ale#Queue(0, 'lint_file') " Stop current jobs when linting. command! -bar ALELintStop :call ale#engine#Stop(bufnr('')) " Commands to manually populate the quickfixes. command! -bar ALEPopulateQuickfix :call ale#list#ForcePopulateErrorList(1) command! -bar ALEPopulateLocList :call ale#list#ForcePopulateErrorList(0) " Define a command to get information about current filetype. command! -bar -nargs=* ALEInfo :call ale#debugging#InfoCommand() " Deprecated and scheduled for removal in 4.0.0. command! -bar ALEInfoToClipboard :call ale#debugging#InfoToClipboardDeprecatedCommand() " Copy ALE information to a file. command! -bar -nargs=1 ALEInfoToFile :call ale#debugging#InfoToFile() " Fix problems in files. command! -bar -bang -nargs=* -complete=customlist,ale#fix#registry#CompleteFixers ALEFix :call ale#fix#Fix(bufnr(''), '', ) " Suggest registered functions to use for fixing problems. command! -bar ALEFixSuggest :call ale#fix#registry#Suggest(&filetype) " Go to definition for tsserver and LSP command! -bar -nargs=* ALEGoToDefinition :call ale#definition#GoToCommandHandler('', ) " Go to type definition for tsserver and LSP command! -bar -nargs=* ALEGoToTypeDefinition :call ale#definition#GoToCommandHandler('type', ) " Go to implementation for tsserver and LSP command! -bar -nargs=* ALEGoToImplementation :call ale#definition#GoToCommandHandler('implementation', ) " Repeat a previous selection in the preview window command! -bar ALERepeatSelection :call ale#preview#RepeatSelection() " Find references for tsserver and LSP command! -bar -nargs=* ALEFindReferences :call ale#references#Find() " Show summary information for the cursor. command! -bar ALEHover :call ale#hover#ShowAtCursor() " Show documentation for the cursor. command! -bar ALEDocumentation :call ale#hover#ShowDocumentationAtCursor() " Search for appearances of a symbol, such as a type name or function name. command! -nargs=1 ALESymbolSearch :call ale#symbol#Search() " Complete text with tsserver and LSP command! -bar ALEComplete :call ale#completion#GetCompletions('ale-manual') " Try to find completions for the current symbol that add additional text. command! -bar ALEImport :call ale#completion#Import() " Rename symbols using tsserver and LSP command! -bar -bang ALERename :call ale#rename#Execute() " Rename file using tsserver command! -bar -bang ALEFileRename :call ale#filerename#Execute() " Apply code actions to a range. command! -bar -range ALECodeAction :call ale#codefix#Execute() " Organize import statements using tsserver command! -bar ALEOrganizeImports :call ale#organize_imports#Execute() " mappings for commands nnoremap (ale_previous) :ALEPrevious nnoremap (ale_previous_wrap) :ALEPreviousWrap nnoremap (ale_previous_error) :ALEPrevious -error nnoremap (ale_previous_wrap_error) :ALEPrevious -wrap -error nnoremap (ale_previous_warning) :ALEPrevious -warning nnoremap (ale_previous_wrap_warning) :ALEPrevious -wrap -warning nnoremap (ale_next) :ALENext nnoremap (ale_next_wrap) :ALENextWrap nnoremap (ale_next_error) :ALENext -error nnoremap (ale_next_wrap_error) :ALENext -wrap -error nnoremap (ale_next_warning) :ALENext -warning nnoremap (ale_next_wrap_warning) :ALENext -wrap -warning nnoremap (ale_first) :ALEFirst nnoremap (ale_last) :ALELast nnoremap (ale_toggle) :ALEToggle nnoremap (ale_enable) :ALEEnable nnoremap (ale_disable) :ALEDisable nnoremap (ale_reset) :ALEReset nnoremap (ale_toggle_buffer) :ALEToggleBuffer nnoremap (ale_enable_buffer) :ALEEnableBuffer nnoremap (ale_disable_buffer) :ALEDisableBuffer nnoremap (ale_reset_buffer) :ALEResetBuffer nnoremap (ale_lint) :ALELint nnoremap (ale_detail) :ALEDetail nnoremap (ale_fix) :ALEFix nnoremap (ale_go_to_definition) :ALEGoToDefinition nnoremap (ale_go_to_definition_in_tab) :ALEGoToDefinition -tab nnoremap (ale_go_to_definition_in_split) :ALEGoToDefinition -split nnoremap (ale_go_to_definition_in_vsplit) :ALEGoToDefinition -vsplit nnoremap (ale_go_to_type_definition) :ALEGoToTypeDefinition nnoremap (ale_go_to_type_definition_in_tab) :ALEGoToTypeDefinition -tab nnoremap (ale_go_to_type_definition_in_split) :ALEGoToTypeDefinition -split nnoremap (ale_go_to_type_definition_in_vsplit) :ALEGoToTypeDefinition -vsplit nnoremap (ale_go_to_implementation) :ALEGoToImplementation nnoremap (ale_go_to_implementation_in_tab) :ALEGoToImplementation -tab nnoremap (ale_go_to_implementation_in_split) :ALEGoToImplementation -split nnoremap (ale_go_to_implementation_in_vsplit) :ALEGoToImplementation -vsplit nnoremap (ale_find_references) :ALEFindReferences nnoremap (ale_hover) :ALEHover nnoremap (ale_documentation) :ALEDocumentation inoremap (ale_complete) :ALEComplete nnoremap (ale_import) :ALEImport nnoremap (ale_rename) :ALERename nnoremap (ale_filerename) :ALEFileRename nnoremap (ale_code_action) :ALECodeAction nnoremap (ale_repeat_selection) :ALERepeatSelection nnoremap (ale_info) :ALEInfo nnoremap (ale_info_echo) :ALEInfo -echo nnoremap (ale_info_clipboard) :ALEInfo -clipboard nnoremap (ale_info_preview) :ALEInfo -preview " Set up autocmd groups now. call ale#events#Init() " Housekeeping augroup ALECleanupGroup autocmd! " Clean up buffers automatically when they are unloaded. autocmd BufDelete * if exists('*ale#engine#Cleanup') | call ale#engine#Cleanup(str2nr(expand(''))) | endif autocmd QuitPre * call ale#events#QuitEvent(str2nr(expand(''))) if exists('##VimSuspend') autocmd VimSuspend * if exists('*ale#engine#CleanupEveryBuffer') | call ale#engine#CleanupEveryBuffer() | endif endif augroup END ================================================ FILE: rplugin/python3/deoplete/sources/ale.py ================================================ """ A Deoplete source for ALE completion via tsserver and LSP. """ __author__ = 'Joao Paulo, w0rp' try: from deoplete.source.base import Base except ImportError: # Mock the Base class if deoplete isn't available, as mock isn't available # in the Docker image. class Base(object): def __init__(self, vim): pass # Make sure this code is valid in Python 2, used for running unit tests. class Source(Base): def __init__(self, vim): super(Source, self).__init__(vim) self.name = 'ale' self.mark = '[L]' self.rank = 1000 self.is_bytepos = True self.min_pattern_length = 1 self.is_volatile = True # Do not forget to update s:trigger_character_map in completion.vim in # updating entries in this map. self.input_patterns = { '_': r'\.\w*$', 'rust': r'(\.|::)\w*$', 'typescript': r'(\.|\'|")\w*$', 'cpp': r'(\.|::|->)\w*$', 'c': r'(\.|->)\w*$', } # Returns an integer for the start position, as with omnifunc. def get_complete_position(self, context): return self.vim.call( 'ale#completion#GetCompletionPositionForDeoplete', context['input'] ) def gather_candidates(self, context): # Stop early if ALE can't provide completion data for this buffer. if not self.vim.call('ale#completion#CanProvideCompletions'): return None event = context.get('event') if event == 'Async': result = self.vim.call('ale#completion#GetCompletionResult') return result or [] if context.get('is_refresh'): self.vim.command( "call ale#completion#GetCompletions('ale-callback', " + "{'callback': {completions -> deoplete#auto_complete() }})" ) return [] ================================================ FILE: run-tests ================================================ #!/usr/bin/env bash # shellcheck disable=SC2317 DOCKER=${DOCKER:-docker} export DOCKER # Author: w0rp # # This script runs tests for the ALE project. Run `./run-tests --help` for # options, or read the output below. # image=docker.io/denseanalysis/ale # Create docker image tag based on Dockerfile contents if [ -n "$(command -v md5)" ]; then image_tag=$(md5 -q Dockerfile) else image_tag=$(md5sum Dockerfile | cut -d' ' -f1) fi git_version=$(git describe --always --tags) # Used in all test scripts for running the selected Docker image. DOCKER_RUN_IMAGE="$image:$image_tag" export DOCKER_RUN_IMAGE tests='test/*.vader test/*/*.vader test/*/*/*.vader' # These flags are forwarded to the script for running Vader tests. verbose_flag='' quiet_flag='' run_neovim_07_tests=1 run_neovim_08_tests=1 run_vim_80_tests=1 run_vim_90_tests=1 run_lua_tests=1 run_linters=1 while [ $# -ne 0 ]; do case $1 in -v) verbose_flag='-v' shift ;; -q) quiet_flag='-q' shift ;; --build-image) run_vim_80_tests=0 run_vim_90_tests=0 run_neovim_07_tests=0 run_neovim_08_tests=0 run_lua_tests=0 run_linters=0 shift ;; --neovim-only) run_vim_80_tests=0 run_vim_90_tests=0 run_lua_tests=0 run_linters=0 shift ;; --neovim-07-only) run_neovim_08_tests=0 run_vim_80_tests=0 run_vim_90_tests=0 run_lua_tests=0 run_linters=0 shift ;; --neovim-08-only) run_neovim_07_tests=0 run_vim_80_tests=0 run_vim_90_tests=0 run_lua_tests=0 run_linters=0 shift ;; --vim-only) run_neovim_07_tests=0 run_neovim_08_tests=0 run_lua_tests=0 run_linters=0 shift ;; --vim-80-only) run_neovim_07_tests=0 run_neovim_08_tests=0 run_vim_90_tests=0 run_lua_tests=0 run_linters=0 shift ;; --vim-90-only) run_neovim_07_tests=0 run_neovim_08_tests=0 run_vim_80_tests=0 run_lua_tests=0 run_linters=0 shift ;; --linters-only) run_vim_80_tests=0 run_vim_90_tests=0 run_neovim_07_tests=0 run_neovim_08_tests=0 run_lua_tests=0 shift ;; --lua-only) run_vim_80_tests=0 run_vim_90_tests=0 run_neovim_07_tests=0 run_neovim_08_tests=0 run_linters=0 shift ;; --fast) run_vim_80_tests=0 run_vim_90_tests=0 run_neovim_07_tests=0 run_neovim_08_tests=1 shift ;; --help) echo 'Usage: ./run-tests [OPTION]... [FILE]...' echo echo 'Filenames can be given as arguments to run a subset of tests.' echo 'For example: ./run-tests test/test_ale_var.vader' echo echo 'Options:' echo ' -v Enable verbose output' echo ' -q Hide output for successful tests' echo ' --build-image Run docker image build only.' echo ' --neovim-only Run tests only for Neovim' echo ' --neovim-07-only Run tests only for Neovim 0.7' echo ' --neovim-08-only Run tests only for Neovim 0.8' echo ' --vim-only Run tests only for Vim' echo ' --vim-80-only Run tests only for Vim 8.2' echo ' --vim-90-only Run tests only for Vim 9.0' echo ' --lua-only Run only Lua tests' echo ' --linters-only Run only Vint and custom checks' echo ' --fast Run only the fastest Vim and custom checks' echo ' --help Show this help text' echo ' -- Stop parsing options after this' exit 0 ;; --) shift break ;; -?*) echo "Invalid argument: $1" 1>&2 exit 1 ;; *) break ;; esac done # Allow tests to be passed as arguments. if [ $# -ne 0 ]; then # This doesn't perfectly handle work splitting, but none of our files # have spaces in the names. tests="$*" # Don't run other tools when targeting tests. run_linters=0 run_lua_tests=0 fi # Delete .swp files in the test directory, which cause Vim 8 to hang. find test -name '*.swp' -delete set -eu # Check if docker un image is available locally has_image=$(docker images --quiet "denseanalysis/ale:${image_tag}" | wc -l) if [[ "$DOCKER" == docker ]]; then arch=$(docker info -f '{{ .Architecture }}') elif [[ "$DOCKER" == podman ]]; then arch=$(podman info -f '{{ .Host.Arch }}') if [[ "$arch" == "amd64" ]]; then arch="x86_64" fi else echo "The DOCKER environment variable must be docker or podman, not ${DOCKER}" exit 1 fi download_image() { if [[ $arch != x86_64 ]]; then echo "Pre-built docker image is not available for architecture ${arch}" return 1 fi echo "Downloading run image ${image}:${image_tag}" docker pull "${image}:${image_tag}" &> /dev/null } if [ "$has_image" -eq 0 ] && ! download_image; then echo "Building run image ${image}:${image_tag}" build_args=( --build-arg GIT_VERSION="$git_version" ) if [[ $arch != x86_64 ]]; then echo "Building testbed/vim:24 for $arch" testbed_vim_ref=902917c4caa50db2f2e80009b839605602f9f014 "$DOCKER" build -t "testbed/vim:$testbed_vim_ref" "https://github.com/Vimjas/vim-testbed.git#$testbed_vim_ref" build_args+=( --build-arg TESTBED_VIM_VERSION="$testbed_vim_ref" ) fi "$DOCKER" build "${build_args[@]}" -t "${image}:${image_tag}" . "$DOCKER" tag "${image}:${image_tag}" "${image}:latest" if [[ -z "${DOCKER_HUB_USER:-}" || -z "${DOCKER_HUB_PASS:-}" ]]; then echo "Docker Hub credentials not set, skip push" else echo "Push ${image}:${image_tag} to Docker Hub" echo "$DOCKER_HUB_PASS" | docker login -u "$DOCKER_HUB_USER" --password-stdin docker push "${image}:${image_tag}" fi else if [ -z "$quiet_flag" ]; then echo "Docker run image ${image}:${image_tag} ready" fi fi "$DOCKER" tag "${image}:${image_tag}" "${image}:latest" output_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir') trap '{ rm -rf "$output_dir"; }' EXIT file_number=0 pid_list='' # Used for killing tests when you kill the script. cancel_tests() { set +e if [ -n "$pid_list" ]; then for pid in $pid_list; do kill "$pid" wait "$pid" done fi # shellcheck disable=SC2046 docker kill $(docker ps -a -q --filter ancestor="$image" --format='{{.ID}}') &> /dev/null if [ -d "$output_dir" ]; then rm -rf "$output_dir" fi echo exit 1 } trap cancel_tests INT TERM for vim in $("$DOCKER" run --rm "$DOCKER_RUN_IMAGE" ls /vim-build/bin | grep '^neovim\|^vim' ); do if ( [[ $vim =~ ^vim-v8.0 ]] && ((run_vim_80_tests)) ) \ || ( [[ $vim =~ ^vim-v9.0 ]] && ((run_vim_90_tests)) ) \ || ( [[ $vim =~ ^neovim-v0.7 ]] && ((run_neovim_07_tests)) ) \ || ( [[ $vim =~ ^neovim-v0.8 ]] && ((run_neovim_08_tests)) ); then echo "Starting Vim: $vim..." file_number=$((file_number+1)) test/script/run-vader-tests $quiet_flag $verbose_flag "$vim" "$tests" \ > "$output_dir/$file_number" 2>&1 & pid_list="$pid_list $!" fi done if ((run_lua_tests)); then echo "Starting Lua tests..." file_number=$((file_number+1)) test/script/run-lua-tests $quiet_flag > "$output_dir/$file_number" 2>&1 & pid_list="$pid_list $!" fi if ((run_linters)); then echo "Starting Vint..." file_number=$((file_number+1)) test/script/run-vint > "$output_dir/$file_number" 2>&1 & pid_list="$pid_list $!" echo "Starting Custom checks..." file_number=$((file_number+1)) test/script/custom-checks &> "$output_dir/$file_number" 2>&1 & pid_list="$pid_list $!" fi echo failed=0 index=0 for pid in $pid_list; do this_failed=0 index=$((index+1)) if ! wait "$pid"; then failed=1 this_failed=1 fi # Hide output for things that passed if -q is set. if [ "$quiet_flag" != '-q' ] || ((this_failed)); then cat "$output_dir/$index" fi done if ((failed)); then echo 'Something went wrong!' else echo 'All tests passed!' fi exit $failed ================================================ FILE: run-tests.bat ================================================ @echo off REM Run tests on Windows. REM REM To run these tests, you should set up your Windows machine with the same REM paths that are used in AppVeyor. set tests=test/*.vader test/*/*.vader test/*/*/*.vader test/*/*/*/*.vader REM Use the first argument for selecting tests to run. if not "%1"=="" set tests=%1 set VADER_OUTPUT_FILE=%~dp0\vader_output REM Automatically re-run Windows tests, which can fail some times. set tries=0 :RUN_TESTS set /a tries=%tries%+1 type nul > "%VADER_OUTPUT_FILE%" C:\vim\vim\vim80\vim.exe -u test/vimrc "+Vader! %tests%" set code=%ERRORLEVEL% IF %code% EQU 0 GOTO :SHOW_RESULTS IF %tries% GEQ 2 GOTO :SHOW_RESULTS GOTO :RUN_TESTS :SHOW_RESULTS type "%VADER_OUTPUT_FILE%" del "%VADER_OUTPUT_FILE%" exit /B %code% ================================================ FILE: supported-tools.md ================================================ # ALE Supported Languages and Tools This plugin supports the following languages and tools. All available tools will be run in combination, so they can be complementary. **Legend** | Key | Definition | | -------------- | ----------------------------------------------------------------- | |:speech_balloon:| Language Server Protocol (LSP) | | :floppy_disk: | May only run on files on disk (see: `help ale-lint-file-linters` | | :warning: | Disabled by default | --- * Ada * [ada_language_server](https://github.com/AdaCore/ada_language_server) :speech_balloon: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [gcc](https://gcc.gnu.org) * [gnatpp](https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ugn/gnat_utility_programs.html#the-gnat-pretty-printer-gnatpp) :floppy_disk: * Ansible * [ansible-language-server](https://github.com/ansible/ansible-language-server/) * [ansible-lint](https://github.com/willthames/ansible-lint) :floppy_disk: * API Blueprint * [drafter](https://github.com/apiaryio/drafter) * APKBUILD * [apkbuild-fixer](https://gitlab.alpinelinux.org/Leo/atools) :speech_balloon: * [apkbuild-lint](https://gitlab.alpinelinux.org/Leo/atools) :speech_balloon: * [secfixes-check](https://gitlab.alpinelinux.org/Leo/atools) :speech_balloon: * AsciiDoc * [alex](https://github.com/get-alex/alex) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [languagetool](https://languagetool.org/) :floppy_disk: :speech_balloon: * [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) * ASM * [gcc](https://gcc.gnu.org) * [llvm-mc](https://llvm.org) * Astro * [eslint](http://eslint.org/) * [prettier](https://github.com/prettier/prettier) * AVRA * [avra](https://github.com/Ro5bert/avra) * Awk * [gawk](https://www.gnu.org/software/gawk/) * Bash * [bashate](https://github.com/openstack/bashate) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [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) * Bats * [shellcheck](https://www.shellcheck.net/) * Bazel * [buildifier](https://github.com/bazelbuild/buildtools) :speech_balloon: * BibTeX * [bibclean](http://ftp.math.utah.edu/pub/bibclean/) * Bicep * [bicep](https://github.com/Azure/bicep) :floppy_disk: :speech_balloon: * Bindzone * [checkzone](https://bind9.readthedocs.io/en/stable/manpages.html#named-checkzone-zone-file-validation-tool) * BitBake * [oelint-adv](https://github.com/priv-kweihmann/oelint-adv) * Bourne Shell * shell [-n flag](http://linux.die.net/man/1/sh) * [shellcheck](https://www.shellcheck.net/) * [shfmt](https://github.com/mvdan/sh) * C * [astyle](http://astyle.sourceforge.net/) * [ccls](https://github.com/MaskRay/ccls) :speech_balloon: * [clang](http://clang.llvm.org/) * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) :floppy_disk: * [clangd](https://clang.llvm.org/extra/clangd.html) :speech_balloon: * [clangtidy](http://clang.llvm.org/extra/clang-tidy/) :floppy_disk: * [cppcheck](http://cppcheck.sourceforge.net) * [cpplint](https://github.com/cpplint/cpplint) * [cquery](https://github.com/cquery-project/cquery) :speech_balloon: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [flawfinder](https://www.dwheeler.com/flawfinder/) * [gcc](https://gcc.gnu.org/) * [uncrustify](https://github.com/uncrustify/uncrustify) * C# * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [csc](http://www.mono-project.com/docs/about-mono/languages/csharp/) :floppy_disk: see:`help ale-cs-csc` for details and configuration * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [dotnet-format](https://github.com/dotnet/format) * [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/) :floppy_disk: see:`help ale-cs-mcsc` for details and configuration * [uncrustify](https://github.com/uncrustify/uncrustify) * C++ (filetype cpp) * [astyle](http://astyle.sourceforge.net/) * [ccls](https://github.com/MaskRay/ccls) :speech_balloon: * [clang](http://clang.llvm.org/) * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [clangcheck](http://clang.llvm.org/docs/ClangCheck.html) :floppy_disk: * [clangd](https://clang.llvm.org/extra/clangd.html) :speech_balloon: * [clangtidy](http://clang.llvm.org/extra/clang-tidy/) :floppy_disk: * [clazy](https://github.com/KDE/clazy) :floppy_disk: * [cppcheck](http://cppcheck.sourceforge.net) * [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) :floppy_disk: * [cquery](https://github.com/cquery-project/cquery) :speech_balloon: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [flawfinder](https://www.dwheeler.com/flawfinder/) * [gcc](https://gcc.gnu.org/) * [uncrustify](https://github.com/uncrustify/uncrustify) * C3 * [c3lsp](https://github.com/pherrymason/c3-lsp) :speech_balloon: * Cairo * [scarb](https://docs.swmansion.com/scarb/) :floppy_disk: * [starknet](https://starknet.io/docs) * Chef * [cookstyle](https://docs.chef.io/cookstyle.html) * [foodcritic](http://www.foodcritic.io/) :floppy_disk: * Clojure * [clj-kondo](https://github.com/borkdude/clj-kondo) * [cljfmt](https://github.com/weavejester/cljfmt) * [joker](https://github.com/candid82/joker) * CloudFormation * [cfn-python-lint](https://github.com/awslabs/cfn-python-lint) * [checkov](https://github.com/bridgecrewio/checkov) * CMake * [cmake-format](https://github.com/cheshirekow/cmake_format) * [cmake-lint](https://github.com/cheshirekow/cmake_format) * [cmakelint](https://github.com/cmake-lint/cmake-lint) * CoffeeScript * [coffee](http://coffeescript.org/) * [coffeelint](https://www.npmjs.com/package/coffeelint) * Crystal * [ameba](https://github.com/veelenga/ameba) :floppy_disk: * [crystal](https://crystal-lang.org/) :floppy_disk: * CSS * [VSCode CSS language server](https://github.com/hrsh7th/vscode-langservers-extracted) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [css-beautify](https://github.com/beautify-web/js-beautify) * [csslint](http://csslint.net/) * [fecs](http://fecs.baidu.com/) * [prettier](https://github.com/prettier/prettier) * [stylelint](https://github.com/stylelint/stylelint) * Cucumber * [cucumber](https://cucumber.io/) * CUDA * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [clangd](https://clang.llvm.org/extra/clangd.html) :speech_balloon: * [nvcc](http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html) :floppy_disk: * Cypher * [cypher-lint](https://github.com/cleishm/libcypher-parser) * Cython (pyrex filetype) * [cython](http://cython.org/) * D * [dfmt](https://github.com/dlang-community/dfmt) * [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) :floppy_disk: * Dart * [analysis_server](https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server) * [dart-analyze](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) :floppy_disk: * [dart-format](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) * [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) * [language_server](https://github.com/natebosch/dart_language_server) * desktop * [desktop-file-validate](https://www.freedesktop.org/wiki/Software/desktop-file-utils/) * Dhall * [dhall-format](https://github.com/dhall-lang/dhall-lang) * [dhall-freeze](https://github.com/dhall-lang/dhall-lang) * [dhall-lint](https://github.com/dhall-lang/dhall-lang) * Dockerfile * [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint) * [dockerlinter](https://github.com/buddy-works/dockerfile-linter) * [dprint](https://dprint.dev) * [hadolint](https://github.com/hadolint/hadolint) * Elixir * [credo](https://github.com/rrrene/credo) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) :warning: * [dialyxir](https://github.com/jeremyjh/dialyxir) * [dogma](https://github.com/lpil/dogma) :floppy_disk: * [elixir-ls](https://github.com/elixir-lsp/elixir-ls) :warning: :speech_balloon: * [expert](https://github.com/elixir-lang/expert) :warning: :speech_balloon: * [lexical](https://github.com/lexical-lsp/lexical) :warning: :speech_balloon: * [mix](https://hexdocs.pm/mix/Mix.html) :warning: :floppy_disk: * Elm * [elm-format](https://github.com/avh4/elm-format) * [elm-ls](https://github.com/elm-tooling/elm-language-server) * [elm-make](https://github.com/elm/compiler) * Erb * [erb](https://apidock.com/ruby/ERB) * [erb-formatter](https://github.com/nebulab/erb-formatter) * [erblint](https://github.com/Shopify/erb-lint) * [erubi](https://github.com/jeremyevans/erubi) * [erubis](https://github.com/kwatch/erubis) * [htmlbeautifier](https://github.com/threedaymonk/htmlbeautifier) * [ruumba](https://github.com/ericqweinstein/ruumba) * Erlang * [SyntaxErl](https://github.com/ten0s/syntaxerl) * [dialyzer](http://erlang.org/doc/man/dialyzer.html) :floppy_disk: * [elvis](https://github.com/inaka/elvis) :floppy_disk: * [erlang-mode](https://www.erlang.org/doc/apps/tools/erlang_mode_chapter.html) (The Erlang mode for Emacs) :speech_balloon: * [erlang_ls](https://github.com/erlang-ls/erlang_ls) :speech_balloon: * [erlc](http://erlang.org/doc/man/erlc.html) * [erlfmt](https://github.com/WhatsApp/erlfmt) * Fish * fish [-n flag](https://linux.die.net/man/1/fish) * [fish_indent](https://fishshell.com/docs/current/cmds/fish_indent.html) * Fortran * [fortitude](https://github.com/PlasmaFAIR/fortitude) * [gcc](https://gcc.gnu.org/) * [language_server](https://github.com/hansec/fortran-language-server) :speech_balloon: * Fountain * [proselint](http://proselint.com/) * FusionScript * [fusion-lint](https://github.com/RyanSquared/fusionscript) * Git Commit Messages * [gitlint](https://github.com/jorisroovers/gitlint) * Gleam * [gleam_format](https://github.com/gleam-lang/gleam) :speech_balloon: * [gleamlsp](https://github.com/gleam-lang/gleam) :speech_balloon: * GLSL * [glslang](https://github.com/KhronosGroup/glslang) * [glslls](https://github.com/svenstaro/glsl-language-server) :speech_balloon: * Go * [bingo](https://github.com/saibing/bingo) :warning: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) :warning: * [go build](https://golang.org/cmd/go/) :warning: :floppy_disk: * [go mod](https://golang.org/cmd/go/) :warning: :floppy_disk: * [go vet](https://golang.org/cmd/vet/) :floppy_disk: * [gofmt](https://golang.org/cmd/gofmt/) * [gofumpt](https://github.com/mvdan/gofumpt) * [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) :warning: :speech_balloon: * [golangci-lint](https://github.com/golangci/golangci-lint) :warning: :floppy_disk: * [golangserver](https://github.com/sourcegraph/go-langserver) :warning: * [golines](https://github.com/segmentio/golines) * [gopls](https://github.com/golang/tools/blob/master/gopls/README.md) :speech_balloon: * [gosimple](https://staticcheck.io/changes/2019.2/#deprecated) :warning: :floppy_disk: :speech_balloon: * [gotype](https://godoc.org/golang.org/x/tools/cmd/gotype) :warning: :floppy_disk: :speech_balloon: * [revive](https://github.com/mgechev/revive) :warning: :floppy_disk: * [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) :warning: :floppy_disk: :speech_balloon: * Go HTML Templates * [djlint](https://djlint.com/) * GraphQL * [eslint](http://eslint.org/) * [gqlint](https://github.com/happylinks/gqlint) * [prettier](https://github.com/prettier/prettier) * Groovy * [npm-groovy-lint](https://github.com/nvuillam/npm-groovy-lint) * Hack * [hack](http://hacklang.org/) * [hackfmt](https://github.com/facebook/hhvm/tree/master/hphp/hack/hackfmt) * [hhast](https://github.com/hhvm/hhast) :warning: (see `:help ale-integration-hack`) :speech_balloon: * Haml * [haml-lint](https://github.com/brigade/haml-lint) * Handlebars * [djlint](https://djlint.com/) * [ember-template-lint](https://github.com/rwjblue/ember-template-lint) * Haskell * [brittany](https://github.com/lspitzner/brittany) :speech_balloon: * [cabal-ghc](https://www.haskell.org/cabal/) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [floskell](https://github.com/ennocramer/floskell) * [fourmolu](https://github.com/fourmolu/fourmolu) * [ghc](https://www.haskell.org/ghc/) * [ghc-mod](https://github.com/DanielG/ghc-mod) * [hdevtools](https://hackage.haskell.org/package/hdevtools) :speech_balloon: * [hfmt](https://github.com/danstiner/hfmt) * [hie](https://github.com/haskell/haskell-ide-engine) * [hindent](https://hackage.haskell.org/package/hindent) * [hlint](https://hackage.haskell.org/package/hlint) * [hls](https://github.com/haskell/haskell-language-server) * [ormolu](https://github.com/tweag/ormolu) * [stack-build](https://haskellstack.org/) :floppy_disk: * [stack-ghc](https://haskellstack.org/) * [stylish-haskell](https://github.com/jaspervdj/stylish-haskell) * HCL * [packer-fmt](https://github.com/hashicorp/packer) * [terraform-fmt](https://github.com/hashicorp/terraform) * HTML * [VSCode HTML language server](https://github.com/hrsh7th/vscode-langservers-extracted) * [alex](https://github.com/get-alex/alex) * [angular](https://www.npmjs.com/package/@angular/language-server) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [djlint](https://www.djlint.com/) * [eslint](https://github.com/BenoitZugmeyer/eslint-plugin-html) * [fecs](http://fecs.baidu.com/) * [html-beautify](https://beautifier.io/) * [htmlhint](http://htmlhint.com/) * [prettier](https://github.com/prettier/prettier) * [proselint](http://proselint.com/) * [rustywind](https://github.com/avencera/rustywind) * [superhtml](https://github.com/kristoff-it/superhtml) * [tidy](http://www.html-tidy.org/) * [write-good](https://github.com/btford/write-good) * HTML Angular * [djlint](https://djlint.com/) * HTML Django * [djlint](https://djlint.com/) * HTTP * [kulala_fmt](https://github.com/mistweaverco/kulala-fmt) * Hurl * [hurlfmt](https://hurl.dev) * Idris * [idris](http://www.idris-lang.org/) * Ink * [ink-language-server](https://github.com/ephread/ink-language-server) * Inko * [inko](https://inko-lang.org/) :floppy_disk: * ISPC * [ispc](https://ispc.github.io/) :floppy_disk: * Java * [PMD](https://pmd.github.io/) * [checkstyle](http://checkstyle.sourceforge.net) :floppy_disk: * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [eclipselsp](https://github.com/eclipse/eclipse.jdt.ls) :speech_balloon: * [google-java-format](https://github.com/google/google-java-format) * [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html) * [javalsp](https://github.com/georgewfraser/vscode-javac) :speech_balloon: * [uncrustify](https://github.com/uncrustify/uncrustify) * JavaScript * [biome](https://biomejs.dev/) * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [deno](https://deno.land/) * [dprint](https://dprint.dev/) * [eslint](http://eslint.org/) * [fecs](http://fecs.baidu.com/) * [flow](https://flowtype.org/) :speech_balloon: * [jscs](https://jscs-dev.github.io/) * [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/) * [tsserver](https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-%28tsserver%29) * [xo](https://github.com/sindresorhus/xo) * Jinja * [djlint](https://djlint.com/) * [j2lint](https://github.com/aristanetworks/j2lint/) * JSON * [VSCode JSON language server](https://github.com/hrsh7th/vscode-langservers-extracted) * [biome](https://biomejs.dev/) * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) :warning: * [dprint](https://dprint.dev) * [eslint](http://eslint.org/) :warning: * [fixjson](https://github.com/rhysd/fixjson) * [jq](https://stedolan.github.io/jq/) :warning: * [json.tool](https://docs.python.org/3/library/json.html#module-json.tool) :warning: * [jsonlint](https://github.com/zaach/jsonlint) * [prettier](https://github.com/prettier/prettier) * [spectral](https://github.com/stoplightio/spectral) * JSON5 * [eslint](http://eslint.org/) :warning: * JSONC * [biome](https://biomejs.dev/) * [eslint](http://eslint.org/) :warning: * Jsonnet * [jsonnet-lint](https://jsonnet.org/learning/tools.html) :speech_balloon: * [jsonnetfmt](https://jsonnet.org/learning/tools.html) :speech_balloon: * Julia * [languageserver](https://github.com/JuliaEditorSupport/LanguageServer.jl) * Kotlin * [kotlinc](https://kotlinlang.org) :floppy_disk: * [ktlint](https://ktlint.github.io) * [languageserver](https://github.com/fwcd/KotlinLanguageServer) see `:help ale-integration-kotlin` for configuration instructions * LaTeX * [alex](https://github.com/get-alex/alex) * [chktex](http://www.nongnu.org/chktex/) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [lacheck](https://www.ctan.org/pkg/lacheck) * [proselint](http://proselint.com/) * [redpen](http://redpen.cc/) * [texlab](https://texlab.netlify.com) :speech_balloon: * [textlint](https://textlint.github.io/) * [vale](https://github.com/ValeLint/vale) * [write-good](https://github.com/btford/write-good) * Lean 4 * [lake](https://github.com/leanprover/lean4) * Less * [lessc](https://www.npmjs.com/package/less) * [prettier](https://github.com/prettier/prettier) * [stylelint](https://github.com/stylelint/stylelint) * LLVM * [llc](https://llvm.org/docs/CommandGuide/llc.html) * Lua * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [lua-format](https://github.com/Koihik/LuaFormatter) * [lua-language-server](https://github.com/LuaLS/lua-language-server) :speech_balloon: * [luac](https://www.lua.org/manual/5.1/luac.html) * [luacheck](https://github.com/mpeterv/luacheck) * [luafmt](https://github.com/trixnz/lua-fmt) * [selene](https://github.com/Kampfkarren/selene) * [stylua](https://github.com/johnnymorganz/stylua) * Mail * [alex](https://github.com/get-alex/alex) * [languagetool](https://languagetool.org/) :floppy_disk: :speech_balloon: * [proselint](http://proselint.com/) * [vale](https://github.com/ValeLint/vale) * Make * [checkmake](https://github.com/mrtazz/checkmake) * Markdown * [alex](https://github.com/get-alex/alex) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [languagetool](https://languagetool.org/) :floppy_disk: :speech_balloon: * [markdownlint](https://github.com/DavidAnson/markdownlint) :floppy_disk: * [marksman](https://github.com/artempyanykh/marksman) :speech_balloon: * [mdl](https://github.com/mivok/markdownlint) * [pandoc](https://pandoc.org) * [prettier](https://github.com/prettier/prettier) * [proselint](http://proselint.com/) * [pymarkdown](https://github.com/jackdewinter/pymarkdown) :floppy_disk: * [redpen](http://redpen.cc/) * [remark-lint](https://github.com/wooorm/remark-lint) * [textlint](https://textlint.github.io/) * [vale](https://github.com/ValeLint/vale) * [write-good](https://github.com/btford/write-good) * MATLAB * [mlint](https://www.mathworks.com/help/matlab/ref/mlint.html) :speech_balloon: * Mercury * [mmc](http://mercurylang.org) :floppy_disk: * NASM * [nasm](https://www.nasm.us/) :floppy_disk: * Nickel * [nickel_format](https://github.com/tweag/nickel#formatting) * Nim * [nim check](https://nim-lang.org/docs/nimc.html) :floppy_disk: * [nimlsp](https://github.com/PMunch/nimlsp) :speech_balloon: * nimpretty * nix * [alejandra](https://github.com/kamadorueda/alejandra) * [deadnix](https://github.com/astro/deadnix) * [nix-instantiate](http://nixos.org/nix/manual/#sec-nix-instantiate) * [nixfmt](https://github.com/serokell/nixfmt) * [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt) * [rnix-lsp](https://github.com/nix-community/rnix-lsp) :speech_balloon: * [statix](https://github.com/nerdypepper/statix) * nroff * [alex](https://github.com/get-alex/alex) * [proselint](http://proselint.com/) * [write-good](https://github.com/btford/write-good) * Nunjucks * [djlint](https://djlint.com/) * Objective-C * [ccls](https://github.com/MaskRay/ccls) :speech_balloon: * [clang](http://clang.llvm.org/) * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [clangd](https://clang.llvm.org/extra/clangd.html) :speech_balloon: * [uncrustify](https://github.com/uncrustify/uncrustify) * Objective-C++ * [clang](http://clang.llvm.org/) * [clangd](https://clang.llvm.org/extra/clangd.html) :speech_balloon: * [uncrustify](https://github.com/uncrustify/uncrustify) * OCaml * [dune](https://dune.build/) * [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions * [ocamlformat](https://github.com/ocaml-ppx/ocamlformat) * [ocamllsp](https://github.com/ocaml/ocaml-lsp) :speech_balloon: * [ocp-indent](https://github.com/OCamlPro/ocp-indent) * [ols](https://github.com/freebroccolo/ocaml-language-server) :speech_balloon: * Odin * [ols](https://github.com/DanielGavin/ols) :speech_balloon: * OpenApi * [ibm_validator](https://github.com/IBM/openapi-validator) * [prettier](https://github.com/prettier/prettier) * [yamllint](https://yamllint.readthedocs.io/) * OpenSCAD * [SCA2D](https://gitlab.com/bath_open_instrumentation_group/sca2d) :floppy_disk: * [scadformat](https://github.com/hugheaves/scadformat) * Packer (HCL) * [packer-fmt-fixer](https://github.com/hashicorp/packer) * Pascal * [ptop](https://www.freepascal.org/tools/ptop.var) :speech_balloon: * Pawn * [uncrustify](https://github.com/uncrustify/uncrustify) * Perl * [languageserver](https://metacpan.org/pod/Perl::LanguageServer) * [perl -c](https://perl.org/) :warning: * [perl-critic](https://metacpan.org/pod/Perl::Critic) * [perltidy](https://metacpan.org/pod/distribution/Perl-Tidy/bin/perltidy) * Perl6 * [perl6 -c](https://perl6.org) :warning: * PHP * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [intelephense](https://github.com/bmewburn/intelephense-docs) :speech_balloon: * [langserver](https://github.com/felixfbecker/php-language-server) :speech_balloon: * [phan](https://github.com/phan/phan) see `:help ale-php-phan` to instructions :speech_balloon: * [php -l](https://secure.php.net/) * [php-cs-fixer](https://cs.symfony.com) * [phpactor](https://github.com/phpactor/phpactor) :speech_balloon: * [phpcbf](https://github.com/squizlabs/PHP_CodeSniffer) * [phpcs](https://github.com/squizlabs/PHP_CodeSniffer) * [phpmd](https://phpmd.org) * [phpstan](https://github.com/phpstan/phpstan) * [pint](https://github.com/laravel/pint) :beer: * [psalm](https://getpsalm.org) :floppy_disk: * [tlint](https://github.com/tightenco/tlint) * PO * [alex](https://github.com/get-alex/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/get-alex/alex) * [proselint](http://proselint.com/) * [write-good](https://github.com/btford/write-good) * Pony * [ponyc](https://github.com/ponylang/ponyc) * PowerShell * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [powershell](https://github.com/PowerShell/PowerShell) * [psscriptanalyzer](https://github.com/PowerShell/PSScriptAnalyzer) * Prolog * [swipl](https://github.com/SWI-Prolog/swipl-devel) * proto * [buf-format](https://github.com/bufbuild/buf) :floppy_disk: * [buf-lint](https://github.com/bufbuild/buf) :floppy_disk: * [clang-format](https://clang.llvm.org/docs/ClangFormat.html) * [protoc-gen-lint](https://github.com/ckaznocha/protoc-gen-lint) :floppy_disk: * [protolint](https://github.com/yoheimuta/protolint) :floppy_disk: * 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) * PureScript * [purescript-language-server](https://github.com/nwolverson/purescript-language-server) :speech_balloon: * [purs-tidy](https://github.com/natefaubion/purescript-tidy) * [purty](https://gitlab.com/joneshf/purty) * Python * [autoflake](https://github.com/myint/autoflake) :floppy_disk: * [autoimport](https://lyz-code.github.io/autoimport/) * [autopep8](https://github.com/hhatto/autopep8) * [bandit](https://github.com/PyCQA/bandit) :warning: * [black](https://github.com/psf/black) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [flake8](http://flake8.pycqa.org/en/latest/) * [flakehell](https://github.com/flakehell/flakehell) * [isort](https://github.com/timothycrosley/isort) * [mypy](http://mypy-lang.org/) * [prospector](https://github.com/PyCQA/prospector) :warning: :floppy_disk: * [pycln](https://github.com/hadialqattan/pycln) * [pycodestyle](https://github.com/PyCQA/pycodestyle) :warning: * [pydocstyle](https://www.pydocstyle.org/) :warning: * [pyflakes](https://github.com/PyCQA/pyflakes) * [pyflyby](https://github.com/deshaw/pyflyby) :warning: * [pylama](https://github.com/klen/pylama) :floppy_disk: * [pylint](https://www.pylint.org/) :floppy_disk: * [pylsp](https://github.com/python-lsp/python-lsp-server) :warning: :speech_balloon: * [pyre](https://github.com/facebook/pyre-check) :warning: * [pyrefly](https://github.com/facebook/pyrefly) :warning: :speech_balloon: * [pyright](https://github.com/microsoft/pyright) :speech_balloon: * [refurb](https://github.com/dosisod/refurb) :floppy_disk: * [reorder-python-imports](https://github.com/asottile/reorder_python_imports) * [ruff](https://github.com/charliermarsh/ruff) * [ruff-format](https://docs.astral.sh/ruff/formatter/) * [unimport](https://github.com/hakancelik96/unimport) * [vulture](https://github.com/jendrikseipp/vulture) :warning: :floppy_disk: * [yapf](https://github.com/google/yapf) * QML * [qmlfmt](https://github.com/jesperhh/qmlfmt) * [qmllint](https://github.com/qt/qtdeclarative/tree/5.11/tools/qmllint) :speech_balloon: * R * [languageserver](https://github.com/REditorSupport/languageserver) * [lintr](https://github.com/jimhester/lintr) * [styler](https://github.com/r-lib/styler) * Racket * [racket-langserver](https://github.com/jeapostrophe/racket-langserver/tree/master) :speech_balloon: * [raco](https://docs.racket-lang.org/raco/) * [raco_fmt](https://docs.racket-lang.org/fmt/) * Re:VIEW * [redpen](http://redpen.cc/) * 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) :speech_balloon: * [reason-language-server](https://github.com/jaredly/reason-language-server) :speech_balloon: * [refmt](https://github.com/reasonml/reason-cli) * Rego * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [opacheck](https://www.openpolicyagent.org/docs/latest/cli/#opa-check) * [opafmt](https://www.openpolicyagent.org/docs/latest/cli/#opa-fmt) * ReScript * [rescript-language-server](https://www.npmjs.com/package/@rescript/language-server) :speech_balloon: * [rescript_format](https://rescript-lang.org/) * REST * [kulala_fmt](https://github.com/mistweaverco/kulala-fmt) * reStructuredText * [alex](https://github.com/get-alex/alex) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [proselint](http://proselint.com/) * [redpen](http://redpen.cc/) * [rstcheck](https://github.com/myint/rstcheck) * [textlint](https://textlint.github.io/) * [vale](https://github.com/ValeLint/vale) * [write-good](https://github.com/btford/write-good) * Robot * [rflint](https://github.com/boakley/robotframework-lint) * Roc * [roc_annotate](https://github.com/roc-lang/roc) * [roc_format](https://github.com/roc-lang/roc) * [roc_language_server](https://github.com/roc-lang/roc) * RPM spec * [rpmlint](https://github.com/rpm-software-management/rpmlint) :warning: (see `:help ale-integration-spec`) :speech_balloon: * Ruby * [brakeman](http://brakemanscanner.org/) :floppy_disk: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [debride](https://github.com/seattlerb/debride) * [packwerk](https://github.com/Shopify/packwerk) :floppy_disk: * [prettier](https://github.com/prettier/plugin-ruby) * [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) :floppy_disk: * [reek](https://github.com/troessner/reek) * [rubocop](https://github.com/bbatsov/rubocop) * [ruby](https://www.ruby-lang.org) * [rubyfmt](https://github.com/fables-tales/rubyfmt) * [rufo](https://github.com/ruby-formatter/rufo) * [solargraph](https://solargraph.org) :speech_balloon: * [sorbet](https://github.com/sorbet/sorbet) :speech_balloon: * [standardrb](https://github.com/testdouble/standard) * [steep](https://github.com/soutaro/steep) * [syntax_tree](https://github.com/ruby-syntax-tree/syntax_tree) * Rust * [cargo](https://github.com/rust-lang/cargo) :floppy_disk: (see `:help ale-integration-rust` for configuration instructions) :speech_balloon: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [rls](https://github.com/rust-lang-nursery/rls) :warning: * [rust-analyzer](https://github.com/rust-analyzer/rust-analyzer) :warning: * [rustc](https://www.rust-lang.org/) :warning: * [rustfmt](https://github.com/rust-lang-nursery/rustfmt) * Salt * [salt-lint](https://github.com/warpnet/salt-lint) * Sass * [sass-lint](https://www.npmjs.com/package/sass-lint) * [stylelint](https://github.com/stylelint/stylelint) * Scala * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [fsc](https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/tools/fsc.html) :speech_balloon: * [metals](https://scalameta.org/metals/) :speech_balloon: * [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) * 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) * Slim * [slim-lint](https://github.com/sds/slim-lint) * SML * [smlnj](http://www.smlnj.org/) * Solidity * [forge](https://github.com/foundry-rs/forge) * [solc](https://solidity.readthedocs.io/) * [solhint](https://github.com/protofire/solhint) * [solium](https://github.com/duaraghav8/Solium) * SQL * [dprint](https://dprint.dev) * [pgformatter](https://github.com/darold/pgFormatter) * [sql-lint](https://github.com/joereynolds/sql-lint) * [sqlfluff](https://github.com/sqlfluff/sqlfluff) * [sqlfmt](https://github.com/jackc/sqlfmt) * [sqlformat](https://github.com/andialbrecht/sqlparse) * [sqlint](https://github.com/purcell/sqlint) * Stylus * [stylelint](https://github.com/stylelint/stylelint) * SugarSS * [stylelint](https://github.com/stylelint/stylelint) * Svelte * [prettier](https://github.com/prettier/prettier) * [svelteserver](https://github.com/sveltejs/language-tools/tree/master/packages/language-server) :speech_balloon: * Swift * [Apple swift-format](https://github.com/apple/swift-format) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [sourcekit-lsp](https://github.com/apple/sourcekit-lsp) :speech_balloon: * [swiftformat](https://github.com/nicklockwood/SwiftFormat) * [swiftlint](https://github.com/realm/SwiftLint) * systemd * [systemd-analyze](https://www.freedesktop.org/software/systemd/man/systemd-analyze.html) :floppy_disk: * Tcl * [nagelfar](http://nagelfar.sourceforge.net) :floppy_disk: * Terraform * [checkov](https://github.com/bridgecrewio/checkov) * [terraform](https://github.com/hashicorp/terraform) * [terraform-fmt-fixer](https://github.com/hashicorp/terraform) * [terraform-ls](https://github.com/hashicorp/terraform-ls) :speech_balloon: * [terraform-lsp](https://github.com/juliosueiras/terraform-lsp) :speech_balloon: * [tflint](https://github.com/wata727/tflint) * [tfsec](https://github.com/aquasecurity/tfsec) * Texinfo * [alex](https://github.com/get-alex/alex) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [proselint](http://proselint.com/) * [write-good](https://github.com/btford/write-good) * Text * [alex](https://github.com/get-alex/alex) :warning: * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [languagetool](https://languagetool.org/) :floppy_disk: :speech_balloon: * [proselint](http://proselint.com/) :warning: * [redpen](http://redpen.cc/) :warning: * [textlint](https://textlint.github.io/) :warning: * [vale](https://github.com/ValeLint/vale) :warning: * [write-good](https://github.com/btford/write-good) :warning: * Thrift * [thrift](http://thrift.apache.org/) * [thriftcheck](https://github.com/pinterest/thriftcheck) * TOML * [dprint](https://dprint.dev) * [tombi](https://tombi-toml.github.io/tombi/) * TypeScript * [biome](https://biomejs.dev/) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [deno](https://deno.land/) * [dprint](https://dprint.dev/) * [eslint](http://eslint.org/) * [fecs](http://fecs.baidu.com/) * [prettier](https://github.com/prettier/prettier) * [standard](http://standardjs.com/) * [tslint](https://github.com/palantir/tslint) * [tsserver](https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-%28tsserver%29) * typecheck * Typst * [typstyle](https://github.com/Enter-tainer/typstyle) * V * [v](https://github.com/vlang/v/) :floppy_disk: * [vfmt](https://github.com/vlang/v/) * VALA * [uncrustify](https://github.com/uncrustify/uncrustify) * [vala_lint](https://github.com/vala-lang/vala-lint) :floppy_disk: * Verilog * [hdl-checker](https://pypi.org/project/hdl-checker) * [iverilog](https://github.com/steveicarus/iverilog) * [slang](https://github.com/MikePopoloski/slang) * [verible](https://github.com/chipsalliance/verible/tree/master) * [verilator](http://www.veripool.org/projects/verilator/wiki/Intro) * [vlog](https://www.mentor.com/products/fv/questa/) * [xvlog](https://www.xilinx.com/products/design-tools/vivado.html) :speech_balloon: * [yosys](http://www.clifford.at/yosys/) :floppy_disk: * VHDL * [ghdl](https://github.com/ghdl/ghdl) * [vcom](https://www.mentor.com/products/fv/questa/) * [xvhdl](https://www.xilinx.com/products/design-tools/vivado.html) :speech_balloon: * Vim * [vimls](https://github.com/iamcco/vim-language-server) :speech_balloon: * [vint](https://github.com/Kuniwak/vint) * Vim help * [alex](https://github.com/get-alex/alex) :warning: * [proselint](http://proselint.com/) :warning: * [write-good](https://github.com/btford/write-good) :warning: * Vue * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [prettier](https://github.com/prettier/prettier) * [vls](https://github.com/vuejs/vetur/tree/master/server) :speech_balloon: * [volar](https://github.com/johnsoncodehk/volar) * WGSL * [naga](https://github.com/gfx-rs/naga) * XHTML * [alex](https://github.com/get-alex/alex) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [proselint](http://proselint.com/) * [write-good](https://github.com/btford/write-good) * XML * [xmllint](http://xmlsoft.org/xmllint.html) * YAML * [actionlint](https://github.com/rhysd/actionlint) * [circleci](https://circleci.com/docs/2.0/local-cli) :floppy_disk: :warning: * [gitlablint](https://github.com/elijah-roberts/gitlab-lint) * [prettier](https://github.com/prettier/prettier) * [spectral](https://github.com/stoplightio/spectral) * [swaglint](https://github.com/byCedric/swaglint) :warning: :speech_balloon: * [yaml-language-server](https://github.com/redhat-developer/yaml-language-server) :speech_balloon: * [yamlfix](https://lyz-code.github.io/yamlfix) * [yamlfmt](https://github.com/google/yamlfmt) * [yamllint](https://yamllint.readthedocs.io/) * [yq](https://github.com/mikefarah/yq) * YANG * [yang-lsp](https://github.com/theia-ide/yang-lsp) :speech_balloon: * Yara * [yls](https://github.com/avast/yls) * Zeek * [zeek](http://zeek.org) :floppy_disk: * Zig * [zigfmt](https://github.com/ziglang/zig) * [zlint](https://github.com/DonIsaac/zlint) * [zls](https://github.com/zigtools/zls) :speech_balloon: ================================================ FILE: syntax/ale-fix-suggest.vim ================================================ if exists('b:current_syntax') finish endif syn match aleFixerComment /^.*$/ syn match aleFixerName /\(^ *\|, \)'[^']*'/ syn match aleFixerHelp /^See :help ale-fix-configuration/ hi def link aleFixerComment Comment hi def link aleFixerName String hi def link aleFixerHelp Statement let b:current_syntax = 'ale-fix-suggest' ================================================ FILE: syntax/ale-info.vim ================================================ if exists('b:current_syntax') finish endif " Exhaustively list different ALE Info directives to match here. " This should hopefully avoid matching too eagerly. syn match aleInfoDirective /^ *Current Filetype:/ syn match aleInfoDirective /^ *Available Linters:/ syn match aleInfoDirective /^ *Enabled Linters:/ syn match aleInfoDirective /^ *Ignored Linters:/ syn match aleInfoDirective /^ *Suggested Fixers:/ syn match aleInfoDirective /^ *Command History:/ syn match aleCommandNoOutput /^<<>>$/ hi def link aleInfoDirective Title hi def link aleInfoDirective Title hi def link aleCommandNoOutput Comment " Use Vim syntax highlighting for Vim options. unlet! b:current_syntax syntax include @srcVim syntax/vim.vim syntax region aleInfoVimRegionLinter matchgroup=aleInfoDirective start="^ *Linter Variables:$" end="^ $" contains=@srcVim syntax region aleInfoVimRegionGlobal matchgroup=aleInfoDirective start="^ *Global Variables:$" end="^ $" contains=@srcVim unlet! b:current_syntax syntax include @srcAleFixSuggest syntax/ale-fix-suggest.vim syntax region aleInfoFixSuggestRegion matchgroup=aleInfoDirective start="^ *Suggested Fixers:$" end="^ $" contains=@srcAleFixSuggest let b:current_syntax = 'ale-info' ================================================ FILE: syntax/ale-preview-selection.vim ================================================ if exists('b:current_syntax') finish endif syn match alePreviewSelectionFilename /\v^([a-zA-Z]?:?[^:]+)/ syn match alPreviewNumber /\v:\d+:\d+$/ hi def link alePreviewSelectionFilename String hi def link alePreviewNumber Number let b:current_syntax = 'ale-preview-selection' ================================================ FILE: test/completion/test_ale_import_command.vader ================================================ Before: Save g:ale_enabled Save b:ale_enabled Save g:ale_lint_on_text_changed Save g:ale_completion_enabled Save g:ale_completion_autoimport Save g:ale_completion_max_suggestions Save g:ale_linters Save b:ale_linters let g:ale_enabled = 0 let b:ale_enabled = 0 let g:ale_lint_on_text_changed = 'always' let g:ale_completion_enabled = 0 let g:ale_completion_autoimport = 0 let g:ale_completion_max_suggestions = 50 let g:ale_linters = {'typescript': ['tsserver'], 'python': ['pyrefly']} unlet! b:ale_linters let g:server_started_value = 1 let g:request_id = 0 let g:LastCallback = v:null let g:LastHandleCallback = v:null let g:sent_message_list = [] let g:code_action_list = [] let g:execute_list = [] let g:ale_queue_call_list = [] runtime autoload/ale.vim runtime autoload/ale/util.vim runtime autoload/ale/code_action.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim function! ale#util#Execute(expr) abort call add(g:execute_list, a:expr) endfunction function! ale#Queue(...) abort call add(g:ale_queue_call_list, a:000) endfunction function! ale#lsp#RegisterCallback(id, Callback) abort let g:LastHandleCallback = a:Callback endfunction function! ale#lsp#NotifyForChanges(id, buffer) abort endfunction function! ale#lsp#HasCapability(id, capability) abort return 1 endfunction function! ale#lsp#Send(id, message) abort let g:request_id += 1 call add(g:sent_message_list, a:message) return g:request_id endfunction function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:LastCallback = a:Callback return g:server_started_value endfunction function! ale#code_action#HandleCodeAction(code_action, options) abort Assert !get(a:options, 'should_save') call add(g:code_action_list, a:code_action) endfunction function GetLastMessage() return get(g:execute_list, -1, '') endfunction function CheckLintStates(conn_id, message) " Check that we request more linter results after adding completions. AssertEqual [[0, '']], g:ale_queue_call_list let g:ale_enabled = 0 let g:ale_queue_call_list = [] call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [], g:ale_queue_call_list let g:ale_enabled = 1 let g:ale_lint_on_text_changed = 1 let g:ale_queue_call_list = [] call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [[0, '']], g:ale_queue_call_list let g:ale_lint_on_text_changed = v:true let g:ale_queue_call_list = [] call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [[0, '']], g:ale_queue_call_list let g:ale_lint_on_text_changed = 'normal' let g:ale_queue_call_list = [] call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [[0, '']], g:ale_queue_call_list let g:ale_lint_on_text_changed = 'insert' let g:ale_queue_call_list = [] call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [[0, '']], g:ale_queue_call_list let g:ale_queue_call_list = [] let g:ale_lint_on_text_changed = 'never' call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [], g:ale_queue_call_list let g:ale_lint_on_text_changed = '0' call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [], g:ale_queue_call_list let g:ale_lint_on_text_changed = 0 call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [], g:ale_queue_call_list let g:ale_lint_on_text_changed = 'xxx' call g:LastHandleCallback(a:conn_id, a:message) AssertEqual [], g:ale_queue_call_list endfunction After: call ale#linter#Reset() Restore delfunction GetLastMessage delfunction CheckLintStates unlet! g:LastCallback unlet! g:LastHandleCallback unlet! g:request_id unlet! g:server_started_value unlet! g:sent_message_list unlet! g:code_action_list unlet! g:ale_queue_call_list unlet! g:execute_list unlet! g:received_message unlet! b:ale_old_omnifunc unlet! b:ale_old_completeopt unlet! b:ale_completion_info unlet! b:ale_completion_result unlet! b:ale_complete_done_time runtime autoload/ale.vim runtime autoload/ale/util.vim runtime autoload/ale/code_action.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim Given typescript(Some example TypeScript code): let xyz = 123 let foo = missingword let abc = 456 Execute(ALEImport should complain when there's no word at the cursor): call setpos('.', [bufnr(''), 3, 1, 0]) ALEImport AssertEqual 'echom ''Nothing to complete at cursor!''', GetLastMessage() Execute(ALEImport should tell the user if no LSP is available): let g:server_started_value = 0 call setpos('.', [bufnr(''), 2, 16, 0]) ALEImport AssertEqual \ 'echom ''No completion providers are available.''', \ GetLastMessage() Execute(ALEImport should request imports correctly for tsserver): call setpos('.', [bufnr(''), 2, 16, 0]) ALEImport AssertEqual \ { \ 'conn_id': 0, \ 'request_id': 0, \ 'source': 'ale-import', \ 'column': 21, \ 'line': 2, \ 'line_length': 21, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ }, \ b:ale_completion_info Assert g:LastCallback isnot v:null call g:LastCallback(ale#linter#Get(&filetype)[0], { \ 'connection_id': 347, \ 'buffer': bufnr(''), \}) AssertEqual \ { \ 'conn_id': 347, \ 'request_id': 1, \ 'source': 'ale-import', \ 'column': 21, \ 'line': 2, \ 'line_length': 21, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ }, \ b:ale_completion_info Assert g:LastHandleCallback isnot v:null call g:LastHandleCallback(347, { \ 'request_seq': 1, \ 'command': 'completions', \ 'body': [ \ {'name': 'missingwordIgnoreMe'}, \ {'name': 'missingword'}, \ ], \}) AssertEqual \ [ \ [0, 'ts@completions', { \ 'file': expand('%:p'), \ 'includeExternalModuleExports': v:true, \ 'offset': 21, \ 'line': 2, \ 'prefix': 'missingword', \ }], \ [0, 'ts@completionEntryDetails', { \ 'file': expand('%:p'), \ 'entryNames': [{'name': 'missingword'}], \ 'offset': 21, \ 'line': 2, \ }] \ ], \ g:sent_message_list AssertEqual 2, b:ale_completion_info.request_id let g:ale_enabled = 1 let g:received_message = { \ 'request_seq': 2, \ 'command': 'completionEntryDetails', \ 'body': [ \ { \ 'name': 'missingword', \ 'kind': 'className', \ 'displayParts': [], \ 'codeActions': [{ \ 'description': 'import { missingword } from "./Something";', \ 'changes': [], \ }], \ }, \ ], \} call g:LastHandleCallback(347, g:received_message) AssertEqual \ [ \ { \ 'description': 'import { missingword } from "./Something";', \ 'changes': [], \ }, \ ], \ g:code_action_list call CheckLintStates(347, g:received_message) Execute(ALEImport should tell the user when no completions were found from tsserver): call setpos('.', [bufnr(''), 2, 16, 0]) ALEImport AssertEqual \ { \ 'conn_id': 0, \ 'request_id': 0, \ 'source': 'ale-import', \ 'column': 21, \ 'line': 2, \ 'line_length': 21, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ }, \ b:ale_completion_info Assert g:LastCallback isnot v:null call g:LastCallback(ale#linter#Get(&filetype)[0], { \ 'connection_id': 347, \ 'buffer': bufnr(''), \}) AssertEqual \ { \ 'conn_id': 347, \ 'request_id': 1, \ 'source': 'ale-import', \ 'column': 21, \ 'line': 2, \ 'line_length': 21, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ }, \ b:ale_completion_info Assert g:LastHandleCallback isnot v:null call g:LastHandleCallback(347, { \ 'request_seq': 1, \ 'command': 'completions', \ 'body': [ \ {'name': 'missingwordIgnoreMe'}, \ ], \}) AssertEqual 'echom ''No possible imports found.''', GetLastMessage() Given python(Some example Python code): xyz = 123 foo = missingword abc = 456 Execute(ALEImport should request imports correctly for language servers): call setpos('.', [bufnr(''), 2, 12, 0]) ALEImport AssertEqual \ { \ 'conn_id': 0, \ 'request_id': 0, \ 'source': 'ale-import', \ 'column': 17, \ 'line': 2, \ 'line_length': 17, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ }, \ b:ale_completion_info Assert g:LastCallback isnot v:null call g:LastCallback(ale#linter#Get(&filetype)[0], { \ 'connection_id': 347, \ 'buffer': bufnr(''), \}) AssertEqual \ { \ 'conn_id': 347, \ 'request_id': 1, \ 'source': 'ale-import', \ 'column': 17, \ 'line': 2, \ 'line_length': 17, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ }, \ b:ale_completion_info Assert g:LastHandleCallback isnot v:null AssertEqual \ [ \ [0, 'textDocument/completion', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'character': 16, 'line': 1} \ }], \ ], \ g:sent_message_list AssertEqual 1, b:ale_completion_info.request_id let g:ale_enabled = 1 let g:received_message = { \ 'id': 1, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'Some other word we should ignore', \ 'filterText': 'missingwordIgnoreMe', \ 'insertText': 'missingwordIgnoreMe', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' missingwordIgnoreMe', \ 'sortText': '3ee19999missingword', \ 'additionalTextEdits': [ \ { \ 'range': { \ 'start': {'line': 1, 'character': 1}, \ 'end': {'line': 2, 'character': 1}, \ }, \ 'newText': 'from something import missingwordIgnoreMe', \ }, \ ], \ }, \ { \ 'detail': 'Some word without text edits', \ 'filterText': 'missingword', \ 'insertText': 'missingword', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' missingword', \ 'sortText': '3ee19999missingword', \ }, \ { \ 'detail': 'The word we should use', \ 'filterText': 'missingword', \ 'insertText': 'missingword', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' missingword', \ 'sortText': '3ee19999missingword', \ 'additionalTextEdits': [ \ { \ 'range': { \ 'start': {'line': 1, 'character': 1}, \ 'end': {'line': 2, 'character': 1}, \ }, \ 'newText': 'from something import missingword', \ }, \ ], \ }, \ { \ 'detail': 'The other word we should not use', \ 'filterText': 'missingword', \ 'insertText': 'missingword', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' missingword', \ 'sortText': '3ee19999missingword', \ 'additionalTextEdits': [ \ { \ 'range': { \ 'start': {'line': 1, 'character': 1}, \ 'end': {'line': 2, 'character': 1}, \ }, \ 'newText': 'from something_else import missingword', \ }, \ ], \ }, \ ], \ }, \} call g:LastHandleCallback(347, g:received_message) AssertEqual \ [ \ { \ 'description': 'completion', \ 'changes': [ \ { \ 'fileName': expand('%:p'), \ 'textChanges': [ \ { \ 'start': {'line': 2, 'offset': 2}, \ 'end': {'line': 3, 'offset': 2}, \ 'newText': 'from something import missingword', \ }, \ ], \ }, \ ], \ }, \ ], \ g:code_action_list call CheckLintStates(347, g:received_message) Execute(ALEImport should tell the user when no completions were found from a language server): call setpos('.', [bufnr(''), 2, 12, 0]) ALEImport AssertEqual \ { \ 'conn_id': 0, \ 'request_id': 0, \ 'source': 'ale-import', \ 'column': 17, \ 'line': 2, \ 'line_length': 17, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ }, \ b:ale_completion_info Assert g:LastCallback isnot v:null call g:LastCallback(ale#linter#Get(&filetype)[0], { \ 'connection_id': 347, \ 'buffer': bufnr(''), \}) AssertEqual \ { \ 'conn_id': 347, \ 'request_id': 1, \ 'source': 'ale-import', \ 'column': 17, \ 'line': 2, \ 'line_length': 17, \ 'prefix': 'missingword', \ 'additional_edits_only': 1, \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ }, \ b:ale_completion_info Assert g:LastHandleCallback isnot v:null AssertEqual \ [ \ [0, 'textDocument/completion', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'character': 16, 'line': 1} \ }], \ ], \ g:sent_message_list AssertEqual 1, b:ale_completion_info.request_id let g:received_message = { \ 'id': 1, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'Some other word we should ignore', \ 'filterText': 'missingwordIgnoreMe', \ 'insertText': 'missingwordIgnoreMe', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' missingwordIgnoreMe', \ 'sortText': '3ee19999missingword', \ 'additionalTextEdits': [ \ { \ 'range': { \ 'start': {'line': 1, 'character': 1}, \ 'end': {'line': 2, 'character': 1}, \ }, \ 'newText': 'from something import missingwordIgnoreMe', \ }, \ ], \ }, \ { \ 'detail': 'Some word without text edits', \ 'filterText': 'missingword', \ 'insertText': 'missingword', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' missingword', \ 'sortText': '3ee19999missingword', \ }, \ ], \ }, \} call g:LastHandleCallback(347, g:received_message) AssertEqual 'echom ''No possible imports found.''', GetLastMessage() ================================================ FILE: test/completion/test_complete_events.vader ================================================ Before: let g:complete_post_triggered = 0 augroup VaderTest autocmd! autocmd User ALECompletePost let g:complete_post_triggered = 1 augroup END After: unlet! b:ale_completion_info unlet! g:complete_post_triggered augroup VaderTest autocmd! augroup END augroup! VaderTest Execute(ALECompletePost should not be triggered when completion is cancelled): call ale#completion#HandleUserData({}) Assert !g:complete_post_triggered Execute(ALECompletePost should not be triggered when tools other than ALE insert completions): call ale#completion#HandleUserData({'user_data': ''}) call ale#completion#HandleUserData({'user_data': '{}'}) Assert !g:complete_post_triggered Execute(ALECompletePost should be triggered when ALE inserts completions): call ale#completion#HandleUserData({ \ 'user_data': json_encode({'_ale_completion_item': 1}), \}) Assert g:complete_post_triggered ================================================ FILE: test/completion/test_completion_events.vader ================================================ Before: Save g:ale_completion_enabled Save g:ale_completion_delay Save g:ale_completion_max_suggestions Save &l:omnifunc Save &l:completeopt unlet! b:ale_completion_enabled let g:ale_completion_enabled = 1 let g:get_completions_called = 0 let g:feedkeys_calls = [] let g:fake_mode = 'i' let b:ale_linters = { \ 'typescript': ['tsserver'], \} let &l:completeopt = 'menu,menuone,preview,noselect,noinsert' runtime autoload/ale/util.vim function! ale#util#FeedKeys(string) abort call add(g:feedkeys_calls, [a:string]) endfunction " Pretend we're in insert mode for most tests. function! ale#util#Mode(...) abort return g:fake_mode endfunction function! CheckCompletionCalled(expect_success) abort let g:get_completions_called = 0 " We just want to check if the function is called. function! ale#completion#GetCompletions(source) let g:get_completions_called = 1 endfunction let g:ale_completion_delay = 0 " Run this check a few times, as it can fail randomly. for l:i in range(has('nvim-0.3') || has('win32') ? 5 : 1) call ale#completion#Queue() sleep 1m if g:get_completions_called is a:expect_success break endif endfor AssertEqual a:expect_success, g:get_completions_called endfunction let g:handle_code_action_called = 0 function! MockHandleCodeAction() abort " delfunction! ale#code_action#HandleCodeAction function! ale#code_action#HandleCodeAction(action, options) abort Assert !get(a:options, 'should_save') let g:handle_code_action_called += 1 endfunction endfunction After: Restore unlet! b:ale_completion_enabled unlet! g:output unlet! g:fake_mode unlet! g:get_completions_called unlet! g:handle_code_action_called unlet! b:ale_old_omnifunc unlet! b:ale_old_completeopt unlet! b:ale_completion_info unlet! b:ale_completion_result unlet! b:ale_complete_done_time unlet! b:ale_linters delfunction CheckCompletionCalled delfunction ale#code_action#HandleCodeAction delfunction MockHandleCodeAction if exists('*CompleteCallback') delfunction CompleteCallback endif " Stop any timers we left behind. " This stops the tests from failing randomly. call ale#completion#StopTimer() " Reset the function. The runtime command below should fix this, but doesn't " seem to fix it. function! ale#util#Mode(...) abort return call('mode', a:000) endfunction runtime autoload/ale/completion.vim runtime autoload/ale/code_action.vim runtime autoload/ale/util.vim Execute(ale#completion#GetCompletions should be called when the cursor position stays the same): call CheckCompletionCalled(1) Execute(ale#completion#GetCompletions should not be called if the global setting is disabled): let g:ale_completion_enabled = 0 call CheckCompletionCalled(0) Execute(ale#completion#GetCompletions should not be called if the buffer setting is disabled): let b:ale_completion_enabled = 0 call CheckCompletionCalled(0) Given typescript(): let abc = y. let foo = ab let foo = (ab) Execute(ale#completion#GetCompletions should not be called when the cursor position changes): call setpos('.', [bufnr(''), 1, 2, 0]) " We just want to check if the function is called. function! ale#completion#GetCompletions(source) let g:get_completions_called = 1 endfunction let g:ale_completion_delay = 0 call ale#completion#Queue() " Change the cursor position before the callback is triggered. call setpos('.', [bufnr(''), 2, 2, 0]) sleep 1m Assert !g:get_completions_called Execute(ale#completion#GetCompletions should not be called if you switch to normal mode): let &l:completeopt = 'menu,preview' let g:fake_mode = 'n' " We just want to check if the function is called. function! ale#completion#GetCompletions(source) let g:get_completions_called = 1 endfunction let g:ale_completion_delay = 0 call ale#completion#Queue() sleep 1m Assert !g:get_completions_called Execute(Completion should not be done shortly after the CompleteDone function): call CheckCompletionCalled(1) call ale#completion#Done() call CheckCompletionCalled(0) Execute(ale#completion#Show() should remember the omnifunc setting and replace it): let &l:omnifunc = 'FooBar' let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual 'FooBar', b:ale_old_omnifunc AssertEqual 'ale#completion#AutomaticOmniFunc', &l:omnifunc AssertEqual [], g:feedkeys_calls sleep 1ms AssertEqual [["\(ale_show_completion_menu)"]], g:feedkeys_calls Execute(ale#completion#Show() should remember the completeopt setting and replace it): let &l:completeopt = 'menu' let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual 'menu', b:ale_old_completeopt AssertEqual 'menu,menuone,noinsert', &l:completeopt AssertEqual [], g:feedkeys_calls sleep 1ms AssertEqual [["\(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' let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual 'menu,preview', b:ale_old_completeopt AssertEqual 'menu,menuone,noinsert,preview', &l:completeopt AssertEqual [], g:feedkeys_calls sleep 1ms AssertEqual [["\(ale_show_completion_menu)"]], g:feedkeys_calls Execute(ale#completion#Show() should not replace the completeopt setting for manual completion): let b:ale_completion_info = {'source': 'ale-manual'} let &l:completeopt = 'menu,preview' call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) Assert !exists('b:ale_old_completeopt') AssertEqual [], g:feedkeys_calls sleep 1ms AssertEqual [["\(ale_show_completion_menu)"]], g:feedkeys_calls Execute(ale#completion#AutomaticOmniFunc() should also remember the completeopt setting and replace it): let &l:completeopt = 'menu,noselect' let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#AutomaticOmniFunc(0, '') AssertEqual 'menu,noselect', b:ale_old_completeopt AssertEqual 'menu,menuone,noinsert,noselect', &l:completeopt Execute(ale#completion#AutomaticOmniFunc() should set the preview option if it's set): let &l:completeopt = 'menu,preview' let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#AutomaticOmniFunc(0, '') AssertEqual 'menu,preview', b:ale_old_completeopt AssertEqual 'menu,menuone,noinsert,preview', &l:completeopt Execute(ale#completion#Show() should make the correct feedkeys() call for automatic completion): let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual [], g:feedkeys_calls sleep 1ms AssertEqual [["\(ale_show_completion_menu)"]], g:feedkeys_calls Execute(ale#completion#Show() should make the correct feedkeys() call for manual completion): let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual [], g:feedkeys_calls sleep 1ms AssertEqual [["\(ale_show_completion_menu)"]], g:feedkeys_calls Execute(ale#completion#Show() should not call feedkeys() for other sources): let b:ale_completion_info = {'source': 'other-source'} call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) sleep 1ms AssertEqual [], g:feedkeys_calls Execute(ale#completion#Show() shouldn't do anything if you switch back to normal mode): let &l:completeopt = 'menu,preview' let g:fake_mode = 'n' call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual 'menu,preview', &l:completeopt Assert !exists('b:ale_old_omnifunc') Assert !exists('b:ale_old_completeopt') Assert !exists('b:ale_completion_result') AssertEqual [], g:feedkeys_calls Execute(ale#completion#Show() should save the result it is given): call ale#completion#Show([]) AssertEqual [], b:ale_completion_result call ale#completion#Show([{'word': 'x', 'kind': 'v', 'icase': 1}]) AssertEqual [{'word': 'x', 'kind': 'v', 'icase': 1}], b:ale_completion_result Execute(ale#completion#Done() should restore old omnifunc values): let b:ale_old_omnifunc = 'FooBar' call ale#completion#Done() " We reset the old omnifunc setting and remove the buffer variable. AssertEqual 'FooBar', &l:omnifunc Assert !has_key(b:, 'ale_old_omnifunc') Execute(ale#completion#Done() should restore the old completeopt setting): let b:ale_old_completeopt = 'menu' call ale#completion#Done() AssertEqual 'menu', &l:completeopt Assert !has_key(b:, 'ale_old_completeopt') Execute(ale#completion#Done() should leave settings alone when none were remembered): let &l:omnifunc = 'BazBoz' let &l:completeopt = 'menu' call ale#completion#Done() AssertEqual 'BazBoz', &l:omnifunc AssertEqual 'menu', &l:completeopt Execute(The completion request_id should be reset when queuing again): let b:ale_completion_info = {'request_id': 123} let g:ale_completion_delay = 0 call ale#completion#Queue() sleep 1m AssertEqual 0, b:ale_completion_info.request_id Execute(b:ale_completion_info should be set up correctly when requesting completions automatically): let b:ale_completion_result = [] call setpos('.', [bufnr(''), 3, 14, 0]) call ale#completion#GetCompletions('ale-automatic') AssertEqual \ { \ 'request_id': 0, \ 'conn_id': 0, \ 'column': 14, \ 'line_length': 14, \ 'line': 3, \ 'prefix': 'ab', \ 'source': 'ale-automatic', \ }, \ b:ale_completion_info Assert !exists('b:ale_completion_result') Execute(b:ale_completion_info should be set up correctly when requesting completions manually): let b:ale_completion_result = [] call setpos('.', [bufnr(''), 3, 14, 0]) ALEComplete AssertEqual \ { \ 'request_id': 0, \ 'conn_id': 0, \ 'column': 14, \ 'line_length': 14, \ 'line': 3, \ 'prefix': 'ab', \ 'source': 'ale-manual', \ }, \ b:ale_completion_info Assert !exists('b:ale_completion_result') Execute(b:ale_completion_info should be set up correctly for other sources): let b:ale_completion_result = [] call setpos('.', [bufnr(''), 3, 14, 0]) call ale#completion#GetCompletions('ale-callback') AssertEqual \ { \ 'request_id': 0, \ 'conn_id': 0, \ 'column': 14, \ 'line_length': 14, \ 'line': 3, \ 'prefix': 'ab', \ 'source': 'ale-callback', \ }, \ b:ale_completion_info Assert !exists('b:ale_completion_result') Execute(b:ale_completion_info should be set up correctly when requesting completions via callback): let b:ale_completion_result = [] call setpos('.', [bufnr(''), 3, 14, 0]) function! CompleteCallback() abort echo 'Called' endfunction call ale#completion#GetCompletions('ale-callback', {'callback': funcref('CompleteCallback')}) AssertEqual \ { \ 'request_id': 0, \ 'conn_id': 0, \ 'column': 14, \ 'line_length': 14, \ 'line': 3, \ 'prefix': 'ab', \ 'source': 'ale-callback', \ }, \ b:ale_completion_info Assert !exists('b:ale_completion_result') Execute(The correct keybinds should be configured): redir => g:output silent map (ale_show_completion_menu) redir END AssertEqual \ [ \ 'n (ale_show_completion_menu) * :call ale#completion#RestoreCompletionOptions()', \ 'o (ale_show_completion_menu) * ', \ 'v (ale_show_completion_menu) * ', \ ], \ sort(split(g:output, "\n")) Execute(Running the normal mode keybind should reset the settings): let b:ale_old_omnifunc = 'FooBar' let b:ale_old_completeopt = 'menu' " We can't run the keybind, but we can call the function. call ale#completion#RestoreCompletionOptions() AssertEqual 'FooBar', &l:omnifunc AssertEqual 'menu', &l:completeopt Assert !has_key(b:, 'ale_old_omnifunc') Assert !has_key(b:, 'ale_old_completeopt') Execute(HandleUserData should call ale#code_action#HandleCodeAction): let b:ale_completion_info = {'source': 'ale-manual'} call MockHandleCodeAction() call ale#completion#HandleUserData({}) AssertEqual g:handle_code_action_called, 0 call ale#completion#HandleUserData({ \ 'user_data': '' \}) AssertEqual g:handle_code_action_called, 0 call ale#completion#HandleUserData({ \ 'user_data': json_encode({}), \}) AssertEqual g:handle_code_action_called, 0 call ale#completion#HandleUserData({ \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [], \ }), \}) AssertEqual g:handle_code_action_called, 0 call ale#completion#HandleUserData({ \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [ \ {'description': '', 'changes': []}, \ ], \ }), \}) AssertEqual g:handle_code_action_called, 1 let b:ale_completion_info = {'source': 'ale-automatic'} call ale#completion#HandleUserData({ \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [ \ {'description': '', 'changes': []}, \ ], \ }), \}) AssertEqual g:handle_code_action_called, 2 let b:ale_completion_info = {'source': 'ale-callback'} call ale#completion#HandleUserData({ \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [ \ {'description': '', 'changes': []}, \ ], \ }), \}) AssertEqual g:handle_code_action_called, 3 let b:ale_completion_info = {'source': 'ale-omnifunc'} call ale#completion#HandleUserData({ \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [ \ {'description': '', 'changes': []}, \ ], \ }), \}) AssertEqual g:handle_code_action_called, 4 Execute(ale#code_action#HandleCodeAction should not be called when when source is not ALE): call MockHandleCodeAction() let b:ale_completion_info = {'source': 'syntastic'} call ale#completion#HandleUserData({ \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [ \ {'description': '', 'changes': []}, \ ], \ }), \}) AssertEqual g:handle_code_action_called, 0 ================================================ FILE: test/completion/test_completion_filtering.vader ================================================ Before: Save g:ale_completion_excluded_words let g:ale_completion_excluded_words = [] After: Restore unlet! b:ale_completion_excluded_words unlet! b:suggestions Execute(Prefix filtering should work for Lists of strings): AssertEqual \ ['FooBar', 'foo'], \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], 'foo', 0) AssertEqual \ ['FooBar', 'FongBar', 'baz', 'foo'], \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '.', 0) AssertEqual \ ['FooBar', 'FongBar', 'baz', 'foo'], \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '', 0) Execute(Exact filtering should work): AssertEqual \ ['foo'], \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], 'foo', 1) AssertEqual \ ['FooBar', 'FongBar', 'baz', 'foo'], \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'baz', 'foo'], '.', 1) AssertEqual \ ['Foo'], \ ale#completion#Filter(bufnr(''), '', ['FooBar', 'FongBar', 'Foo', 'foo'], 'Foo', 1) Execute(Prefix filtering should work for completion items): AssertEqual \ [{'word': 'FooBar'}, {'word': 'foo'}], \ ale#completion#Filter( \ bufnr(''), \ '', \ [ \ {'word': 'FooBar'}, \ {'word': 'FongBar'}, \ {'word': 'baz'}, \ {'word': 'foo'}, \ ], \ 'foo', \ 0, \ ) AssertEqual \ [ \ {'word': 'FooBar'}, \ {'word': 'FongBar'}, \ {'word': 'baz'}, \ {'word': 'foo'}, \ ], \ ale#completion#Filter( \ bufnr(''), \ '', \ [ \ {'word': 'FooBar'}, \ {'word': 'FongBar'}, \ {'word': 'baz'}, \ {'word': 'foo'}, \ ], \ '.', \ 0, \ ) Execute(Excluding words from completion results should work): let b:ale_completion_excluded_words = ['it', 'describe'] AssertEqual \ [{'word': 'Italian'}], \ ale#completion#Filter( \ bufnr(''), \ '', \ [ \ {'word': 'Italian'}, \ {'word': 'it'}, \ ], \ 'it', \ 0, \ ) AssertEqual \ [{'word': 'Deutsch'}], \ ale#completion#Filter( \ bufnr(''), \ '', \ [ \ {'word': 'describe'}, \ {'word': 'Deutsch'}, \ ], \ 'de', \ 0, \ ) AssertEqual \ [{'word': 'Deutsch'}], \ ale#completion#Filter( \ bufnr(''), \ '', \ [ \ {'word': 'describe'}, \ {'word': 'Deutsch'}, \ ], \ '.', \ 0, \ ) Execute(Excluding words from completion results should work with lists of Strings): let b:ale_completion_excluded_words = ['it', 'describe'] AssertEqual \ ['Italian'], \ ale#completion#Filter(bufnr(''), '', ['Italian', 'it'], 'it', 0) AssertEqual \ ['Deutsch'], \ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], 'de', 0) AssertEqual \ ['Deutsch'], \ ale#completion#Filter(bufnr(''), '', ['describe', 'Deutsch'], '.', 0) AssertEqual \ ['Deutsch'], \ ale#completion#Filter(bufnr(''), '', ['Deutsch'], '', 0) 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, '.', 0) AssertEqual b:suggestions, [{'word': 'describe'}] AssertEqual [], ale#completion#Filter(bufnr(''), '', b:suggestions, 'de', 0) 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, '.', 0) AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '.', 0) AssertEqual b:suggestions, ale#completion#Filter(bufnr(''), 'rust', b:suggestions, '::', 0) ================================================ FILE: test/completion/test_completion_prefixes.vader ================================================ Given typescript(): let abc = y. let foo = ab let foo = (ab) let string1 = ' let string2 = " Execute(Completion should be done after dots in TypeScript): AssertEqual '.', ale#completion#GetPrefix(&filetype, 1, 13) Execute(Completion should be done after words in TypeScript): AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 2, 13) Execute(Completion should be done after words in parens in TypeScript): AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 3, 14) Execute(Completion should not be done after parens in TypeScript): AssertEqual '', ale#completion#GetPrefix(&filetype, 3, 15) Execute(Completion should be done after strings in TypeScript): AssertEqual '''', ale#completion#GetPrefix(&filetype, 4, 16) AssertEqual '"', ale#completion#GetPrefix(&filetype, 5, 16) Execute(Completion prefixes should work for other filetypes): AssertEqual 'ab', ale#completion#GetPrefix('xxxyyyzzz', 3, 14) Execute(Completion prefixes should work for other filetypes): AssertEqual 'ab', ale#completion#GetPrefix('xxxyyyzzz', 3, 14) Given rust(): let abc = y. let abc = String:: let foo = (ab) Execute(Completion should be done after dots in Rust): AssertEqual '.', ale#completion#GetPrefix(&filetype, 1, 13) Execute(Completion should be done after colons in Rust): AssertEqual '::', ale#completion#GetPrefix(&filetype, 2, 19) Execute(Completion should be done after words in parens in Rust): AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 3, 14) 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) ================================================ FILE: test/completion/test_lsp_completion_messages.vader ================================================ Before: Save g:ale_completion_delay Save g:ale_completion_enabled Save g:ale_completion_max_suggestions Save g:ale_completion_info Save g:ale_completion_autoimport Save &l:omnifunc Save &l:completeopt let g:ale_completion_enabled = v:true let g:ale_completion_autoimport = v:true call ale#test#SetDirectory('/testplugin/test/completion') call ale#test#SetFilename('dummy.txt') runtime autoload/ale/lsp.vim let g:message_list = [] let g:capability_checked = '' let g:conn_id = v:null let g:Callback = '' let g:init_callback_list = [] function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} call add(g:init_callback_list, {-> a:Callback(a:linter, l:details)}) endfunction " Pretend we're in insert mode for most tests. function! ale#util#Mode(...) abort return 'i' endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 endfunction function! ale#lsp#RegisterCallback(conn_id, callback) abort let g:Callback = a:callback endfunction " Replace the Send function for LSP, so we can monitor calls to it. function! ale#lsp#Send(conn_id, message) abort call add(g:message_list, a:message) return 1 endfunction 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:init_callback_list unlet! g:conn_id unlet! g:Callback unlet! b:ale_old_omnifunc unlet! b:ale_old_completeopt unlet! b:ale_completion_info unlet! b:ale_complete_done_time unlet! b:ale_linters unlet! b:ale_tsserver_completion_names " Reset the function. function! ale#util#Mode(...) abort return call('mode', a:000) endfunction call ale#test#RestoreDirectory() call ale#linter#Reset() " Stop any timers we left behind. " This stops the tests from failing randomly. call ale#completion#StopTimer() runtime autoload/ale/completion.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(The right message should be sent for the initial tsserver request): runtime ale_linters/typescript/tsserver.vim let b:ale_linters = ['tsserver'] " The cursor position needs to match what was saved before. call setpos('.', [bufnr(''), 1, 3, 0]) call ale#completion#GetCompletions('ale-automatic') " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual 1, len(g:init_callback_list) call map(g:init_callback_list, 'v:val()') AssertEqual 'completion', g:capability_checked " We should send the right callback. AssertEqual \ 'function(''ale#completion#HandleTSServerResponse'')', \ string(g:Callback) " We should send the right message. AssertEqual \ [[0, 'ts@completions', { \ 'file': expand('%:p'), \ 'line': 1, \ 'offset': 3, \ 'prefix': 'fo', \ 'includeExternalModuleExports': g:ale_completion_autoimport, \ }]], \ g:message_list " We should set up the completion info correctly. AssertEqual \ { \ 'line_length': 3, \ 'conn_id': g:conn_id, \ 'column': 3, \ 'request_id': 1, \ 'line': 1, \ 'prefix': 'fo', \ 'source': 'ale-automatic', \ }, \ get(b:, 'ale_completion_info', {}) Execute(The right message sent to the tsserver LSP when the first completion message is received): " The cursor position needs to match what was saved before. call setpos('.', [bufnr(''), 1, 1, 0]) let b:ale_completion_info = { \ 'conn_id': 123, \ 'prefix': 'f', \ 'request_id': 4, \ 'line': 1, \ 'column': 1, \} " We should only show up to this many suggestions. let g:ale_completion_max_suggestions = 3 " Handle the response for completions. call ale#completion#HandleTSServerResponse(123, { \ 'request_seq': 4, \ 'command': 'completions', \ 'body': [ \ {'name': 'Baz'}, \ {'name': 'dingDong'}, \ {'name': 'Foo', 'source': '/path/to/foo.ts'}, \ {'name': 'FooBar'}, \ {'name': 'frazzle'}, \ {'name': 'FFS'}, \ ], \}) " We should save the names we got in the buffer, as TSServer doesn't return " details for every name. AssertEqual [{ \ 'word': 'Foo', \ 'source': '/path/to/foo.ts', \ }, { \ 'word': 'FooBar', \ 'source': '', \ }, { \ 'word': 'frazzle', \ 'source': '', \}], \ get(b:, 'ale_tsserver_completion_names', []) " The entry details messages should have been sent. AssertEqual \ [[ \ 0, \ 'ts@completionEntryDetails', \ { \ 'file': expand('%:p'), \ 'entryNames': [{ \ 'name': 'Foo', \ 'source': '/path/to/foo.ts', \ }, { \ 'name': 'FooBar', \ }, { \ 'name': 'frazzle', \ }], \ 'offset': 1, \ 'line': 1, \ }, \ ]], \ g:message_list Given python(Some Python file): foo somelongerline bazxyzxyzxyz Execute(The right message should be sent for the initial LSP request): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] " The cursor position needs to match what was saved before. call setpos('.', [bufnr(''), 1, 5, 0]) call ale#completion#GetCompletions('ale-automatic') " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual 1, len(g:init_callback_list) call map(g:init_callback_list, 'v:val()') AssertEqual 'completion', g:capability_checked " We should send the right callback. AssertEqual \ 'function(''ale#completion#HandleLSPResponse'')', \ string(g:Callback) " We should send the right message. " The character index needs to be at most the index of the last character on " the line, or integration with pylsp will be broken. " " We need to send the message for changing the document first. AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/completion', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list " We should set up the completion info correctly. AssertEqual \ { \ 'line_length': 3, \ 'conn_id': g:conn_id, \ 'column': 3, \ 'request_id': 1, \ 'line': 1, \ 'prefix': 'fo', \ 'source': 'ale-automatic', \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ }, \ get(b:, 'ale_completion_info', {}) Execute(Two completion requests shouldn't be sent in a row): call ale#linter#PreventLoading('python') call ale#linter#Define('python', { \ 'name': 'foo', \ 'lsp': 'stdio', \ 'executable': 'foo', \ 'command': 'foo', \ 'project_root': {-> '/foo/bar'}, \}) call ale#linter#Define('python', { \ 'name': 'bar', \ 'lsp': 'stdio', \ 'executable': 'foo', \ 'command': 'foo', \ 'project_root': {-> '/foo/bar'}, \}) let b:ale_linters = ['foo', 'bar'] " The cursor position needs to match what was saved before. call setpos('.', [bufnr(''), 1, 5, 0]) call ale#completion#GetCompletions('ale-automatic') " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual 2, len(g:init_callback_list) call map(g:init_callback_list, 'v:val()') AssertEqual 'completion', g:capability_checked " We should only send one completion message for two LSP servers. AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/completion', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list ================================================ FILE: test/completion/test_lsp_completion_parsing.vader ================================================ Before: Save g:ale_completion_autoimport Save g:ale_completion_max_suggestions let g:ale_completion_max_suggestions = 50 After: Restore unlet! b:ale_completion_info Execute(Should handle Rust completion results correctly): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ {'word': 'new', 'dup': 0, 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'with_capacity', 'dup': 0, 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_utf8', 'dup': 0, 'menu': 'pub fn from_utf8(vec: Vec) -> Result', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_utf8_lossy', 'dup': 0, 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_utf16', 'dup': 0, 'menu': 'pub fn from_utf16(v: &[u16]) -> Result', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_utf16_lossy', 'dup': 0, 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_raw_parts', 'dup': 0, 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_utf8_unchecked', 'dup': 0, 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_iter', 'dup': 0, 'menu': 'fn from_iter>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Searcher', 'dup': 0, 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'default', 'dup': 0, 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = String;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Output', 'dup': 0, 'menu': 'type Output = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Target', 'dup': 0, 'menu': 'type Target = str;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'Err', 'dup': 0, 'menu': 'type Err = ParseError;', 'info': '', 'kind': 't', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from_str', 'dup': 0, 'menu': 'fn from_str(s: &str) -> Result', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: Box) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'from', 'dup': 0, 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'to_vec', 'dup': 0, 'menu': 'pub fn to_vec(&self) -> Vec where T: Clone,', 'info': '', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \], \ ale#completion#ParseLSPCompletions({ \ "jsonrpc":"2.0", \ "id":65, \ "result":[ \ { \ "label":"new", \ "kind":3, \ "detail":"pub fn new() -> String" \ }, \ { \ "label":"with_capacity", \ "kind":3, \ "detail":"pub fn with_capacity(capacity: usize) -> String" \ }, \ { \ "label":"from_utf8", \ "kind":3, \ "detail":"pub fn from_utf8(vec: Vec) -> Result" \ }, \ { \ "label":"from_utf8_lossy", \ "kind":3, \ "detail":"pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str>" \ }, \ { \ "label":"from_utf16", \ "kind":3, \ "detail":"pub fn from_utf16(v: &[u16]) -> Result" \ }, \ { \ "label":"from_utf16_lossy", \ "kind":3, \ "detail":"pub fn from_utf16_lossy(v: &[u16]) -> String" \ }, \ { \ "label":"from_raw_parts", \ "kind":3, \ "detail":"pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String" \ }, \ { \ "label":"from_utf8_unchecked", \ "kind":3, \ "detail":"pub unsafe fn from_utf8_unchecked(bytes: Vec) -> String" \ }, \ { \ "label":"from_iter", \ "kind":3, \ "detail":"fn from_iter>(iter: I) -> String" \ }, \ { \ "label":"from_iter", \ "kind":3, \ "detail":"fn from_iter>(iter: I) -> String" \ }, \ { \ "label":"from_iter", \ "kind":3, \ "detail":"fn from_iter>(iter: I) -> String" \ }, \ { \ "label":"from_iter", \ "kind":3, \ "detail":"fn from_iter>(iter: I) -> String" \ }, \ { \ "label":"from_iter", \ "kind":3, \ "detail":"fn from_iter>>(iter: I) -> String" \ }, \ { \ "label":"Searcher", \ "kind":8, \ "detail":"type Searcher = <&'b str as Pattern<'a>>::Searcher;" \ }, \ { \ "label":"default", \ "kind":3, \ "detail":"fn default() -> String" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = String;" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = str;" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = str;" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = str;" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = str;" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = str;" \ }, \ { \ "label":"Output", \ "kind":8, \ "detail":"type Output = str;" \ }, \ { \ "label":"Target", \ "kind":8, \ "detail":"type Target = str;" \ }, \ { \ "label":"Err", \ "kind":8, \ "detail":"type Err = ParseError;" \ }, \ { \ "label":"from_str", \ "kind":3, \ "detail":"fn from_str(s: &str) -> Result" \ }, \ { \ "label":"from", \ "kind":3, \ "detail":"fn from(s: &'a str) -> String" \ }, \ { \ "label":"from", \ "kind":3, \ "detail":"fn from(s: Box) -> String" \ }, \ { \ "label":"from", \ "kind":3, \ "detail":"fn from(s: Cow<'a, str>) -> String" \ }, \ { \ "label":"to_vec", \ "kind":3, \ "detail":"pub fn to_vec(&self) -> Vec\nwhere\n T: Clone," \ } \ ] \ }) Execute(Should handle Python completion results correctly): let g:ale_completion_autoimport = 0 let b:ale_completion_info = { \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \} AssertEqual \ [ \ {'word': 'what', 'dup': 0, 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ ], \ ale#completion#ParseLSPCompletions({ \ "jsonrpc":"2.0", \ "id":6, \ "result":{ \ "isIncomplete":v:false, \ "items":[ \ { \ "label":"what()", \ "kind":3, \ "detail":"example-python-project.bar.Bar", \ "documentation":"what()\n\n", \ "sortText":"awhat", \ "insertText":"what" \ }, \ { \ "label":"__class__", \ "kind":7, \ "detail":"object", \ "documentation":"type(object_or_name, bases, dict)\ntype(object) -> the object's type\ntype(name, bases, dict) -> a new type", \ "sortText":"z__class__", \ "insertText":"__class__" \ }, \ { \ "label":"__delattr__(name)", \ "kind":3, \ "detail":"object", \ "documentation":"Implement delattr(self, name).", \ "sortText":"z__delattr__", \ "insertText":"__delattr__" \ }, \ { \ "label":"__dir__()", \ "kind":3, \ "detail":"object", \ "documentation":"__dir__() -> list\ndefault dir() implementation", \ "sortText":"z__dir__", \ "insertText":"__dir__" \ }, \ { \ "label":"__doc__", \ "kind":18, \ "detail":"object", \ "documentation":"str(object='') -> str\nstr(bytes_or_buffer[, encoding[, errors]]) -> str\n\nCreate a new string object from the given object. If encoding or\nerrors is specified, then the object must expose a data buffer\nthat will be decoded using the given encoding and error handler.\nOtherwise, returns the result of object.__str__() (if defined)\nor repr(object).\nencoding defaults to sys.getdefaultencoding().\nerrors defaults to 'strict'.", \ "sortText":"z__doc__", \ "insertText":"__doc__" \ }, \ { \ "label":"__eq__(value)", \ "kind":3, \ "detail":"object", \ "documentation":"Return self==value.", \ "sortText":"z__eq__", \ "insertText":"__eq__" \ }, \ { \ "label":"__format__()", \ "kind":3, \ "detail":"object", \ "documentation":"default object formatter", \ "sortText":"z__format__", \ "insertText":"__format__" \ }, \ { \ "label":"__ge__(value)", \ "kind":3, \ "detail":"object", \ "documentation":"Return self>=value.", \ "sortText":"z__ge__", \ "insertText":"__ge__" \ }, \ { \ "label":"__getattribute__(name)", \ "kind":3, \ "detail":"object", \ "documentation":"Return getattr(self, name).", \ "sortText":"z__getattribute__", \ "insertText":"__getattribute__" \ }, \ { \ "label":"__gt__(value)", \ "kind":3, \ "detail":"object", \ "documentation":"Return self>value.", \ "sortText":"z__gt__", \ "insertText":"__gt__" \ }, \ { \ "label":"__hash__()", \ "kind":3, \ "detail":"object", \ "documentation":"Return hash(self).", \ "sortText":"z__hash__", \ "insertText":"__hash__" \ }, \ { \ "label":"__init__(args, kwargs)", \ "kind":3, \ "detail":"object", \ "documentation":"Initialize self.\u00a0\u00a0See help(type(self)) for accurate signature.", \ "sortText":"z__init__", \ "insertText":"__init__" \ }, \ { \ "label":"__init_subclass__()", \ "kind":3, \ "detail":"object", \ "documentation":"This method is called when a class is subclassed.\n\nThe default implementation does nothing. It may be\noverridden to extend subclasses.", \ "sortText":"z__init_subclass__", \ "insertText":"__init_subclass__" \ }, \ { \ "label":"__le__(value)", \ "kind":3, \ "detail":"object", \ "documentation":"Return self<=value.", \ "sortText":"z__le__", \ "insertText":"__le__" \ }, \ { \ "label":"__lt__(value)", \ "kind":3, \ "detail":"object", \ "documentation":"Return self int\nsize of object in memory, in bytes", \ "sortText":"z__sizeof__", \ "insertText":"__sizeof__" \ }, \ { \ "label":"__str__()", \ "kind":3, \ "detail":"object", \ "documentation":"Return str(self).", \ "sortText":"z__str__", \ "insertText":"__str__" \ }, \ { \ "label":"__subclasshook__()", \ "kind":3, \ "detail":"object", \ "documentation":"Abstract classes can override this to customize issubclass().\n\nThis is invoked early on by abc.ABCMeta.__subclasscheck__().\nIt should return True, False or NotImplemented.\u00a0\u00a0If it returns\nNotImplemented, the normal algorithm is used.\u00a0\u00a0Otherwise, it\noverrides the normal algorithm (and the outcome is cached).", \ "sortText":"z__subclasshook__", \ "insertText":"__subclasshook__" \ } \ ] \ } \ }) Execute(Should handle extra Python completion results correctly): let g:ale_completion_autoimport = 0 let b:ale_completion_info = { \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', \ 'prefix': 'mig', \} AssertEqual \ [ \ {'word': 'migrations', 'dup': 0, 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ {'word': 'MigEngine', 'dup': 0, 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ ], \ ale#completion#ParseLSPCompletions({ \ 'jsonrpc': '2.0', \ 'id': 6, \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'label': 'migrations', \ 'kind': 3, \ 'detail': 'xxx', \ 'documentation': 'migrations', \ }, \ { \ 'label': 'MigEngine', \ 'kind': 3, \ 'detail': 'xxx', \ 'documentation': 'mig engine', \ }, \ { \ 'label': 'ignore me', \ 'kind': 3, \ 'detail': 'nope', \ 'documentation': 'nope', \ }, \ ] \ } \ }) Execute(Should handle missing keys): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ {'word': 'x', 'dup': 0, 'menu': '', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ ], \ ale#completion#ParseLSPCompletions({ \ 'jsonrpc': '2.0', \ 'id': 6, \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'label': 'x', \ }, \ ] \ } \ }) Execute(Should handle documentation in the markdown format): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ {'word': 'migrations', 'dup': 0, 'menu': 'xxx', 'info': 'Markdown documentation', 'kind': 'f', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 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', \ }, \ }, \ ], \ }, \ }) Execute(Should handle completion messages with textEdit objects): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ ], \ ale#completion#ParseLSPCompletions({ \ 'id': 226, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'PlayTimeCallback', \ 'filterText': 'next_callback', \ 'insertText': 'ignoreme', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' next_callback', \ 'sortText': '3ee19999next_callback', \ 'textEdit': { \ 'newText': 'next_callback', \ 'range': { \ 'end': {'character': 13, 'line': 12}, \ 'start': {'character': 4, 'line': 12}, \ }, \ }, \ }, \ ], \ }, \ }) Execute(Should handle completion messages with textEdit objects and no insertTextFormat key): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ ], \ ale#completion#ParseLSPCompletions({ \ 'id': 226, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'PlayTimeCallback', \ 'filterText': 'next_callback', \ 'insertText': 'ignoreme', \ 'kind': 6, \ 'label': ' next_callback', \ 'sortText': '3ee19999next_callback', \ 'textEdit': { \ 'newText': 'next_callback', \ 'range': { \ 'end': {'character': 13, 'line': 12}, \ 'start': {'character': 4, 'line': 12}, \ }, \ }, \ }, \ ], \ }, \ }) Execute(Should handle completion messages with the deprecated insertText attribute): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ {'word': 'next_callback', 'dup': 0, 'menu': 'PlayTimeCallback', 'info': '', 'kind': 'v', 'icase': 1, 'user_data': json_encode({'_ale_completion_item': 1})}, \ ], \ ale#completion#ParseLSPCompletions({ \ 'id': 226, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'PlayTimeCallback', \ 'filterText': 'next_callback', \ 'insertText': 'next_callback', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' next_callback', \ 'sortText': '3ee19999next_callback', \ }, \ ], \ }, \ }) Execute(Should handle completion messages with additionalTextEdits when ale_completion_autoimport is turned on): let g:ale_completion_autoimport = 1 AssertEqual \ [ \ { \ 'word': 'next_callback', \ 'dup': 1, \ 'menu': 'PlayTimeCallback', \ 'info': '', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [ \ { \ 'description': 'completion', \ 'changes': [ \ { \ 'fileName': expand('#' . bufnr('') . ':p'), \ 'textChanges': [ \ { \ 'start': { \ 'line': 11, \ 'offset': 2, \ }, \ 'end': { \ 'line': 13, \ 'offset': 4, \ }, \ 'newText': 'from "module" import next_callback', \ }, \ ], \ }, \ ], \ }, \ ], \ }), \ }, \ ], \ ale#completion#ParseLSPCompletions({ \ 'id': 226, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'PlayTimeCallback', \ 'filterText': 'next_callback', \ 'insertText': 'next_callback', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' next_callback', \ 'sortText': '3ee19999next_callback', \ 'additionalTextEdits': [ \ { \ 'range': { \ 'start': { \ 'line': 10, \ 'character': 1, \ }, \ 'end': { \ 'line': 12, \ 'character': 3, \ }, \ }, \ 'newText': 'from "module" import next_callback', \ }, \ ], \ }, \ ], \ }, \ }) Execute(Should not handle completion messages with additionalTextEdits when ale_completion_autoimport is turned off): let g:ale_completion_autoimport = 0 let b:ale_completion_info = {'line': 30} AssertEqual \ [], \ ale#completion#ParseLSPCompletions({ \ 'id': 226, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'PlayTimeCallback', \ 'filterText': 'next_callback', \ 'insertText': 'next_callback', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' next_callback', \ 'sortText': '3ee19999next_callback', \ 'additionalTextEdits': [ \ { \ 'range': { \ 'start': { \ 'line': 10, \ 'character': 1, \ }, \ 'end': { \ 'line': 12, \ 'character': 3, \ }, \ }, \ 'newText': 'from "module" import next_callback', \ }, \ ], \ }, \ ], \ }, \ }) Execute(Should still handle completion messages with empty additionalTextEdits with ale_completion_autoimport turned off): let g:ale_completion_autoimport = 0 AssertEqual \ [ \ { \ 'word': 'next_callback', \ 'dup': 0, \ 'menu': 'PlayTimeCallback', \ 'info': '', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({'_ale_completion_item': 1}), \ } \ ], \ ale#completion#ParseLSPCompletions({ \ 'id': 226, \ 'jsonrpc': '2.0', \ 'result': { \ 'isIncomplete': v:false, \ 'items': [ \ { \ 'detail': 'PlayTimeCallback', \ 'filterText': 'next_callback', \ 'insertText': 'next_callback', \ 'insertTextFormat': 1, \ 'kind': 6, \ 'label': ' next_callback', \ 'sortText': '3ee19999next_callback', \ 'additionalTextEdits': [], \ }, \ ], \ }, \ }) ================================================ FILE: test/completion/test_omnifunc_completion.vader ================================================ Before: unlet! b:ale_completion_info unlet! b:ale_completion_result let b:lsp_started = 0 runtime autoload/ale/lsp_linter.vim function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort return b:lsp_started endfunction function! SetCompletionResult(...) abort let b:ale_completion_result = ['foo'] endfunction function! SetCompletionResponse(...) abort let b:ale_completion_result = ['foo'] endfunction After: unlet! b:ale_completion_info unlet! b:ale_completion_result unlet! b:lsp_started delfunction SetCompletionResult delfunction SetCompletionResponse runtime autoload/ale/lsp_linter.vim call ale#linter#Reset() Given typescript(): let abc = y. let foo = ab let foo = (ab) Execute(-3 should be returned when completion results cannot be requested): AssertEqual -3, ale#completion#OmniFunc(1, '') Execute(The start position should be returned when results can be requested): let b:lsp_started = 1 call setpos('.', [bufnr(''), 3, 14, 0]) AssertEqual 11, ale#completion#OmniFunc(1, '') Execute(The omnifunc function should return async results): " Neovim struggles at running these tests. if !has('nvim') call timer_start(0, function('SetCompletionResult')) AssertEqual ['foo'], ale#completion#OmniFunc(0, '') endif Execute(The omnifunc function should parse and return async responses): if !has('nvim') call timer_start(0, function('SetCompletionResponse')) AssertEqual ['foo'], ale#completion#OmniFunc(0, '') endif ================================================ FILE: test/completion/test_public_completion_api.vader ================================================ Before: call ale#linter#Reset() unlet! b:ale_linters unlet! b:ale_completion_info unlet! b:ale_completion_result After: call ale#linter#Reset() unlet! b:ale_linters unlet! b:ale_completion_info unlet! b:ale_completion_result Execute(ale#completion#GetCompletionResult() should return v:null when there are no results): AssertEqual v:null, ale#completion#GetCompletionResult() Execute(ale#completion#GetCompletionResult() should return a result computed previously): let b:ale_completion_result = [1] AssertEqual [1], ale#completion#GetCompletionResult() Execute(ale#completion#GetCompletionPosition() should return 0 when there is no completion information): AssertEqual 0, ale#completion#GetCompletionPosition() Given python(Some Python file): foo bar Execute(ale#completion#GetCompletionPosition() should return the position in the file when information is available): let b:ale_completion_info = {'line': 1, 'column': 6} " This is the first character of 'bar' AssertEqual 4, ale#completion#GetCompletionPosition() Execute(ale#completion#GetCompletionPositionForDeoplete() should return the position on the given input string): " This is the first character of 'bar' AssertEqual 4, ale#completion#GetCompletionPositionForDeoplete('foo bar') Execute(ale#completion#CanProvideCompletions should return 0 when no completion sources are available): let b:ale_linters = ['flake8'] AssertEqual 0, ale#completion#CanProvideCompletions() Execute(ale#completion#CanProvideCompletions should return 1 when at least one completion source is available): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] AssertEqual 1, ale#completion#CanProvideCompletions() ================================================ FILE: test/completion/test_tsserver_completion_parsing.vader ================================================ Before: Save g:ale_completion_autoimport Save g:ale_completion_tsserver_remove_warnings let g:ale_completion_autoimport = v:true let g:ale_completion_tsserver_remove_warnings = v:false After: Restore unlet! b:ale_tsserver_completion_names Execute(TypeScript completions responses should be parsed correctly): AssertEqual [], \ ale#completion#ParseTSServerCompletions({ \ 'body': [], \}) AssertEqual \ [ \ { \ 'word': 'foo', \ 'source': '/path/to/foo.ts', \ }, \ { \ 'word': 'bar', \ 'source': '', \ }, \ { \ 'word': 'baz', \ 'source': '', \ } \ ], \ ale#completion#ParseTSServerCompletions({ \ 'body': [ \ {'name': 'foo', 'source': '/path/to/foo.ts'}, \ {'name': 'bar'}, \ {'name': 'baz'}, \ ], \}) Execute(TypeScript completions responses should include warnings): AssertEqual \ [ \ { \ 'word': 'foo', \ 'source': '/path/to/foo.ts', \ }, \ { \ 'word': 'bar', \ 'source': '', \ }, \ { \ 'word': 'baz', \ 'source': '', \ } \ ], \ ale#completion#ParseTSServerCompletions({ \ 'body': [ \ {'name': 'foo', 'source': '/path/to/foo.ts'}, \ {'name': 'bar', 'kind': 'warning'}, \ {'name': 'baz'}, \ ], \}) Execute(TypeScript completions responses should not include warnings if excluded): let g:ale_completion_tsserver_remove_warnings = 1 AssertEqual \ [ \ { \ 'word': 'foo', \ 'source': '/path/to/foo.ts', \ }, \ { \ 'word': 'baz', \ 'source': '', \ } \ ], \ ale#completion#ParseTSServerCompletions({ \ 'body': [ \ {'name': 'foo', 'source': '/path/to/foo.ts'}, \ {'name': 'bar', 'kind': 'warning'}, \ {'name': 'baz'}, \ ], \}) Execute(TypeScript completion details responses should be parsed correctly): AssertEqual \ [ \ { \ 'word': 'abc', \ 'menu': '(property) Foo.abc: number', \ 'info': '', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({'_ale_completion_item': 1}), \ 'dup': g:ale_completion_autoimport + 0, \ }, \ { \ 'word': 'def', \ 'menu': '(property) Foo.def: number', \ 'info': 'foo bar baz', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({'_ale_completion_item': 1}), \ 'dup': g:ale_completion_autoimport + 0, \ }, \ { \ 'word': 'ghi', \ 'menu': '(class) Foo', \ 'info': '', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({'_ale_completion_item': 1}), \ 'dup': g:ale_completion_autoimport + 0, \ }, \ ], \ ale#completion#ParseTSServerCompletionEntryDetails({ \ 'body': [ \ { \ 'name': 'abc', \ 'kind': 'parameterName', \ 'displayParts': [ \ {'text': '('}, \ {'text': 'property'}, \ {'text': ')'}, \ {'text': ' '}, \ {'text': 'Foo'}, \ {'text': '.'}, \ {'text': 'abc'}, \ {'text': ':'}, \ {'text': ' '}, \ {'text': 'number'}, \ ], \ }, \ { \ 'name': 'def', \ 'kind': 'parameterName', \ 'displayParts': [ \ {'text': '('}, \ {'text': 'property'}, \ {'text': ')'}, \ {'text': ' '}, \ {'text': 'Foo'}, \ {'text': '.'}, \ {'text': 'def'}, \ {'text': ':'}, \ {'text': ' '}, \ {'text': 'number'}, \ ], \ 'documentation': [ \ {'text': 'foo'}, \ {'text': ' '}, \ {'text': 'bar'}, \ {'text': ' '}, \ {'text': 'baz'}, \ ], \ }, \ { \ 'name': 'ghi', \ 'kind': 'className', \ 'displayParts': [ \ {'text': '('}, \ {'text': 'class'}, \ {'text': ')'}, \ {'text': ' '}, \ {'text': 'Foo'}, \ ], \ }, \ ], \}) Execute(Entries without details should be included in the responses): let b:ale_tsserver_completion_names = [{ \ 'word': 'xyz', \ 'source': '/path/to/xyz.ts', \ }] AssertEqual \ [ \ { \ 'word': 'abc', \ 'menu': 'import { def } from "./Foo"; (property) Foo.abc: number', \ 'info': '', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [{ \ 'description': 'import { def } from "./Foo";', \ 'changes': [], \ }], \ }), \ 'dup': g:ale_completion_autoimport + 0, \ }, \ { \ 'word': 'def', \ 'menu': '(property) Foo.def: number', \ 'info': 'foo bar baz', \ 'kind': 'v', \ 'icase': 1, \ 'user_data': json_encode({'_ale_completion_item': 1}), \ 'dup': g:ale_completion_autoimport + 0, \ }, \ { \ 'word': 'xyz', \ 'menu': '', \ 'info': '', \ 'kind': 'v', \ 'user_data': json_encode({'_ale_completion_item': 1}), \ 'icase': 1, \ }, \ ], \ ale#completion#ParseTSServerCompletionEntryDetails({ \ 'body': [ \ { \ 'name': 'abc', \ 'kind': 'parameterName', \ 'displayParts': [ \ {'text': '('}, \ {'text': 'property'}, \ {'text': ')'}, \ {'text': ' '}, \ {'text': 'Foo'}, \ {'text': '.'}, \ {'text': 'abc'}, \ {'text': ':'}, \ {'text': ' '}, \ {'text': 'number'}, \ ], \ 'codeActions': [{ \ 'description': 'import { def } from "./Foo";', \ 'changes': [], \ }], \ }, \ { \ 'name': 'def', \ 'kind': 'parameterName', \ 'displayParts': [ \ {'text': '('}, \ {'text': 'property'}, \ {'text': ')'}, \ {'text': ' '}, \ {'text': 'Foo'}, \ {'text': '.'}, \ {'text': 'def'}, \ {'text': ':'}, \ {'text': ' '}, \ {'text': 'number'}, \ ], \ 'documentation': [ \ {'text': 'foo'}, \ {'text': ' '}, \ {'text': 'bar'}, \ {'text': ' '}, \ {'text': 'baz'}, \ ], \ }, \ ], \}) Execute(Default imports should be handled correctly): AssertEqual \ [ \ { \ 'word': 'abcd', \ 'menu': 'Import default ''abcd'' from module "./foo" (alias) const abcd: 3', \ 'info': '', \ 'kind': 't', \ 'icase': 1, \ 'user_data': json_encode({ \ '_ale_completion_item': 1, \ 'code_actions': [{ \ 'description': 'Import default ''abcd'' from module "./foo"', \ 'changes': [], \ }], \ }), \ 'dup': g:ale_completion_autoimport + 0, \ }, \ ], \ ale#completion#ParseTSServerCompletionEntryDetails({ \ 'body': [ \ { \ 'name': 'default', \ 'kind': 'alias', \ 'displayParts': [ \ {'kind': 'punctuation', 'text': '('}, \ {'kind': 'text', 'text': 'alias'}, \ {'kind': 'punctuation', 'text': ')'}, \ {'kind': 'space', 'text': ' '}, \ {'kind': 'keyword', 'text': 'const'}, \ {'kind': 'space', 'text': ' '}, \ {'kind': 'localName', 'text': 'abcd'}, \ {'kind': 'punctuation', 'text': ':'}, \ {'kind': 'space', 'text': ' '}, \ {'kind': 'stringLiteral', 'text': '3'}, \ {'kind': 'lineBreak', 'text': '^@'}, \ {'kind': 'keyword', 'text': 'export'}, \ {'kind': 'space', 'text': ' '}, \ {'kind': 'keyword', 'text': 'default'}, \ {'kind': 'space', 'text': ' '}, \ {'kind': 'aliasName', 'text': 'abcd'} \ ], \ 'codeActions': [ \ { \ 'description': 'Import default ''abcd'' from module "./foo"', \ 'changes': [], \ }, \ ], \ }, \ ], \ }) ================================================ FILE: test/fix/test_ale_fix.vader ================================================ Before: Save g:ale_fixers Save &shell Save g:ale_enabled Save g:ale_fix_on_save Save g:ale_lint_on_save Save g:ale_echo_cursor Save g:ale_command_wrapper Save g:ale_filename_mappings silent! cd /testplugin/test/fix unlet! b:ale_lint_on_save let g:ale_enabled = 0 let g:ale_echo_cursor = 0 let g:ale_command_wrapper = '' let g:ale_run_synchronously = 1 let g:ale_set_lists_synchronously = 1 let g:ale_fix_buffer_data = {} let g:ale_fixers = { \ 'testft': [], \} let g:ale_filename_mappings = {} let g:pre_success = 0 let g:post_success = 0 augroup VaderTest autocmd! autocmd User ALEFixPre let g:pre_success = 1 autocmd User ALEFixPost let g:post_success = 1 augroup END if !has('win32') let &shell = '/bin/bash' endif call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('test.txt') call ale#linter#PreventLoading('testft') function AddCarets(buffer, lines) abort " map() is applied to the original lines here. " This way, we can ensure that defensive copies are made. return map(a:lines, '''^'' . v:val') endfunction function Capitalize(buffer, lines) abort return map(a:lines, 'toupper(v:val)') endfunction function DoNothing(buffer, lines) abort return 0 endfunction function CatLine(buffer, lines) abort return {'command': 'cat - <(echo d)'} endfunction function CatLineOneArg(buffer) abort return {'command': 'cat - <(echo d)'} endfunction function CatLineDeferred(buffer, lines) abort return ale#command#Run(a:buffer, 'echo', { \ -> ale#command#Run(a:buffer, 'echo', {-> {'command': 'cat - <(echo d)'}}) \}) endfunction function ReplaceWithTempFile(buffer, lines) abort return {'command': 'echo x > %t', 'read_temporary_file': 1} endfunction function CatWithTempFile(buffer, lines) abort return {'command': 'cat %t <(echo d)'} endfunction function EchoFilename(buffer, lines) abort return {'command': 'echo %s'} endfunction function RemoveLastLine(buffer, lines) abort return ['a', 'b'] endfunction function RemoveLastLineOneArg(buffer) abort return ['a', 'b'] endfunction function! TestCallback(buffer, output) return [{'lnum': 1, 'col': 1, 'text': 'xxx'}] endfunction " echo will output a single blank line, and we should ignore it. function! IgnoredEmptyOutput(buffer, output) return {'command': has('win32') ? 'echo(' : 'echo'} endfunction function! EchoLineNoPipe(buffer, output) return {'command': 'echo new line', 'read_buffer': 0} endfunction function! SetUpLinters() call ale#linter#Define('testft', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': 'true', \ 'command': 'true', \}) endfunction function GetLastMessage() redir => l:output silent mess redir END let l:lines = split(l:output, "\n") return empty(l:lines) ? '' : l:lines[-1] endfunction function! FixWithJSONPostProcessing(buffer) abort let l:ProcessWith = 'JSONPostProcessor' " Test with lambdas where support is available. if has('lambda') let l:ProcessWith = {buffer, output -> JSONPostProcessor(buffer, output)} endif " Escaping needs to be handled specially for CMD on Windows. let l:json_string = has('win32') \ ? '{"output":["x","y","z"]}' \ : ale#Escape('{"output": ["x", "y", "z"]}') return { \ 'command': 'echo ' . l:json_string, \ 'read_buffer': 0, \ 'process_with': l:ProcessWith, \} endfunction function! JSONPostProcessor(buffer, output) abort return json_decode(a:output[0]).output endfunction After: Restore unlet! g:test_filename unlet! g:ale_run_synchronously unlet! g:ale_set_lists_synchronously unlet! g:ale_run_synchronously_callbacks unlet! g:ale_emulate_job_failure unlet! b:ale_fixers unlet! b:ale_lint_on_save unlet! b:ale_fix_on_save unlet! b:ale_quitting delfunction AddCarets delfunction Capitalize delfunction DoNothing delfunction CatLine delfunction CatLineOneArg delfunction CatLineDeferred delfunction ReplaceWithTempFile delfunction CatWithTempFile delfunction EchoFilename delfunction RemoveLastLine delfunction RemoveLastLineOneArg delfunction TestCallback delfunction SetUpLinters delfunction GetLastMessage delfunction IgnoredEmptyOutput delfunction EchoLineNoPipe delfunction FixWithJSONPostProcessing delfunction JSONPostProcessor augroup VaderTest autocmd! augroup END augroup! VaderTest call ale#test#RestoreDirectory() call ale#fix#registry#ResetToDefaults() call ale#linter#Reset() setlocal buftype=nofile if exists('g:test_filename') && filereadable(g:test_filename) call delete(g:test_filename) endif call setloclist(0, []) let g:ale_fix_buffer_data = {} " Clear the messages between tests. echomsg '' if !exists('g:ale_command_wrapper') let g:ale_command_wrapper = '' endif Given testft (A file with three lines): a b c Execute(ALEFix should complain when there are no functions to call): ALEFix call ale#test#FlushJobs() AssertEqual 'No fixers have been defined. Try :ALEFixSuggest', GetLastMessage() Execute(ALEFix should not complain when the command is run with a bang): echom 'none' ALEFix! call ale#test#FlushJobs() AssertEqual 'none', GetLastMessage() Execute(ALEFix should apply simple functions): let g:ale_fixers.testft = ['AddCarets'] ALEFix call ale#test#FlushJobs() Expect(The first function should be used): ^a ^b ^c Execute(Should apply filename mpapings): " The command echos %s, and we'll map the current path so we can check " that ALEFix applies filename mappings, end-to-end. let g:ale_filename_mappings = { \ 'echo_filename': [ \ [expand('%:p:h') . '/', '/some/fake/path/'], \ ], \} call ale#fix#registry#Add('echo_filename', 'EchoFilename', [], 'echo filename') let g:ale_fixers.testft = ['echo_filename'] ALEFix call ale#test#FlushJobs() " Remote trailing whitespace from the line. call setline(1, substitute(getline(1), '[ \r]\+$', '', '')) Expect(The mapped filename should be printed): /some/fake/path/test.txt Execute(ALEFix should apply simple functions in a chain): let g:ale_fixers.testft = ['AddCarets', 'Capitalize'] ALEFix call ale#test#FlushJobs() Expect(Both functions should be used): ^A ^B ^C Execute(ALEFix should allow 0 to be returned to skip functions): let g:ale_fixers.testft = ['DoNothing', 'Capitalize'] ALEFix call ale#test#FlushJobs() Expect(Only the second function should be applied): A B C Execute(The * fixers shouldn't be used if an empty list is set for fixers): let g:ale_fixers.testft = [] let g:ale_fixers['*'] = ['Capitalize'] ALEFix call ale#test#FlushJobs() Expect(Nothing should be changed): a b c Execute(* fixers should be used if no filetype is matched): let g:ale_fixers = {'*': ['Capitalize']} ALEFix call ale#test#FlushJobs() Expect(The file should be changed): A B C Execute(ALEFix should allow commands to be run): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['a', 'b', 'c', 'd']) else let g:ale_fixers.testft = ['CatLine'] ALEFix call ale#test#FlushJobs() endif Expect(An extra line should be added): a b c d Execute(ALEFix should use fixers passed in commandline when provided): let g:ale_fixers.testft = ['RemoveLastLine'] ALEFix AddCarets Capitalize call ale#test#FlushJobs() Expect(Only fixers passed via command line should be run): ^A ^B ^C Execute(ALEFix should allow temporary files to be read): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['x']) 2,3d else let g:ale_fixers.testft = ['ReplaceWithTempFile'] ALEFix call ale#test#FlushJobs() endif Expect(The line we wrote to the temporary file should be used here): x Execute(ALEFix should not read the temporary file when the option is not set): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['a', 'b', 'c', 'd']) else let g:ale_fixers.testft = ['CatWithTempFile'] ALEFix call ale#test#FlushJobs() endif Expect(An extra line should be added): a b c d Execute(ALEFix should allow jobs and simple functions to be combined): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['X']) 2,3d else let g:ale_fixers.testft = ['ReplaceWithTempFile', 'Capitalize'] ALEFix call ale#test#FlushJobs() endif Expect(The lines from the temporary file should be modified): X Execute(ALEFix should send lines modified by functions to jobs): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['A', 'B', 'C', 'd']) else let g:ale_fixers.testft = ['Capitalize', 'CatLine'] ALEFix call ale#test#FlushJobs() endif Expect(The lines should first be modified by the function, then the job): A B C d Execute(ALEFix should skip commands when jobs fail to run): let g:ale_emulate_job_failure = 1 let g:ale_fixers.testft = ['CatLine', 'Capitalize'] ALEFix call ale#test#FlushJobs() Expect(Only the second function should be applied): A B C Execute(ALEFix should handle strings for selecting a single function): let g:ale_fixers.testft = 'AddCarets' ALEFix call ale#test#FlushJobs() Expect(The first function should be used): ^a ^b ^c Execute(ALEFix should use functions from the registry): call ale#fix#registry#Add('add_carets', 'AddCarets', [], 'Add some carets') let g:ale_fixers.testft = ['add_carets'] ALEFix call ale#test#FlushJobs() Expect(The registry function should be used): ^a ^b ^c Execute(ALEFix should be able to remove the last line for files): let g:ale_fixers.testft = ['RemoveLastLine'] ALEFix call ale#test#FlushJobs() Expect(There should be only two lines): a b Execute(ALEFix should accept funcrefs): let g:ale_fixers.testft = [function('RemoveLastLine')] ALEFix call ale#test#FlushJobs() Expect(There should be only two lines): a b Execute(ALEFix should accept lambdas): if has('nvim') " NeoVim 0.1.7 can't interpret lambdas correctly, so just set the lines " to make the test pass. call setline(1, ['a', 'b', 'c', 'd']) else let g:ale_fixers.testft = [{buffer, lines -> lines + ['d']}] ALEFix call ale#test#FlushJobs() endif Expect(There should be an extra line): a b c d Execute(ALEFix should user buffer-local fixer settings): let g:ale_fixers.testft = ['AddCarets', 'Capitalize'] let b:ale_fixers = {'testft': ['RemoveLastLine']} ALEFix call ale#test#FlushJobs() Expect(There should be only two lines): a b Execute(ALEFix should allow Lists to be used for buffer-local fixer settings): let g:ale_fixers.testft = ['AddCarets', 'Capitalize'] let b:ale_fixers = ['RemoveLastLine'] ALEFix call ale#test#FlushJobs() Expect(There should be only two lines): a b Given testft (A file with three lines): a b c 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 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) call writefile(getline(1, '$'), g:test_filename) let g:ale_fixers.testft = ['Capitalize'] " We have to set the buftype to empty so the file will be written. setlocal buftype= call SetUpLinters() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() " We should save the file. AssertEqual ['A', 'B', 'C'], readfile(g:test_filename) Assert !&modified, 'The file was marked as ''modified''' if !has('win32') " We should have run the linter. AssertEqual [{ \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 1, \ 'text': 'xxx', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}], ale#test#GetLoclistWithoutNewerKeys() endif Expect(The buffer should be modified): A B C Given testft (A file with three lines): a b c Execute(ALEFix should run the linters with b:ale_lint_on_save = 1): let g:ale_fix_on_save = 0 let b:ale_fix_on_save = 1 let g:ale_lint_on_save = 1 let g:ale_enabled = 1 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) call writefile(getline(1, '$'), g:test_filename) let g:ale_fixers.testft = ['Capitalize'] " We have to set the buftype to empty so the file will be written. setlocal buftype= call SetUpLinters() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() " We should save the file. AssertEqual ['A', 'B', 'C'], readfile(g:test_filename) Assert !&modified, 'The file was marked as ''modified''' if !has('win32') " We should have run the linter. AssertEqual [{ \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 1, \ 'text': 'xxx', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}], ale#test#GetLoclistWithoutNewerKeys() endif Expect(The buffer should be modified): A 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 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) call writefile(getline(1, '$'), g:test_filename) let g:ale_fixers.testft = ['Capitalize'] " 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(g:test_filename) Assert &modified, 'The was not marked as ''modified''' " We should not run the linter. AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() Expect(The buffer should not be modified): a b c Given testft (A file with three lines): a b c Execute(ALEFix should still lint with no linters to be applied): let g:ale_fix_on_save = 1 let g:ale_lint_on_save = 1 let g:ale_enabled = 1 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) let g:ale_fixers.testft = [] call SetUpLinters() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() Assert !filereadable(g:test_filename), 'The file should not have been saved' if !has('win32') " We have run the linter. AssertEqual [{ \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 1, \ 'text': 'xxx', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}], ale#test#GetLoclistWithoutNewerKeys() endif Expect(The buffer should be the same): a b c Execute(ALEFix should still lint when nothing was fixed on save): let g:ale_fix_on_save = 1 let g:ale_lint_on_save = 1 let g:ale_enabled = 1 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) let g:ale_fixers.testft = ['DoNothing'] call SetUpLinters() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() Assert !filereadable(g:test_filename), 'The file should not have been saved' if !has('win32') " We should have run the linter. AssertEqual [{ \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 1, \ 'text': 'xxx', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}], ale#test#GetLoclistWithoutNewerKeys() endif Expect(The buffer should be the same): a b c Execute(ALEFix should not lint the buffer on save if linting on save is disabled globally): let g:ale_fix_on_save = 1 let g:ale_lint_on_save = 0 let g:ale_enabled = 1 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) let g:ale_fixers.testft = ['DoNothing'] call SetUpLinters() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() Assert !filereadable(g:test_filename), 'The file should not have been saved' AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() Expect(The buffer should be the same): a b c Execute(ALEFix should not lint the buffer on save if linting on save is disabled locally): let g:ale_fix_on_save = 1 let b:ale_lint_on_save = 0 let g:ale_enabled = 1 let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) let g:ale_fixers.testft = ['DoNothing'] call SetUpLinters() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() Assert !filereadable(g:test_filename), 'The file should not have been saved' AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() Expect(The buffer should be the same): a b c Given testft (A file with three lines): a b c Execute(ale#fix#InitBufferData() should set up the correct data): let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) call ale#fix#InitBufferData(bufnr(''), 'save_file') AssertEqual { \ bufnr(''): { \ 'temporary_directory_list': [], \ 'done': 0, \ 'lines_before': ['a', 'b', 'c'], \ 'should_save': 1, \ 'ignore_file_changed_errors': 0, \ }, \}, g:ale_fix_buffer_data call ale#fix#InitBufferData(bufnr(''), '!') AssertEqual { \ bufnr(''): { \ 'temporary_directory_list': [], \ 'done': 0, \ 'lines_before': ['a', 'b', 'c'], \ 'should_save': 0, \ 'ignore_file_changed_errors': 1, \ }, \}, g:ale_fix_buffer_data Execute(ALEFix simple functions should be able to accept one argument, the buffer): let g:ale_fixers.testft = ['RemoveLastLineOneArg'] ALEFix call ale#test#FlushJobs() Expect(There should be only two lines): a b Execute(ALEFix should modify a buffer that is not modifiable, if it becomes modifiable later): let g:ale_fixers.testft = ['RemoveLastLineOneArg'] set nomodifiable ALEFix call ale#test#FlushJobs() set modifiable call ale#fix#ApplyQueuedFixes(bufnr('')) Expect(There should be only two lines): a b Execute(b:ale_fix_on_save = 1 should override g:ale_fix_on_save = 0): let g:ale_fix_on_save = 0 let b:ale_fix_on_save = 1 let g:ale_fixers.testft = ['RemoveLastLineOneArg'] call ale#events#SaveEvent(bufnr('')) Expect(There should be only two lines): a b Execute(b:ale_fix_on_save = 0 should override g:ale_fix_on_save = 1): let g:ale_fix_on_save = 1 let b:ale_fix_on_save = 0 let g:ale_fixers.testft = ['RemoveLastLineOneArg'] call ale#events#SaveEvent(bufnr('')) Expect(The lines should be the same): a b c Execute(ALEFix functions returning jobs should be able to accept one argument): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['a', 'b', 'c', 'd']) else let g:ale_fixers.testft = ['CatLine'] ALEFix call ale#test#FlushJobs() endif Expect(An extra line should be added): a b c d Execute(ALE should print a message telling you something isn't a valid fixer when you type some nonsense): let g:ale_fixers.testft = ['CatLine', 'invalidname'] ALEFix call ale#test#FlushJobs() AssertEqual 'There is no fixer named `invalidname`. Check :ALEFixSuggest', GetLastMessage() Execute(ALE should complain about invalid fixers with minuses in the name): let g:ale_fixers.testft = ['foo-bar'] ALEFix call ale#test#FlushJobs() AssertEqual 'There is no fixer named `foo-bar`. Check :ALEFixSuggest', GetLastMessage() Execute(ALE should tolerate valid fixers with minuses in the name): let g:ale_fixers.testft = ['prettier-standard'] ALEFix call ale#test#FlushJobs() Execute(Empty output should be ignored): let g:ale_fixers.testft = ['IgnoredEmptyOutput'] ALEFix call ale#test#FlushJobs() Expect(The lines should be the same): a b c Execute(A temporary file shouldn't be piped into the command when disabled): let g:ale_fixers.testft = ['EchoLineNoPipe'] ALEFix call ale#test#FlushJobs() AssertEqual \ string(ale#job#PrepareCommand(bufnr(''), 'echo new line')), \ string(ale#history#Get(bufnr(''))[-1].command) " Remove trailing whitespace for Windows. if has('win32') %s/[[:space:]]*$//g endif Expect(The new line should be used): new line Execute(Post-processing should work): let g:ale_fixers.testft = ['FixWithJSONPostProcessing'] ALEFix call ale#test#FlushJobs() Expect(The lines in the JSON should be used): x y z Execute(ALEFix should apply autocmds): let g:ale_fixers.testft = ['AddCarets'] ALEFix call ale#test#FlushJobs() AssertEqual g:pre_success, 1 AssertEqual g:post_success, 1 Execute(ALEFix should support ale#command#Run): if has('win32') " Just skip this test on Windows, we can't run it. call setline(1, ['a', 'b', 'c', 'd']) else let g:ale_fixers.testft = ['CatLineDeferred'] ALEFix call ale#test#FlushJobs() endif Expect(The extra line should be added): a b c d ================================================ FILE: test/fix/test_ale_fix_aliases.vader ================================================ Execute(prettier-eslint should be aliased): AssertEqual 'ale#fixers#prettier_eslint#Fix', ale#fix#registry#GetFunc('prettier-eslint') Execute(prettier-standard should be aliased): AssertEqual 'ale#fixers#prettier_standard#Fix', ale#fix#registry#GetFunc('prettier-standard') ================================================ FILE: test/fix/test_ale_fix_completion.vader ================================================ Execute (List of available fixers is empty): call ale#fix#registry#Clear() Then (List of applicable fixers for python file is empty): AssertEqual [], ale#fix#registry#GetApplicableFixers('python') Execute (Add ruby fixer): call ale#fix#registry#Add('ruby_fixer', 'fixer_fun', ['ruby'], 'ruby fixer') Then (List of applicable fixers for python file is still empty): AssertEqual [], ale#fix#registry#GetApplicableFixers('python') Execute (Add generic fixer): call ale#fix#registry#Add('generic_fixer', 'fixer_fun', [], 'generic fixer') Then (Generic fixer should be returned as applicable for python file): AssertEqual ['generic_fixer'], ale#fix#registry#GetApplicableFixers('python') Execute (Add python fixer): call ale#fix#registry#Add('python_fixer', 'fixer_func', ['python'], 'python fixer') Then (List of fixers should contain both generic and python fixers): AssertEqual ['generic_fixer', 'python_fixer'], ale#fix#registry#GetApplicableFixers('python') ================================================ FILE: test/fix/test_ale_fix_completion_filter.vader ================================================ Before: call ale#fix#registry#Clear() call ale#test#SetFilename('test.js') call ale#fix#registry#Add('prettier', '', ['javascript'], 'prettier') call ale#fix#registry#Add('eslint', '', ['javascript'], 'eslint') setfiletype javascript Execute(completeFixers returns all of the applicable fixers without an arglead): AssertEqual ['eslint', 'prettier'], \ ale#fix#registry#CompleteFixers('', 'ALEFix ', 7) Execute(completeFixers returns all of the applicable fixers without an arglead): AssertEqual ['prettier'], \ ale#fix#registry#CompleteFixers('pre', 'ALEFix ', 10) ================================================ FILE: test/fix/test_ale_fix_ignore.vader ================================================ Before: Save g:ale_fixers Save g:ale_fix_on_save Save g:ale_fix_on_save_ignore let g:ale_fix_on_save = 1 let g:ale_fixers = {'abc': ['a', 'b'], 'xyz': ['c', 'd']} unlet! b:ale_fixers unlet! b:ale_fix_on_save_ignore function FixerA(buffer, lines) abort return a:lines + ['a'] endfunction function FixerB(buffer, lines) abort return a:lines + ['b'] endfunction function FixerC(buffer, lines) abort return a:lines + ['c'] endfunction function FixerD(buffer, lines) abort return a:lines + ['d'] endfunction set filetype=abc.xyz let g:test_filename = tempname() execute 'noautocmd silent file ' . fnameescape(g:test_filename) call ale#fix#registry#Add('a', 'FixerA', ['abc'], '') call ale#fix#registry#Add('b', 'FixerB', ['abc'], '') call ale#fix#registry#Add('c', 'FixerC', ['xyz'], '') call ale#fix#registry#Add('d', 'FixerD', ['xyz'], '') After: Restore if exists('g:test_filename') && filereadable(g:test_filename) call delete(g:test_filename) endif unlet! b:ale_fixers unlet! b:ale_fix_on_save_ignore unlet! g:test_filename delfunction FixerA delfunction FixerB delfunction FixerC delfunction FixerD call ale#fix#registry#ResetToDefaults() Given abc.xyz (An empty file): Execute(Ignoring with a filetype in a global Dictionary should work): let g:ale_fix_on_save_ignore = {'abc': ['b'], 'xyz': ['c']} call ale#events#SaveEvent(bufnr('')) AssertEqual ['', 'a', 'd'], getline(1, '$') Execute(Ignoring with a filetype in a global List should work): let g:ale_fix_on_save_ignore = ['b', 'c'] call ale#events#SaveEvent(bufnr('')) AssertEqual ['', 'a', 'd'], getline(1, '$') Execute(Ignoring with a filetype in a local Dictionary should work): let g:ale_fix_on_save_ignore = {'abc': ['b'], 'xyz': ['c']} " The local Dictionary should entirely replace the global one. let b:ale_fix_on_save_ignore = {'abc': ['b']} call ale#events#SaveEvent(bufnr('')) AssertEqual ['', 'a', 'c', 'd'], getline(1, '$') Execute(Ignoring with a filetype in a local List should work): let g:ale_fix_on_save_ignore = {'abc': ['b'], 'xyz': ['c']} " The local List should entirely replace the global Dictionary. let b:ale_fix_on_save_ignore = ['b'] call ale#events#SaveEvent(bufnr('')) AssertEqual ['', 'a', 'c', 'd'], getline(1, '$') Execute(Ignoring functions by reference with a Dictionary should work): let g:ale_fixers = { \ 'abc': [function('FixerA'), function('FixerB')], \ 'xyz': [function('FixerC'), function('FixerD')], \} let b:ale_fix_on_save_ignore = { \ 'abc': [function('FixerB')], \ 'xyz': [function('FixerC')], \} call ale#events#SaveEvent(bufnr('')) AssertEqual ['', 'a', 'd'], getline(1, '$') Execute(Ignoring functions by reference with a List should work): let g:ale_fixers = { \ 'abc': [function('FixerA'), function('FixerB')], \ 'xyz': [function('FixerC'), function('FixerD')], \} let b:ale_fix_on_save_ignore = [function('FixerB'), function('FixerC')] call ale#events#SaveEvent(bufnr('')) AssertEqual ['', 'a', 'd'], getline(1, '$') ================================================ FILE: test/fix/test_ale_fix_suggest.vader ================================================ Before: call ale#fix#registry#Clear() let g:buffer = bufnr('') function GetSuggestions() silent ALEFixSuggest if bufnr('') != g:buffer let l:lines = getline(1, '$') else let l:lines = [] endif return l:lines endfunction After: if bufnr('') != g:buffer :q! endif unlet! g:buffer call ale#fix#registry#ResetToDefaults() delfunction GetSuggestions Execute(ALEFixSuggest should return something sensible with no suggestions): AssertEqual \ [ \ 'There is nothing in the registry to suggest.', \ '', \ 'Press q to close this window', \ ], \ GetSuggestions() Execute(ALEFixSuggest should set the appropriate settings): silent ALEFixSuggest AssertEqual 'ale-fix-suggest', &filetype Assert !&modified, 'The buffer was marked as modified' Assert !&modifiable, 'The buffer was modifiable' Execute(ALEFixSuggest output should be correct for only generic handlers): call ale#fix#registry#Add('zed', 'XYZ', [], 'Zedify things.') call ale#fix#registry#Add('alpha', 'XYZ', [], 'Alpha things.') AssertEqual \ [ \ 'Try the following generic fixers:', \ '', \ '''alpha'' - Alpha things.', \ '''zed'' - Zedify things.', \ '', \ 'See :help ale-fix-configuration', \ '', \ 'Press q to close this window', \ ], \ GetSuggestions() Execute(ALEFixSuggest output should be correct for only filetype handlers): let &filetype = 'testft2.testft' call ale#fix#registry#Add('zed', 'XYZ', ['testft2'], 'Zedify things.') call ale#fix#registry#Add('alpha', 'XYZ', ['testft'], 'Alpha things.') AssertEqual \ [ \ 'Try the following fixers appropriate for the filetype:', \ '', \ '''alpha'' - Alpha things.', \ '''zed'' - Zedify things.', \ '', \ 'See :help ale-fix-configuration', \ '', \ 'Press q to close this window', \ ], \ GetSuggestions() Execute(ALEFixSuggest should suggest filetype and generic handlers): let &filetype = 'testft2.testft' call ale#fix#registry#Add('zed', 'XYZ', ['testft2'], 'Zedify things.', ['foobar']) call ale#fix#registry#Add('alpha', 'XYZ', ['testft'], 'Alpha things.') call ale#fix#registry#Add('generic', 'XYZ', [], 'Generic things.') AssertEqual \ [ \ 'Try the following fixers appropriate for the filetype:', \ '', \ '''alpha'' - Alpha things.', \ '''zed'', ''foobar'' - Zedify things.', \ '', \ 'Try the following generic fixers:', \ '', \ '''generic'' - Generic things.', \ '', \ 'See :help ale-fix-configuration', \ '', \ 'Press q to close this window', \ ], \ GetSuggestions() ================================================ FILE: test/fixers/test_alejandra_fixer_callback.vader ================================================ Before: Save g:ale_nix_alejandra_executable Save g:ale_nix_alejandra_options After: Restore Execute(The alejandra callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('alejandra') . ' -- -' \ }, \ ale#fixers#alejandra#Fix(bufnr('')) Execute(The alejandra executable and options should be configurable): let g:ale_nix_alejandra_executable = '/path/to/alejandra' let g:ale_nix_alejandra_options = '-q' AssertEqual \ { \ 'command': ale#Escape('/path/to/alejandra') \ . ' -q -- -', \ }, \ ale#fixers#alejandra#Fix(bufnr('')) ================================================ FILE: test/fixers/test_apkbuild_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('apkbuild', 'apkbuild-fixer') After: call ale#assert#TearDownFixerTest() Execute(The apkbuild-fixer callback should return the correct default values): AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('apkbuild-fixer') . ' -p apkbuild-lint %t', \} Execute(The apkbuild-fixer callback should include custom apkbuild-fixer options): let g:ale_apkbuild_apkbuild_fixer_executable = "another-apkbuild-fixer" let g:ale_apkbuild_apkbuild_fixer_options = "-s" AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('another-apkbuild-fixer') . ' -p apkbuild-lint -s %t' \} ================================================ FILE: test/fixers/test_appleswiftformat_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('swift', 'apple-swift-format') After: call ale#assert#TearDownFixerTest() Execute(The swiftformat callback should return the correct default values): call ale#test#SetFilename('../test-files/swift/dummy.swift') let g:ale_swift_appleswiftformat_executable = 'xxxinvalid' let g:ale_swift_appleswiftformat_use_swiftpm = 0 AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_swift_appleswiftformat_executable) \ . ' format --in-place %t', \ }, \ ale#fixers#appleswiftformat#Fix(bufnr('')) Execute(The swiftformat callback should return the correct default values and located configuration): call ale#test#SetDirectory('/testplugin/test/test-files/swift/swift-package-project-with-config') call ale#test#SetFilename('src/folder/dummy.swift') let g:ale_swift_appleswiftformat_executable = 'xxxinvalid' let g:ale_swift_appleswiftformat_use_swiftpm = 0 AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_swift_appleswiftformat_executable) \ . ' format --in-place %t --configuration ' . glob(g:dir . '/.swift-format'), \ }, \ ale#fixers#appleswiftformat#Fix(bufnr('')) call ale#test#RestoreDirectory() Execute(The swiftformat callback should use swiftpm is use_swiftpm is set to 1): call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift') let g:ale_swift_appleswiftformat_use_swiftpm = 1 AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('swift') \ . ' run swift-format format --in-place %t', \ }, \ ale#fixers#appleswiftformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_astyle_fixer_callback.vader ================================================ Before: Save g:ale_c_astyle_executable Save g:ale_c_astyle_project_options Save g:ale_cpp_astyle_project_options " Use an invalid global executable, so we don't match it. let g:ale_c_astyle_executable = 'xxxinvalid' let g:ale_cpp_astyle_executable = 'invalidpp' let g:ale_c_astyle_project_options = '' let g:ale_cpp_astyle_project_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The astyle callback should return the correct default values): " Because this file doesn't exist, no astylrc config " exists near it. Therefore, project_options is empty. call ale#test#SetFilename('../c_files/testfile.c') let targetfile = bufname(bufnr('%')) AssertEqual \ { \ 'command': ale#Escape(g:ale_c_astyle_executable) \ . ' --stdin=' . ale#Escape(targetfile) \ }, \ ale#fixers#astyle#Fix(bufnr('')) Execute(The astyle callback should support cpp files): " Because this file doesn't exist, no astylrc config " exists near it. Therefore, project_options is empty. call ale#test#SetFilename('../cpp_files/dummy.cpp') set filetype=cpp " The test fails without this let targetfile = bufname(bufnr('%')) AssertEqual \ { \ 'command': ale#Escape(g:ale_cpp_astyle_executable) \ . ' --stdin=' . ale#Escape(targetfile) \ }, \ ale#fixers#astyle#Fix(bufnr('')) Execute(The astyle callback should support cpp files with option file set): call ale#test#SetFilename('../cpp_files/dummy.cpp') let g:ale_cpp_astyle_project_options = '.astylerc_cpp' let targetfile = bufname(bufnr('%')) set filetype=cpp " The test fails without this AssertEqual \ { \ 'command': ale#Escape('invalidpp') \ . ' --project=' . g:ale_cpp_astyle_project_options \ . ' --stdin=' . ale#Escape(targetfile) \ }, \ ale#fixers#astyle#Fix(bufnr('')) Execute(The astyle callback should return the correct default values with a specified option file): call ale#test#SetFilename('../c_files/testfile.c') let g:ale_c_astyle_project_options = '.astylerc_c' let targetfile = bufname(bufnr('%')) AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' --project=' . g:ale_c_astyle_project_options \ . ' --stdin=' . ale#Escape(targetfile) \ }, \ ale#fixers#astyle#Fix(bufnr('')) Execute(The astyle callback should find nearest default option file _astylrc): call ale#test#SetFilename('../test-files/c/makefile_project/subdir/file.c') let targetfile = bufname(bufnr('%')) AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' --project=_astylerc' \ . ' --stdin=' . ale#Escape(targetfile) \ }, \ ale#fixers#astyle#Fix(bufnr('')) Execute(The astyle callback should find .astylrc in the same directory as src): call ale#test#SetFilename('../test-files/cpp/dummy.cpp') set filetype=cpp " The test fails without this let targetfile = bufname(bufnr('%')) AssertEqual \ { \ 'command': ale#Escape('invalidpp') \ . ' --project=.astylerc' \ . ' --stdin=' . ale#Escape(targetfile) \ }, \ ale#fixers#astyle#Fix(bufnr('')) ================================================ FILE: test/fixers/test_autoflake_fixer_callback.vader ================================================ Before: Save g:ale_python_autoflake_executable Save g:ale_python_autoflake_options " Use an invalid global executable, so we don't match it. let g:ale_python_autoflake_executable = 'xxxinvalid' let g:ale_python_autoflake_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') let g:dir = getcwd() let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: Restore unlet! b:bin_dir call ale#test#RestoreDirectory() Execute(The autoflake callback should include options): let g:ale_python_autoflake_options = '--some-option' silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ { \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/autoflake')) \ . ' --some-option' \ . ' --in-place ' \ . ' %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#autoflake#Fix(bufnr('')) Execute(pipenv is detected when python_autoflake_auto_pipenv is set): let g:ale_python_autoflake_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('pipenv') . ' run autoflake --in-place %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#autoflake#Fix(bufnr('')) Execute(Poetry is detected when python_autoflake_auto_poetry is set): let g:ale_python_autoflake_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertEqual \ { \ 'command': ale#Escape('poetry') . ' run autoflake --in-place %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#autoflake#Fix(bufnr('')) Execute(uv is detected when python_autoflake_auto_uv is set): let g:ale_python_autoflake_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('uv') . ' run autoflake --in-place %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#autoflake#Fix(bufnr('')) ================================================ FILE: test/fixers/test_autoimport_fixer_callback.vader ================================================ Before: Save g:ale_python_autoimport_executable Save g:ale_python_autoimport_options " Use an invalid global executable, so we don't match it. let g:ale_python_autoimport_executable = 'xxxinvalid' let g:ale_python_autoimport_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: Restore unlet! b:bin_dir call ale#test#RestoreDirectory() Execute(The autoimport callback should return the correct default values): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/autoimport')) . ' -', \ }, \ ale#fixers#autoimport#Fix(bufnr('')) Execute(The autoimport callback should respect custom options): let g:ale_python_autoimport_options = '--multi-line=3 --trailing-comma' silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/autoimport')) \ . ' --multi-line=3 --trailing-comma -', \ }, \ ale#fixers#autoimport#Fix(bufnr('')) Execute(pipenv is detected when python_autoimport_auto_pipenv is set): let g:ale_python_autoimport_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pipenv') . ' run autoimport -', \ }, \ ale#fixers#autoimport#Fix(bufnr('')) Execute(Poetry is detected when python_autoimport_auto_poetry is set): let g:ale_python_autoimport_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('poetry') . ' run autoimport -', \ }, \ ale#fixers#autoimport#Fix(bufnr('')) Execute(uv is detected when python_autoimport_auto_uv is set): let g:ale_python_autoimport_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('uv') . ' run autoimport -', \ }, \ ale#fixers#autoimport#Fix(bufnr('')) ================================================ FILE: test/fixers/test_autopep8_fixer_callback.vader ================================================ Before: Save g:ale_python_autopep8_executable Save g:ale_python_autopep8_options " Use an invalid global executable, so we don't match it. let g:ale_python_autopep8_executable = 'xxxinvalid' let g:ale_python_autopep8_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') let g:dir = getcwd() let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: Restore unlet! b:bin_dir call ale#test#RestoreDirectory() Execute(The autopep8 callback should return the correct default values): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/autopep8')) . ' -'}, \ ale#fixers#autopep8#Fix(bufnr('')) Execute(The autopep8 callback should include options): let g:ale_python_autopep8_options = '--some-option' silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/autopep8')) . ' --some-option -' }, \ ale#fixers#autopep8#Fix(bufnr('')) Execute(pipenv is detected when python_autopep8_auto_pipenv is set): let g:ale_python_autopep8_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('pipenv') . ' run autopep8 -', \ }, \ ale#fixers#autopep8#Fix(bufnr('')) Execute(Poetry is detected when python_autopep8_auto_poetry is set): let g:ale_python_autopep8_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertEqual \ { \ 'command': ale#Escape('poetry') . ' run autopep8 -', \ }, \ ale#fixers#autopep8#Fix(bufnr('')) Execute(uv is detected when python_autopep8_auto_uv is set): let g:ale_python_autopep8_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('uv') . ' run autopep8 -', \ }, \ ale#fixers#autopep8#Fix(bufnr('')) ================================================ FILE: test/fixers/test_bibclean_fixer_callback.vader ================================================ Before: Save g:ale_bib_bibclean_executable Save g:ale_bib_bibclean_options let g:ale_bib_bibclean_executable = 'xxxinvalid' let g:ale_bib_bibclean_options = '-align-equals' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The bibclean callback should return the correct default values): call ale#test#SetFilename('../test-files/bib/dummy.bib') AssertEqual \ {'command': ale#Escape(g:ale_bib_bibclean_executable) . ' -align-equals'}, \ ale#fixers#bibclean#Fix(bufnr('')) Execute(The bibclean callback should include custom bibclean options): let g:ale_bib_bibclean_options = '-author -check-values' call ale#test#SetFilename('../test-files/bib/dummy.bib') AssertEqual \ { \ 'command': ale#Escape(g:ale_bib_bibclean_executable) . ' -author -check-values' \ }, \ ale#fixers#bibclean#Fix(bufnr('')) ================================================ FILE: test/fixers/test_biome_fixer_callback.vader ================================================ Before: Save g:ale_biome_options Save g:ale_biome_fixer_apply_unsafe let g:ale_biome_options = '' let g:ale_biome_fixer_apply_unsafe = 0 call ale#assert#SetUpFixerTest('typescript', 'biome') After: call ale#assert#TearDownFixerTest() Execute(The default biome command should be correct): call ale#test#SetFilename('../test-files/biome/jsonc/src/test.ts') AssertFixer \ { \ 'command': ale#Escape('biome') \ . ' check --write --stdin-file-path %s' \ } Execute(Unsafe fixes can be applied via an option): call ale#test#SetFilename('../test-files/biome/jsonc/src/test.ts') let g:ale_biome_fixer_apply_unsafe = 1 AssertFixer \ { \ 'command': ale#Escape('biome') \ . ' check --write --stdin-file-path %s --unsafe' \ } Execute(The fixer should accept options): call ale#test#SetFilename('../test-files/biome/jsonc/src/test.ts') let g:ale_biome_options = '--foobar' AssertFixer \ { \ 'command': ale#Escape('biome') \ . ' check --write --stdin-file-path %s --foobar', \ } ================================================ FILE: test/fixers/test_black_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'black') let g:dir = getcwd() let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: call ale#assert#TearDownFixerTest() unlet! g:dir unlet! b:bin_dir Execute(The black callback should return the correct default values): let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --stdin-filename ' . fname . ' -'}, \ ale#fixers#black#Fix(bufnr('')) Execute(The black callback should include options): let g:ale_python_black_options = '--some-option' let g:ale_python_black_change_directory = 0 let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --some-option --stdin-filename ' . fname . ' -'}, \ ale#fixers#black#Fix(bufnr('')) Execute(The black callback should include --pyi for .pyi files): let g:ale_python_black_change_directory = 0 let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.pyi' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --stdin-filename ' . fname . ' --pyi -'}, \ ale#fixers#black#Fix(bufnr('')) Execute(The black callback should not concatenate options): let g:ale_python_black_options = '--some-option' let g:ale_python_black_change_directory = 0 let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.pyi' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --some-option --stdin-filename ' . fname. ' --pyi -'}, \ ale#fixers#black#Fix(bufnr('')) Execute(Pipenv is detected when python_black_auto_pipenv is set): let g:ale_python_black_auto_pipenv = 1 let g:ale_python_black_change_directory = 0 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/pipenv/whatever.py')) AssertEqual \ {'command': ale#Escape('pipenv') . ' run black --stdin-filename '.fname.' -'}, \ ale#fixers#black#Fix(bufnr('')) Execute(Poetry is detected when python_black_auto_poetry is set): let g:ale_python_black_auto_poetry = 1 let g:ale_python_black_change_directory = 0 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) AssertEqual \ {'command': ale#Escape('poetry') . ' run black --stdin-filename '.fname.' -'}, \ ale#fixers#black#Fix(bufnr('')) Execute(uv is detected when python_black_auto_uv is set): let g:ale_python_black_auto_uv = 1 let g:ale_python_black_change_directory = 0 call ale#test#SetFilename('../test-files/python/uv/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/uv/whatever.py')) AssertEqual \ {'command': ale#Escape('uv') . ' run black --stdin-filename '.fname.' -'}, \ ale#fixers#black#Fix(bufnr('')) ================================================ FILE: test/fixers/test_break_up_long_lines_python_fixer.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') After: call ale#test#RestoreDirectory() Execute(Long lines with basic function calls should be broken up correctly): AssertEqual \ [ \ 'def foo():', \ ' some_variable = this_is_a_longer_function(', \ 'first_argument,', \ ' second_argument,', \ ' third_with_function_call(', \ 'foo,', \ ' bar,', \ '))', \ ], \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), [ \ 'def foo():', \ ' some_variable = this_is_a_longer_function(first_argument, second_argument, third_with_function_call(foo, bar))', \ ]) Execute(Longer lines should be permitted if a configuration file allows it): call ale#test#SetFilename('../test-files/long-line/foo/bar.py') AssertEqual \ [ \ 'x = this_line_is_between_79_and_90_characters(first, second, third, fourth, fifth)', \ 'y = this_line_is_longer_than_90_characters(', \ 'much_longer_word,', \ ' another_longer_word,', \ ' a_third_long_word,', \ ')' \ ], \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), [ \ 'x = this_line_is_between_79_and_90_characters(first, second, third, fourth, fifth)', \ 'y = this_line_is_longer_than_90_characters(much_longer_word, another_longer_word, a_third_long_word)', \ ]) ================================================ FILE: test/fixers/test_brittany_fixer_callback.vader ================================================ Before: Save g:ale_haskell_brittany_executable " Use an invalid global executable, so we don't match it. let g:ale_haskell_brittany_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The brittany callback should return the correct default values): call ale#test#SetFilename('../haskell_files/testfile.hs') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' --write-mode inplace' \ . ' %t', \ }, \ ale#fixers#brittany#Fix(bufnr('')) ================================================ FILE: test/fixers/test_buf_format_fixer_callback.vader ================================================ Before: Save g:ale_proto_buf_format_executable " Use an invalid global executable, so we don't match it. let g:ale_proto_buf_format_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The buf-format callback should return the correct default values): call ale#test#SetFilename('../test-files/proto/testfile.proto') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' format %t', \ }, \ ale#fixers#buf_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_buildifier_fixer_callback.vader ================================================ Before: let g:ale_bazel_buildifier_options = '' call ale#assert#SetUpFixerTest('bzl', 'buildifier') After: call ale#assert#TearDownFixerTest() Execute(The buildifier callback should return the correct default values): call ale#test#SetFilename('../test-files/bazel/WORKSPACE') AssertFixer \ { \ 'command': ale#Escape(g:ale_bazel_buildifier_executable) \ . ' -mode fix -lint fix -path ' \ . ale#Escape(ale#test#GetFilename('../test-files/bazel/WORKSPACE')) \ . ' -' \ } Execute(The buildifier callback should include any additional options): call ale#test#SetFilename('../test-files/bazel/WORKSPACE') let g:ale_bazel_buildifier_options = '--some-option' AssertFixer \ { \ 'command': ale#Escape(g:ale_bazel_buildifier_executable) \ . ' -mode fix -lint fix -path ' \ . ale#Escape(ale#test#GetFilename('../test-files/bazel/WORKSPACE')) \ . ' --some-option -' \ } ================================================ FILE: test/fixers/test_clangformat_fixer_callback.vader ================================================ Before: Save g:ale_c_clangformat_executable Save g:c_clangformat_style_option Save g:c_clangformat_use_local_file " Use an invalid global executable, so we don't match it. let g:ale_c_clangformat_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') 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('../test-files/c/dummy.c') AssertEqual \ { \ 'command': ale#Escape(g:ale_c_clangformat_executable) \ . ' --assume-filename=' . ale#Escape(bufname(bufnr(''))) \ }, \ ale#fixers#clangformat#Fix(bufnr('')) Execute(The clangformat callback should include any additional options): call ale#test#SetFilename('../test-files/c/dummy.c') let g:ale_c_clangformat_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape(g:ale_c_clangformat_executable) \ . ' --assume-filename=' . ale#Escape(bufname(bufnr(''))) \ . ' --some-option', \ }, \ ale#fixers#clangformat#Fix(bufnr('')) Execute(The clangformat callback should include style options as well): call ale#test#SetFilename('../test-files/c/dummy.c') let g:ale_c_clangformat_options = '--some-option' let g:ale_c_clangformat_style_option = '{BasedOnStyle: Microsoft, ColumnLimit:80,}' AssertEqual \ { \ 'command': ale#Escape(g:ale_c_clangformat_executable) \ . ' --assume-filename=' . ale#Escape(bufname(bufnr(''))) \ . ' --some-option' \ . ' -style=' . ale#Escape(g:ale_c_clangformat_style_option) \ }, \ ale#fixers#clangformat#Fix(bufnr('')) Execute(The clangformat callback should use local file instead of style options): call ale#test#SetFilename('../test-files/clangformat/with_clangformat/dummy.c') let g:ale_c_clangformat_options = '--some-option' let g:ale_c_clangformat_style_option = '{BasedOnStyle: Microsoft, ColumnLimit:80,}' let g:ale_c_clangformat_use_local_file = 1 AssertEqual \ { \ 'command': ale#Escape(g:ale_c_clangformat_executable) \ . ' --assume-filename=' . ale#Escape(bufname(bufnr(''))) \ . ' --some-option' . ' -style=file', \ }, \ ale#fixers#clangformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_clangtidy_fixer_callback.vader ================================================ Before: Save g:ale_c_build_dir Save g:ale_c_clangtidy_executable Save g:ale_c_clangtidy_checks Save g:ale_c_clangtidy_extra_options Save g:ale_cpp_clangtidy_executable Save g:ale_cpp_clangtidy_checks Save g:ale_cpp_clangtidy_extra_options " Use an invalid global executable, so we don't match it. let g:ale_c_clangtidy_executable = 'xxxinvalid' let g:ale_c_clangtidy_checks = [] let g:ale_c_clangtidy_extra_options = '' let g:ale_cpp_clangtidy_executable = 'xxxinvalidpp' let g:ale_cpp_clangtidy_checks = [] let g:ale_cpp_clangtidy_extra_options = '' let g:ale_c_build_dir = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The clangtidy callback should return the correct default values): call ale#test#SetFilename('../test-files/c/dummy.c') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_c_clangtidy_executable) \ . ' -fix -fix-errors %t' \ }, \ ale#fixers#clangtidy#Fix(bufnr('')) Execute(The clangtidy callback should include any additional options): call ale#test#SetFilename('../test-files/c/dummy.c') let g:ale_c_clangtidy_extra_options = '--some-option' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_c_clangtidy_executable) \ . ' -fix -fix-errors --some-option %t', \ }, \ ale#fixers#clangtidy#Fix(bufnr('')) ================================================ FILE: test/fixers/test_cljfmt_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('clojure', 'cljfmt') After: call ale#assert#TearDownFixerTest() Execute(The cljfmt callback should return the correct default values): AssertFixer { \ 'command': ale#Escape('cljfmt') . ' fix %t', \ 'read_temporary_file': 1, \} ================================================ FILE: test/fixers/test_cmakeformat_fixer_callback.vader ================================================ Before: Save g:ale_cmake_cmakeformat_executable Save g:ale_cmake_cmakeformat_options " Use an invalid global executable, so we don't match it. let g:ale_cmake_cmakeformat_executable = 'xxxinvalid' let g:ale_cmake_cmakeformat_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The cmakeformat callback should return the correct default values): call ale#test#SetFilename('../cmake_files/CMakeList.txt') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' -' \ }, \ ale#fixers#cmakeformat#Fix(bufnr('')) Execute(The cmakeformat callback should include custom cmakeformat options): let g:ale_cmake_cmakeformat_options = "-r '(a) -> a'" call ale#test#SetFilename('../cmake_files/CMakeList.txt') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_cmake_cmakeformat_options \ . ' -', \ }, \ ale#fixers#cmakeformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_crystal_format_fixer_callback.vader ================================================ Before: Save g:ale_crystal_format_executable Save g:ale_crystal_format_options " Use an invalid global executable, so we don't match it. let g:ale_crystal_format_executable = 'xxxinvalid' let g:ale_crystal_format_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The crystal format callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' tool format -', \ }, \ ale#fixers#crystal#Fix(bufnr('')) Execute(The crystal format callback should include custom options): let g:ale_crystal_format_options = "-list=true" AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' tool format ' . g:ale_crystal_format_options \ . ' -', \ }, \ ale#fixers#crystal#Fix(bufnr('')) ================================================ FILE: test/fixers/test_css_beautify_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('css', 'css-beautify', 'beautify') After: Restore call ale#assert#TearDownFixerTest() Execute(The css-beautify callback should return the correct default command): AssertEqual \ {'command': ale#Escape('css-beautify') . ' -'}, \ ale#fixers#css_beautify#Fix(bufnr('')) ================================================ FILE: test/fixers/test_dart_format_fixer_callback.vader ================================================ Before: Save g:ale_dart_format_executable Save g:ale_dart_format_options " Use an invalid global executable, so we don't match it. let g:ale_dart_format_executable = 'xxxinvalid' let g:ale_dart_format_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The dart format callback should return the correct default values): call ale#test#SetFilename('../test-files/dart/testfile.dart') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' format' \ . ' %t', \ }, \ ale#fixers#dart_format#Fix(bufnr('')) Execute(The dart format callback should include custom dart format options): let g:ale_dart_format_options = "-l 80" call ale#test#SetFilename('../test-files/dart/testfile.dart') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' format' \ . ' ' . g:ale_dart_format_options \ . ' %t', \ }, \ ale#fixers#dart_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_dartfmt_fixer_callback.vader ================================================ Before: Save g:ale_dart_dartfmt_executable Save g:ale_dart_dartfmt_options " Use an invalid global executable, so we don't match it. let g:ale_dart_dartfmt_executable = 'xxxinvalid' let g:ale_dart_dartfmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The dartfmt callback should return the correct default values): call ale#test#SetFilename('../test-files/dart/testfile.dart') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -w' \ . ' %t', \ }, \ ale#fixers#dartfmt#Fix(bufnr('')) Execute(The dartfmt callback should include custom dartfmt options): let g:ale_dart_dartfmt_options = "-l 80" call ale#test#SetFilename('../test-files/dart/testfile.dart') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -w' \ . ' ' . g:ale_dart_dartfmt_options \ . ' %t', \ }, \ ale#fixers#dartfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_dfmt_fixer_callback.vader ================================================ Before: Save g:ale_d_dfmt_executable Save g:ale_d_dfmt_options " Use an invalid global executable, so we don't match it. let g:ale_d_dfmt_executable = 'xxxinvalid' let g:ale_d_dfmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The dfmt callback should return the correct default values): call ale#test#SetFilename('../test-files/d/test.d') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -i' \ . ' %t', \ }, \ ale#fixers#dfmt#Fix(bufnr('')) Execute(The dfmt callback should include custom dfmt options): let g:ale_d_dfmt_options = "--space-after-cast" call ale#test#SetFilename('../test-files/d/test.d') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -i' \ . ' ' . g:ale_d_dfmt_options \ . ' %t', \ }, \ ale#fixers#dfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_dhall_format_fixer_callback.vader ================================================ Before: Save g:ale_dhall_executable Save g:ale_dhall_options " Use an invalid global executable, so we don’t match it. let g:ale_dhall_executable = 'odd-dhall' let g:ale_dhall_options = '--ascii' call ale#assert#SetUpFixerTest('dhall', 'dhall-format') After: call ale#assert#TearDownFixerTest() Execute(The dhall-format callback should return the correct options): call ale#test#SetFilename('../dhall_files/testfile.dhall') AssertFixer \ { \ 'command': ale#Escape('odd-dhall') \ . ' --ascii' \ . ' format' \ } ================================================ FILE: test/fixers/test_dhall_freeze_fixer_callback.vader ================================================ Before: Save g:ale_dhall_executable Save g:ale_dhall_options " Use an invalid global executable, so we don’t match it. let g:ale_dhall_executable = 'odd-dhall' let g:ale_dhall_options = '--ascii' let g:ale_dhall_freeze_options = '--all' call ale#assert#SetUpFixerTest('dhall', 'dhall-freeze') After: call ale#assert#TearDownFixerTest() Execute(The dhall-freeze callback should return the correct options): AssertFixer \ { \ 'command': ale#Escape('odd-dhall') \ . ' --ascii' \ . ' freeze' \ . ' --all' \ } ================================================ FILE: test/fixers/test_dhall_lint_fixer_callback.vader ================================================ Before: Save g:ale_dhall_executable Save g:ale_dhall_options " Use an invalid global executable, so we don’t match it. let g:ale_dhall_executable = 'odd-dhall' let g:ale_dhall_options = '--ascii' call ale#assert#SetUpFixerTest('dhall', 'dhall-lint') After: call ale#assert#TearDownFixerTest() Execute(The dhall-lint callback should return the correct options): AssertFixer \ { \ 'command': ale#Escape('odd-dhall') \ . ' --ascii' \ . ' lint' \ } ================================================ FILE: test/fixers/test_djlint_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('html', 'djlint', 'djlint') After: Restore call ale#assert#TearDownFixerTest() Execute(The djlint callback should return the correct default command): AssertEqual \ {'command': ale#Escape('djlint') . ' --reformat -'}, \ ale#fixers#djlint#Fix(bufnr('')) Execute(The --profile option should not be overridden): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=htmldjango let g:ale_html_djlint_options = '--profile jinja' AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile jinja' \ . ' -', \ } Execute(Should set --profile for experimental language, Handlebars): call ale#test#SetFilename('../test-files/djlint/testfile.hbs') set filetype=handlebars AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile handlebars' \ . ' -', \ } Execute(Should set --profile for htmldjango, Django templates): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=htmldjango AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile django' \ . ' -', \ } Execute(Should set --profile for htmlangular): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=htmlangular AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile angular' \ . ' -', \ } Execute(Should set --profile for jinja): call ale#test#SetFilename('../test-files/djlint/testfile.jinja2') set filetype=jinja AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile jinja' \ . ' -', \ } Execute(Should set --profile for nunjucks): call ale#test#SetFilename('../test-files/djlint/testfile.njk') set filetype=nunjucks AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile nunjucks' \ . ' -', \ } Execute(Should set --profile for Go HTML templates): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=gohtmltmpl AssertFixer \ { 'command': ale#Escape(g:ale_html_djlint_executable) \ . ' --reformat' \ . ' --profile golang' \ . ' -', \ } ================================================ FILE: test/fixers/test_dotnet_format_fixer_callback.vader ================================================ Before: Save g:ale_cs_dotnet_format_executable Save g:ale_cs_dotnet_format_options " Use an invalid global executable, so we don't match it. let g:ale_cs_dotnet_format_executable = 'xxxinvalid' let g:ale_cs_dotnet_format_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The dotnet format callback should return the correct default values): call ale#test#SetFilename('../test-files/cs/testfile.cs') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' format' \ . ' --folder --include %t "$(dirname %t)"', \ }, \ ale#fixers#dotnet_format#Fix(bufnr('')) Execute(The dotnet format callback should include custom dotnet format options): let g:ale_cs_dotnet_format_options = "-l 80" call ale#test#SetFilename('../test-files/cs/testfile.cs') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' format' \ . ' ' . g:ale_cs_dotnet_format_options \ . ' --folder --include %t "$(dirname %t)"', \ }, \ ale#fixers#dotnet_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_dprint_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('typescript', 'dprint') call ale#test#SetFilename('../test-files/dprint/blank.ts') let g:ale_dprint_executable_override = 0 let g:ale_dprint_executable = 'dprint' let g:ale_dprint_config = '' After: Restore call ale#assert#TearDownFixerTest() Execute(The dprint callback should return 0 for a non-existent executable): let g:ale_dprint_executable = 'foo' AssertFixer 0 Execute(The dprint callback should return the correct default values): let g:ale_dprint_executable_override = 1 AssertFixer { \ 'command': ale#Escape('dprint') \ . ' fmt ' \ . ' --stdin %s' \ } Execute(The dprint callback should include config): let g:ale_dprint_executable_override = 1 let g:ale_dprint_config = 'dprint.json' AssertFixer { \ 'command': ale#Escape('dprint') \ . ' fmt ' \ . ' -c ' \ . ale#Escape((has('win32') ? 'C:\testplugin\test\test-files\dprint\dprint.json' : '/testplugin/test/test-files/dprint/dprint.json')) \ . ' --stdin %s' \ } Execute(The dprint callback should include custom options): let g:ale_dprint_executable_override = 1 let g:ale_dprint_options = '--verbose' AssertFixer { \ 'command': ale#Escape('dprint') \ . ' fmt ' \ . '--verbose' . ' --stdin %s' \ } ================================================ FILE: test/fixers/test_dune_fixer_callback.vader ================================================ Before: Save g:ale_ocaml_dune_executable Save g:ale_ocaml_dune_options " Use an invalid global executable, so we don't match it. let g:ale_ocaml_dune_executable = 'xxxinvalid' let g:ale_ocaml_dune_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The dune callback should return the correct default values): call ale#test#SetFilename('../test-files/ocaml/testfile.re') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' format', \ }, \ ale#fixers#dune#Fix(bufnr('')) Execute(The dune callback should include custom dune options): let g:ale_ocaml_dune_options = "--random-option" call ale#test#SetFilename('../test-files/ocaml/testfile.re') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' format' \ . ' ' . g:ale_ocaml_dune_options, \ }, \ ale#fixers#dune#Fix(bufnr('')) ================================================ FILE: test/fixers/test_elm_format_fixer_callback.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') After: unlet! b:ale_elm_format_executable unlet! b:ale_elm_format_use_global unlet! b:ale_elm_format_options call ale#test#RestoreDirectory() Execute(The elm-format command should have default params): call ale#test#SetFilename('../test-files/elm/src/subdir/testfile.elm') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/elm/node_modules/.bin/elm-format')) \ . ' %t --yes', \ }, \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage use_global = 1 param): call ale#test#SetFilename('../test-files/elm/src/subdir/testfile.elm') let b:ale_elm_format_use_global = 1 AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('elm-format') \ . ' %t --yes', \ }, \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage executable param): call ale#test#SetFilename('../test-files/elm/src/subdir/testfile.elm') let b:ale_elm_format_use_global = 1 let b:ale_elm_format_executable = 'elmformat' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('elmformat') \ . ' %t --yes', \ }, \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage empty options): call ale#test#SetFilename('../test-files/elm/src/subdir/testfile.elm') let b:ale_elm_format_options = '' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/elm/node_modules/.bin/elm-format')) \ . ' %t', \ }, \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage custom options): call ale#test#SetFilename('../test-files/elm/src/subdir/testfile.elm') let b:ale_elm_format_options = '--param1 --param2' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/elm/node_modules/.bin/elm-format')) \ . ' %t --param1 --param2', \ }, \ ale#fixers#elm_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_erbformatter_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('eruby', 'erb-formatter') After: call ale#assert#TearDownFixerTest() Execute(The erb-formatter callback should return the correct default values): AssertFixer { \ 'command': ale#Escape('erb-formatter') . ' -w %t', \ 'read_temporary_file': 1, \} Execute(The erb-formatter callback should allow custom erb-formatter executables): let g:ale_eruby_erbformatter_executable = 'foo/bar' AssertFixer { \ 'command': ale#Escape('foo/bar') . ' -w %t', \ 'read_temporary_file': 1, \} ================================================ FILE: test/fixers/test_erblint_fixer_callback.vader ================================================ Before: Save g:ale_eruby_erblint_executable Save g:ale_eruby_erblint_options " Use an invalid global executable, so we don't match it. let g:ale_eruby_erblint_executable = 'xxxinvalid' let g:ale_eruby_erblint_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The erblint callback should return the correct default values): call ale#test#SetFilename('../test-files/eruby/dummy.html.erb') AssertEqual \ { \ 'process_with': 'ale#fixers#erblint#PostProcess', \ 'command': ale#Escape(g:ale_eruby_erblint_executable) \ . ' --autocorrect --stdin %s', \ }, \ ale#fixers#erblint#Fix(bufnr('')) Execute(The erblint callback should include custom erblint options): let g:ale_eruby_erblint_options = '--lint-all' call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') AssertEqual \ { \ 'process_with': 'ale#fixers#erblint#PostProcess', \ 'command': ale#Escape(g:ale_eruby_erblint_executable) \ . ' --lint-all' \ . ' --autocorrect --stdin %s', \ }, \ ale#fixers#erblint#Fix(bufnr('')) Execute(The erblint post-processor should remove diagnostics content): AssertEqual \ [ \ '
', \ '', \ '
', \ ], \ ale#fixers#erblint#PostProcess(bufnr(''), [ \ 'Linting 1 files with 11 autocorrectable linters...', \ '', \ '1 error(s) corrected in ERB files', \ '================ /home/user/demo.html.erb ==================', \ '
', \ '', \ '
', \ ]) ================================================ FILE: test/fixers/test_erlang_mode_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('erlang', 'erlang_mode') function! Fixer(key, ...) abort let l:name = get(a:, 1, 'erlang_mode') let l:func = ale#fix#registry#GetFunc(l:name) let l:dict = call(l:func, [bufnr('')]) return l:dict[a:key] endfunction After: delfunction Fixer call ale#assert#TearDownFixerTest() Execute(Emacs should edit temporary file in batch mode): AssertEqual 0, stridx( \ Fixer('command'), \ ale#Escape('emacs') . ' --batch --find-file=%t --eval=', \) Execute(The temporary file should be read): AssertEqual 1, Fixer('read_temporary_file') Execute(Fixer alias erlang-mode should be provided): AssertEqual 0, stridx( \ Fixer('command', 'erlang-mode'), \ ale#Escape('emacs') . ' --batch --find-file=%t --eval=', \) Execute(Emacs executable should be configurable): let b:ale_erlang_erlang_mode_emacs_executable = '/path/to/emacs' AssertEqual 0, stridx(Fixer('command'), ale#Escape('/path/to/emacs')) Execute(enable-local-variables should be :safe): Assert Fixer('command') =~# '\m\' Execute(erlang-indent-level should be 4 by default): Assert Fixer('command') =~# '\m\' Execute(erlang-indent-level should be configurable): let b:ale_erlang_erlang_mode_indent_level = 2 Assert Fixer('command') =~# '\m\' Execute(erlang-icr-indent should be nil by default): Assert Fixer('command') =~# '\m\' Execute(erlang-icr-indent should be configurable): let b:ale_erlang_erlang_mode_icr_indent = 0 Assert Fixer('command') =~# '\m\' Execute(erlang-indent-guard should be 2 by default): Assert Fixer('command') =~# '\m\' Execute(erlang-indent-guard should be configurable): let b:ale_erlang_erlang_mode_indent_guard = 0 Assert Fixer('command') =~# '\m\' Execute(erlang-argument-indent should be 2 by default): Assert Fixer('command') =~# '\m\' Execute(erlang-argument-indent should be configurable): let b:ale_erlang_erlang_mode_argument_indent = 4 Assert Fixer('command') =~# '\m\' Execute(indent-tabs-mode should be nil by default): Assert Fixer('command') =~# '\m\' Execute(indent-tabs-mode should be configurable): let b:ale_erlang_erlang_mode_indent_tabs_mode = 't' Assert Fixer('command') =~# '\m\' ================================================ FILE: test/fixers/test_erlfmt_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('erlang', 'erlfmt') After: unlet! b:root call ale#assert#TearDownFixerTest() Execute(The local erlfmt executable should be used by default): " Not sure if this is a good default though. It seems to imply " that the executable is committed to the repository. let b:root = '../test-files/erlang/app_with_erlfmt' call ale#test#SetFilename(b:root . '/src/app.erl') AssertFixer { \ 'command': ale#Escape(ale#test#GetFilename(b:root . '/erlfmt')) . ' -', \} Execute(The global erlfmt executable should be configurable): let b:root = '../test-files/erlang/app_with_erlfmt' let b:ale_erlang_erlfmt_executable = '/path/to/erlfmt' let b:ale_erlang_erlfmt_use_global = 1 call ale#test#SetFilename(b:root . '/src/app.erl') AssertFixer {'command': ale#Escape('/path/to/erlfmt') . ' -'} Execute(The erlfmt command should handle empty options): AssertFixer {'command': ale#Escape('erlfmt') . ' -'} Execute(The erlfmt command should handle custom options): let b:ale_erlang_erlfmt_options = '--insert-pragma' AssertFixer {'command': ale#Escape('erlfmt') . ' --insert-pragma -'} ================================================ FILE: test/fixers/test_eslint_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('javascript', 'eslint') Save g:ale_command_wrapper runtime autoload/ale/handlers/eslint.vim let g:ale_command_wrapper = '' After: call ale#assert#TearDownFixerTest() Execute(The executable path should be correct): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.js') " eslint_d output with an older eslint version is used here. GivenCommandOutput ['v4.4.1 (eslint_d v5.1.0)'] AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/.eslintrc.js')) \ . ' --fix %t', \ } Execute(The ESLint fixer shouldn't run if no configuration file can be found): call ale#test#SetFilename('../no-configuration') AssertFixerNotExecuted Execute(The ESLint fixer should use a config file option if set for old versions): call ale#test#SetFilename('../no-configuration') let b:ale_javascript_eslint_options = '-c /foo.cfg' AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': '', \ 'command': ale#Escape('eslint') . ' -c /foo.cfg --fix %t', \ } let b:ale_javascript_eslint_options = '--bar -c /foo.cfg' AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': '', \ 'command': ale#Escape('eslint') . ' --bar -c /foo.cfg --fix %t', \ } let b:ale_javascript_eslint_options = '--config /foo.cfg' AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': '', \ 'command': ale#Escape('eslint') . ' --config /foo.cfg --fix %t', \ } let b:ale_javascript_eslint_options = '--bar --config /foo.cfg' AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': '', \ 'command': ale#Escape('eslint') . ' --bar --config /foo.cfg --fix %t', \ } Execute(The ESLint fixer should use a -c file option if set for eslint_d): let b:ale_javascript_eslint_executable = '/bin/eslint_d' GivenCommandOutput ['v3.19.0 (eslint_d v4.2.0)'] call ale#test#SetFilename('../no-configuration') let b:ale_javascript_eslint_options = '-c /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'cwd': '', \ 'command': ale#Escape('/bin/eslint_d') \ . ' -c /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-to-stdout' \ } let b:ale_javascript_eslint_options = '--bar -c /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'cwd': '', \ 'command': ale#Escape('/bin/eslint_d') \ . ' --bar -c /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-to-stdout' \ } let b:ale_javascript_eslint_options = '--config /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'cwd': '', \ 'command': ale#Escape('/bin/eslint_d') \ . ' --config /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-to-stdout' \ } let b:ale_javascript_eslint_options = '--bar --config /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'cwd': '', \ 'command': ale#Escape('/bin/eslint_d') \ . ' --bar --config /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-to-stdout' \ } Execute(The ESLint fixer should use a config file option if set for new versions): GivenCommandOutput ['4.9.0'] call ale#test#SetFilename('../no-configuration') let b:ale_javascript_eslint_options = '-c /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'cwd': '', \ 'command': ale#Escape('eslint') \ . ' -c /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json' \ } let b:ale_javascript_eslint_options = '--bar -c /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'cwd': '', \ 'command': ale#Escape('eslint') \ . ' --bar -c /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json' \ } let b:ale_javascript_eslint_options = '--config /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'cwd': '', \ 'command': ale#Escape('eslint') \ . ' --config /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json' \ } let b:ale_javascript_eslint_options = '--bar --config /foo.cfg' AssertFixer \ { \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'cwd': '', \ 'command': ale#Escape('eslint') \ . ' --bar --config /foo.cfg' \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json' \ } Execute(The lower priority configuration file in a nested directory should be preferred): call ale#test#SetFilename('../test-files/eslint/react-app/subdir-with-config/testfile.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/subdir-with-config'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/subdir-with-config/.eslintrc')) \ . ' --fix %t', \ } Execute(--config in options should override configuration file detection for old versions): call ale#test#SetFilename('../test-files/eslint/react-app/subdir-with-config/testfile.js') let b:ale_javascript_eslint_options = '--config /foo.cfg' AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/subdir-with-config'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' --config /foo.cfg' \ . ' --fix %t', \ } let b:ale_javascript_eslint_options = '-c /foo.cfg' AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/subdir-with-config'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c /foo.cfg' \ . ' --fix %t', \ } Execute(package.json should be used as a last resort): call ale#test#SetFilename('../test-files/eslint/react-app/subdir-with-package-json/testfile.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/.eslintrc.js')) \ . ' --fix %t', \ } call ale#test#SetFilename('../test-files/eslint/package.json') AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/node_modules/.bin/eslint')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/package.json')) \ . ' --fix %t', \ } Execute(The version check should be correct): call ale#test#SetFilename('../test-files/eslint/react-app/subdir-with-config/testfile.js') " We should run the command to get the version the first time. GivenCommandOutput ['4.9.0'] AssertFixer [ \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' --version', \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/subdir-with-config'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ }, \] AssertFixer [ \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/subdir-with-config'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ }, \] Execute(--fix-dry-run should be used for 4.9.0 and up): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.js') GivenCommandOutput ['4.9.0'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/react-app'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js')) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ } Execute(The --fix-dry-run post-processor should handle JSON output correctly): AssertEqual \ [], \ ale#fixers#eslint#ProcessFixDryRunOutput(bufnr(''), []) AssertEqual \ [], \ ale#fixers#eslint#ProcessFixDryRunOutput(bufnr(''), ['']) AssertEqual \ [], \ ale#fixers#eslint#ProcessFixDryRunOutput(bufnr(''), ['[{}]']) AssertEqual \ ['foo', 'bar'], \ ale#fixers#eslint#ProcessFixDryRunOutput(bufnr(''), ['[{"output": "foo\nbar"}]']) Execute(The eslint_d post-processor should permit regular JavaScript content): AssertEqual \ [ \ 'const x = ''Error: foo''', \ 'const y = 3', \ ], \ ale#fixers#eslint#ProcessEslintDOutput(bufnr(''), [ \ 'const x = ''Error: foo''', \ 'const y = 3', \ ]) Execute(The eslint_d post-processor should handle error messages correctly): AssertEqual \ [], \ 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', \ ]) Execute(The executable path should be correct for astro app): call ale#test#SetFilename('../test-files/eslint/astro-app/src/pages/index.astro') " eslint_d output with an older eslint version is used here. GivenCommandOutput ['v4.4.1 (eslint_d v5.1.0)'] AssertFixer \ { \ 'read_temporary_file': 1, \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/eslint/astro-app'), \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/astro-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/astro-app/.eslintrc.js')) \ . ' --fix %t', \ } ================================================ FILE: test/fixers/test_fecs_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('javascript', 'fecs') runtime autoload/ale/handlers/fecs.vim After: call ale#assert#TearDownFixerTest() Execute(The fecs fixer should respect to g:ale_javascript_fecs_executable): let g:ale_javascript_fecs_executable = '../test-files/fecs/fecs' let g:ale_javascript_fecs_use_global = 1 AssertEqual \ { \ 'command': ale#Escape(g:ale_javascript_fecs_executable) . ' format --replace=true %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#fecs#Fix(bufnr('')) Execute(The fecs fixer should return 0 when executable not found): let g:ale_javascript_fecs_executable = 'fecs-invalid' let g:ale_javascript_fecs_use_global = 1 AssertEqual \ 0, \ ale#fixers#fecs#Fix(bufnr('')) ================================================ FILE: test/fixers/test_fish_indent_fixer_callback.vader ================================================ Before: Save g:ale_fish_fish_indent_executable Save g:ale_fish_fish_indent_options " Use an invalid global executable, so we don't match it. let g:ale_fish_fish_indent_executable = 'xxxinvalid' let g:ale_fish_fish_indent_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The fish_indent callback should return the correct default values): call ale#test#SetFilename('../test-files/fish/testfile.fish') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -w ' \ . ' %t', \ }, \ ale#fixers#fish_indent#Fix(bufnr('')) Execute(The fish_indent callback should include custom fish_indent options): let g:ale_fish_fish_indent_options = "-d" call ale#test#SetFilename('../test-files/fish/testfile.fish') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -w ' \ . ' -d' \ . ' %t', \ }, \ ale#fixers#fish_indent#Fix(bufnr('')) ================================================ FILE: test/fixers/test_fixjson_fixer_callback.vader ================================================ Before: Save g:ale_json_fixjson_executable Save g:ale_json_fixjson_options let g:ale_json_fixjson_executable = '/path/to/fixjson' let g:ale_json_fixjson_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore Execute(The fixjson callback should return the correct default command): AssertEqual \ { \ 'command': ale#Escape('/path/to/fixjson') \ . ' --stdin-filename ' \ . ale#Escape(bufname(bufnr(''))) \ }, \ ale#fixers#fixjson#Fix(bufnr('')) Execute(The fixjson callback should set the buffer name as file name): call ale#test#SetFilename('../test-files/json/testfile.json') AssertEqual \ { \ 'command': ale#Escape('/path/to/fixjson') \ . ' --stdin-filename ' \ . ale#Escape(bufname(bufnr(''))) \ }, \ ale#fixers#fixjson#Fix(bufnr('')) AssertNotEqual \ stridx( \ ale#fixers#fixjson#Fix(bufnr('')).command, \ 'testfile.json', \ ), \ -1 Execute(The fixjson callback should include additional options): let g:ale_json_fixjson_options = '-i 2' AssertEqual \ { \ 'command': ale#Escape('/path/to/fixjson') \ . ' --stdin-filename ' \ . ale#Escape(bufname(bufnr(''))) \ . ' -i 2' \ }, \ ale#fixers#fixjson#Fix(bufnr('')) ================================================ FILE: test/fixers/test_floskell_fixer_callback.vader ================================================ Before: Save g:ale_haskell_floskell_executable " Use an invalid global executable, so we don't match it. let g:ale_haskell_floskell_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The floskell callback should return the correct default values): call ale#test#SetFilename('../haskell_files/testfile.hs') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' %t', \ }, \ ale#fixers#floskell#Fix(bufnr('')) ================================================ FILE: test/fixers/test_forge_fixer_callback.vader ================================================ Before: Save g:ale_solidity_forge_executable After: Restore Execute(The forge fmt callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('forge') \ . ' fmt %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#forge#Fix(bufnr('')) ================================================ FILE: test/fixers/test_fourmolu_fixer_callback.vader ================================================ Before: Save g:ale_haskell_fourmolu_executable Save g:ale_haskell_fourmolu_options After: Restore Execute(The fourmolu callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('fourmolu') \ . ' --stdin-input-file ' \ . ale#Escape(@%) \ }, \ ale#fixers#fourmolu#Fix(bufnr('')) Execute(The fourmolu executable and options should be configurable): let g:ale_haskell_fourmolu_executable = '/path/to/fourmolu' let g:ale_haskell_fourmolu_options = '-h' AssertEqual \ { \ 'command': ale#Escape('/path/to/fourmolu') \ . ' -h' \ . ' --stdin-input-file ' \ . ale#Escape(@%) \ }, \ ale#fixers#fourmolu#Fix(bufnr('')) ================================================ FILE: test/fixers/test_gleam_format_fixer_callback.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The gleam_format command should have default values): call ale#test#SetFilename('../test-files/elixir/testfile.gleam') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('gleam') . ' format %t', \ }, \ ale#fixers#gleam_format#Fix(bufnr('')) Execute(The gleam_format executable should be configurable): let g:ale_gleam_format_executable = 'xxxinvalid' call ale#test#SetFilename('../test-files/elixir/testfile.gleam') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') . ' format %t', \ }, \ ale#fixers#gleam_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_gnatpp_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('ada', 'gnatpp') After: " Reset fixers, variables, etc. " " Vader's 'Restore' command will be called here. call ale#assert#TearDownFixerTest() Execute(The default command should be correct): call ale#test#SetFilename('../test-files/ada/testfile.adb') AssertFixer \ { \ 'command': ale#Escape(g:ale_ada_gnatpp_executable) .' %t', \ 'read_temporary_file': 1, \ } Execute(The version check should be correct): call ale#test#SetFilename('../test-files/ada/testfile.adb') let g:ale_ada_gnatpp_options = '--no-alignment' AssertFixer \ { \ 'command': ale#Escape(g:ale_ada_gnatpp_executable) \ . ' --no-alignment %t', \ 'read_temporary_file': 1, \ } ================================================ FILE: test/fixers/test_gofmt_fixer_callback.vader ================================================ Before: Save g:ale_go_gofmt_executable Save g:ale_go_gofmt_options Save g:ale_go_go111module " Use an invalid global executable, so we don't match it. let g:ale_go_gofmt_executable = 'xxxinvalid' let g:ale_go_gofmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore unlet! b:ale_go_go111module call ale#test#RestoreDirectory() Execute(The gofmt callback should return the correct default values): call ale#test#SetFilename('../test-files/go/testfile.go') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid'), \ }, \ ale#fixers#gofmt#Fix(bufnr('')) Execute(The gofmt callback should include custom gofmt options): let g:ale_go_gofmt_options = "-r '(a) -> a'" call ale#test#SetFilename('../test-files/go/testfile.go') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_go_gofmt_options, \ }, \ ale#fixers#gofmt#Fix(bufnr('')) Execute(The gofmt callback should support Go environment variables): let g:ale_go_go111module = 'off' call ale#test#SetFilename('../test-files/go/testfile.go') AssertEqual \ { \ 'command': ale#Env('GO111MODULE', 'off') \ . ale#Escape('xxxinvalid') \ }, \ ale#fixers#gofmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_gofumpt_fixer.vader ================================================ Before: call ale#assert#SetUpFixerTest('go', 'gofumpt') After: call ale#assert#TearDownFixerTest() Execute(The gofumpt callback should return the correct default values): AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('gofumpt') . ' -w -- %t' \} Execute(The gofumpt callback should allow custom gofumpt executables): let g:ale_go_gofumpt_executable = 'foo/bar' AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('foo/bar') . ' -w -- %t' \} Execute(The gofumpt callback should allow custom gofumpt options): let g:ale_go_gofumpt_options = '--foobar' AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('gofumpt') . ' --foobar -w -- %t' \} ================================================ FILE: test/fixers/test_goimports_fixer_callback.vader ================================================ Before: Save g:ale_go_goimports_executable Save g:ale_go_goimports_options Save g:ale_go_go111module " Use an invalid global executable, so we don't match it. let g:ale_go_goimports_executable = 'xxxinvalid' let g:ale_go_goimports_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') call ale#test#SetFilename('../test-files/go/testfile.go') After: Restore unlet! b:ale_go_go111module call ale#test#RestoreDirectory() Execute(The goimports callback should return 0 when the executable isn't executable): AssertEqual \ 0, \ ale#fixers#goimports#Fix(bufnr('')) Execute(The goimports callback should the command when the executable test passes): let g:ale_go_goimports_executable = has('win32') ? 'cmd' : 'echo' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_go_goimports_executable) . ' -l -w -srcdir %s %t' \ }, \ ale#fixers#goimports#Fix(bufnr('')) Execute(The goimports callback should include extra options): let g:ale_go_goimports_executable = has('win32') ? 'cmd' : 'echo' let g:ale_go_goimports_options = '--xxx' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_go_goimports_executable) . ' -l -w -srcdir %s --xxx %t' \ }, \ ale#fixers#goimports#Fix(bufnr('')) Execute(The goimports callback should support Go environment variables): let g:ale_go_goimports_executable = has('win32') ? 'cmd' : 'echo' let g:ale_go_go111module = 'on' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Env('GO111MODULE', 'on') \ . ale#Escape(g:ale_go_goimports_executable) \ . ' -l -w -srcdir %s %t' \ }, \ ale#fixers#goimports#Fix(bufnr('')) ================================================ FILE: test/fixers/test_golangci_lint_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('go', 'golangci_lint') Save g:ale_go_go111module Save g:ale_go_golangci_formatter_executable Save g:ale_go_golangci_formatter_options call ale#test#SetDirectory('/testplugin/test/fixers') call ale#test#SetFilename('../test-files/go/testfile.go') After: call ale#test#RestoreDirectory() call ale#assert#TearDownFixerTest() unlet! b:ale_go_go111module Execute(The golangci-lint callback should return the correct default values with v1): GivenCommandOutput ['golangci-lint has version 1.64.8 built with go1.23.0'] AssertFixer \ { \ 'command': ale#Escape('golangci-lint') . ' run --fix ' . ale#Escape('testfile.go'), \ } Execute(The golangci-lint callback should include custom golangci-lint options with v1): let g:ale_go_golangci_formatter_options = "--new --config /dev/null" GivenCommandOutput ['golangci-lint has version 1.64.8 built with go1.23.0'] AssertFixer \ { \ 'command': ale#Escape('golangci-lint') \ . ' run --fix ' . g:ale_go_golangci_formatter_options . ' ' . ale#Escape('testfile.go'), \ }, Execute(The golangci-lint callback should override executable with v1): let g:ale_go_golangci_formatter_executable = 'xxxinvalid' GivenCommandOutput ['golangci-lint has version 1.64.8 built with go1.23.0'] AssertFixer \ { \ 'command': ale#Escape('xxxinvalid') \ . ' run --fix ' \ . g:ale_go_golangci_formatter_options \ . ' ' . ale#Escape('testfile.go'), \ }, Execute(The golangci-lint callback should return the correct default values with v2): GivenCommandOutput ['golangci-lint has version 2.1.5 built with go1.23.0'] AssertFixer \ { \ 'command': ale#Escape('golangci-lint') . ' fmt --stdin ', \ } Execute(The golangci-lint callback should include custom golangci-lint options with v2): let g:ale_go_golangci_formatter_options = "--new --config /dev/null" GivenCommandOutput ['golangci-lint has version 2.1.5 built with go1.23.0'] AssertFixer \ { \ 'command': ale#Escape('golangci-lint') \ . ' fmt --stdin ' . g:ale_go_golangci_formatter_options, \ }, Execute(The golangci-lint callback should override executable with v2): let g:ale_go_golangci_formatter_executable = 'xxxinvalid' GivenCommandOutput ['golangci-lint has version 2.1.5 built with go1.23.0'] AssertFixer \ { \ 'command': ale#Escape('xxxinvalid') \ . ' fmt --stdin ' \ . g:ale_go_golangci_formatter_options \ }, ================================================ FILE: test/fixers/test_golines_fixer_callback.vader ================================================ Before: Save g:ale_go_golines_executable Save g:ale_go_golines_options Save g:ale_go_go111module " Use an invalid global executable, so we don't match it. let g:ale_go_golines_executable = 'xxxinvalid' let g:ale_go_golines_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore unlet! b:ale_go_go111module call ale#test#RestoreDirectory() Execute(The golines callback should return 0 when the executable isn't executable): AssertEqual \ 0, \ ale#fixers#golines#Fix(bufnr('')) Execute(The golines callback should return the correct default values): let g:ale_go_golines_executable = has('win32') ? 'cmd' : 'echo' AssertEqual \ { \ 'command': ale#Escape(g:ale_go_golines_executable), \ }, \ ale#fixers#golines#Fix(bufnr('')) Execute(The golines callback should include custom golines options): let g:ale_go_golines_executable = has('win32') ? 'cmd' : 'echo' let g:ale_go_golines_options = "--max-len --shorten-comments" AssertEqual \ { \ 'command': ale#Escape(g:ale_go_golines_executable) \ . ' ' . g:ale_go_golines_options, \ }, \ ale#fixers#golines#Fix(bufnr('')) Execute(The golines callback should support Go environment variables): let g:ale_go_golines_executable = has('win32') ? 'cmd' : 'echo' let g:ale_go_go111module = 'off' AssertEqual \ { \ 'command': ale#Env('GO111MODULE', 'off') \ . ale#Escape(g:ale_go_golines_executable) \ }, \ ale#fixers#golines#Fix(bufnr('')) ================================================ FILE: test/fixers/test_gomod_fixer_callback.vader ================================================ Before: Save g:ale_go_go_executable Save g:ale_go_go111module " Use an invalid global executable, so we don't match it. let g:ale_go_go_executable = 'xxxinvalid' let g:ale_go_go111module = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore unlet! b:ale_go_go111module call ale#test#RestoreDirectory() Execute(The gomod callback should return the correct default values): call ale#test#SetFilename('../test-files/go/go.mod') setl filetype=gomod AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' mod edit -fmt' \ . ' %t', \ }, \ ale#fixers#gomod#Fix(bufnr('')) Execute(The gomod callback should support Go environment variables): call ale#test#SetFilename('../test-files/go/go.mod') setl filetype=gomod let g:ale_go_go111module = 'on' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Env('GO111MODULE', 'on') \ . ale#Escape('xxxinvalid') . ' mod edit -fmt %t' \ }, \ ale#fixers#gomod#Fix(bufnr('')) ================================================ FILE: test/fixers/test_goofle_java_format_fixer_callback.vader ================================================ Before: Save g:ale_java_google_java_format_executable " Use an invalid global executable, so we don't match it. let g:ale_java_google_java_format_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The google-java-format callback should return 0 when the executable isn't executable): AssertEqual \ 0, \ 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_java_google_java_format_executable = has('win32') ? 'cmd' : 'echo' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(ale_java_google_java_format_executable) . ' --replace %t' \ }, \ ale#fixers#google_java_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_gopls_fixer_callback.vader ================================================ Before: Save g:ale_go_gopls_fix_executable Save g:ale_go_gopls_fix_options Save g:ale_go_go111module " Use an invalid global executable, so we don't match it. let g:ale_go_gopls_fix_executable = 'xxxinvalid' let g:ale_go_gopls_fix_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') call ale#test#SetFilename('../test-files/go/testfile.go') After: Restore unlet! b:ale_go_go111module call ale#test#RestoreDirectory() Execute(The gopls callback should return 0 when the executable isn't executable): AssertEqual \ 0, \ ale#fixers#gopls#Fix(bufnr('')) Execute(The gopls callback should the command when the executable test passes): let g:ale_go_gopls_fix_executable = has('win32') ? 'cmd' : 'echo' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_go_gopls_fix_executable) . ' format -l -w %t' \ }, \ ale#fixers#gopls#Fix(bufnr('')) Execute(The gopls callback should include extra options): let g:ale_go_gopls_fix_executable = has('win32') ? 'cmd' : 'echo' let g:ale_go_gopls_fix_options = '--xxx' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_go_gopls_fix_executable) . ' format --xxx -l -w %t' \ }, \ ale#fixers#gopls#Fix(bufnr('')) Execute(The gopls callback should support Go environment variables): let g:ale_go_gopls_fix_executable = has('win32') ? 'cmd' : 'echo' let g:ale_go_go111module = 'on' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Env('GO111MODULE', 'on') \ . ale#Escape(g:ale_go_gopls_fix_executable) \ . ' format -l -w %t' \ }, \ ale#fixers#gopls#Fix(bufnr('')) ================================================ FILE: test/fixers/test_hackfmt_fixer_callback.vader ================================================ Before: 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_hack_hackfmt_executable = 'xxxinvalid' let g:ale_hack_hackfmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The hackfmt callback should return the correct default values): call ale#test#SetFilename('../hack_files/testfile.hack') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -i %t', \ }, \ ale#fixers#hackfmt#Fix(bufnr('')) Execute(The hackfmt callback should include custom hackfmt options): let g:ale_hack_hackfmt_options = "--some-option" call ale#test#SetFilename('../hack_files/testfile.hack') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -i --some-option %t', \ }, \ ale#fixers#hackfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_hfmt_fixer_callback.vader ================================================ Before: Save g:ale_haskell_hfmt_executable " Use an invalid global executable, so we don't match it. let g:ale_haskell_hfmt_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The hfmt callback should return the correct default values): call ale#test#SetFilename('../haskell_files/testfile.hs') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -w' \ . ' %t', \ }, \ ale#fixers#hfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_hindent_fixer_callback.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The hindent callback should return the correct default values): call ale#test#SetFilename('../haskell_files/testfile.hs') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('hindent') \ . ' %t', \ }, \ ale#fixers#hindent#Fix(bufnr('')) ================================================ FILE: test/fixers/test_hlint_fixer_callback.vader ================================================ 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('')) ================================================ FILE: test/fixers/test_html_beautify_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('html', 'html-beautify', 'beautify') After: Restore call ale#assert#TearDownFixerTest() Execute(The html-beautify callback should return the correct default command): AssertEqual \ {'command': ale#Escape('html-beautify') . ' -'}, \ ale#fixers#html_beautify#Fix(bufnr('')) ================================================ FILE: test/fixers/test_htmlbeautifier_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('eruby', 'htmlbeautifier') After: call ale#assert#TearDownFixerTest() Execute(The htmlbeautifier callback should return the correct default values): AssertFixer { \ 'command': ale#Escape('htmlbeautifier') . ' %t', \ 'read_temporary_file': 1, \} Execute(The htmlbeautifier callback should allow custom htmlbeautifier executables): let g:ale_eruby_htmlbeautifier_executable = 'foo/bar' AssertFixer { \ 'command': ale#Escape('foo/bar') . ' %t', \ 'read_temporary_file': 1, \} ================================================ FILE: test/fixers/test_hurlfmt_fixer_callback.vader ================================================ Before: Save g:ale_hurl_hurlfmt_executable " Use an invalid global executable, so we don't match it. let g:ale_hurl_hurlfmt_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The hurlfmt callback should return the correct default values): call ale#test#SetFilename('../test-files/hurl/dummy.hurl') AssertEqual \ { \ 'command': ale#Escape(g:ale_hurl_hurlfmt_executable) \ . ' --out hurl', \ }, \ ale#fixers#hurlfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_importjs_fixer_callback.vader ================================================ Before: Save g:ale_javascript_importjs_executable " Use an invalid global executable, so we don't match it. let g:ale_javascript_importjs_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') call ale#test#SetFilename('../test-files/javascript/test.js') After: Restore call ale#test#RestoreDirectory() Execute(The importjs callback should return 0 when the executable isn't executable): AssertEqual \ 0, \ ale#fixers#importjs#Fix(bufnr('')) Execute(The importjs callback should run the command when the executable test passes): let g:ale_javascript_importjs_executable = has('win32') ? 'cmd' : 'echo' AssertEqual \ { \ 'process_with': 'ale#fixers#importjs#ProcessOutput', \ 'command': ale#Escape(g:ale_javascript_importjs_executable) . ' fix %s' \ }, \ ale#fixers#importjs#Fix(bufnr('')) Execute(The ProcessOutput callback should return the expected output): let g:testOutput = '{"messages":[],"fileContent":"one\ntwo","unresolvedImports":{}}' AssertEqual \ ['one', 'two'], \ ale#fixers#importjs#ProcessOutput(bufnr(''), g:testOutput) ================================================ FILE: test/fixers/test_isort_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'isort') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: call ale#assert#TearDownFixerTest() unlet! g:dir unlet! b:bin_dir Execute(The isort callback should return the correct default values): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') " --filename option exists only after 5.7.0 GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/isort')) . ' --filename %s' . ' -', \ } Execute(The isort callback should respect custom options): let g:ale_python_isort_options = '--multi-line=3 --trailing-comma' silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') " --filename option exists only after 5.7.0 GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/isort')) \ . ' --filename %s' . ' --multi-line=3 --trailing-comma -', \ } Execute(Pipenv is detected when python_isort_auto_pipenv is set): let g:ale_python_isort_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pipenv') . ' run isort' . ' --filename %s' . ' -' \ } Execute(Poetry is detected when python_isort_auto_poetry is set): let g:ale_python_isort_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('poetry') . ' run isort' . ' --filename %s' . ' -' \ } Execute(uv is detected when python_isort_auto_uv is set): let g:ale_python_isort_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('uv') . ' run isort' . ' --filename %s' . ' -' \ } Execute(The isort callback should not use --filename for older versions): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') " --filename option exists only after 5.7.0 GivenCommandOutput ['VERSION 5.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/isort')) . ' -', \ } ================================================ FILE: test/fixers/test_jq_fixer_callback.vader ================================================ Before: Save g:ale_json_jq_executable Save g:ale_json_jq_options Save g:ale_json_jq_filters After: Restore 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') . ' .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('')) ================================================ FILE: test/fixers/test_jsonnetfmt_fixer_callback.vader ================================================ Before: Save g:ale_jsonnet_jsonnetfmt_executable Save g:ale_jsonnet_jsonnetfmt_options " Use an invalid global executable, so we don't match it. let g:ale_jsonnet_jsonnetfmt_executable = 'xxxinvalid' let g:ale_jsonnet_jsonnetfmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') call ale#assert#SetUpFixerTest('jsonnet', 'jsonnetfmt') After: call ale#test#RestoreDirectory() call ale#assert#TearDownFixerTest() Execute(The jsonnetfmt callback should return the correct default values): call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_jsonnet_jsonnetfmt_executable) \ . ' -i' \ . ' %t', \} Execute(The jsonnetfmt callback should include custom options): let g:ale_jsonnet_jsonnetfmt_options = '--pad-arrays' call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_jsonnet_jsonnetfmt_executable) \ . ' -i' \ . ' ' . g:ale_jsonnet_jsonnetfmt_options \ . ' %t', \} ================================================ FILE: test/fixers/test_ktlint_fixer_callback.vader ================================================ Before: Save g:ale_kotlin_ktlint_executable Save g:ale_kotlin_ktlint_options Save g:ale_kotlin_ktlint_rulesets " Use an invalid global executable, so we don't match it. let g:ale_kotlin_ktlint_executable = 'xxxinvalid' let g:ale_kotlin_ktlint_options = '' let g:ale_kotlin_ktlint_rulesets = [] call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The ktlint callback should return the correct default values): call ale#test#SetFilename('../test-files/kotlin/testfile.kt') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' --stdin' \ . ' --format', \ }, \ ale#fixers#ktlint#Fix(bufnr('')) Execute(The ktlint callback should include custom ktlint options): let g:ale_kotlin_ktlint_options = "--android" let g:ale_kotlin_ktlint_rulesets = ['/path/to/custom/ruleset.jar'] call ale#test#SetFilename('../test-files/kotlin/testfile.kt') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_kotlin_ktlint_options \ . ' --ruleset /path/to/custom/ruleset.jar' \ . ' --stdin' \ . ' --format', \ }, \ ale#fixers#ktlint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_kulala_fmt_fixer_callback.vader ================================================ Before: Save g:ale_http_kulala_fmt_executable " Use an invalid global executable, so we don't match it. let g:ale_http_kulala_fmt_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The kualala_fmt callback should return the correct default values): call ale#test#SetFilename('../test-files/http/dummy.http') AssertEqual \ { \ 'command': ale#Escape(g:ale_http_kulala_fmt_executable) \ . ' format %t > /dev/null', \ 'read_temporary_file': 1, \ }, \ ale#fixers#kulala_fmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_latexindent_fixer_callback.vader ================================================ Before: Save g:ale_tex_latexindent_executable Save g:ale_tex_latexindent_options " Use an invalid global executable, so we don't match it. let g:ale_tex_latexindent_executable = 'xxxinvalid' let g:ale_tex_latexindent_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The latexindent callback should return the correct default values): call ale#test#SetFilename('../test-files/tex/testfile.tex') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' -l' \ }, \ ale#fixers#latexindent#Fix(bufnr('')) Execute(The latexindent callback should include custom gofmt options): let g:ale_tex_latexindent_options = "-l '~/.indentconfig.yaml'" call ale#test#SetFilename('../test-files/tex/testfile.tex') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' -l' \ . ' ' . g:ale_tex_latexindent_options \ }, \ ale#fixers#latexindent#Fix(bufnr('')) ================================================ FILE: test/fixers/test_lua_format_fixer_callback.vader ================================================ Before: Save g:ale_lua_lua_format_executable Save g:ale_lua_lua_format_options " Use an invalid global executable, so we don't match it. let g:ale_lua_lua_format_executable = 'xxxinvalid' let g:ale_lua_lua_format_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The lua_format callback should return the correct default values): call ale#test#SetFilename('../test-files/lua/testfile.lua') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' -i', \ }, \ ale#fixers#lua_format#Fix(bufnr('')) Execute(The lua_format callback should include custom lua_format options): let g:ale_lua_lua_format_options = "--no-chop-down-table" call ale#test#SetFilename('../test-files/lua/testfile.lua') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_lua_lua_format_options \ . ' -i', \ }, \ ale#fixers#lua_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_luafmt_fixer_callback.vader ================================================ Before: Save g:ale_lua_luafmt_executable Save g:ale_lua_luafmt_options " Use an invalid global executable, so we don't match it. let g:ale_lua_luafmt_executable = 'xxxinvalid' let g:ale_lua_luafmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The luafmt callback should return the correct default values): call ale#test#SetFilename('../test-files/lua/testfile.lua') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' --stdin', \ }, \ ale#fixers#luafmt#Fix(bufnr('')) Execute(The luafmt callback should include custom luafmt options): let g:ale_lua_luafmt_options = "--skip-children" call ale#test#SetFilename('../test-files/lua/testfile.lua') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_lua_luafmt_options \ . ' --stdin', \ }, \ ale#fixers#luafmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_markdownlint_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('markdown', 'markdownlint') After: call ale#assert#TearDownFixerTest() Execute: AssertFixer { \ 'command': ale#Escape('markdownlint') . ' --fix', \} Execute: let g:ale_markdownlint_executable = 'custom_markdownlint' AssertFixer { \ 'command': ale#Escape('custom_markdownlint') . ' --fix', \} ================================================ FILE: test/fixers/test_mix_format_fixer_callback.vader ================================================ Before: Save g:ale_elixir_mix_executable Save g:ale_elixir_mix_format_options let g:ale_elixir_mix_executable = 'xxxinvalid' let g:ale_elixir_mix_format_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The mix_format callback should return the correct default values): call ale#test#SetFilename('../test-files/elixir/testfile.ex') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' format %t', \ }, \ ale#fixers#mix_format#Fix(bufnr('')) Execute(The mix_format callback should include the correct format options): let g:ale_elixir_mix_format_options = 'invalid_options' call ale#test#SetFilename('../test-files/elixir/testfile.ex') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' format invalid_options %t', \ }, \ ale#fixers#mix_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_nickel_format_fixer_callback.vader ================================================ Before: Save g:ale_nickel_nickel_format_executable Save g:ale_nickel_nickel_format_options Save &l:expandtab Save &l:shiftwidth Save &l:tabstop After: Restore Execute(The nickel_format callback should return 'nickel format' as default command): setlocal noexpandtab Assert \ ale#fixers#nickel_format#Fix(bufnr('')).command =~# '^' . ale#Escape('nickel') . ' format', \ "Default command name is expected to be 'nickel format'" Execute(The nickel executable and options should be configurable): let g:ale_nickel_nickel_format_executable = 'foobar' let g:ale_nickel_nickel_format_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape('foobar') \ . ' format' \ . ' --some-option', \ }, \ ale#fixers#nickel_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_nimpretty_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('nim', 'nimpretty') After: call ale#assert#TearDownFixerTest() Execute(The nimpretty callback should return the correct default values): AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('nimpretty') . ' %t --maxLineLen:80' \ }, \ ale#fixers#nimpretty#Fix(bufnr('')) Execute(The nimpretty callback should include any additional options): let g:ale_nim_nimpretty_options = '--some-option' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('nimpretty') . ' %t --some-option' \ }, \ ale#fixers#nimpretty#Fix(bufnr('')) ================================================ FILE: test/fixers/test_nixfmt_fixer_callback.vader ================================================ Before: Save g:ale_nix_nixfmt_executable Save g:ale_nix_nixfmt_options After: Restore Execute(The nixfmt callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('nixfmt') \ }, \ ale#fixers#nixfmt#Fix(bufnr('')) Execute(The nixfmt executable and options should be configurable): let g:ale_nix_nixfmt_executable = '/path/to/nixfmt' let g:ale_nix_nixfmt_options = '--help' AssertEqual \ { \ 'command': ale#Escape('/path/to/nixfmt') \ . ' --help', \ }, \ ale#fixers#nixfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_nixpkgsfmt_fixer_callback.vader ================================================ Before: Save g:ale_nix_nixpkgsfmt_executable Save g:ale_nix_nixpkgsfmt_options After: Restore Execute(The nixpkgs-fmt callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('nixpkgs-fmt') \ }, \ ale#fixers#nixpkgsfmt#Fix(bufnr('')) Execute(The nixpkgs-fmt executable and options should be configurable): let g:ale_nix_nixpkgsfmt_executable = '/path/to/nixpkgs-fmt' let g:ale_nix_nixpkgsfmt_options = '-h' AssertEqual \ { \ 'command': ale#Escape('/path/to/nixpkgs-fmt') \ . ' -h', \ }, \ ale#fixers#nixpkgsfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_npmgroovylint_fixer_callback.vader ================================================ Before: Save b:ale_groovy_npmgroovylint_fix_options call ale#assert#SetUpFixerTest('groovy', 'npm-groovy-lint') After: Restore call ale#assert#TearDownFixerTest() Execute(The callback should return the correct default values): AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('npm-groovy-lint') . ' --fix %t', \ } Execute(The callback should include custom options): let b:ale_groovy_npmgroovylint_fix_options = '--format' AssertFixer { \ 'read_temporary_file': 1, \ 'command': ale#Escape('npm-groovy-lint') . ' --format %t', \ } ================================================ FILE: test/fixers/test_ocamlformat_fixer_callback.vader ================================================ 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('../test-files/ocaml/testfile.re') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' --name=%s -', \ }, \ 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('../test-files/ocaml/testfile.re') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_ocaml_ocamlformat_options \ . ' --name=%s -', \ }, \ ale#fixers#ocamlformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_ocp_indent_fixer_callback.vader ================================================ Before: Save g:ale_ocaml_ocp_indent_executable Save g:ale_ocaml_ocpindent_options " Use an invalid global executable let g:ale_ocaml_ocp_indent_executable = 'xxxinvalid' let g:ale_ocaml_ocp_indent_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The ocp_indent callback should return the correct default values): call ale#test#SetFilename('../test-files/ocaml/ocp_inden_testfile.re') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ }, \ ale#fixers#ocp_indent#Fix(bufnr('')) Execute(The ocp_indent callback should include custom ocp_indent options): let g:ale_ocaml_ocp_indent_config = "base=4, type=4" call ale#test#SetFilename('../test-files/ocaml/ocp_inden_testfile.re') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' --config=' . ale#Escape(g:ale_ocaml_ocp_indent_config) \ }, \ ale#fixers#ocp_indent#Fix(bufnr('')) ================================================ FILE: test/fixers/test_opa_fmt_fixer_callback.vader ================================================ Before: Save g:ale_opa_fmt_executable Save g:ale_opa_fmt_options " Use an invalid global executable, so we don't match it. let g:ale_opa_fmt_executable = 'xxxinvalid' let g:ale_opa_fmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The opa fmt callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' fmt', \ }, \ ale#fixers#opafmt#Fix(bufnr('')) Execute(The opa fmt callback should include custom options): let g:ale_opa_fmt_options = "--list" AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' fmt' \ . ' ' . g:ale_opa_fmt_options \ }, \ ale#fixers#opafmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_ormolu_fixer_callback.vader ================================================ Before: Save g:ale_haskell_ormolu_executable Save g:ale_haskell_ormolu_options After: Restore Execute(The ormolu callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('ormolu') \ }, \ ale#fixers#ormolu#Fix(bufnr('')) Execute(The ormolu executable and options should be configurable): let g:ale_nix_nixpkgsfmt_executable = '/path/to/ormolu' let g:ale_nix_nixpkgsfmt_options = '-h' AssertEqual \ { \ 'command': ale#Escape('/path/to/ormolu') \ . ' -h', \ }, \ ale#fixers#nixpkgsfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_packer_fmt_fixer_callback.vader ================================================ Before: Save g:ale_packer_fmt_executable Save g:ale_packer_fmt_options " Use an invalid global executable, so we don't match it. let g:ale_packer_fmt_executable = 'xxxinvalid' let g:ale_packer_fmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The packer fmt callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' fmt -', \ }, \ ale#fixers#packer#Fix(bufnr('')) Execute(The packer fmt callback should include custom options): let g:ale_packer_fmt_options = "-list=true" AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' fmt' \ . ' ' . g:ale_packer_fmt_options \ . ' -', \ }, \ ale#fixers#packer#Fix(bufnr('')) ================================================ FILE: test/fixers/test_pandoc_fixer_callback.vader ================================================ Before: Save g:ale_markdown_pandoc_executable Save g:ale_markdown_pandoc_options After: Restore Execute(The pandoc callback should return 'pandoc' as default command): setlocal noexpandtab Assert \ ale#fixers#pandoc#Fix(bufnr('')).command =~# '^' . ale#Escape('pandoc'), \ "Default command name is expected to be 'pandoc'" Execute(The pandoc executable and options should be configurable): let g:ale_markdown_pandoc_executable = 'foobar' let g:ale_markdown_pandoc_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape('foobar') \ . ' --some-option', \ }, \ ale#fixers#pandoc#Fix(bufnr('')) ================================================ FILE: test/fixers/test_perltidy_fixer_callback.vader ================================================ Before: Save g:ale_perl_perltidy_executable Save g:ale_perl_perltidy_options " Use an invalid global executable, so we don't match it. let g:ale_perl_perltidy_executable = 'xxxinvalid' let g:ale_perl_perltidy_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The perltidy callback should return the correct default values): call ale#test#SetFilename('../pl_files/testfile.pl') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -b' \ . ' %t', \ }, \ ale#fixers#perltidy#Fix(bufnr('')) Execute(The perltidy callback should include custom perltidy options): let g:ale_perl_perltidy_options = "-r '(a) -> a'" call ale#test#SetFilename('../pl_files/testfile.pl') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' -b' \ . ' ' . g:ale_perl_perltidy_options \ . ' %t', \ }, \ ale#fixers#perltidy#Fix(bufnr('')) ================================================ FILE: test/fixers/test_pgformatter_fixer_callback.vader ================================================ Before: Save g:ale_sql_pgformatter_executable Save g:ale_sql_pgformatter_options After: Restore Execute(The pgFormatter callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('pg_format') \ }, \ ale#fixers#pgformatter#Fix(bufnr('')) Execute(The pgFormatter executable and options should be configurable): let g:ale_sql_pgformatter_executable = '/path/to/pg_format' let g:ale_sql_pgformatter_options = '-n' AssertEqual \ { \ 'command': ale#Escape('/path/to/pg_format') \ . ' -n', \ }, \ ale#fixers#pgformatter#Fix(bufnr('')) ================================================ FILE: test/fixers/test_php_cs_fixer.vader ================================================ Before: Save g:ale_php_cs_fixer_executable Save g:ale_php_cs_fixer_options Save g:ale_php_cs_fixer_fix_options let g:ale_php_cs_fixer_executable = 'php-cs-fixer' let g:ale_php_cs_fixer_options = '' let g:ale_php_cs_fixer_fix_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(project with php-cs-fixer should use local by default): call ale#test#SetFilename('../test-files/php/project-with-php-cs-fixer/test.php') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/php/project-with-php-cs-fixer/vendor/bin/php-cs-fixer'), \ ale#fixers#php_cs_fixer#GetExecutable(bufnr('')) Execute(use-global should override local detection): let g:ale_php_cs_fixer_use_global = 1 call ale#test#SetFilename('../test-files/php/project-with-php-cs-fixer/test.php') AssertEqual \ 'php-cs-fixer', \ ale#fixers#php_cs_fixer#GetExecutable(bufnr('')) Execute(project without php-cs-fixer should use global): call ale#test#SetFilename('../test-files/php/project-without-php-cs-fixer/test.php') AssertEqual \ 'php-cs-fixer', \ ale#fixers#php_cs_fixer#GetExecutable(bufnr('')) Execute(The php-cs-fixer callback should return the correct default values): call ale#test#SetFilename('../test-files/php/project-without-php-cs-fixer/foo/test.php') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('php-cs-fixer') \ . ' ' . g:ale_php_cs_fixer_options \ . ' fix ' . g:ale_php_cs_fixer_fix_options \ . ' %t' \ }, \ ale#fixers#php_cs_fixer#Fix(bufnr('')) Execute(The php-cs-fixer callback should include custom php-cs-fixer options): let g:ale_php_cs_fixer_options = '-nq' let g:ale_php_cs_fixer_fix_options = '--config="$HOME/.php_cs"' call ale#test#SetFilename('../test-files/php/project-without-php-cs-fixer/test.php') AssertEqual \ { \ 'command': ale#Escape(g:ale_php_cs_fixer_executable) \ . ' -nq fix --config="$HOME/.php_cs" %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#php_cs_fixer#Fix(bufnr('')) ================================================ FILE: test/fixers/test_phpcbf_fixer_callback.vader ================================================ Before: Save g:ale_php_phpcbf_executable Save g:ale_php_phpcbf_standard Save g:ale_php_phpcbf_use_global let g:ale_php_phpcbf_executable = 'phpcbf_test' let g:ale_php_phpcbf_standard = '' let g:ale_php_phpcbf_options = '' let g:ale_php_phpcbf_use_global = 0 call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(project with phpcbf should use local by default): call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf'), \ ale#fixers#phpcbf#GetExecutable(bufnr('')) Execute(use-global should override local detection): let g:ale_php_phpcbf_use_global = 1 call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ 'phpcbf_test', \ ale#fixers#phpcbf#GetExecutable(bufnr('')) Execute(project without phpcbf should use global): call ale#test#SetFilename('../test-files/php/project-without-phpcbf/foo/test.php') AssertEqual \ 'phpcbf_test', \ ale#fixers#phpcbf#GetExecutable(bufnr('')) Execute(The phpcbf callback should return the correct default values): call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s -' }, \ ale#fixers#phpcbf#Fix(bufnr('')) Execute(The phpcbf callback should include the phpcbf_standard option): let g:ale_php_phpcbf_standard = 'phpcbf_ruleset.xml' call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . '--standard=phpcbf_ruleset.xml' . ' -'}, \ ale#fixers#phpcbf#Fix(bufnr('')) Execute(User provided options should be used): let g:ale_php_phpcbf_options = '--my-user-provided-option my-value' call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . ale#Pad('--my-user-provided-option my-value') . ' -'}, \ ale#fixers#phpcbf#Fix(bufnr('')) Before: Save g:ale_php_phpcbf_executable Save g:ale_php_phpcbf_standard Save g:ale_php_phpcbf_use_global let g:ale_php_phpcbf_executable = 'phpcbf_test' let g:ale_php_phpcbf_standard = '' let g:ale_php_phpcbf_options = '' let g:ale_php_phpcbf_use_global = 0 call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(project with phpcbf should use local by default): call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf'), \ ale#fixers#phpcbf#GetExecutable(bufnr('')) Execute(use-global should override local detection): let g:ale_php_phpcbf_use_global = 1 call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ 'phpcbf_test', \ ale#fixers#phpcbf#GetExecutable(bufnr('')) Execute(project without phpcbf should use global): call ale#test#SetFilename('../test-files/php/project-without-phpcbf/foo/test.php') AssertEqual \ 'phpcbf_test', \ ale#fixers#phpcbf#GetExecutable(bufnr('')) Execute(The phpcbf callback should return the correct default values): call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s -' }, \ ale#fixers#phpcbf#Fix(bufnr('')) Execute(The phpcbf callback should include the phpcbf_standard option): let g:ale_php_phpcbf_standard = 'phpcbf_ruleset.xml' call ale#test#SetFilename('../test-files/php/project-with-phpcbf/foo/test.php') AssertEqual \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/php/project-with-phpcbf/vendor/bin/phpcbf')) . ' --stdin-path=%s ' . '--standard=phpcbf_ruleset.xml' . ' -'}, \ ale#fixers#phpcbf#Fix(bufnr('')) ================================================ FILE: test/fixers/test_pint_fixer.vader ================================================ Before: Save g:ale_php_pint_executable Save g:ale_php_pint_options let g:ale_php_pint_executable = 'pint' let g:ale_php_pint_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(project with pint should use local by default): call ale#test#SetFilename('../test-files/php/project-with-pint/test.php') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/php/project-with-pint/vendor/bin/pint'), \ ale#fixers#pint#GetExecutable(bufnr('')) Execute(use-global should override local detection): let g:ale_php_pint_use_global = 1 call ale#test#SetFilename('../test-files/php/project-with-pint/test.php') AssertEqual \ 'pint', \ ale#fixers#pint#GetExecutable(bufnr('')) Execute(project without pint should use global): call ale#test#SetFilename('../test-files/php/project-without-pint/test.php') AssertEqual \ 'pint', \ ale#fixers#pint#GetExecutable(bufnr('')) Execute(The pint callback should return the correct default values): call ale#test#SetFilename('../test-files/php/project-without-pint/foo/test.php') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('pint') \ . ' ' . g:ale_php_pint_options \ . ' %t' \ }, \ ale#fixers#pint#Fix(bufnr('')) Execute(The pint callback should include custom pint options): let g:ale_php_pint_options = '--test' call ale#test#SetFilename('../test-files/php/project-without-pint/test.php') AssertEqual \ { \ 'command': ale#Escape(g:ale_php_pint_executable) \ . ' --test %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_prettier_eslint_fixer.callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('javascript', 'prettier_eslint') Save g:ale_command_wrapper let g:ale_command_wrapper = '' After: call ale#assert#TearDownFixerTest() Execute(The default command should be correct): AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --write' \ } Execute(Additional options should be used when set): let b:ale_javascript_prettier_eslint_options = '--foobar' AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --foobar --write' \ } Execute(--eslint-config-path should be set for 4.2.0 and up): call ale#test#SetFilename('../test-files/eslint/react-app/foo/bar.js') GivenCommandOutput ['4.2.0'] AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --eslint-config-path ' . ale#Escape(ale#test#GetFilename('../test-files/eslint/react-app/.eslintrc.js')) \ . ' --write' \ } Execute(--eslint-config-path shouldn't be used for older versions): call ale#test#SetFilename('../test-files/eslint/react-app/foo/bar.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --write' \ } Execute(The version check should be correct): AssertFixer [ \ ale#Escape('prettier-eslint') . ' --version', \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --write' \ } \] Execute(The new --stdin-filepath option should be used when the version is new enough): call ale#test#SetFilename('../test-files/eslint/react-app/foo/bar.js') GivenCommandOutput ['4.4.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('prettier-eslint') \ . ' --eslint-config-path ' . ale#Escape(ale#test#GetFilename('../test-files/eslint/react-app/.eslintrc.js')) \ . ' --stdin-filepath %s --stdin', \ } Execute(The version number should be cached): GivenCommandOutput ['4.4.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('prettier-eslint') \ . ' --stdin-filepath %s --stdin', \ } GivenCommandOutput [] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('prettier-eslint') \ . ' --stdin-filepath %s --stdin', \ } ================================================ FILE: test/fixers/test_prettier_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('javascript', 'prettier') Save g:ale_command_wrapper let g:ale_command_wrapper = '' After: call ale#assert#TearDownFixerTest() Execute(The prettier callback should return the correct default values): call ale#test#SetFilename('../test-files/prettier/testfile.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' %t' \ . ' --write', \ } Execute(The --config option should not be set automatically): let g:ale_javascript_prettier_use_local_config = 1 call ale#test#SetFilename('../test-files/prettier/with_config/testfile.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' %t' \ . ' --write', \ } Execute(The prettier callback should include custom prettier options): let g:ale_javascript_prettier_options = '--no-semi' call ale#test#SetFilename('../test-files/prettier/with_config/testfile.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' %t' \ . ' --no-semi' \ . ' --write', \ } Execute(The version check should be correct): call ale#test#SetFilename('../test-files/prettier/testfile.js') AssertFixer [ \ ale#Escape('prettier') . ' --version', \ {'read_temporary_file': 1, 'command': ale#Escape('prettier') . ' %t --write'} \] Execute(--stdin-filepath should be used when prettier is new enough): let g:ale_javascript_prettier_options = '--no-semi' call ale#test#SetFilename('../test-files/prettier/with_config/testfile.js') GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --no-semi' \ . ' --stdin-filepath %s --stdin', \ } Execute(The version number should be cached): call ale#test#SetFilename('../test-files/prettier/with_config/testfile.js') GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --stdin-filepath %s --stdin', \ } GivenCommandOutput [] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser to `babylon` by default, < 1.16.0): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=javascript GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser babylon' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser to `babel` by default, >= 1.16.0): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=javascript GivenCommandOutput ['1.16.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser babel' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, TypeScript): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=typescript GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser typescript' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, CSS): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=css GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser css' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, LESS): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=less GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser less' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, SCSS): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=scss GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser scss' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, JSON): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=json GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser json' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, JSON5): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=json5 GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser json5' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, GraphQL): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=graphql GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser graphql' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, Markdown): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=markdown GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser markdown' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, Vue): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=vue GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser vue' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, YAML): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=yaml GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser yaml' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, HTML): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=html GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser html' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on filetype, Ruby): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=ruby GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser ruby' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on first filetype of multiple filetypes): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=css.scss GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser css' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser based on first filetype of multiple filetypes): call ale#test#SetFilename('../test-files/prettier/testfile') set filetype=astro GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser astro' \ . ' --stdin-filepath %s --stdin', \ } Execute(Should set --parser for experimental language, Handlebars): call ale#test#SetFilename('../test-files/prettier/testfile.hbs') set filetype=html.handlebars GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser glimmer' \ . ' --stdin-filepath %s --stdin', \ } Execute(Changes to directory where .prettierignore is found): call ale#test#SetFilename('../test-files/prettier/with_prettierignore/src/testfile.js') GivenCommandOutput ['1.6.0'] AssertFixer \ { \ 'cwd': expand('%:p:h:h'), \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' --stdin-filepath %s --stdin', \ } 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)', \ ]) ================================================ FILE: test/fixers/test_prettier_standard_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('javascript', 'prettier_standard') After: call ale#assert#TearDownFixerTest() Execute(The prettier callback should return the correct default values): call ale#test#SetFilename('../test-files/prettier/testfile.js') AssertFixer \ { \ 'command': ale#Escape(g:ale_javascript_prettier_standard_executable) \ . ' --stdin' \ . ' --stdin-filepath=%s ', \ } ================================================ FILE: test/fixers/test_protolint_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('proto', 'protolint') call ale#test#SetFilename('test.proto') After: call ale#assert#TearDownFixerTest() Execute(The default command should be correct): AssertFixer \ { \ 'command': ale#Escape('protolint') \ . ' -fix' \ . ' %t', \ 'read_temporary_file': 1, \ } Execute(The callback should include any additional options): let b:ale_proto_protolint_executable = '/tmp/protolint' let b:ale_proto_protolint_config = '/tmp/protolint.yaml' AssertFixer \ { \ 'command': ale#Escape('/tmp/protolint') \ . ' -config_path=' . ale#Escape('/tmp/protolint.yaml') \ . ' -fix' \ . ' %t', \ 'read_temporary_file': 1, \ } ================================================ FILE: test/fixers/test_ptop_fixer_callback.vader ================================================ Before: Save g:ale_pascal_ptop_executable Save g:ale_pascal_ptop_options " Use an invalid global executable, so we don't match it. let g:ale_pascal_ptop_executable = 'xxxinvalid' let g:ale_pascal_ptop_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The ptop callback should return the correct default values): call ale#test#SetFilename('../test-files/pascal/test.pas') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' %s %t', \ }, \ ale#fixers#ptop#Fix(bufnr('')) Execute(The ptop callback should include custom ptop options): let g:ale_pascal_ptop_options = "-i 2" call ale#test#SetFilename('../test-files/pascal/test.pas') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_pascal_ptop_options \ . ' %s %t', \ }, \ ale#fixers#ptop#Fix(bufnr('')) ================================================ FILE: test/fixers/test_puppetlint_fixer_callback.vader ================================================ Before: Save g:ale_puppet_puppetlint_executable Save g:ale_puppet_puppetlint_options " Use an invalid global executable, so we don't match it. let g:ale_puppet_puppetlint_executable = 'xxxinvalid' let g:ale_puppet_puppetlint_options = '--invalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The puppetlint callback should return the correct default values): silent execute 'file ' . fnameescape(g:dir . '/../test-files/puppet/dummy.pp') AssertEqual \ {'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_puppet_puppetlint_executable) \ . ' ' . g:ale_puppet_puppetlint_options \ . ' --fix %t' }, \ ale#fixers#puppetlint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_purs_tidy_fixer_callback.vader ================================================ Before: Save g:ale_purescript_tidy_executable Save g:ale_purescript_tidy_options " Use an invalid global executable, so we don’t match it. let g:ale_purescript_tidy_executable = 'odd-purs-tidy' let g:ale_purescript_tidy_options = '--indent 3' call ale#assert#SetUpFixerTest('purescript', 'purs-tidy') After: call ale#assert#TearDownFixerTest() Execute(The purs-tidy callback should return the correct custom options): AssertFixer \ { \ 'command': ale#Escape('odd-purs-tidy') \ . ' format' \ . ' --indent 3' \ } ================================================ FILE: test/fixers/test_purty_fixer_callback.vader ================================================ Before: Save g:ale_purescript_purty_executable " Use an invalid global executable, so we don't match it. let g:ale_purescript_purty_executable = 'my-special-purty' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The purty callback should return the correct options): call ale#test#SetFilename('../purescript_files/testfile.purs') AssertEqual \ { \ 'command': ale#Escape('my-special-purty') \ . ' --write' \ . ' %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#purty#Fix(bufnr('')) ================================================ FILE: test/fixers/test_pycln_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'pycln') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:cmd_tail = ' --silence' After: call ale#assert#TearDownFixerTest() unlet! g:dir unlet! b:bin_dir Execute(The pycln callback should return the correct default values): let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pycln')) . b:cmd_tail . ' -', \ } Execute(The pycln callback should not use stdin for older versions (< 1.3.0)): let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) GivenCommandOutput ['pycln, version 1.2.99'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pycln')) . b:cmd_tail . ' %s', \ } Execute(The pycln callback should not change directory if the option is set to 0): let g:ale_python_pycln_change_directory = 0 let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pycln')) . b:cmd_tail . ' -', \ } Execute(The pycln callback should respect custom options): let g:ale_python_pycln_options = '--expand-stars --no-gitignore' let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pycln')) \ . ' --expand-stars --no-gitignore' . b:cmd_tail . ' -', \ } Execute(Pipenv is detected when python_pycln_auto_pipenv is set): let g:ale_python_pycln_auto_pipenv = 1 let g:ale_python_pycln_change_directory = 0 let file_path = '../test-files/python/pipenv/whatever.py' call ale#test#SetFilename(file_path) GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pipenv') . ' run pycln' . b:cmd_tail . ' -' \ } Execute(Poetry is detected when python_pycln_auto_poetry is set): let g:ale_python_pycln_auto_poetry = 1 let g:ale_python_pycln_change_directory = 0 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('poetry') . ' run pycln' . b:cmd_tail . ' -' \ } Execute(Poetry is detected when python_pycln_auto_poetry is set, and cwd respects change_directory option): let g:ale_python_pycln_auto_poetry = 1 let g:ale_python_pycln_change_directory = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/poetry'), \ 'command': ale#Escape('poetry') . ' run pycln' . b:cmd_tail . ' -' \ } Execute(uv is detected when python_pycln_auto_uv is set): let g:ale_python_pycln_auto_uv = 1 let g:ale_python_pycln_change_directory = 0 call ale#test#SetFilename('../test-files/python/uv/whatever.py') GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('uv') . ' run pycln' . b:cmd_tail . ' -' \ } Execute(configuration files set in _config should be supported): let g:ale_python_pycln_change_directory = 0 let g:ale_python_pycln_config_file = ale#path#Simplify(g:dir . '/../test-files/pycln/other_config.xml') GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pycln') \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/pycln/other_config.xml')) \ . b:cmd_tail . ' -' \ } Execute(configuration file set in _options overrides _config): let g:ale_python_pycln_change_directory = 0 let g:ale_python_pycln_config_file = '/foo.xml' let g:ale_python_pycln_options = '--config /bar.xml' GivenCommandOutput ['pycln, version 1.3.0'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pycln') . ' --config /bar.xml' . b:cmd_tail . ' -' \ } let b:ale_python_pycln_options = '-x --config /bar.xml' AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pycln') . ' -x --config /bar.xml' . b:cmd_tail . ' -' \ } ================================================ FILE: test/fixers/test_pyflyby_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'pyflyby') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: call ale#assert#TearDownFixerTest() unlet! b:bin_dir Execute(The pyflyby callback should return the correct default values): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertFixer \ { \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/tidy-imports')), \ } Execute(Pipenv is detected when python_pyflyby_auto_pipenv is set): let g:ale_python_pyflyby_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertFixer \ { \ 'command': ale#Escape('pipenv') . ' run tidy-imports' \ } Execute(Poetry is detected when python_pyflyby_auto_poetry is set): let g:ale_python_pyflyby_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'command': ale#Escape('poetry') . ' run tidy-imports' \ } Execute(uv is detected when python_pyflyby_auto_uv is set): let g:ale_python_pyflyby_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') GivenCommandOutput ['VERSION 5.7.0'] AssertFixer \ { \ 'command': ale#Escape('uv') . ' run tidy-imports' \ } ================================================ FILE: test/fixers/test_pymarkdown_fixer_callback.vader ================================================ Before: Save g:ale_markdown_pymarkdown_executable Save g:ale_markdown_pymarkdown_options Save g:ale_markdown_pymarkdown_auto_pipenv Save g:ale_markdown_pymarkdown_auto_poetry Save g:ale_markdown_pymarkdown_auto_uv After: Restore Execute(The pymarkdown callback should return 'pymarkdown' as default command): AssertEqual \ { \ 'command': ale#Escape('pymarkdown') . ' fix %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) Execute(The pymarkdown executable and options should be configurable): let g:ale_markdown_pymarkdown_executable = 'foobar' let g:ale_markdown_pymarkdown_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape('foobar') . ' fix --some-option %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) Execute(Setting executable to 'pipenv' appends 'run pymarkdown'): let g:ale_markdown_pymarkdown_executable = 'path/to/pipenv' AssertEqual \ { \ 'command': ale#Escape('path/to/pipenv') . ' run pymarkdown fix %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) Execute(Pipenv is detected when markdown_pymarkdown_auto_pipenv is set): let g:ale_markdown_pymarkdown_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('pipenv') . ' run pymarkdown fix %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) Execute(Setting executable to 'poetry' appends 'run pymarkdown'): let g:ale_markdown_pymarkdown_executable = 'path/to/poetry' AssertEqual \ { \ 'command': ale#Escape('path/to/poetry') . ' run pymarkdown fix %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) Execute(Poetry is detected when markdown_pymarkdown_auto_poetry is set): let g:ale_markdown_pymarkdown_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertEqual \ { \ 'command': ale#Escape('poetry') . ' run pymarkdown fix %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) Execute(uv is detected when markdown_pymarkdown_auto_uv is set): let g:ale_markdown_pymarkdown_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('uv') . ' run pymarkdown fix %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#pymarkdown#Fix(bufnr('')) ================================================ FILE: test/fixers/test_python_add_blank_lines_fixer.vader ================================================ Before: Save g:ale_fixers After: Restore 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: pass for l in x: pass break continue elif x: pass while x: pass while x: pass else: pass if x: pass elif x: pass else: pass Execute(Blank lines should be added appropriately): let g:ale_fixers = {'python': ['add_blank_lines_for_python_control_statements']} ALEFix 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 for l in x: pass for l in x: pass break continue elif x: pass while x: pass while x: pass else: pass if x: pass elif x: pass else: pass Given python(A file with a main block): import os def main(): print('hello') if __name__ == '__main__': main() Execute(Fix the file): let g:ale_fixers = {'python': ['add_blank_lines_for_python_control_statements']} ALEFix Expect python(extra newlines shouldn't be added to the main block): import os def main(): print('hello') 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 ================================================ FILE: test/fixers/test_qmlfmt_fixer_callback.vader ================================================ Before: Save g:ale_qml_qmlfmt_executable After: Restore Execute(The qmlfmt fixer should use the options you set): let g:ale_qml_qmlfmt_executable = 'foo-exe' AssertEqual \ {'command': ale#Escape('foo-exe')}, \ ale#fixers#qmlfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_raco_fmt_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('racket', 'raco_fmt') After: call ale#assert#TearDownFixerTest() Execute(The raco_fmt callback should return the correct default values): call ale#test#SetFilename('../test-files/racket/simple-script/foo.rkt') AssertFixer {'command': ale#Escape('raco') . ' fmt'} Execute(The raco_fmt callback should include custom raco_fmt options): let g:ale_racket_raco_fmt_options = "--width 100" call ale#test#SetFilename('../test-files/racket/simple-script/foo.rkt') AssertFixer {'command': ale#Escape('raco') . ' fmt ' . g:ale_racket_raco_fmt_options} ================================================ FILE: test/fixers/test_refmt_fixer_callback.vader ================================================ Before: Save g:ale_reasonml_refmt_executable Save g:ale_reasonml_refmt_options " Use an invalid global executable, so we don't match it. let g:ale_reasonml_refmt_executable = 'xxxinvalid' let g:ale_reasonml_refmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The refmt callback should return the correct default values): call ale#test#SetFilename('../test-files/reasonml/testfile.re') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' --in-place' \ . ' %t', \ }, \ ale#fixers#refmt#Fix(bufnr('')) Execute(The refmt callback should include custom refmt options): let g:ale_reasonml_refmt_options = "-w 80" call ale#test#SetFilename('../test-files/reasonml/testfile.re') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_reasonml_refmt_options \ . ' --in-place' \ . ' %t', \ }, \ ale#fixers#refmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_remark_lint_fixer_callback.vader ================================================ Before: Save g:ale_markdown_remark_lint_executable Save g:ale_markdown_remark_lint_options After: Restore Execute(The remark callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('remark') \ }, \ ale#fixers#remark_lint#Fix(bufnr('')) Execute(The remark executable and options should be configurable): let g:ale_markdown_remark_lint_executable = '/path/to/remark' let g:ale_markdown_remark_lint_options = '-h' AssertEqual \ { \ 'command': ale#Escape('/path/to/remark') \ . ' -h', \ }, \ ale#fixers#remark_lint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_reorder_python_imports_fixer_callback.vader ================================================ Before: Save g:ale_python_reorder_python_imports_executable Save g:ale_python_reorder_python_imports_options " Use an invalid global executable, so we don't match it. let g:ale_python_reorder_python_imports_executable = 'xxxinvalid' let g:ale_python_reorder_python_imports_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: Restore unlet! b:bin_dir call ale#test#RestoreDirectory() Execute(The reorder_python_imports callback should return the correct default values): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ { \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' \ . b:bin_dir . '/reorder-python-imports')) . ' -', \ }, \ ale#fixers#reorder_python_imports#Fix(bufnr('')) Execute(The reorder_python_imports callback should respect custom options): let g:ale_python_reorder_python_imports_options = '--py3-plus' silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertEqual \ { \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' \ . b:bin_dir . '/reorder-python-imports')) . ' --py3-plus -', \ }, \ ale#fixers#reorder_python_imports#Fix(bufnr('')) Execute(pipenv is detected when python_reorder_python_imports_auto_pipenv is set): let g:ale_python_reorder_python_imports_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('pipenv') . ' run reorder-python-imports -', \ }, \ ale#fixers#reorder_python_imports#Fix(bufnr('')) Execute(Poetry is detected when python_reorder_python_imports_auto_poetry is set): let g:ale_python_reorder_python_imports_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertEqual \ { \ 'command': ale#Escape('poetry') . ' run reorder-python-imports -', \ }, \ ale#fixers#reorder_python_imports#Fix(bufnr('')) Execute(uv is detected when python_reorder_python_imports_auto_uv is set): let g:ale_python_reorder_python_imports_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('uv') . ' run reorder-python-imports -', \ }, \ ale#fixers#reorder_python_imports#Fix(bufnr('')) ================================================ FILE: test/fixers/test_rescript_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('rescript', 'rescript_format') After: call ale#assert#TearDownFixerTest() Execute(The rescript callback should return the correct default values): call ale#test#SetFilename('../test-files/rescript/testfile-noextension') set filetype=rescript GivenCommandOutput ['12.0.0'] AssertFixer \ { \ 'command': \ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .res' \ } Execute(The rescript callback should correctly detect res files): call ale#test#SetFilename('../test-files/rescript/testfile.res') GivenCommandOutput ['12.0.0'] AssertFixer \ { \ 'command': \ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .res' \ } Execute(The rescript callback should correctly detect resi files): call ale#test#SetFilename('../test-files/rescript/testfile.resi') GivenCommandOutput ['12.0.0'] AssertFixer \ { \ 'command': \ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .resi' \ } Execute(The version check should be correct): call ale#test#SetFilename('../test-files/rescript/testfile.res') GivenCommandOutput ['11.0.0'] AssertFixer \ { \ 'command': \ ale#Escape(g:ale_rescript_format_executable) . ' format -stdin .res' \ } ================================================ FILE: test/fixers/test_roc_annotate_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('roc', 'roc_annotate') After: call ale#assert#TearDownFixerTest() Execute(The roc annotate callback should return the correct default values): AssertFixer { \ 'command': 'roc format annotate %t', \ 'read_temporary_file': 1, \} Execute(The roc annotate callback should allow a custom executable): let g:ale_roc_roc_annotate_executable = 'foo/bar' AssertFixer { \ 'command': 'foo/bar format annotate %t', \ 'read_temporary_file': 1, \} ================================================ FILE: test/fixers/test_roc_format_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('roc', 'roc_format') After: call ale#assert#TearDownFixerTest() Execute(The roc format callback should return the correct default values): AssertFixer { \ 'command': 'roc format %t', \ 'read_temporary_file': 1, \} Execute(The roc format callback should allow a custom executable): let g:ale_roc_roc_format_executable = 'foo/bar' AssertFixer { \ 'command': 'foo/bar format %t', \ 'read_temporary_file': 1, \} ================================================ FILE: test/fixers/test_rubocop_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('ruby', 'rubocop') After: call ale#assert#TearDownFixerTest() Execute(The rubocop callback should return the correct default values): call ale#test#SetFilename('../test-files/ruby/dummy.rb') GivenCommandOutput ['1.61.0'] AssertFixer \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ . ' --auto-correct --editor-mode --force-exclusion --stdin %s', \ } Execute(The rubocop callback should include custom rubocop options): let g:ale_ruby_rubocop_options = '--except Lint/Debugger' call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') GivenCommandOutput ['1.61.0'] AssertFixer \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ . ' --except Lint/Debugger' \ . ' --auto-correct --editor-mode --force-exclusion --stdin %s', \ } Execute(The rubocop callback should use auto-correct-all option when set): let g:ale_ruby_rubocop_auto_correct_all = 1 call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') GivenCommandOutput ['1.61.0'] AssertFixer \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ . ' --auto-correct-all --editor-mode --force-exclusion --stdin %s' \ } Execute(The rubocop post-processor should remove diagnostics content): AssertEqual \ [ \ 'class MyModel < ApplicationRecord', \ ' # rubocop:disable Rails/InverseOf', \ ' has_one :something', \ ' # rubocop:enable Rails/InverseOf', \ 'end', \ '', \ 'array = [1, 2, 3,', \ ' 4, 5, 6]', \ 'array = [''run'',', \ ' ''forrest'',', \ ' ''run'']', \ ], \ ale#fixers#rubocop#PostProcess(bufnr(''), [ \ 'Inspecting 1 file', \ 'C', \ '', \ 'Offenses:', \ 'app/models/my_model.rb:8:3: C: [Corrected] Layout/ArrayAlignment: ', \ '4, 5, 6]', \ '^', \ '', \ '1 file inspected, 3 offenses detected, 3 offenses corrected', \ '====================', \ 'class MyModel < ApplicationRecord', \ ' # rubocop:disable Rails/InverseOf', \ ' has_one :something', \ ' # rubocop:enable Rails/InverseOf', \ 'end', \ '', \ 'array = [1, 2, 3,', \ ' 4, 5, 6]', \ 'array = [''run'',', \ ' ''forrest'',', \ ' ''run'']', \ ]) Execute(The rubocop callback should not use editor-mode option with older versions): call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') GivenCommandOutput ['1.59.0'] AssertFixer \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ . ' --auto-correct --force-exclusion --stdin %s' \ } ================================================ FILE: test/fixers/test_rubyfmt_fixer_callback.vader ================================================ Before: Save g:ale_ruby_rubyfmt_executable Save g:ale_ruby_rubyfmt_options Save &l:expandtab Save &l:shiftwidth Save &l:tabstop After: Restore Execute(The rubyfmt callback should return 'rubyfmt' as default command): setlocal noexpandtab Assert \ ale#fixers#rubyfmt#Fix(bufnr('')).command =~# '^' . ale#Escape('rubyfmt'), \ "Default command name is expected to be 'rubyfmt'" Execute(The ruby executable and options should be configurable): let g:ale_ruby_rubyfmt_executable = 'foobar' let g:ale_ruby_rubyfmt_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape('foobar') \ . ' --some-option', \ }, \ ale#fixers#rubyfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_ruff_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'ruff') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: call ale#assert#TearDownFixerTest() unlet! g:dir unlet! b:bin_dir Execute(The ruff callback should return the correct default values): let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) " --fix does not support stdin until 0.0.72 GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' --stdin-filename ' . fname . ' --fix -', \ } Execute(The ruff callback should not use stdin for older versions (< 0.0.72)): let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) " --fix does not support stdin until 0.0.72 GivenCommandOutput ['ruff 0.0.71'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' --stdin-filename ' . fname . ' --fix %s', \ } Execute(The ruff callback should not change directory if the option is set to 0): let g:ale_python_ruff_change_directory = 0 let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) " --fix does not support stdin until 0.0.72 GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' --stdin-filename ' . fname . ' --fix -', \ } Execute(The ruff callback should respect custom options): let g:ale_python_ruff_options = '--ignore F401 -q' let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) \ . ' --ignore F401 -q --stdin-filename '. fname . ' --fix -', \ } Execute(The ruff callback should use ruff check for 0.5.0): let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) GivenCommandOutput ['ruff 0.5.0'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' check --stdin-filename ' . fname . ' --fix -', \ } Execute(Pipenv is detected when python_ruff_auto_pipenv is set): let g:ale_python_ruff_auto_pipenv = 1 let g:ale_python_ruff_change_directory = 0 let file_path = '../test-files/python/pipenv/whatever.py' call ale#test#SetFilename(file_path) let fname = ale#Escape(ale#path#Simplify(g:dir . '/'. file_path)) GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pipenv') . ' run ruff --stdin-filename ' . fname . ' --fix -' \ } Execute(Poetry is detected when python_ruff_auto_poetry is set): let g:ale_python_ruff_auto_poetry = 1 let g:ale_python_ruff_change_directory = 0 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('poetry') . ' run ruff --stdin-filename ' . fname . ' --fix -' \ } Execute(Poetry is detected when python_ruff_auto_poetry is set, and cwd respects change_directory option): let g:ale_python_ruff_auto_poetry = 1 let g:ale_python_ruff_change_directory = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/poetry'), \ 'command': ale#Escape('poetry') . ' run ruff --stdin-filename ' . fname . ' --fix -' \ } Execute(uv is detected when python_ruff_auto_uv is set): let g:ale_python_ruff_auto_uv = 1 let g:ale_python_ruff_change_directory = 0 call ale#test#SetFilename('../test-files/python/uv/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/uv/whatever.py')) GivenCommandOutput ['ruff 0.0.72'] AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('uv') . ' run ruff --stdin-filename ' . fname . ' --fix -' \ } ================================================ FILE: test/fixers/test_ruff_format_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'ruff_format') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: call ale#assert#TearDownFixerTest() unlet! g:dir unlet! b:bin_dir Execute(The ruff callback should not change directory if the option is set to 0): let g:ale_python_ruff_format_change_directory = 0 let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) . ' format --stdin-filename ' . fname . ' -', \ } Execute(The ruff callback should respect custom options): let g:ale_python_ruff_format_options = '--ignore F401 -q' let file_path = g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.py' silent execute 'file ' . fnameescape(file_path) let fname = ale#Escape(ale#path#Simplify(file_path)) AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir'), \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff')) \ . ' format --ignore F401 -q --stdin-filename '. fname . ' -', \ } Execute(Pipenv is detected when python_ruff_format_auto_pipenv is set): let g:ale_python_ruff_format_auto_pipenv = 1 let g:ale_python_ruff_format_change_directory = 0 let file_path = '../test-files/python/pipenv/whatever.py' call ale#test#SetFilename(file_path) let fname = ale#Escape(ale#path#Simplify(g:dir . '/'. file_path)) AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('pipenv') . ' run ruff format --stdin-filename ' . fname . ' -' \ } Execute(Poetry is detected when python_ruff_auto_poetry is set): let g:ale_python_ruff_format_auto_poetry = 1 let g:ale_python_ruff_format_change_directory = 0 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('poetry') . ' run ruff format --stdin-filename ' . fname . ' -' \ } Execute(Poetry is detected when python_ruff_format_auto_poetry is set, and cwd respects change_directory option): let g:ale_python_ruff_format_auto_poetry = 1 let g:ale_python_ruff_format_change_directory = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/poetry/whatever.py')) AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/python/poetry'), \ 'command': ale#Escape('poetry') . ' run ruff format --stdin-filename ' . fname . ' -' \ } Execute(uv is detected when python_ruff_format_auto_uv is set): let g:ale_python_ruff_format_auto_uv = 1 let g:ale_python_ruff_format_change_directory = 0 call ale#test#SetFilename('../test-files/python/uv/whatever.py') let fname = ale#Escape(ale#path#Simplify(g:dir .'/../test-files/python/uv/whatever.py')) AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('uv') . ' run ruff format --stdin-filename ' . fname . ' -' \ } ================================================ FILE: test/fixers/test_rufo_fixer_callback.vader ================================================ Before: Save g:ale_ruby_rufo_executable " Use an invalid global executable, so we don't match it. let g:ale_ruby_rufo_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The rufo command should contain `bundle exec` when executable is `bundle`): let g:ale_ruby_rufo_executable = 'bundle' call ale#test#SetFilename('../test-files/ruby/dummy.rb') AssertEqual \ ale#Escape('bundle') . ' exec rufo %t', \ ale#fixers#rufo#GetCommand(bufnr('')) Execute(The rufo callback should return the correct default values): call ale#test#SetFilename('../test-files/ruby/dummy.rb') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') . ' %t' \ }, \ ale#fixers#rufo#Fix(bufnr('')) ================================================ FILE: test/fixers/test_rustfmt_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('rust', 'rustfmt') After: call ale#assert#TearDownFixerTest() Execute(The rustfmt callback should return the correct default values): call ale#test#SetFilename('../test-files/rust/testfile.rs') AssertFixer {'command': ale#Escape('rustfmt')} Execute(The rustfmt callback should include custom rustfmt options): let g:ale_rust_rustfmt_options = "--skip-children" call ale#test#SetFilename('../test-files/rust/testfile.rs') AssertFixer {'command': ale#Escape('rustfmt') . ' ' . g:ale_rust_rustfmt_options} ================================================ FILE: test/fixers/test_rustywind_fixer_callback.vader ================================================ Before: Save g:ale_html_rustywind_executable Save g:ale_html_rustywind_options " Use an invalid global executable, so we don't match it. let g:ale_html_rustywind_executable = 'xxxinvalid' let g:ale_html_rustywind_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The rustywind callback should return the correct default values): call ale#test#SetFilename('../test-files/rustywind/test.html') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' --stdin', \ }, \ ale#fixers#rustywind#Fix(bufnr('')) Execute(The rustywind callback should include custom rustywind options): let g:ale_html_rustywind_options = "--custom-regex some-regex" call ale#test#SetFilename('../test-files/rustywind/test.html') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_html_rustywind_options \ . ' --stdin', \ }, \ ale#fixers#rustywind#Fix(bufnr('')) ================================================ FILE: test/fixers/test_scadformat_fixer.vader ================================================ Before: Save g:ale_openscad_scadformat_executable Save g:ale_openscad_scadformat_options let g:ale_openscad_scadformat_executable = 'xxx' let g:ale_openscad_scadformat_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(scadformat - defaults OK): call ale#test#SetFilename('../test-files/openscad/dummy.scad') AssertEqual \ { \ 'command': ale#Escape('xxx') \ }, \ ale#fixers#scadformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_scalafmt_fixer_callback.vader ================================================ Before: Save g:ale_scala_scalafmt_executable Save g:ale_scala_scalafmt_options " Use an invalid global executable, so we don't match it. let g:ale_scala_scalafmt_executable = 'xxxinvalid' let g:ale_scala_scalafmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The scalafmt callback should return the correct default values): call ale#test#SetFilename('../test-files/scala/dummy.scala') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_scala_scalafmt_executable) \ . ' %t', \ }, \ ale#fixers#scalafmt#Fix(bufnr('')) Execute(The scalafmt callback should use ng with scalafmt automatically): let g:ale_scala_scalafmt_executable = 'ng' call ale#test#SetFilename('../test-files/scala/dummy.scala') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('ng') \ . ' scalafmt' \ . ' %t', \ }, \ ale#fixers#scalafmt#Fix(bufnr('')) Execute(The scalafmt callback should include custom scalafmt options): let g:ale_scala_scalafmt_options = '--diff' call ale#test#SetFilename('../test-files/scala/dummy.scala') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_scala_scalafmt_executable) \ . ' --diff' \ . ' %t', \ }, \ ale#fixers#scalafmt#Fix(bufnr('')) Execute(The scalafmt callback should include custom scalafmt options and use ng with scalafmt): let g:ale_scala_scalafmt_options = '--diff' let g:ale_scala_scalafmt_executable = 'ng' call ale#test#SetFilename('../test-files/scala/dummy.scala') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('ng') \ . ' scalafmt' \ . ' --diff' \ . ' %t', \ }, \ ale#fixers#scalafmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_shfmt_fixer_callback.vader ================================================ 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 '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 executable and options should be configurable): let g:ale_sh_shfmt_executable = 'foobar' let g:ale_sh_shfmt_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape('foobar') \ . ' -filename=%s' \ . ' --some-option', \ }, \ ale#fixers#shfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_sorbet_fixer_callback.vader ================================================ Before: Save g:ale_ruby_sorbet_executable Save g:ale_ruby_sorbet_options " Use an invalid global executable, so we don't match it. let g:ale_ruby_sorbet_executable = 'xxxinvalid' let g:ale_ruby_sorbet_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The sorbet callback should return the correct default values): call ale#test#SetFilename('../test-files/ruby/dummy.rb') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_ruby_sorbet_executable) \ . ' tc --autocorrect --file %t', \ }, \ ale#fixers#sorbet#Fix(bufnr('')) Execute(The sorbet callback should include custom sorbet options): let g:ale_ruby_sorbet_options = '--enable-experimental-lsp-hover' call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_ruby_sorbet_executable) \ . ' tc --enable-experimental-lsp-hover' \ . ' --autocorrect --file %t', \ }, \ ale#fixers#sorbet#Fix(bufnr('')) ================================================ FILE: test/fixers/test_sqlfmt_fixer_callback.vader ================================================ 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('')) ================================================ FILE: test/fixers/test_sqlformat_fixer_callback.vader ================================================ Before: Save g:ale_sql_sqlformat_executable Save g:ale_sql_sqlformat_options After: Restore Execute(The sqlformat callback should return the correct default values): AssertEqual \ { \ 'command': ale#Escape('sqlformat') . ' -' \ }, \ ale#fixers#sqlformat#Fix(bufnr('')) Execute(The sqlformat executable and options should be configurable): let g:ale_sql_sqlformat_executable = '/path/to/sqlformat' let g:ale_sql_sqlformat_options = '-a' AssertEqual \ { \ 'command': ale#Escape('/path/to/sqlformat') \ . ' -a -' \ }, \ ale#fixers#sqlformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_standard_fixer_callback.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') unlet! b:ale_javascript_standard_executable unlet! b:ale_javascript_standard_options After: call ale#test#RestoreDirectory() Execute(The executable path should be correct): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.js') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/standard/bin/cmd.js')) \ . ' --fix --stdin < %s > %t', \ }, \ ale#fixers#standard#Fix(bufnr('')) Execute(Custom options should be supported): let b:ale_javascript_standard_use_global = 1 let b:ale_javascript_standard_options = '--foo-bar' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('standard') . ' --foo-bar --fix --stdin < %s > %t', \ }, \ ale#fixers#standard#Fix(bufnr('')) ================================================ FILE: test/fixers/test_standardrb_fixer_callback.vader ================================================ Before: Save g:ale_ruby_standardrb_executable Save g:ale_ruby_standardrb_options " Use an invalid global executable, so we don't match it. let g:ale_ruby_standardrb_executable = 'xxxinvalid' let g:ale_ruby_standardrb_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The standardrb callback should return the correct default values): call ale#test#SetFilename('../test-files/ruby/dummy.rb') AssertEqual \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_standardrb_executable) \ . ' --fix --force-exclusion --stdin %s', \ }, \ ale#fixers#standardrb#Fix(bufnr('')) Execute(The standardrb callback should include configuration files): call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') AssertEqual \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_standardrb_executable) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/ruby/with_config/.standard.yml')) \ . ' --fix --force-exclusion --stdin %s', \ }, \ ale#fixers#standardrb#Fix(bufnr('')) Execute(The standardrb callback should include custom rubocop options): let g:ale_ruby_standardrb_options = '--except Lint/Debugger' call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') AssertEqual \ { \ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'command': ale#Escape(g:ale_ruby_standardrb_executable) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/ruby/with_config/.standard.yml')) \ . ' --except Lint/Debugger' \ . ' --fix --force-exclusion --stdin %s', \ }, \ ale#fixers#standardrb#Fix(bufnr('')) ================================================ FILE: test/fixers/test_statix_fixer.vader ================================================ Before: call ale#assert#SetUpFixerTest('nix', 'statix') After: call ale#assert#TearDownFixerTest() Execute(The callback should return the correct default values): AssertFixer { 'command': ale#Escape('statix') . ' fix --stdin' } Execute(The callback should include a custom runtime): let g:ale_nix_statix_fix_executable = 'foo/bar' AssertFixer { 'command': ale#Escape('foo/bar') . ' fix --stdin' } Execute(The callback should include custom options): let g:ale_nix_statix_fix_options = '--foobar' AssertFixer { 'command': ale#Escape('statix') . ' fix --stdin --foobar' } ================================================ FILE: test/fixers/test_stylelint_fixer_callback.vader ================================================ Before: Save g:ale_stylelint_options let g:ale_stylelint_options = '' call ale#assert#SetUpFixerTest('css', 'stylelint') After: call ale#assert#TearDownFixerTest() Execute(The stylelint callback should return the correct default values): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.css') AssertFixer \ { \ 'read_temporary_file': 0, \ 'cwd': '%s:h', \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/stylelint/bin/stylelint.js')) \ . ' --fix --stdin --no-color --stdin-filename %s', \ } Execute(The stylelint callback should include custom stylelint options): let g:ale_stylelint_options = '--cache' call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.css') AssertFixer \ { \ 'read_temporary_file': 0, \ 'cwd': '%s:h', \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/stylelint/bin/stylelint.js')) \ . ' --cache --fix --stdin --no-color --stdin-filename %s', \ } ================================================ FILE: test/fixers/test_styler_fixer_callback.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The styler callback should include custom styler options): let g:ale_r_styler_options = "a_custom_option" AssertEqual \ { \ 'command': 'Rscript --vanilla -e ' \ . '"suppressPackageStartupMessages(library(styler));' \ . 'style_file(commandArgs(TRUE), transformers = ' \ . 'a_custom_option)"' \ . ' %t', \ 'read_temporary_file': 1, \ }, \ ale#fixers#styler#Fix(bufnr('')) ================================================ FILE: test/fixers/test_stylish_haskell_fixer_callback.vader ================================================ 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('')) ================================================ FILE: test/fixers/test_stylua_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('lua', 'stylua') After: call ale#assert#TearDownFixerTest() Execute(The default command should be correct): AssertFixer {'cwd': '%s:h', 'command': ale#Escape('stylua') . ' --stdin-filepath %s -'} Execute(The stylua callback should include custom stylua options): let g:ale_lua_stylua_executable = 'xxxinvalid' let g:ale_lua_stylua_options = '--search-parent-directories' AssertFixer \ { \ 'cwd': '%s:h', \ 'command': ale#Escape('xxxinvalid') \ . ' ' . g:ale_lua_stylua_options \ . ' --stdin-filepath %s -', \ } Execute(stylua should detect stylua.toml): call ale#test#SetFilename('../test-files/stylua/stylua_config_dir/subdir/test.lua') AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/stylua/stylua_config_dir'), \ 'command': ale#Escape('stylua') . ' --stdin-filepath %s -', \ } Execute(stylua should detect .stylua.toml): call ale#test#SetFilename('../test-files/stylua/stylua_dot_config_dir/subdir/test.lua') AssertFixer \ { \ 'cwd': ale#path#Simplify(g:dir . '/../test-files/stylua/stylua_dot_config_dir'), \ 'command': ale#Escape('stylua') . ' --stdin-filepath %s -', \ } ================================================ FILE: test/fixers/test_swiftformat_fixer_callback.vader ================================================ Before: Save g:ale_swift_swiftformat_executable " Use an invalid global executable, so we don't match it. let g:ale_swift_swiftformat_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The swiftformat callback should return the correct default values): call ale#test#SetFilename('../test-files/swift/dummy.swift') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_swift_swiftformat_executable) \ . ' %t ', \ }, \ ale#fixers#swiftformat#Fix(bufnr('')) Execute(The swiftformat callback should include any additional options): call ale#test#SetFilename('../test-files/swift/dummy.swift') let g:ale_swift_swiftformat_options = '--some-option' AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_swift_swiftformat_executable) \ . ' %t --some-option', \ }, \ ale#fixers#swiftformat#Fix(bufnr('')) ================================================ FILE: test/fixers/test_syntax_tree_fixer_callback.vader ================================================ Before: Save g:ale_ruby_syntax_tree_executable Save g:ale_ruby_syntax_tree_options " Use an invalid global executable, so we don't match it. let g:ale_ruby_syntax_tree_executable = 'xxxinvalid' let g:ale_ruby_syntax_tree_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The syntax_tree callback should return the correct default values): call ale#test#SetFilename('../test-files/ruby/dummy.rb') AssertEqual \ { \ 'command': ale#Escape(g:ale_ruby_syntax_tree_executable) \ . ' format %t', \ }, \ ale#fixers#syntax_tree#Fix(bufnr('')) Execute(The syntax_tree callback should include custom options): let g:ale_ruby_syntax_tree_options = '--print-width=100 --plugins=plugin/trailing_comma' call ale#test#SetFilename('../test-files/ruby/with_config/dummy.rb') AssertEqual \ { \ 'command': ale#Escape(g:ale_ruby_syntax_tree_executable) \ . ' format --print-width=100 --plugins=plugin/trailing_comma %t', \ }, \ ale#fixers#syntax_tree#Fix(bufnr('')) ================================================ FILE: test/fixers/test_terraform_fmt_fixer_callback.vader ================================================ 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('')) ================================================ FILE: test/fixers/test_textlint_fixer_callback.vader ================================================ Before: Save g:ale_textlint_executable Save g:ale_textlint_options Save g:ale_textlint_use_global " Use an invalid global executable, so we don't match it. let g:ale_textlint_executable = 'xxxinvalid' let g:ale_textlint_options = '' let g:ale_textlint_use_global = 0 call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The textlint callback should return the correct default values): call ale#test#SetFilename('../test-files/markdown/testfile.md') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' --fix' \ . ' %t', \ }, \ ale#fixers#textlint#Fix(bufnr('')) Execute(The textlint callback should include custom textlint options): let g:ale_textlint_options = "--quiet" call ale#test#SetFilename('../test-files/markdown/testfile.md') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') \ . ' --fix' \ . ' ' . g:ale_textlint_options \ . ' %t', \ }, \ ale#fixers#textlint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_tidy_fixer_callback.vader ================================================ Before: Save g:ale_html_tidy_executable let g:ale_html_tidy_executable = '../test-files/tidy/tidy' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The tidy callback should return 0 if tidy not found): let g:ale_html_tidy_executable = 'xxxinvalidpath' AssertEqual \ 0, \ ale#fixers#tidy#Fix(bufnr('')) Execute(The tidy callback should return the correct default command): AssertEqual \ { \ 'command': ale#Escape('../test-files/tidy/tidy') \ . ' -q --tidy-mark no --show-errors 0 --show-warnings 0' \ }, \ ale#fixers#tidy#Fix(bufnr('')) ================================================ FILE: test/fixers/test_tombi_format_fixer_callback.vader ================================================ Before: Save g:ale_toml_tombi_executable Save g:ale_toml_tombi_format_options Save g:ale_toml_tombi_online " Use an invalid global executable, so we don't match it. let g:ale_toml_tombi_executable = 'xxxinvalid' let g:ale_toml_tombi_format_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The tombi format callback should return the correct default values): AssertEqual \ {'command': ale#Escape('xxxinvalid') . ' format --offline'}, \ ale#fixers#tombi_format#Fix(bufnr('')) Execute(The tombi format callback should obey `toml_tombi_online`): let g:ale_toml_tombi_online = 1 AssertEqual \ {'command': ale#Escape('xxxinvalid') . ' lint'}, \ ale#fixers#tombi_lint#Fix(bufnr('')) Execute(The tombi format callback should include custom options): let g:ale_toml_tombi_format_options = "--no-cache" AssertEqual \ {'command': ale#Escape('xxxinvalid') . ' format --offline --no-cache'}, \ ale#fixers#tombi_format#Fix(bufnr('')) ================================================ FILE: test/fixers/test_tombi_lint_fixer_callback.vader ================================================ Before: Save g:ale_toml_tombi_executable Save g:ale_toml_tombi_lint_options Save g:ale_toml_tombi_online " Use an invalid global executable, so we don't match it. let g:ale_toml_tombi_executable = 'xxxinvalid' let g:ale_toml_tombi_lint_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The tombi lint callback should return the correct default values): AssertEqual \ {'command': ale#Escape('xxxinvalid') . ' lint --offline'}, \ ale#fixers#tombi_lint#Fix(bufnr('')) Execute(The tombi lint callback should obey `toml_tombi_online`): let g:ale_toml_tombi_online = 1 AssertEqual \ {'command': ale#Escape('xxxinvalid') . ' lint'}, \ ale#fixers#tombi_lint#Fix(bufnr('')) Execute(The tombi lint callback should include custom options): let g:ale_toml_tombi_lint_options = "--no-cache" AssertEqual \ {'command': ale#Escape('xxxinvalid') . ' lint --offline --no-cache'}, \ ale#fixers#tombi_lint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_trim_whitespace.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/fixers') After: call ale#test#RestoreDirectory() Execute(Should delete all whitespace at the end of different lines): AssertEqual \ [ \ 'def foo():', \ ' some_variable = this_is_a_longer_function(', \ 'first_argument,', \ ' second_argument,', \ ' third_with_function_call(', \ 'foo,', \ ' bar,', \ '))', \ ], \ ale#fixers#generic#TrimWhitespace(bufnr(''), [ \ 'def foo():', \ ' some_variable = this_is_a_longer_function(', \ 'first_argument,', \ ' second_argument,', \ ' third_with_function_call(', \ 'foo,', \ ' bar,', \ '))', \ ]) ================================================ FILE: test/fixers/test_tslint_fixer_callback.vader ================================================ Before: Save g:ale_typescript_tslint_executable Save g:ale_typescript_tslint_config_path unlet! g:ale_typescript_tslint_executable unlet! g:ale_typescript_tslint_config_path unlet! b:ale_typescript_tslint_executable unlet! b:ale_typescript_tslint_config_path call ale#handlers#tslint#InitVariables() call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The tslint callback should return the correct default values): let g:ale_typescript_tslint_config_path = 'tslint.json' call ale#test#SetFilename('../test-files/prettier/testfile.ts') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('tslint') \ . ' -c ' . ale#Escape('tslint.json') \ . ' --outputAbsolutePaths --fix %t', \ }, \ ale#fixers#tslint#Fix(bufnr('')) Execute(The tslint callback should include custom tslint config option): let g:ale_typescript_tslint_config_path = '.tslintrc' call ale#test#SetFilename('../test-files/prettier/testfile.ts') AssertEqual \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('tslint') \ . ' -c ' . ale#Escape('.tslintrc') \ . ' --outputAbsolutePaths --fix %t', \ }, \ ale#fixers#tslint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_typstyle_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('typst', 'typstyle', 'typstyle') After: Restore call ale#assert#TearDownFixerTest() Execute(The typstyle callback should return the correct default command): AssertEqual \ {'command': ale#Escape('typstyle') . ' '}, \ ale#fixers#typstyle#Fix(bufnr('')) Execute(The typstyle options should be considered): call ale#test#SetFilename('../test-files/typstyle/testfile.typ') let g:ale_typst_typstyle_options = '-c 100' AssertFixer \ { 'command': ale#Escape(g:ale_typst_typstyle_executable) \ . ' -c 100', \ } ================================================ FILE: test/fixers/test_uncrustify_fixer_callback.vader ================================================ 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') After: Restore call ale#test#RestoreDirectory() Execute(The clang-format callback should return the correct default values): call ale#test#SetFilename('../test-files/c/dummy.c') AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l C' \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) Execute(The uncrustify callback should include any additional options): call ale#test#SetFilename('../test-files/c/dummy.c') let b:ale_c_uncrustify_options = '--some-option' AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l C --some-option', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) Execute(The uncrustify callback should set proper language): unlet b:ale_c_uncrustify_options set filetype=c AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l C', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=cpp AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l CPP', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=cs AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l CS', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=objc AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l OC', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=objcpp AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l OC+', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=d AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l D', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=java AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l JAVA', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=vala AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l VALA', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) set filetype=p AssertEqual \ { \ 'command': ale#Escape(g:ale_c_uncrustify_executable) \ . ' --no-backup -l PAWN', \ }, \ ale#fixers#uncrustify#Fix(bufnr('')) ================================================ FILE: test/fixers/test_unimport_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('python', 'unimport') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: call ale#assert#TearDownFixerTest() unlet! b:bin_dir Execute(The unimport callback should return the correct default values): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertFixer \ { \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/unimport')), \ } Execute(Pipenv is detected when python_unimport_auto_pipenv is set): let g:ale_python_unimport_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertFixer \ { \ 'command': ale#Escape('pipenv') . ' run unimport' \ } Execute(Poetry is detected when python_unimport_auto_poetry is set): let g:ale_python_unimport_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertFixer \ { \ 'command': ale#Escape('poetry') . ' run unimport' \ } Execute(uv is detected when python_unimport_auto_uv is set): let g:ale_python_unimport_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertFixer \ { \ 'command': ale#Escape('uv') . ' run unimport' \ } ================================================ FILE: test/fixers/test_verible_format_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('verilog', 'verible_format') After: call ale#assert#TearDownFixerTest() Execute(The verible format callback should return the correct default values): AssertFixer {'command': ale#Escape('verible-verilog-format') .' -'} Execute(The verible format callback should allow a custom executable): let g:ale_verilog_verible_format_executable = 'foo/bar' AssertFixer {'command': ale#Escape('foo/bar') . ' -'} Execute(The verible format callback should allow custom options): let g:ale_verilog_verible_format_options = '--foo --bar' AssertFixer {'command': ale#Escape('verible-verilog-format') .' --foo --bar -'} ================================================ FILE: test/fixers/test_vfmt_fixer_callback.vader ================================================ Before: Save g:ale_v_v_executable Save g:ale_v_vfmt_options " Use an invalid global executable, so we don't match it. let g:ale_v_v_executable = 'xxxinvalid' let g:ale_v_vfmt_options = '' call ale#test#SetDirectory('/testplugin/test/fixers') After: Restore call ale#test#RestoreDirectory() Execute(The vfmt callback should return the correct default values): call ale#test#SetFilename('../v_files/testfile.v') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' fmt', \ }, \ ale#fixers#vfmt#Fix(bufnr('')) Execute(The vfmt callback should include custom vfmt options): let g:ale_v_vfmt_options = "-r '(a) -> a'" call ale#test#SetFilename('../v_files/testfile.v') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') \ . ' fmt ' . g:ale_v_vfmt_options, \ }, \ ale#fixers#vfmt#Fix(bufnr('')) Execute(The vfmt callback should support Go environment variables): call ale#test#SetFilename('../v_files/testfile.v') AssertEqual \ { \ 'command': ale#Escape('xxxinvalid') . ' fmt', \ }, \ ale#fixers#vfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_vim_help_tags_alignment_fixer.vader ================================================ Before: Save g:ale_fixers After: Restore Given help(A vim help file with badly aligned tags): foo *foo* bar *bar* baz *bar* Execute(Tags should be aligned at the right margin): let g:ale_fixers = {'help': ['align_help_tags']} ALEFix Expect help(Tags should be aligned): foo *foo* bar *bar* baz *bar* ================================================ FILE: test/fixers/test_xmllint_fixer_callback.vader ================================================ 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 with unpersisted buffer): new AssertEqual \ { \ 'command': ale#Escape('/path/to/xmllint') \ . ' --format -' \ }, \ ale#fixers#xmllint#Fix(bufnr('')) Execute(The xmllint callback should return the correct default command): call ale#test#SetFilename('../test-files/xml/dummy.xml') AssertEqual \ { \ 'command': ale#Escape('/path/to/xmllint') \ . ' --format -' \ }, \ ale#fixers#xmllint#Fix(bufnr('')) Execute(The xmllint callback should include the XMLLINT_INDENT variable): call ale#test#SetFilename('../test-files/xml/dummy.xml') let g:ale_xml_xmllint_indentsize = 2 AssertEqual \ { \ 'command': ale#Env('XMLLINT_INDENT', ' ') \ . ale#Escape('/path/to/xmllint') \ . ' --format -' \ }, \ ale#fixers#xmllint#Fix(bufnr('')) Execute(The xmllint callback should include additional options): call ale#test#SetFilename('../test-files/xml/dummy.xml') let g:ale_xml_xmllint_options = '--nonet --custom-opt 2' AssertEqual \ { \ 'command': ale#Escape('/path/to/xmllint') \ . ' --format --nonet --custom-opt 2 -' \ }, \ ale#fixers#xmllint#Fix(bufnr('')) ================================================ FILE: test/fixers/test_xo_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('javascript', 'xo') runtime autoload/ale/handlers/xo.vim set filetype=javascript After: call ale#assert#TearDownFixerTest() Execute(The xo callback should return the correct default values): call ale#test#SetFilename('../test-files/xo/monorepo/packages/a/index.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/xo/monorepo/node_modules/xo/cli.js')) \ . ' --fix %t', \ } Execute(The xo callback should include custom xo options): let g:ale_javascript_xo_options = '--space' call ale#test#SetFilename('../test-files/xo/monorepo/packages/a/index.js') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/xo/monorepo/node_modules/xo/cli.js')) \ . ' --fix %t' \ . ' --space', \ } Execute(--stdin should be used when xo is new enough): let g:ale_javascript_xo_options = '--space' call ale#test#SetFilename('../test-files/xo/monorepo/packages/a/index.js') GivenCommandOutput ['0.30.0'] AssertFixer \ { \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/xo/monorepo/node_modules/xo/cli.js')) \ . ' --stdin --stdin-filename %s' \ . ' --fix' \ . ' --space', \ } ================================================ FILE: test/fixers/test_xots_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('typescript', 'xo') runtime autoload/ale/handlers/xo.vim set filetype=typescript After: call ale#assert#TearDownFixerTest() Execute(The xo callback should return the correct default values): call ale#test#SetFilename('../test-files/xo/monorepo/packages/a/index.ts') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/xo/monorepo/node_modules/xo/cli.js')) \ . ' --fix %t', \ } Execute(The xo callback should include custom xo options): let g:ale_typescript_xo_options = '--space' call ale#test#SetFilename('../test-files/xo/monorepo/packages/a/index.ts') AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/xo/monorepo/node_modules/xo/cli.js')) \ . ' --fix %t' \ . ' --space', \ } Execute(--stdin should be used when xo is new enough): let g:ale_typescript_xo_options = '--space' call ale#test#SetFilename('../test-files/xo/monorepo/packages/a/index.ts') GivenCommandOutput ['0.30.0'] AssertFixer \ { \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/xo/monorepo/node_modules/xo/cli.js')) \ . ' --stdin --stdin-filename %s' \ . ' --fix' \ . ' --space', \ } ================================================ FILE: test/fixers/test_yamlfix_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('yaml', 'yamlfix') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir call ale#assert#TearDownFixerTest() Execute(The yamlfix callback should return the correct default values): AssertEqual \ 0, \ ale#fixers#yamlfix#Fix(bufnr('')) silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.yaml') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/yamlfix')) . ' -', \ }, \ ale#fixers#yamlfix#Fix(bufnr('')) Execute(The yamlfix callback should respect custom options): let g:ale_yaml_yamlfix_options = '--multi-line=3 --trailing-comma' silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_virtualenv/subdir/foo/bar.yaml') AssertEqual \ { \ 'cwd': '%s:h', \ 'command': ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/yamlfix')) \ . ' --multi-line=3 --trailing-comma -', \ }, \ ale#fixers#yamlfix#Fix(bufnr('')) ================================================ FILE: test/fixers/test_yamlfmt_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('yaml', 'yamlfmt') After: Restore call ale#assert#TearDownFixerTest() Execute(The yamlfmt callback should return the correct default command): AssertEqual \ {'command': ale#Escape('yamlfmt') . ' -in'}, \ ale#fixers#yamlfmt#Fix(bufnr('')) ================================================ FILE: test/fixers/test_yapf_fixer_callback.vader ================================================ Before: Save g:ale_python_yapf_executable " Use an invalid global executable, so we don't match it. let g:ale_python_yapf_executable = 'xxxinvalid' call ale#test#SetDirectory('/testplugin/test/fixers') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: Restore unlet! b:bin_dir call ale#test#RestoreDirectory() Execute(The yapf should include the .style.yapf file if present): call ale#test#SetFilename('../test-files/python/with_virtualenv/dir_with_yapf_config/foo/bar.py') AssertEqual \ { \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/yapf')) \ . ' --no-local-style' \ . ' --style ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/dir_with_yapf_config/.style.yapf')), \ }, \ ale#fixers#yapf#Fix(bufnr('')) Execute(pipenv is detected when python_yapf_auto_pipenv is set): let g:ale_python_yapf_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('pipenv') . ' run yapf', \ }, \ ale#fixers#yapf#Fix(bufnr('')) Execute(Poetry is detected when python_yapf_auto_poetry is set): let g:ale_python_yapf_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertEqual \ { \ 'command': ale#Escape('poetry') . ' run yapf', \ }, \ ale#fixers#yapf#Fix(bufnr('')) Execute(uv is detected when python_yapf_auto_uv is set): let g:ale_python_yapf_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertEqual \ { \ 'command': ale#Escape('uv') . ' run yapf', \ }, \ ale#fixers#yapf#Fix(bufnr('')) ================================================ FILE: test/fixers/test_zigfmt_fixer_callback.vader ================================================ Before: call ale#assert#SetUpFixerTest('zig', 'zigfmt') After: call ale#assert#TearDownFixerTest() Execute(The zig callback should return the correct default values): AssertFixer { \ 'command': ale#Escape('zig') . ' fmt %t', \ 'read_temporary_file': 1, \} Execute(The zig callback should allow custom zig executables): let g:ale_zig_zigfmt_executable = 'foo/bar' AssertFixer { \ 'command': ale#Escape('foo/bar') . ' fmt %t', \ 'read_temporary_file': 1, \} ================================================ FILE: test/handler/test_actionlint_handler.vader ================================================ Before: runtime ale_linters/yaml/actionlint.vim After: call ale#linter#Reset() Execute(Problems should be parsed correctly for actionlint): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': '"jobs" section is missing in workflow', \ 'code': 'syntax-check', \ }, \ { \ 'lnum': 56, \ 'col': 23, \ 'type': 'E', \ 'text': 'property "unknown_input" is not defined in object type {input7: bool; input0: any; input1: any; input2: string; input3: any; input4: any; input5: number; input6: number}', \ 'code': 'expression', \ }, \ ], \ ale_linters#yaml#actionlint#Handle(bufnr(''), [ \ '.codecov.yaml:2:1: "jobs" section is missing in workflow [syntax-check]', \ 'workflow_call_event.yaml:56:23: property "unknown_input" is not defined in object type {input7: bool; input0: any; input1: any; input2: string; input3: any; input4: any; input5: number; input6: number} [expression]', \ ]) Execute(Shellcheck issues should be reported at the line they appear): AssertEqual \ [ \ { \ 'lnum': 19, \ 'col': 9, \ 'type': 'E', \ 'text': 'Double quote to prevent globbing and word splitting', \ 'code': 'shellcheck SC2086', \ }, \ ], \ ale_linters#yaml#actionlint#Handle(bufnr(''), [ \ 'validate.yml:19:9: shellcheck reported issue in this script: SC2086:info:1:15: Double quote to prevent globbing and word splitting [shellcheck]' \ ]) ================================================ FILE: test/handler/test_ada_gcc_handler.vader ================================================ 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', \ ]) ================================================ FILE: test/handler/test_alex_handler.vader ================================================ Execute(The alex handler should handle the example from the alex README): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 5, \ 'end_lnum': 1, \ 'end_col': 13, \ 'type': 'W', \ 'text': '`boogeyman` may be insensitive, use `boogey` instead (retext-equality)', \ }, \ { \ 'lnum': 1, \ 'col': 42, \ 'end_lnum': 1, \ 'end_col': 47, \ 'type': 'W', \ 'text': '`master` / `slaves` may be insensitive, use `primary` / `replica` instead (retext-equality)', \ }, \ { \ 'lnum': 1, \ 'col': 69, \ 'end_lnum': 1, \ 'end_col': 74, \ 'type': 'W', \ 'text': 'Don’t use “slaves”, it’s profane (retext-profanities)', \ }, \ { \ 'lnum': 2, \ 'col': 52, \ 'end_lnum': 2, \ 'end_col': 53, \ 'type': 'W', \ 'text': '`he` may be insensitive, use `they`, `it` instead (retext-equality)', \ }, \ { \ 'lnum': 2, \ 'col': 61, \ 'end_lnum': 2, \ 'end_col': 67, \ 'type': 'W', \ 'text': '`cripple` may be insensitive, use `person with a limp` instead (retext-equality)', \ }, \ ], \ ale#handlers#alex#Handle(bufnr(''), [ \ 'example.md', \ ' 1:5-1:14 warning `boogeyman` may be insensitive, use `boogey` instead boogeyman-boogeywoman retext-equality', \ ' 1:42-1:48 warning `master` / `slaves` may be insensitive, use `primary` / `replica` instead master-slave retext-equality', \ ' 1:69-1:75 warning Don’t use “slaves”, it’s profane slaves retext-profanities', \ ' 2:52-2:54 warning `he` may be insensitive, use `they`, `it` instead he-she retext-equality', \ ' 2:61-2:68 warning `cripple` may be insensitive, use `person with a limp` instead cripple retext-equality', \ '', \ '⚠ 5 warnings', \ ]) ================================================ FILE: test/handler/test_ameba_handler.vader ================================================ Before: runtime ale_linters/crystal/ameba.vim After: unlet! g:lines call ale#linter#Reset() Execute(The ameba handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 24, \ 'col': 28, \ 'end_col': 29, \ 'text': 'Trailing whitespace detected', \ 'code': 'Layout/TrailingWhitespace', \ 'type': 'W', \ }, \ ], \ ale_linters#crystal#ameba#HandleAmebaOutput(123, [ \ '{"sources":[{"path":"my_file_with_issues.cr","issues":[{"rule_name":"Layout/TrailingWhitespace","message":"Trailing whitespace detected","location":{"line":24,"column":28},"end_location":{"line":null,"column":null}}]},{"path":"my_file_without_issues.cr","issues":[]}],"metadata":{"ameba_version":"0.8.1","crystal_version":"0.26.1"},"summary":{"target_sources_count":2,"issues_count":1}}' \ ]) Execute(The ameba handler should handle when files are checked and no offenses are found): AssertEqual \ [], \ ale_linters#crystal#ameba#HandleAmebaOutput(123, [ \ '{"sources":[{"path":"my_file_with_issues.cr",issues":[]},{"path":"my_file_without_issues.cr",issues":[]}],"metadata":{ameba_version":"0.8.1",crystal_version":"0.26.1"},"summary":{target_sources_count":2,issues_count":0}}' \ ]) Execute(The ameba handler should handle when no files are checked): AssertEqual \ [], \ ale_linters#crystal#ameba#HandleAmebaOutput(123, [ \ '{"sources":[],"metadata":{ameba_version":"0.8.1",crystal_version":"0.26.1"},"summary":{target_sources_count":0,issues_count":0}}' \ ]) Execute(The ameba handler should handle blank output without any errors): AssertEqual \ [], \ ale_linters#crystal#ameba#HandleAmebaOutput(123, ['{}']) AssertEqual \ [], \ ale_linters#crystal#ameba#HandleAmebaOutput(123, []) ================================================ FILE: test/handler/test_ansible_lint_handler.vader ================================================ Before: Save b:ale_warn_about_trailing_whitespace runtime ale_linters/ansible/ansible_lint.vim call ale#test#SetFilename('test_playbook.yml') let b:ale_warn_about_trailing_whitespace = 1 After: Restore call ale#linter#Reset() Execute(The ansible-lint handler for version group <5 should handle basic errors): AssertEqual \ [ \ { \ 'lnum': 35, \ 'col': 0, \ 'type': 'E', \ 'text': 'Trailing whitespace', \ 'code': 'EANSIBLE0002', \ }, \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [4, 1, 2], [ \ fnamemodify(tempname(), ':h') . '/test_playbook.yml:35: [EANSIBLE0002] Trailing whitespace', \ ]) Execute(The ansible-lint handler for version group <5 should suppress trailing whitespace output when the option is used): let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [4, 1, 2], [ \ fnamemodify(tempname(), ':h') . '/test_playbook.yml:35: [EANSIBLE0002] Trailing whitespace', \ ]) Execute(The ansible-lint handler for version group >=5 should handle basic errors): AssertEqual \ [ \ { \ 'lnum': 35, \ 'col': 0, \ 'type': 'E', \ 'text': 'File permissions unset or incorrect', \ 'code': 'risky-file-permissions', \ }, \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [5, 1, 2], [ \ fnamemodify(tempname(), ':h') . '/test_playbook.yml:35: [risky-file-permissions] [VERY_HIGH] File permissions unset or incorrect', \ ]) Before: runtime ale_linters/ansible/ansible_lint.vim call ale#test#SetFilename('test playbook.yml') After: call ale#linter#Reset() Execute (The ansible-lint handler for version group <5 should handle names with spaces): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 6, \ 'type': 'E', \ 'text': 'indentation is not a multiple of four', \ 'code': 'E111', \ }, \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [4, 1, 2], [ \ fnamemodify(tempname(), ':h') . '/test playbook.yml:6:6: E111 indentation is not a multiple of four', \ ]) Execute (The ansible-lint handler for version group >=5 should handle names with spaces): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 148, \ 'type': 'E', \ 'text': "'var' is not a valid attribute for a Play", \ 'code': 'syntax-check', \ }, \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [5, 1, 2], [ \ fnamemodify(tempname(), ':h') . "/test playbook.yml:3:148: [syntax-check] [VERY_HIGH] 'var' is not a valid attribute for a Play", \ ]) Execute (The ansible-lint handler should work with issues with positions and lines members): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 7, \ 'code': 'major', \ 'type': 'W', \ 'text': "syntax-check[specific]", \ 'detail': 'fakedesc', \ }, \ { \ 'lnum': 6, \ 'col': 0, \ 'code': 'major', \ 'type': 'W', \ 'text': 'fqcn[action-core]', \ 'detail': 'fakedesc2' \ } \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [6, 11, 0], [ \ '[', \ ' {', \ ' "type": "issue",', \ ' "check_name": "syntax-check[specific]",', \ ' "categories": [', \ ' "core",', \ ' "unskippable"', \ ' ],', \ ' "url": "https://ansible-lint.readthedocs.io/rules/syntax-check/",', \ ' "severity": "major",', \ ' "description": "fakedesc",', \ ' "fingerprint": "4",', \ ' "location": {', \ ' "path": "test playbook.yml",', \ ' "positions": {', \ ' "begin": {', \ ' "line": 6,', \ ' "column": 7', \ ' }', \ ' }', \ ' }', \ ' },', \ ' {', \ ' "type": "issue",', \ ' "check_name": "fqcn[action-core]",', \ ' "categories": [', \ ' "formatting"', \ ' ],', \ ' "url": "https://ansible-lint.readthedocs.io/rules/fqcn/",', \ ' "severity": "major",', \ ' "description": "fakedesc2",', \ ' "fingerprint": "f",', \ ' "location": {', \ ' "path": "test playbook.yml",', \ ' "lines": {', \ ' "begin": 6', \ ' }', \ ' },', \ ' "content": {', \ ' "body": "Use `ansible.builtin.command` or `ansible.legacy.command` instead."', \ ' }', \ ' }', \ ']' \ ]) Execute (The ansible-lint handler should ignore errors from other files): AssertEqual \ [ \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [5, 1, 2], [ \ '/foo/bar/roles/test_playbook.yml:6: [command-instead-of-module] [VERY_LOW] curl used in place of get_url or uri module', \ ]) Execute (The ansible-lint handler should work with empty input): AssertEqual \ [ \ ], \ ale_linters#ansible#ansible_lint#Handle(bufnr(''), [6, 0, 0], []) ================================================ FILE: test/handler/test_appleswiftformat_handler.vader ================================================ Before: runtime ale_linters/swift/appleswiftformat.vim After: call ale#linter#Reset() Execute(The appleswiftformat handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 21, \ 'type': 'W', \ 'code': 'DoNotUseSemicolons', \ 'text': 'remove '';'' and move the next statement to the new line', \ }, \ { \ 'lnum': 3, \ 'col': 12, \ 'type': 'W', \ 'code': 'Spacing', \ 'text': 'remove 1 space' \ }, \ ], \ ale_linters#swift#appleswiftformat#Handle(bufnr(''), [ \ 'Sources/main.swift:4:21: warning: [DoNotUseSemicolons] remove '';'' and move the next statement to the new line', \ 'Sources/main.swift:3:12: warning: [Spacing] remove 1 space', \ ]) ================================================ FILE: test/handler/test_asm_handler.vader ================================================ Before: runtime ale_linters/asm/gcc.vim After: call ale#linter#Reset() Execute(The asm GCC handler should parse lines from GCC 6.3.1 correctly): AssertEqual \ [ \ { \ 'lnum': 38, \ 'text': "too many memory references for `mov'", \ 'type': 'E', \ }, \ { \ 'lnum': 42, \ 'text': "incorrect register `%ax' used with `l' suffix", \ 'type': 'E', \ }, \ ], \ ale_linters#asm#gcc#Handle(357, [ \ "{standard input}: Assembler messages:", \ "{standard_input}:38: Error: too many memory references for `mov'", \ "{standard input}:42: Error: incorrect register `%ax' used with `l' suffix", \ ]) ================================================ FILE: test/handler/test_atools_handler.vader ================================================ Before: runtime autoload/ale/handlers/atools.vim After: call ale#linter#Reset() Execute(The atools handler should handle basic errors or warings): AssertEqual \ [ \ { \ 'lnum': 2, \ 'text': 'trailing whitespace', \ 'type': 'E', \ 'code': 'AL8', \ }, \ { \ 'lnum': 15, \ 'text': '$pkgname should not be used in the source url', \ 'type': 'W', \ 'code': 'AL29', \ }, \ ], \ ale#handlers#atools#Handle(bufnr(''), [ \ 'IC:[AL8]:APKBUILD:2:trailing whitespace', \ 'MC:[AL29]:APKBUILD:15:$pkgname should not be used in the source url', \ ]) " Regardless of the severity, if the certainty is [P]ossible and not [C]ertain " or if regardless of the Certainty the Severity is not [I]mportant or [S]erious " then it must be a [W]arning Execute(If we are not Certain or Importantly Serious, be a Warning): AssertEqual \ [ \ { \ 'lnum': 3, \ 'text': 'This violation is Serious but Possible false positive, I am a Warning!', \ 'type': 'W', \ 'code': 'AL', \ }, \ { \ 'lnum': 4, \ 'text': 'This violation is Important but Possible false positive, I am a Warning!', \ 'type': 'W', \ 'code': 'AL', \ }, \ { \ 'lnum': 5, \ 'text': 'This violation is Minor, I am a Warning!', \ 'type': 'W', \ 'code': 'AL', \ }, \ { \ 'lnum': 6, \ 'text': 'This violation is Style, I am a Warning!', \ 'type': 'W', \ 'code': 'AL', \ }, \ ], \ ale#handlers#atools#Handle(bufnr(''), [ \ 'SP:[AL]:APKBUILD:3:This violation is Serious but Possible false positive, I am a Warning!', \ 'IP:[AL]:APKBUILD:4:This violation is Important but Possible false positive, I am a Warning!', \ 'MC:[AL]:APKBUILD:5:This violation is Minor, I am a Warning!', \ 'TC:[AL]:APKBUILD:6:This violation is Style, I am a Warning!', \ ]) Execute(We should be error if we are Certain it is Serious or Important): AssertEqual \ [ \ { \ 'lnum': 7, \ 'text': 'This is Certainly Serious, I am an Error!', \ 'type': 'E', \ 'code': 'AL', \ }, \ { \ 'lnum': 8, \ 'text': 'This is Certainly Important, I am an Error!', \ 'type': 'E', \ 'code': 'AL', \ }, \ ], \ ale#handlers#atools#Handle(bufnr(''), [ \ 'SC:[AL]:APKBUILD:7:This is Certainly Serious, I am an Error!', \ 'IC:[AL]:APKBUILD:8:This is Certainly Important, I am an Error!', \ ]) ================================================ FILE: test/handler/test_avra_handler.vader ================================================ Before: runtime ale_linters/avra/avra.vim After: call ale#linter#Reset() Execute(The avra handler should parse errors correctly): AssertEqual \ [ \ { \ 'lnum': 3, \ 'text': "Unknown device: atmega3228p", \ 'type': 'E' \ }, \ { \ 'lnum': 12, \ 'text': "Unknown directive: .EQ", \ 'type': 'E' \ } \ ], \ ale_linters#avra#avra#Handle(bufnr(''), [ \ "main.asm(3) : Error : Unknown device: atmega3228p", \ "main.asm(12) : Error : Unknown directive: .EQ" \ ]) ================================================ FILE: test/handler/test_bandit_handler.vader ================================================ Before: runtime ale_linters/python/bandit.vim After: call ale#linter#Reset() Execute(The bandit handler for Python should parse input correctly): AssertEqual \ [ \ { \ 'bufnr': 0, \ 'lnum': 2, \ 'code': 'B404', \ 'type': 'I', \ 'text': 'Consider possible security implications associated with subprocess module.', \ }, \ { \ 'bufnr': 0, \ 'lnum': 4, \ 'code': 'B305', \ 'type': 'W', \ 'text': 'Use of insecure cipher mode cryptography.hazmat.primitives.ciphers.modes.ECB.', \ }, \ { \ 'bufnr': 0, \ 'lnum': 6, \ 'code': 'B609', \ 'type': 'E', \ 'text': 'Possible wildcard injection in call: subprocess.Popen', \ }, \ ], \ ale_linters#python#bandit#Handle(0, [ \ '[main] INFO profile include tests: None', \ '[main] INFO profile exclude tests: None', \ '[main] INFO cli include tests: None', \ '[main] INFO cli exclude tests: None', \ '[main] INFO running on Python 3.7.2', \ '[node_visitor] INFO Unable to find qualified name for module: ', \ '2:B404:LOW:Consider possible security implications associated with subprocess module.', \ '4:B305:MEDIUM:Use of insecure cipher mode cryptography.hazmat.primitives.ciphers.modes.ECB.', \ '6:B609:HIGH:Possible wildcard injection in call: subprocess.Popen', \ ]) ================================================ FILE: test/handler/test_bashate_handler.vader ================================================ Before: runtime ale_linters/sh/bashate.vim After: call ale#linter#Reset() Execute(The bashate handler should handle basic errors): AssertEqual \ [ \ { \ 'lnum': 777, \ 'col': 1, \ 'text': 'E003 Indent not multiple of 4', \ }, \ { \ 'lnum': 783, \ 'col': 1, \ 'text': 'E020 Function declaration not in format ^function name {$', \ }, \ { \ 'lnum': 786, \ 'col': 1, \ 'text': 'E010 The "do" should be on same line as for', \ }, \ { \ 'lnum': 791, \ 'col': 1, \ 'text': 'E006 Line too long', \ }, \ ], \ ale_linters#sh#bashate#Handle(bufnr(''), [ \ 'run:777:1: E003 Indent not multiple of 4', \ 'run:783:1: E020 Function declaration not in format ^function name {$', \ 'run:786:1: E010 The "do" should be on same line as for', \ 'run:791:1: E006 Line too long', \ ]) ================================================ FILE: test/handler/test_bibclean_handler.vader ================================================ Before: runtime ale_linters/bib/bibclean.vim After: call ale#linter#Reset() Execute(The bibclean handler should parse lines from bibclean <= v2.11.4 correctly): AssertEqual \ [ \ { \ 'lnum': '60', \ 'type': 'W', \ 'text': 'Unexpected value in ``month = "09"''''.', \ 'col': '17' \ }, \ { \ 'lnum': '63', \ 'type': 'E', \ 'text': 'Expected comma after last field ``keywords''''.', \ 'col': ' 1' \ }, \ { \ 'lnum': '176', \ 'type': 'W', \ 'text': 'Unexpected DOI in URL value ``"https://doi.org/DOI"'''': move to separate DOI = "..." key/value in this entry.', \ 'col': '14' \ } \ ], \ ale_linters#bib#bibclean#Handle(255, [ \ "%% \"stdin\", line 60: Unexpected value in ``month = \"09\"''.", \ "%% File positions: input [main.bib] output [stdout]", \ "%% Entry input byte=1681 line=50 column= 1 output byte=1680 line=50 column= 0", \ "%% Value input byte=2137 line=60 column=17 output byte=2137 line=60 column=17", \ "%% Current input byte=2139 line=60 column=19 output byte=2137 line=60 column=17", \ "?? \"stdin\", line 71: Expected comma after last field ``keywords''.", \ "?? File positions: input [main.bib] output [stdout]", \ "?? Entry input byte=2145 line=63 column= 1 output byte=2146 line=63 column= 0", \ "?? Value input byte=2528 line=71 column= 2 output byte=2527 line=70 column=49", \ "?? Current input byte=2529 line=71 column= 3 output byte=2528 line=70 column=50", \ "%% \"stdin\", line 176: Unexpected DOI in URL value ``\"https://doi.org/DOI\"'': move to separate DOI = \"...\" key/value in this entry.", \ "%% File positions: input [stdin] output [stdout]", \ "%% Entry input byte=6813 line=174 column= 1 output byte=8543 line=227 column= 0", \ "%% Value input byte=6890 line=176 column=14 output byte=8641 line=229 column=17", \ "%% Current input byte=6938 line=176 column=62 output byte=8641 line=229 column=17" \ ]) Execute(The bibclean handler should parse lines of bibclean > v2.11.4 correctly): AssertEqual \ [ \ { \ 'lnum': '60', \ 'type': 'W', \ 'text': 'Unexpected value in ``month = "09"''''.', \ 'col': '17' \ }, \ { \ 'lnum': '63', \ 'type': 'E', \ 'text': 'Expected comma after last field ``keywords''''.', \ 'col': ' 1' \ }, \ { \ 'lnum': '176', \ 'type': 'W', \ 'text': 'Unexpected DOI in URL value ``"https://doi.org/DOI"'''': move to separate DOI = "..." key/value in this entry.', \ 'col': '14' \ } \ ], \ ale_linters#bib#bibclean#Handle(255, [ \ "%% stdin:60:Unexpected value in ``month = \"09\"''.", \ "%% File positions: input [main.bib] output [stdout]", \ "%% Entry input byte=1681 line=50 column= 1 output byte=1680 line=50 column= 0", \ "%% Value input byte=2137 line=60 column=17 output byte=2137 line=60 column=17", \ "%% Current input byte=2139 line=60 column=19 output byte=2137 line=60 column=17", \ "?? stdin:71:Expected comma after last field ``keywords''.", \ "?? File positions: input [main.bib] output [stdout]", \ "?? Entry input byte=2145 line=63 column= 1 output byte=2146 line=63 column= 0", \ "?? Value input byte=2528 line=71 column= 2 output byte=2527 line=70 column=49", \ "?? Current input byte=2529 line=71 column= 3 output byte=2528 line=70 column=50", \ "%% stdin:176:Unexpected DOI in URL value ``\"https://doi.org/DOI\"'': move to separate DOI = \"...\" key/value in this entry.", \ "%% File positions: input [stdin] output [stdout]", \ "%% Entry input byte=6813 line=174 column= 1 output byte=8543 line=227 column= 0", \ "%% Value input byte=6890 line=176 column=14 output byte=8641 line=229 column=17", \ "%% Current input byte=6938 line=176 column=62 output byte=8641 line=229 column=17" \ ]) ================================================ FILE: test/handler/test_bicep_az_bicep_handler.vader ================================================ Before: runtime ale_linters/bicep/az_bicep.vim After: call ale#linter#Reset() Execute(The az_bicep handler should handle basic warnings): AssertEqual \ [ \ { \ 'filename': '/tmp/nvimhxqs5D/1/dns.bicep', \ 'lnum': 7, \ 'col': 10, \ 'type': 'W', \ 'code': 'no-unused-existing-resources', \ 'text': 'Existing resource "asdasd" is declared but never used. [https://aka.ms/bicep/linter/no-unused-existing-resources]', \ }, \ { \ 'filename': '/tmp/nvimhxqs5D/1/dns.bicep', \ 'lnum': 106, \ 'col': 6, \ 'type': 'E', \ 'code': 'BCP019', \ 'text': 'Expected a new line character at this location.', \ }, \ { \ 'filename': '/tmp/cluster.bicep', \ 'lnum': 25, \ 'col': 30, \ 'type': 'E', \ 'code': 'BCP334', \ 'text': 'The provided value has no configured minimum length and may be too short to assign to a target with a configured minimum length of 1.', \ }, \ ], \ ale_linters#bicep#az_bicep#Handle(1, [ \ '/tmp/nvimhxqs5D/1/dns.bicep(7,10) : Warning no-unused-existing-resources: Existing resource "asdasd" is declared but never used. [https://aka.ms/bicep/linter/no-unused-existing-resources]', \ '/tmp/nvimhxqs5D/1/dns.bicep(106,6) : Error BCP019: Expected a new line character at this location.', \ 'ERROR: /tmp/cluster.bicep(25,30) : Warning BCP334: The provided value has no configured minimum length and may be too short to assign to a target with a configured minimum length of 1.', \ ]) ================================================ FILE: test/handler/test_bicep_bicep_handler.vader ================================================ Before: runtime ale_linters/bicep/bicep.vim After: call ale#linter#Reset() Execute(The bicep handler should handle basic warnings): AssertEqual \ [ \ { \ 'filename': '/tmp/nvimhxqs5D/1/dns.bicep', \ 'lnum': 7, \ 'col': 10, \ 'type': 'W', \ 'code': 'no-unused-existing-resources', \ 'text': 'Existing resource "asdasd" is declared but never used. [https://aka.ms/bicep/linter/no-unused-existing-resources]', \ }, \ { \ 'filename': '/tmp/nvimhxqs5D/1/dns.bicep', \ 'lnum': 106, \ 'col': 6, \ 'type': 'E', \ 'code': 'BCP019', \ 'text': 'Expected a new line character at this location.', \ }, \ ], \ ale_linters#bicep#bicep#Handle(1, [ \ '/tmp/nvimhxqs5D/1/dns.bicep(7,10) : Warning no-unused-existing-resources: Existing resource "asdasd" is declared but never used. [https://aka.ms/bicep/linter/no-unused-existing-resources]', \ '/tmp/nvimhxqs5D/1/dns.bicep(106,6) : Error BCP019: Expected a new line character at this location.', \ ]) ================================================ FILE: test/handler/test_bindzone_checkzone.vader ================================================ Before: runtime ale_linters/bindzone/checkzone.vim After: call ale#linter#Reset() Execute(The checkzone handler should handle basic warnings): AssertEqual \ [ \ { \ 'lnum': 2, \ 'type': 'E', \ 'text': 'unknown RR type ''fasd''', \ }, \ { \ 'lnum': 0, \ 'type': 'W', \ 'text': '_some_srv._tcp.example.com/SRV ''some.example.com'' (out of zone) has no addresses records (A or AAAA)', \ }, \ ], \ ale_linters#bindzone#checkzone#Handle(1, [ \ 'zone example.com/IN: _some_srv._tcp.example.com/SRV ''some.example.com'' (out of zone) has no addresses records (A or AAAA)', \ 'zone example.com/IN: loaded serial 2025050400', \ 'zone example.com/IN: not loaded due to errors', \ '/tmp/vb3wXsu/2/example.com:2: unknown RR type ''fasd''', \ ]) ================================================ FILE: test/handler/test_bitbake_oelint_adv_handler.vader ================================================ Before: runtime ale_linters/bitbake/oelint_adv.vim After: Restore call ale#linter#Reset() Execute(The oelint_adv handler should handle warnings): AssertEqual \ [ \ { \ 'lnum': 1234, \ 'type': 'I', \ 'code': 'oelint.var.suggestedvar.BUGTRACKER', \ 'text': 'Variable ''BUGTRACKER'' should be set', \ }, \ { \ 'lnum': 17, \ 'type': 'E', \ 'code': 'oelint.var.mandatoryvar.DESCRIPTION', \ 'text': 'Variable ''DESCRIPTION'' should be set', \ }, \ ], \ ale_linters#bitbake#oelint_adv#Handle(1, [ \ '/meta-x/recipes-y/example/example_1.0.bb:1234:info:oelint.var.suggestedvar.BUGTRACKER:Variable ''BUGTRACKER'' should be set [branch:true]', \ 'example2_1.1.bb:17:error:oelint.var.mandatoryvar.DESCRIPTION:Variable ''DESCRIPTION'' should be set [branch:true]', \ ]) Execute(The oelint_adv handler should handle warnings without branch message): AssertEqual \ [ \ { \ 'lnum': 1234, \ 'type': 'I', \ 'code': 'oelint.var.suggestedvar.BUGTRACKER', \ 'text': 'Variable ''BUGTRACKER'' should be set', \ }, \ { \ 'lnum': 17, \ 'type': 'E', \ 'code': 'oelint.var.mandatoryvar.DESCRIPTION', \ 'text': 'Variable ''DESCRIPTION'' should be set', \ }, \ ], \ ale_linters#bitbake#oelint_adv#Handle(1, [ \ '/meta-x/recipes-y/example/example_1.0.bb:1234:info:oelint.var.suggestedvar.BUGTRACKER:Variable ''BUGTRACKER'' should be set', \ 'example2_1.1.bb:17:error:oelint.var.mandatoryvar.DESCRIPTION:Variable ''DESCRIPTION'' should be set', \ ]) ================================================ FILE: test/handler/test_brakeman_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') runtime ale_linters/ruby/brakeman.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The brakeman handler should parse JSON correctly): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/app/models/thing.rb') AssertEqual \ [ \ { \ 'filename': expand('%:p'), \ 'lnum': 84, \ 'text': 'SQL Injection Possible SQL injection (Medium)', \ 'type': 'W', \ }, \ { \ 'filename': expand('%:p'), \ 'lnum': 1, \ 'text': 'Mass Assignment Potentially dangerous attribute available for mass assignment (Weak)', \ 'type': 'W', \ } \ ], \ ale_linters#ruby#brakeman#Handle(bufnr(''), [ \ '{', \ '"warnings": [', \ '{', \ '"warning_type": "SQL Injection",', \ '"warning_code": 0,', \ '"fingerprint": "1234",', \ '"check_name": "SQL",', \ '"message": "Possible SQL injection",', \ '"file": "' . substitute(ale#path#Simplify('app/models/thing.rb'), '\\', '\\\\', 'g') . '",', \ '"line": 84,', \ '"link": "http://brakemanscanner.org/docs/warning_types/sql_injection/",', \ '"code": "Thing.connection.execute(params[:data])",', \ '"render_path": null,', \ '"location": {', \ '"type": "method",', \ '"class": "Thing",', \ '"method": "run_raw_sql_from_internet"', \ '},', \ '"user_input": "whatever",', \ '"confidence": "Medium"', \ '},', \ '{', \ '"warning_type": "Mass Assignment",', \ '"warning_code": 60,', \ '"fingerprint": "1235",', \ '"check_name": "ModelAttrAccessible",', \ '"message": "Potentially dangerous attribute available for mass assignment",', \ '"file": "' . substitute(ale#path#Simplify('app/models/thing.rb'), '\\', '\\\\', 'g') . '",', \ '"line": null,', \ '"link": "http://brakemanscanner.org/docs/warning_types/mass_assignment/",', \ '"code": ":name",', \ '"render_path": null,', \ '"location": {', \ '"type": "model",', \ '"model": "Thing"', \ '},', \ '"user_input": null,', \ '"confidence": "Weak"', \ '}', \ ']', \ '}' \ ]) Execute(The brakeman handler should parse JSON correctly when there is no output from brakeman): AssertEqual \ [], \ ale_linters#ruby#brakeman#Handle(347, [ \ ]) Execute(The brakeman handler should handle garbage output): AssertEqual \ [], \ ale_linters#ruby#brakeman#Handle(347, [ \ 'No such command in 2.4.1 of ruby', \ ]) ================================================ FILE: test/handler/test_buildifier_handler.vader ================================================ Before: runtime ale_linters/bzl/buildifier.vim After: call ale#linter#Reset() Execute(The buildifier handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 26, \ 'col': 1, \ 'type': 'E', \ 'text': 'syntax error near'';'' and move the next statement to the new line', \ }, \ { \ 'lnum': 7, \ 'col': 0, \ 'type': 'W', \ 'text': 'unused-variable: Variable "foo" is unused. Please remove it. (https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#unused-variable)' \ }, \ ], \ ale_linters#bzl#buildifier#Handle(bufnr(''), [ \ 'swiftformat/toolchains/assets.bzl:26:1: syntax error near'';'' and move the next statement to the new line', \ 'swiftformat/toolchains/assets.bzl:7: unused-variable: Variable "foo" is unused. Please remove it. (https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#unused-variable)', \ ]) ================================================ FILE: test/handler/test_cfn_python_lint_handler.vader ================================================ Before: runtime! ale_linters/cloudformation/cfn_python_lint.vim call ale#test#SetFilename('sample.template.yaml') After: call ale#linter#Reset() Execute(The cfn_python_lint handler should parse items correctly): AssertEqual \ [ \ { \ 'lnum': '96', \ 'col': '7', \ 'end_lnum': '96', \ 'end_col': '15', \ 'text': 'Property Resources/Sample/Properties/FromPort should be of type Integer', \ 'code': 'E3012', \ 'type': 'E', \ }, \ { \ 'lnum': '97', \ 'col': '7', \ 'end_lnum': '97', \ 'end_col': '15', \ 'text': 'AllowedPattern and/or AllowedValues for Parameter should be specified at Parameters/SampleIpAddress. Example for AllowedPattern "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$"', \ 'code': 'W2509', \ 'type': 'W', \ }, \ ], \ ale_linters#cloudformation#cfn_python_lint#Handle(bufnr(''), [ \ fnamemodify(tempname(), ':h') . '/sample.template.yaml:96:7:96:15:E3012:Property Resources/Sample/Properties/FromPort should be of type Integer', \ fnamemodify(tempname(), ':h') . '/sample.template.yaml:97:7:97:15:W2509:AllowedPattern and/or AllowedValues for Parameter should be specified at Parameters/SampleIpAddress. Example for AllowedPattern "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$"', \ ]) ================================================ FILE: test/handler/test_checkmake_handler.vader ================================================ Before: runtime ale_linters/make/checkmake.vim After: call ale#linter#Reset() Execute(Parsing checkmake errors should work): AssertEqual \ [ \ { \ 'bufnr': 42, \ 'lnum': 1, \ 'type': 'E', \ 'code': 'woops', \ 'text': 'an error has occurred', \ } \ ], \ ale_linters#make#checkmake#Handle(42, [ \ "This shouldn't match", \ '1:woops:an error has occurred', \ ]) ================================================ FILE: test/handler/test_checkov_handler.vader ================================================ Before: runtime ale_linters/terraform/checkov.vim call ale#test#SetFilename('main.tf') After: call ale#linter#Reset() Execute(The JSON output of checkov should be handled correctly): AssertEqual \ [ \ { \ 'filename': '/main.tf', \ 'lnum': 22, \ 'end_lnum': 27, \ 'text': 'Enable VPC Flow Logs and Intranode Visibility [CKV_GCP_61]', \ 'detail': "CKV_GCP_61: Enable VPC Flow Logs and Intranode Visibility\n" . \ 'For more information, see: https://docs.bridgecrew.io/docs/enable-vpc-flow-logs-and-intranode-visibility', \ 'type': 'W', \ } \ ], \ ale_linters#terraform#checkov#Handle(bufnr(''), [ \'{', \' "check_type": "terraform",', \' "results": {', \' "failed_checks": [', \' {', \' "check_id": "CKV_GCP_61",', \' "bc_check_id": "BC_GCP_KUBERNETES_18",', \' "check_name": "Enable VPC Flow Logs and Intranode Visibility",', \' "check_result": {', \' "result": "FAILED",', \' "evaluated_keys": [', \' "enable_intranode_visibility"', \' ]', \' },', \' "file_path": "/main.tf",', \' "repo_file_path": "/main.tf",', \' "file_line_range": [', \' 22,', \' 27', \' ],', \' "resource": "google_container_cluster.cluster-name",', \' "evaluations": null,', \' "check_class": "checkov.terraform.checks.resource.gcp.GKEEnableVPCFlowLogs",', \' "entity_tags": null,', \' "resource_address": null,', \' "guideline": "https://docs.bridgecrew.io/docs/enable-vpc-flow-logs-and-intranode-visibility"', \' }', \' ]', \' }', \'}' \ ]) Execute(Handle output for no findings correctly): AssertEqual \ [], \ ale_linters#terraform#checkov#Handle(bufnr(''), [ \'{', \' "passed": 0,', \' "failed": 0,', \' "skipped": 0,', \' "parsing_errors": 0,', \' "resource_count": 0,', \' "checkov_version": "2.0.632"', \'}' \]) ================================================ FILE: test/handler/test_checkstyle_handler.vader ================================================ Before: runtime ale_linters/java/checkstyle.vim After: call ale#linter#Reset() Execute(The checkstyle handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 101, \ 'col': 0, \ 'text': '''method def rcurly'' has incorrect indentation level 4, expected level should be 2.', \ 'code': 'Indentation', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 63, \ 'col': 3, \ 'text': 'Missing a Javadoc comment.', \ 'code': 'JavadocMethod', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 11, \ 'col': 7, \ 'text': 'WhitespaceAround: ''if'' is not followed by whitespace.', \ 'code': 'WhitespaceAround', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ ], \ ale_linters#java#checkstyle#Handle(666, [ \ '[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]', \ '[WARN] whatever:11:7: WhitespaceAround: ''if'' is not followed by whitespace. [WhitespaceAround]', \ ]) 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', \ 'sub_type': 'style', \ }, \ ], \ 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.', \ ]) ================================================ FILE: test/handler/test_circleci_handler.vader ================================================ Before: runtime ale_linters/yaml/circleci.vim After: call ale#linter#Reset() Execute(The circlei handler should return nothing when configs are valid): AssertEqual \ [], \ ale_linters#yaml#circleci#Handle(0, [ \ 'Config input is valid.', \ ]) Execute(The circlei handler put errors at the top when something is wrong): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': '[#/jobs] expected type: Mapping, found: Integer', \ 'detail': join([ \ '[#/jobs] expected type: Mapping, found: Integer', \ 'Jobs is a map', \ 'SCHEMA:', \ ' type: object', \ 'INPUT:', \ ' 4', \ ], "\n"), \ }, \ ], \ ale_linters#yaml#circleci#Handle(0, [ \ 'Error: ERROR IN CONFIG FILE:', \ '[#/jobs] expected type: Mapping, found: Integer', \ 'Jobs is a map', \ 'SCHEMA:', \ ' type: object', \ 'INPUT:', \ ' 4', \ ]) ================================================ FILE: test/handler/test_clang_handler.vader ================================================ Execute(clang errors from included files should be parsed correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'filename': './b.h', \ 'type': 'E', \ 'text': 'expected identifier or ''(''', \ }, \ { \ 'lnum': 3, \ 'text': 'Error found in header. See :ALEDetail', \ 'detail': join([ \ 'In file included from :3:', \ 'In file included from ./a.h:1:', \ './b.h:1:1: error: expected identifier or ''(''', \ '{{{', \ '^', \ ], "\n"), \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ 'In file included from :3:', \ 'In file included from ./a.h:1:', \ './b.h:1:1: error: expected identifier or ''(''', \ '{{{', \ '^', \ '1 error generated.', \ ]) ================================================ FILE: test/handler/test_clojure_clj_kondo_handler.vader ================================================ Before: runtime ale_linters/clojure/clj_kondo.vim After: call ale#linter#Reset() Execute(the clojure clj-kondo handler should be able to handle errors): AssertEqual \ [ \ { \ 'lnum': 123, \ 'col': 44, \ 'type': 'E', \ 'text': 'error: Unexpected )', \ }, \ ], \ ale_linters#clojure#clj_kondo#HandleCljKondoFormat(0, [ \ 'test.clj:123:44: error: Unexpected )', \ ]) Execute(the clojure clj-kondo handler should be able to handle warnings): AssertEqual \ [ \ { \ 'lnum': 654, \ 'col': 321, \ 'type': 'W', \ 'text': 'warning: inline def', \ } \ ], \ ale_linters#clojure#clj_kondo#HandleCljKondoFormat(0, [ \ 'test.clj:654:321: warning: inline def' \ ]) Execute(the clojure clj-kondo handler should be able to handle exceptions): AssertEqual \ [ \ { \ 'lnum': 123, \ 'col': 321, \ 'type': 'E', \ 'text': 'Exception: something horrible happen', \ } \ ], \ ale_linters#clojure#clj_kondo#HandleCljKondoFormat(0, [ \ 'test.clj:123:321: Exception: something horrible happen' \ ]) Execute(the clojure clj-kondo handler should be able to handle errors from stdin): AssertEqual \ [ \ { \ 'lnum': 16, \ 'col': 1, \ 'type': 'E', \ 'text': 'error: Unexpected )', \ }, \ ], \ ale_linters#clojure#clj_kondo#HandleCljKondoFormat(0, [ \ ':16:1: error: Unexpected )', \ ]) Execute(the clojure clj-kondo handler should be able to handle windows files): AssertEqual \ [ \ { \ 'lnum': 123, \ 'col': 44, \ 'type': 'E', \ 'text': 'error: Unexpected )', \ } \ ], \ ale_linters#clojure#clj_kondo#HandleCljKondoFormat(0, [ \ 'C:\my\operating\system\is\silly\core.clj:123:44: error: Unexpected )', \ ]) Execute(the clojure clj-kondo handler should be able to lines without row/col): AssertEqual \ [ \ { \ 'lnum': 0, \ 'col': 0, \ 'type': 'E', \ 'text': 'error: Unexpected )', \ }, \ ], \ ale_linters#clojure#clj_kondo#HandleCljKondoFormat(0, [ \ 'test.clj::: error: Unexpected )', \ ]) ================================================ FILE: test/handler/test_clojure_joker_handler.vader ================================================ Before: runtime ale_linters/clojure/joker.vim After: call ale#linter#Reset() Execute(the clojure joker handler should be able to handle errors): AssertEqual \ [ \ { \ 'lnum': 123, \ 'col': 44, \ 'type': 'E', \ 'text': 'Read error: Unexpected )', \ }, \ ], \ ale_linters#clojure#joker#HandleJokerFormat(0, [ \ 'test.clj:123:44: Read error: Unexpected )', \ ]) Execute(the clojure joker handler should be able to handle warnings): AssertEqual \ [ \ { \ 'lnum': 654, \ 'col': 321, \ 'type': 'W', \ 'text': 'Parse warning: let form with empty body', \ } \ ], \ ale_linters#clojure#joker#HandleJokerFormat(0, [ \ 'test.clj:654:321: Parse warning: let form with empty body' \ ]) Execute(the clojure joker handler should be able to handle exceptions): AssertEqual \ [ \ { \ 'lnum': 123, \ 'col': 321, \ 'type': 'E', \ 'text': 'Exception: something horrible happen', \ } \ ], \ ale_linters#clojure#joker#HandleJokerFormat(0, [ \ 'test.clj:123:321: Exception: something horrible happen' \ ]) Execute(the clojure joker handler should be able to handle errors from stdin): AssertEqual \ [ \ { \ 'lnum': 16, \ 'col': 1, \ 'type': 'E', \ 'text': 'Read error: Unexpected )', \ }, \ ], \ ale_linters#clojure#joker#HandleJokerFormat(0, [ \ ':16:1: Read error: Unexpected )', \ ]) Execute(the clojure joker handler should be able to handle windows files): AssertEqual \ [ \ { \ 'lnum': 123, \ 'col': 44, \ 'type': 'E', \ 'text': 'Read error: Unexpected )', \ } \ ], \ ale_linters#clojure#joker#HandleJokerFormat(0, [ \ 'C:\my\operating\system\is\silly\core.clj:123:44: Read error: Unexpected )', \ ]) ================================================ FILE: test/handler/test_cloudformation_checkov_handler.vader ================================================ Before: runtime ale_linters/cloudformation/checkov.vim call ale#test#SetFilename('sample.template.yaml') After: call ale#linter#Reset() Execute(Handle output for no findings correctly): AssertEqual \ [], \ ale_linters#cloudformation#checkov#Handle(bufnr(''), [ \'{', \' "passed": 0,', \' "failed": 0,', \' "skipped": 0,', \' "parsing_errors": 0,', \' "resource_count": 0,', \' "checkov_version": "3.2.415"', \'}' \]) Execute(Handle output for all tests passed): AssertEqual \ [], \ ale_linters#cloudformation#checkov#Handle(bufnr(''), [ \'{', \' "check_type": "cloudformation",', \' "results": {', \' "failed_checks": []', \' },', \' "summary": {', \' "passed": 18,', \' "failed": 0,', \' "skipped": 0,', \' "parsing_errors": 0,', \' "resource_count": 3,', \' "checkov_version": "3.2.415"', \' }', \'}' \]) Execute(The JSON output of checkov should be handled correctly): AssertEqual \ [ \ { \ 'filename': '/sample.template.yaml', \ 'lnum': 57, \ 'end_lnum': 79, \ 'text': 'Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ) [CKV_AWS_116]', \ 'detail': "CKV_AWS_116: Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)\n" . \ 'For more information, see: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/ensure-that-aws-lambda-function-is-configured-for-a-dead-letter-queue-dlq', \ 'type': 'W', \ } \ ], \ ale_linters#cloudformation#checkov#Handle(bufnr(''), [ \'{', \' "check_type": "cloudformation",', \' "results": {', \' "failed_checks": [', \' {', \' "check_id": "CKV_AWS_116",', \' "bc_check_id": "BC_AWS_GENERAL_64",', \' "check_name": "Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)",', \' "check_result": {', \' "result": "FAILED",', \' "evaluated_keys": [', \' "Properties/DeadLetterQueue/TargetArn"', \' ]', \' },', \' "file_path": "/sample.template.yaml",', \' "repo_file_path": "/sample.template.yaml",', \' "file_line_range": [', \' 57,', \' 79', \' ],', \' "resource": "AWS::Serverless::Function.FunctionName",', \' "evaluations": {},', \' "check_class": "checkov.cloudformation.checks.resource.aws.LambdaDLQConfigured",', \' "entity_tags": null,', \' "resource_address": null,', \' "guideline": "https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/ensure-that-aws-lambda-function-is-configured-for-a-dead-letter-queue-dlq"', \' }', \' ]', \' }', \'}' \ ]) ================================================ FILE: test/handler/test_cmake_lint_handler.vader ================================================ Before: runtime ale_linters/cmake/cmake_lint.vim After: call ale#linter#Reset() Execute(The cmake_lint handler should handle basic warnings): AssertEqual \ [ \ { \ 'lnum': 126, \ 'col': 0, \ 'type': 'W', \ 'code': 'C0301', \ 'text': 'Line too long (136/80)', \ }, \ { \ 'lnum': 139, \ 'col': 4, \ 'type': 'W', \ 'code': 'C0113', \ 'text': 'Missing COMMENT in statement which allows it', \ }, \ ], \ ale_linters#cmake#cmake_lint#Handle(1, [ \ 'CMakeLists.txt:126: [C0301] Line too long (136/80)', \ 'CMakeLists.txt:139,04: [C0113] Missing COMMENT in statement which allows it', \ ]) ================================================ FILE: test/handler/test_coffeelint_handler.vader ================================================ Before: runtime ale_linters/coffee/coffeelint.vim After: call ale#linter#Reset() Execute(The coffeelint handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 125, \ 'text': "Line exceeds maximum allowed length Length is 122, max is 120.", \ 'type': 'E', \ }, \ ], \ ale_linters#coffee#coffeelint#Handle(347, [ \ "path,lineNumber,lineNumberEnd,level,message", \ "stdin,125,,error,Line exceeds maximum allowed length Length is 122, max is 120.", \ ]) ================================================ FILE: test/handler/test_common_handlers.vader ================================================ Execute(HandleCSSLintFormat should handle CSS errors): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Expected RBRACE at line 2, col 1.', \ 'code': 'errors', \ }, \ { \ 'lnum': 2, \ 'col': 5, \ 'type': 'W', \ 'text': 'Expected ... but found ''wat''.', \ 'code': 'known-properties', \ }, \ ], \ ale#handlers#css#HandleCSSLintFormat(42, [ \ 'something.css: line 2, col 1, Error - Expected RBRACE at line 2, col 1. (errors)', \ 'something.css: line 2, col 5, Warning - Expected ... but found ''wat''. (known-properties)', \ ]) Execute(HandleCSSLintFormat should handle CSS errors without groups): AssertEqual \ [ \ { \ 'lnum': 7, \ 'col': 3, \ 'type': 'W', \ 'text': 'Unknown property ''fill''.', \ }, \ { \ 'lnum': 8, \ 'col': 3, \ 'type': 'W', \ 'text': 'Unknown property ''fill-opacity''.', \ }, \ ], \ ale#handlers#css#HandleCSSLintFormat(42, [ \ 'something.css: line 7, col 3, Warning - Unknown property ''fill''.', \ 'something.css: line 8, col 3, Warning - Unknown property ''fill-opacity''.', \ ]) Execute (HandleGCCFormat should handle the correct lines of output): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 5, \ 'type': 'W', \ 'text': 'conversion lacks type at end of format [-Wformat=]', \ }, \ { \ 'lnum': 10, \ 'col': 27, \ 'type': 'E', \ 'text': 'invalid operands to binary - (have ''int'' and ''char *'')', \ }, \ ], \ ale#handlers#gcc#HandleGCCFormat(42, [ \ ':8:5: warning: conversion lacks type at end of format [-Wformat=]', \ ':10:27: error: invalid operands to binary - (have ‘int’ and ‘char *’)', \ ]) Execute (HandleGCCFormat should replace Unicode quotes): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 5, \ 'type': 'W', \ 'text': "'''' \"\"", \ }, \ ], \ ale#handlers#gcc#HandleGCCFormat(42, [':8:5: warning: `´‘’ “”']) Execute (HandleUnixFormatAsError should handle some example lines of output): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 0, \ 'type': 'E', \ 'text': 'missing argument for Printf("%s"): format reads arg 2, have only 1 args', \ }, \ { \ 'lnum': 53, \ 'col': 10, \ 'type': 'E', \ 'text': '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)', \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': '".b" is not a valid class name. Class names must begin with "-", "_" or a letter and can only contain "_", "-", a-z and 0-9.', \ }, \ ], \ ale#handlers#unix#HandleAsError(42, [ \ '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)', \ 'test.pug:1:1 ".b" is not a valid class name. Class names must begin with "-", "_" or a letter and can only contain "_", "-", a-z and 0-9.', \ ]) Execute (HandleUnixFormatAsError should handle lines with no space after the colon): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 0, \ 'type': 'E', \ 'text': 'foo', \ }, \ { \ 'lnum': 53, \ 'col': 10, \ 'type': 'E', \ 'text': 'bar', \ }, \ ], \ ale#handlers#unix#HandleAsError(42, [ \ 'some_file.xyz:27:foo', \ 'some_file.xyz:53:10:bar', \ ]) Execute (HandleUnixFormatAsError should handle names with spaces): AssertEqual \ [ \ { \ 'lnum': 13, \ 'col': 90, \ 'type': 'E', \ 'text': 'leonard.exclamation.30ppm More than 30 ppm of exclamations. Keep them under control.', \ }, \ ], \ ale#handlers#unix#HandleAsError(42, [ \ '/Users/rrj/Notes/Astro/Taurus December SM.txt:13:90: leonard.exclamation.30ppm More than 30 ppm of exclamations. Keep them under control.', \ ]) Execute (HandleUnixFormatAsWarning should handle some example lines of output): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 0, \ 'type': 'W', \ 'text': 'missing argument for Printf("%s"): format reads arg 2, have only 1 args', \ }, \ { \ 'lnum': 53, \ 'col': 10, \ 'type': 'W', \ 'text': '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)', \ }, \ ], \ ale#handlers#unix#HandleAsWarning(42, [ \ '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)', \ ]) Execute (Unix format functions should handle Windows paths): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 0, \ 'type': 'E', \ 'text': 'foo', \ }, \ { \ 'lnum': 53, \ 'col': 10, \ 'type': 'E', \ 'text': 'foo', \ }, \ ], \ ale#handlers#unix#HandleAsError(42, [ \ 'C:\Users\w0rp\AppData\Local\Temp\Xyz123.go:27: foo', \ 'C:\Users\w0rp\AppData\Local\Temp\Xyz123.go:53:10: foo', \ ]) ================================================ FILE: test/handler/test_cookstyle_handler.vader ================================================ Before: runtime ale_linters/chef/cookstyle.vim After: call ale#linter#Reset() Execute(Basic warnings should be handled): AssertEqual \ [ \ { \ 'lnum': 58, \ 'col': 24, \ 'code': 'Style/UnneededInterpolation', \ 'type': 'W', \ 'end_col': 40, \ 'text': 'Style/UnneededInterpolation: Prefer `to_s` over string interpolation.', \ } \ ], \ ale_linters#chef#cookstyle#Handle(bufnr(''), [ \ '{"metadata":{"rubocop_version":"0.62.0","ruby_engine":"ruby","ruby_version":"2.6.0","ruby_patchlevel":"0","ruby_platform":"x86_64-linux"},"files":[{"path":"recipes/default.rb","offenses":[{"severity":"convention","message":"Style/UnneededInterpolation: Prefer `to_s` over string interpolation.","cop_name":"Style/UnneededInterpolation","corrected":false,"location":{"start_line":58,"start_column":24,"last_line":58,"last_column":40,"length":17,"line":58,"column":24}}]}],"summary":{"offense_count":1,"target_file_count":1,"inspected_file_count":1}}' \ ]) ================================================ FILE: test/handler/test_cppcheck_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') After: call ale#test#RestoreDirectory() Execute(Basic errors should be handled by cppcheck): call ale#test#SetFilename('test.cpp') AssertEqual \ [ \ { \ 'lnum': 974, \ 'col' : 6, \ 'type': 'E', \ 'sub_type': '', \ 'text': 'Array ''n[3]'' accessed at index 3, which is out of bounds.', \ 'code': 'arrayIndexOutOfBounds' \ }, \ { \ 'lnum': 1185, \ 'col' : 10, \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'The scope of the variable ''indxStr'' can be reduced.', \ 'code': 'variableScope' \ }, \ ], \ ale#handlers#cppcheck#HandleCppCheckFormat(bufnr(''), [ \ 'test.cpp:974:6: error: Array ''n[3]'' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\', \ ' n[3]=3;', \ ' ^', \ 'test.cpp:1185:10: style: The scope of the variable ''indxStr'' can be reduced. [variableScope]\', \ ' char indxStr[16];', \ ' ^', \ ]) AssertEqual \ [ \ { \ 'lnum': 974, \ 'col' : 1, \ 'type': 'E', \ 'sub_type': '', \ 'text': 'inconclusive Array ''n[3]'' accessed at index 3, which is out of bounds.', \ 'code': 'arrayIndexOutOfBounds' \ }, \ { \ 'lnum': 1185, \ 'col' : 1, \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'The scope of the variable ''indxStr'' can be reduced.', \ 'code': 'variableScope' \ }, \ ], \ ale#handlers#cppcheck#HandleCppCheckFormat(bufnr(''), [ \ 'test.cpp:974:{column}: error:inconclusive Array ''n[3]'' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\', \ ' n[3]=3;', \ ' ^', \ 'test.cpp:1185:{column}: style:{inconclusive:inconclusive} The scope of the variable ''indxStr'' can be reduced. [variableScope]\', \ ' char indxStr[16];', \ ' ^', \ ]) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col' : 16, \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'misra violation (use --rule-texts= to get proper output)', \ 'code': 'misra-c2012-2.7' \ }, \ ], \ ale#handlers#cppcheck#HandleCppCheckFormat(bufnr(''), [ \ 'test.cpp:1:16: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.7]\', \ 'void test( int parm ) {}', \ ' ^', \ ]) Execute(Problems from other files should be ignored by cppcheck): call ale#test#SetFilename('test.cpp') AssertEqual \ [ \ ], \ ale#handlers#cppcheck#HandleCppCheckFormat(bufnr(''), [ \ 'bar.cpp:974:6: error: Array ''n[3]'' accessed at index 3, which is out of bounds. [arrayIndexOutOfBounds]\', \ ' n[3]=3;', \ ' ^', \ ]) ================================================ FILE: test/handler/test_cpplint_handler.vader ================================================ Before: runtime ale_linters/cpp/cpplint.vim After: call ale#linter#Reset() Execute(cpplint warnings from included files should be parsed correctly): AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 0, \ 'text': 'Extra space after ( in function call', \ 'code': 'whitespace/parents', \ 'type': 'W', \ }, \ { \ 'lnum': 120, \ 'col': 0, \ 'text': 'At least two spaces is best between code and comments', \ 'code': 'whitespace/comments', \ 'type': 'W', \ }, \ ], \ ale#handlers#cpplint#HandleCppLintFormat(347, [ \ 'test.cpp:5: Extra space after ( in function call [whitespace/parents] [4]', \ 'keymap_keys.hpp:120: At least two spaces is best between code and comments [whitespace/comments] [2]', \ ]) ================================================ FILE: test/handler/test_credo_handler.vader ================================================ Before: runtime ale_linters/elixir/credo.vim After: call ale#linter#Reset() Execute(The credo handler should parse lines correctly): AssertEqual \ [ \ { \ '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': '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', \ ]) ================================================ FILE: test/handler/test_crystal_handler.vader ================================================ Before: runtime ale_linters/crystal/crystal.vim After: call ale#linter#Reset() Execute(The crystal handler should parse lines correctly and add the column if it can): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'unexpected token: EOF' \ } \ ], \ ale_linters#crystal#crystal#Handle(255, [ \ '[{"file":"/tmp/test.cr","line":2,"column":1,"size":null,"message":"unexpected token: EOF"}]' \ ]) Execute(The crystal handler should not fail when a missing file is required): AssertEqual \ [ { 'lnum':1, 'col': 1, 'text': 'while requiring "./nonexistent.cr"' } ], \ ale_linters#crystal#crystal#Handle(255, \ json_encode([ \ { "file":"/tmp/file.cr","line":1,"column":1,"size":0,"message":"while requiring \"./nonexistent.cr\"" }, \ { "message": "can't find file './nonexistent.cr' relative to '/tmp'" }, \ ]) \ ) ================================================ FILE: test/handler/test_csc_handler.vader ================================================ Before: Save g:ale_cs_csc_source unlet! g:ale_cs_csc_source call ale#test#SetDirectory('/testplugin/test/handler') call ale#test#SetFilename('Test.cs') runtime ale_linters/cs/csc.vim After: Restore call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The csc handler should work with the default of the buffer's directory): AssertEqual \ [ \ { \ 'lnum': 12, \ 'col' : 29, \ 'text': '; expected', \ 'code': 'CS1001', \ 'type': 'E', \ 'filename': ale#path#Simplify(g:dir . '/Test.cs'), \ }, \ ], \ ale_linters#cs#csc#Handle(bufnr(''), [ \ 'Test.cs(12,29): error CS1001: ; expected', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) Execute(The csc handler should handle cannot find symbol errors): let g:ale_cs_csc_source = '/home/foo/project/bar' AssertEqual \ [ \ { \ 'lnum': 12, \ 'col' : 29, \ 'text': '; expected', \ 'code': 'CS1001', \ 'type': 'E', \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ { \ 'lnum': 101, \ 'col': 0, \ 'text': 'Unexpected processor directive (no #if for this #endif)', \ 'code': 'CS1028', \ 'type': 'E', \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ { \ 'lnum': 10, \ 'col': 12, \ 'text': 'some warning', \ 'code': 'CS0123', \ 'type': 'W', \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ ], \ ale_linters#cs#csc#Handle(bufnr(''), [ \ 'Test.cs(12,29): error CS1001: ; expected', \ 'Test.cs(101,0): error CS1028: Unexpected processor directive (no #if for this #endif)', \ 'Test.cs(10,12): warning CS0123: some warning', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) Execute(The csc handler should handle non file specific compiler errors without reporting overal status report as error): let g:ale_cs_csc_source = '/home/foo/project/bar' AssertEqual \ [ \ { \ 'lnum': -1, \ 'col' : -1, \ 'text': 'No source files specified.', \ 'code': 'CS2008', \ 'type': 'W', \ 'filename': '', \ }, \ { \ 'lnum': -1, \ 'col': -1, \ 'text': 'Outputs without source must have the /out option specified', \ 'code': 'CS1562', \ 'type': 'E', \ 'filename': '', \ }, \ ], \ ale_linters#cs#csc#Handle(bufnr(''), [ \ 'Microsoft (R) Visual C# Compiler version 2.8.2.62916 (2ad4aabc)', \ 'Copyright (C) Microsoft Corporation. All rights reserved.', \ 'warning CS2008: No source files specified.', \ 'error CS1562: Outputs without source must have the /out option specified', \ ]) ================================================ FILE: test/handler/test_cspell_handler.vader ================================================ Execute(The cspell handler should handle cspell output): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 128, \ 'end_col': 133, \ 'type': 'W', \ 'text': 'Unknown word (Neovim)', \ }, \ ], \ ale#handlers#cspell#Handle(bufnr(''), \ '/:3:128 - Unknown word (Neovim)' \) ================================================ FILE: test/handler/test_cucumber_handler.vader ================================================ Before: runtime ale_linters/cucumber/cucumber.vim After: call ale#linter#Reset() Execute(The cucumber handler parses JSON correctly): AssertEqual \ [ \ { \ 'lnum': 13, \ 'code': 'E', \ 'text': 'Undefined step' \ } \ ], \ ale_linters#cucumber#cucumber#Handle(bufnr(''), [ \ '[{"elements": [{"steps": [{"result": {"status": "undefined"},"match": {"location": "features/cuke.feature:13"},"line": 13,"name": "Something undefined","keyword": "Given "},{"result": {"status": "skipped"},"match": {"location": "/var/lib/gems/2.3.0/gems/cucumber-3.1.0/lib/cucumber/step_match.rb:103"},"line": 14,"name": "I visit the profile page for Alice","keyword": "When "}],"type": "scenario","line": 12,"description": "","name": "Another scenario","keyword": "Scenario","id": "a-user-can-view-another-users-profile;another-scenario"}],"line": 1,"description": "","name": "A user can view another users profile","keyword": "Feature","id": "a-user-can-view-another-users-profile","uri": "features/cuke.feature"}]' \ ]) ================================================ FILE: test/handler/test_cuda_nvcc_handler.vader ================================================ Before: runtime ale_linters/cuda/nvcc.vim After: call ale#linter#Reset() Execute(The cuda nvcc handler should parse errors from multiple files for NVCC 8.0): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': 'this declaration has no storage class or type specifier', \ 'filename': has('win32') \ ? 'C:\tmp\cudatest\test.cu' \ : '/tmp/cudatest/test.cu', \ }, \ { \ 'lnum': 2, \ 'type': 'E', \ 'text': 'attribute "global" does not apply here', \ 'filename': has('win32') \ ? 'C:\tmp\cudatest\common.h' \ : '/tmp/cudatest/common.h', \ }, \ { \ 'lnum': 2, \ 'type': 'E', \ 'text': 'expected a ";"', \ 'filename': has('win32') \ ? 'C:\tmp\cudatest\common.h' \ : '/tmp/cudatest/common.h', \ }, \ ], \ ale_linters#cuda#nvcc#HandleNVCCFormat(0, [ \ '/tmp/cudatest/test.cu(1): error: this declaration has no storage class or type specifier', \ '/tmp/cudatest/common.h(2): error: attribute "global" does not apply here', \ '/tmp/cudatest/common.h(2): error: expected a ";"', \ 'At end of source: warning: parsing restarts here after previous syntax error', \ '3 errors detected in the compilation of "/tmp/tmpxft_00003a9f_00000000-7_test.cpp1.ii".', \ ]) ================================================ FILE: test/handler/test_cypher_lint_handler.vader ================================================ Before: runtime ale_linters/cypher/cypher_lint.vim After: call ale#linter#Reset() Execute(The cypher-lint handler should handle errors for the current file correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 75, \ 'type': 'E', \ 'text': "Invalid input ',': expected an identifier, shortestPath, allShortestPaths or '('", \ }, \ ], \ ale_linters#cypher#cypher_lint#Handle(bufnr(''), [ \ "shakespeare.cql:1:75: Invalid input ',': expected an identifier, shortestPath, allShortestPaths or '('", \ "CREATE (shakespeare:Author {firstname:'William', lastname:'Shakespeare'}),,", \ " ^", \ ]) ================================================ FILE: test/handler/test_dafny_handler.vader ================================================ Before: runtime ale_linters/dafny/dafny.vim After: call ale#linter#Reset() Execute(The Dafny handler should parse output correctly): AssertEqual \ [ \ { \ 'filename': 'File.dfy', \ 'col': 45, \ 'lnum': 123, \ 'text': 'A precondition for this call might not hold.', \ 'type': 'E' \ }, \ { \ 'filename': 'File.dfy', \ 'col': 90, \ 'lnum': 678, \ 'text': 'This is the precondition that might not hold.', \ 'type': 'W' \ }, \ { \ 'filename': 'File.dfy', \ 'col': 45, \ 'lnum': 123, \ 'text': "Verification of 'Impl$$_22_Proof.__default.PutKeepsMapsFull' timed out after 2 seconds", \ 'type': 'E' \ }, \ ], \ ale_linters#dafny#dafny#Handle(0, [ \ 'File.dfy(123,45): Error BP5002: A precondition for this call might not hold.', \ 'File.dfy(678,90): Related location: This is the precondition that might not hold.', \ "File.dfy(123,45): Verification of 'Impl$$_22_Proof.__default.PutKeepsMapsFull' timed out after 2 seconds", \ ]) ================================================ FILE: test/handler/test_dart_analyze_handler.vader ================================================ Before: runtime ale_linters/dart/dart_analyze.vim After: call ale#linter#Reset() Execute(Basic problems should be parsed correctly): AssertEqual \ [ \ { \ 'type': 'E', \ 'text': 'expected_token: Expected to find ''}''', \ 'lnum': 5, \ 'col': 1, \ }, \ { \ 'type': 'W', \ 'text': 'invalid_assignment: A value of type ''String'' can''t be assigned to a variable of type ''int''', \ 'lnum': 2, \ 'col': 16, \ }, \ { \ 'type': 'I', \ 'text': 'dead_code: Dead code. Try removing the code, or fixing the code before it so that it can be reached.', \ 'lnum': 8, \ 'col': 3, \ }, \ ], \ ale_linters#dart#dart_analyze#Handle(bufnr(''), [ \ 'Analyzing main.dart...', \ ' error - main.dart:5:1 - Expected to find ''}'' - expected_token', \ 'warning - main.dart:2:16 - A value of type ''String'' can''t be assigned to a variable of type ''int'' - invalid_assignment', \ ' info - main.dart:8:3 - Dead code. Try removing the code, or fixing the code before it so that it can be reached. - dead_code', \ '3 issues found.', \ ]) ================================================ FILE: test/handler/test_deadnix_handler.vader ================================================ Execute(The deadnix handler should handle deadnix output): AssertEqual \ [ \ { \ 'lnum': 23, \ 'col': 5, \ 'end_col': 9, \ 'text': 'Unused lambda pattern: self', \ 'type': 'W', \ }, \ { \ 'lnum': 1, \ 'col': 2, \ 'end_col': 6, \ 'text': 'Unused lambda pattern: pkgs', \ 'type': 'W', \ }, \ ], \ ale#handlers#deadnix#Handle(bufnr(''), [ \ '{"file":"./flake.nix","results":[{"column":5,"endColumn":9,"line":23,"message":"Unused lambda pattern: self"},{"column":2,"endColumn":6,"line":1,"message":"Unused lambda pattern: pkgs"}]}' \ ]) AssertEqual [], ale#handlers#deadnix#Handle(bufnr(''), ['']) AssertEqual [], ale#handlers#deadnix#Handle(bufnr(''), ['not json']) AssertEqual [], ale#handlers#deadnix#Handle(bufnr(''), ['{"results":[{}]}']) ================================================ FILE: test/handler/test_debride_handler.vader ================================================ Before: runtime ale_linters/ruby/debride.vim After: call ale#linter#Reset() Execute(The debride linter parses output correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'text': 'Possible unused method: image_tags', \ 'type': 'W', \ }, \ { \ 'lnum': 7, \ 'text': 'Possible unused method: not_deleted', \ 'type': 'W', \ } \ ], \ ale_linters#ruby#debride#HandleOutput(0, [ \ 'These methods MIGHT not be called:', \ '', \ 'Image', \ ' image_tags app/models/image.rb:2', \ ' not_deleted app/models/image.rb:7' \]) ================================================ FILE: test/handler/test_desktop_file_validate_handler.vader ================================================ Before: runtime ale_linters/desktop/desktop_file_validate.vim After: call ale#linter#Reset() Execute(The desktop-file-validate handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'W', \ 'text': 'key "TerminalOptions" in group "Desktop Entry" is deprecated', \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': 'action "new-private-window" is defined, but there is no matching "Desktop Action new-private-window" group', \ }, \ ], \ ale_linters#desktop#desktop_file_validate#Handle(bufnr(''), [ \ 'foo.desktop: warning: key "TerminalOptions" in group "Desktop Entry" is deprecated', \ 'foo.desktop: error: action "new-private-window" is defined, but there is no matching "Desktop Action new-private-window" group', \ ]) ================================================ FILE: test/handler/test_djlint_handler.vader ================================================ Before: runtime ale_linters/html/djlint.vim After: call ale#linter#Reset() Execute(The Djlint handler should parse output with a column correctly): AssertEqual \ [ \ { \ 'lnum': 47, \ 'vcol': 1, \ 'col': 8, \ 'code': 'H008', \ 'text': 'Attributes should be double quoted.', \ 'type': 'W' \ } \ ], \ ale#handlers#djlint#Handle(0, [ \ 'H008 47:8 Attributes should be double quoted.' \ ]) ================================================ FILE: test/handler/test_dmd_handler.vader ================================================ Before: runtime ale_linters/d/dmd.vim call ale#test#SetDirectory('/testplugin/test/dmd') call ale#test#SetFilename('test.d') After: call ale#linter#Reset() call ale#test#RestoreDirectory() Execute(Basic errors should be handled by dmd): AssertEqual \ [ \ { \ 'filename': ale#path#Simplify(g:dir . '/test.d'), \ 'lnum': '5', \ 'col' : '8', \ 'type': 'E', \ 'text': 'module weak_reference is in file ''dstruct/weak_reference.d'' which cannot be read' \ }, \ { \ 'filename': ale#path#Simplify(g:dir . '/test.d'), \ 'lnum': '20', \ 'col' : '10', \ 'type': 'W', \ 'text': 'function test.thisoldfunc is deprecated' \ }, \ { \ 'filename': ale#path#Simplify(g:dir . '/foo.d'), \ 'lnum': '230', \ 'col' : '9', \ 'type': 'W', \ 'text': 'statement is not reachable' \ } \ ], \ ale_linters#d#dmd#Handle(bufnr(''), [ \ 'test.d(5,8): Error: module weak_reference is in file ''dstruct/weak_reference.d'' which cannot be read', \ 'import path[0] = source', \ 'import path[1] = /usr/include/dlang/dmd', \ ale#path#Simplify(g:dir . '/test.d') . '(20,10): Deprecation: function test.thisoldfunc is deprecated', \ 'foo.d(230,9): Warning: statement is not reachable', \ ]) ================================================ FILE: test/handler/test_dockerfile_lint_handler.vader ================================================ 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", \ 'detail': "Required LABEL name/key 'Name' is not defined\n\nhttp://docs.projectatomic.io/container-best-practices/#_recommended_labels_for_your_project", \ }, \ { \ 'lnum': -1, \ 'type': 'E', \ 'text': "Required LABEL name/key 'Version' is not defined", \ 'detail': "Required LABEL name/key 'Version' is not defined\n\nhttp://docs.projectatomic.io/container-best-practices/#_recommended_labels_for_your_project", \ }, \ { \ 'lnum': 3, \ 'type': 'I', \ 'text': "the MAINTAINER command is deprecated", \ 'detail': "the MAINTAINER command is deprecated\n\nMAINTAINER is deprecated in favor of using LABEL since Docker v1.13.0\n\nhttps://github.com/docker/cli/blob/master/docs/deprecated.md#maintainer-in-dockerfile", \ }, \ { \ 'lnum': -1, \ 'type': 'I', \ 'text': "There is no 'CMD' instruction", \ 'detail': "There is no 'CMD' instruction\n\nhttps://docs.docker.com/engine/reference/builder/#cmd", \ }, \ ], \ 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 ",', \ ' "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": []', \ '}', \ ]) ================================================ FILE: test/handler/test_dockerlinter_handler.vader ================================================ Before: runtime ale_linters/dockerfile/dockerlinter.vim After: call ale#linter#Reset() Execute(The dockerlinter handler should handle broken JSON): AssertEqual \ [], \ ale_linters#dockerfile#dockerlinter#Handle(bufnr(''), ["{asdf"]) Execute(The dockerlinter handler should handle an empty string response): AssertEqual \ [], \ ale_linters#dockerfile#dockerlinter#Handle(bufnr(''), []) Execute(The dockerlinter handler should handle an empty result, even if it shouldn't happen): AssertEqual \ [], \ ale_linters#dockerfile#dockerlinter#Handle(bufnr(''), ["{}"]) Execute(The dockerlinter handler should handle a normal example): AssertEqual \ [ \ { \ 'lnum': 11, \ 'type': 'I', \ 'code': 'ER0002', \ 'text': "Delete the apt-get lists after installing something", \ 'detail': "Delete the apt-get lists after installing something\n\nhttps://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md#ER0002", \ }, \ { \ 'lnum': 11, \ 'type': 'I', \ 'code': 'ER0010', \ 'text': "Avoid additional packages by specifying --no-install-recommends", \ 'detail': "Avoid additional packages by specifying --no-install-recommends\n\nhttps://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md#ER0010", \ }, \ { \ 'lnum': 11, \ 'type': 'I', \ 'code': 'ER0012', \ 'text': "Pin versions in apt get install", \ 'detail': "Pin versions in apt get install\n\nhttps://github.com/buddy-works/dockerfile-linter/blob/master/Rules.md#ER0012", \ }, \ { \ 'lnum': 30, \ 'type': 'W', \ 'code': 'SC2155', \ 'text': "Declare and assign separately to avoid masking return values.", \ 'detail': "Declare and assign separately to avoid masking return values.\n\nhttps://www.shellcheck.net/wiki/SC2155", \ }, \ { \ 'lnum': 30, \ 'type': 'W', \ 'code': 'SC2046', \ 'text': "Quote this to prevent word splitting.", \ 'detail': "Quote this to prevent word splitting.\n\nhttps://www.shellcheck.net/wiki/SC2046", \ }, \ { \ 'lnum': 30, \ 'type': 'I', \ 'code': 'SC2086', \ 'text': "Double quote to prevent globbing and word splitting.", \ 'detail': "Double quote to prevent globbing and word splitting.\n\nhttps://www.shellcheck.net/wiki/SC2086", \ }, \ { \ 'lnum': 31, \ 'type': 'W', \ 'code': 'SC2046', \ 'text': "Quote this to prevent word splitting.", \ 'detail': "Quote this to prevent word splitting.\n\nhttps://www.shellcheck.net/wiki/SC2046", \ }, \ ], \ ale_linters#dockerfile#dockerlinter#Handle(bufnr(''), [ \ '[{"lineNumber":11,"message":"Delete the apt-get lists after installing something","level":"info","code":"ER0002"},{"lineNumber":11,"message":"Avoid additional packages by specifying --no-install-recommends","level":"info","code":"ER0010"},{"lineNumber":11,"message":"Pin versions in apt get install","level":"info","code":"ER0012"},{"lineNumber":30,"message":"Declare and assign separately to avoid masking return values.","level":"warning","code":"SC2155"},{"lineNumber":30,"message":"Quote this to prevent word splitting.","level":"warning","code":"SC2046"},{"lineNumber":30,"message":"Double quote to prevent globbing and word splitting.","level":"info","code":"SC2086"},{"lineNumber":31,"message":"Quote this to prevent word splitting.","level":"warning","code":"SC2046"}]', \ ]) ================================================ FILE: test/handler/test_dogma_handler.vader ================================================ Before: runtime ale_linters/elixir/dogma.vim After: call ale#linter#Reset() Execute(The dogma handler should parse lines correctly): AssertEqual \ [ \ { \ 'bufnr': 347, \ 'lnum': 18, \ 'col': 5, \ 'text': 'Some error', \ 'type': 'E', \ }, \ { \ 'bufnr': 347, \ 'lnum': 19, \ 'col': 7, \ 'text': 'Some warning', \ 'type': 'W', \ }, \ ], \ ale_linters#elixir#dogma#Handle(347, [ \ 'This line should be ignored completely', \ 'lib/filename.ex:18:5: C: Some error', \ 'lib/filename.ex:19:7: R: Some warning', \ ]) ================================================ FILE: test/handler/test_drafter_handler.vader ================================================ Before: runtime! ale_linters/apiblueprint/drafter.vim After: call ale#linter#Reset() Execute(drafter handler should handle errors output): AssertEqual \ [ \ { \ 'lnum': 25, \ 'col': 3, \ 'text': "unable to parse response signature, expected 'response [] [()]'", \ 'type': "W", \ }, \ { \ 'lnum': 25, \ 'col': 3, \ 'text': "missing response HTTP status code, assuming 'Response 200'", \ 'type': "W", \ }, \ { \ 'lnum': 30, \ 'col': 7, \ 'end_lnum': 32, \ 'end_col': 7, \ 'text': "message-body asset is expected to be a pre-formatted code block, separate it by a newline and indent every of its line by 12 spaces or 3 tabs", \ 'type': "W", \ }, \ ], \ ale_linters#apiblueprint#drafter#HandleErrors(bufnr(''), [ \ "", \ "OK.", \ "warning: (3) unable to parse response signature, expected 'response [] [()]'; line 25, column 3 - line 25, column 29", \ "warning: (6) missing response HTTP status code, assuming 'Response 200'; line 25, column 3 - line 25, column 29", \ "warning: (10) message-body asset is expected to be a pre-formatted code block, separate it by a newline and indent every of its line by 12 spaces or 3 tabs; line 30, column 7 - line 30, column 11; line 31, column 6 - line 31, column 7; line 32, column 6 - line 32, column 7" \ ]) ================================================ FILE: test/handler/test_elmmake_handler.vader ================================================ Before: runtime ale_linters/elm/make.vim After: unlet! g:config_error_lines call ale#linter#Reset() " Elm 0.19 Execute(The elm-make handler should parse Elm 0.19 general problems correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': "error details\n\nstyled details" \ } \ ], \ ale_linters#elm#make#Handle(347, [ \ json_encode({ \ 'type': 'error', \ 'path': ale#util#Tempname() . '/Module.elm', \ 'title': 'UNKNOWN IMPORT', \ 'message': ["error details\n\n", { 'string': 'styled details' }] \ }), \ ]) Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly): AssertEqual \ [ \ { \ 'lnum': 404, \ 'col': 1, \ 'end_lnum': 408, \ 'end_col': 18, \ 'type': 'E', \ 'text': "error details 1\n\nstyled details" \ }, \ { \ 'lnum': 406, \ 'col': 5, \ 'end_lnum': 407, \ 'end_col': 17, \ 'type': 'E', \ 'text': 'error details 2', \ }, \ { \ 'lnum': 406, \ 'col': 5, \ 'end_lnum': 406, \ 'end_col': 93, \ 'type': 'E', \ 'text': 'error details 3', \ }, \ ], \ ale_linters#elm#make#Handle(347, [ \ json_encode({ \ 'type': 'compile-errors', \ 'errors': [ \ { \ 'path': ale#util#Tempname() . '/Module.elm', \ 'problems': [ \ { \ 'title': 'TYPE MISMATCH', \ 'message': ["error details 1\n\n", { 'string': 'styled details' }], \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } } \ }, \ { \ 'title': 'TYPE MISMATCH', \ 'message': ['error details 2'], \ 'region': { 'start': {'line': 406, 'column': 5}, 'end': {'line': 407, 'column': 17 } } \ }, \ { \ 'title': 'TYPE MISMATCH', \ 'message': ['error details 3'], \ 'region': { 'start': { 'line': 406, 'column': 5}, 'end': {'line': 406, 'column': 93 } } \ } \ ] \ } \ ] \ }), \ ]) Execute(The elm-make handler should handle errors in Elm 0.19 imported modules): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': "src/Module.elm - error details\n\nstyled details", \ 'detail': "src/Module.elm ----------\n\nerror details\n\nstyled details" \ }, \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': "Elm - error details\n\nstyled details", \ 'detail': "Elm ----------\n\nerror details\n\nstyled details" \ }, \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': "src/Module.elm:404 - error details\n\nstyled details", \ 'detail': "src/Module.elm:404 ----------\n\nerror details\n\nstyled details" \ }, \ ], \ ale_linters#elm#make#Handle(347, [ \ json_encode({ \ 'type': 'error', \ 'path': 'src/Module.elm', \ 'title': 'UNKNOWN IMPORT', \ 'message': ["error details\n\n", { 'string': 'styled details' }] \ }), \ json_encode({ \ 'type': 'error', \ 'path': v:null, \ 'title': 'UNKNOWN IMPORT', \ 'message': ["error details\n\n", { 'string': 'styled details' }] \ }), \ json_encode({ \ 'type': 'compile-errors', \ 'errors': [ \ { \ 'path': 'src/Module.elm', \ 'problems': [ \ { \ 'title': 'TYPE MISMATCH', \ 'message': ["error details\n\n", { 'string': 'styled details' }], \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } } \ } \ ] \ } \ ] \ }), \ ]) " Elm 0.18 Execute(The elm-make handler should parse Elm 0.18 compilation errors correctly): AssertEqual \ [ \ { \ 'lnum': 33, \ 'col': 1, \ 'end_lnum': 33, \ 'end_col': 19, \ 'type': 'W', \ 'text': 'warning overview', \ 'detail': "warning overview\n\nwarning details", \ }, \ { \ 'lnum': 404, \ 'col': 1, \ 'end_lnum': 408, \ 'end_col': 18, \ 'type': 'E', \ 'text': 'error overview 1', \ 'detail': "error overview 1\n\nerror details 1", \ }, \ { \ 'lnum': 406, \ 'col': 5, \ 'end_lnum': 407, \ 'end_col': 17, \ 'type': 'E', \ 'text': 'error overview 2', \ 'detail': "error overview 2\n\nerror details 2", \ }, \ { \ 'lnum': 406, \ 'col': 5, \ 'end_lnum': 406, \ 'end_col': 93, \ 'type': 'E', \ 'text': 'error overview 3', \ 'detail': "error overview 3\n\nerror details 3", \ }, \ ], \ ale_linters#elm#make#Handle(347, [ \ json_encode([ \ { \ 'tag': 'unused import', \ 'overview': 'warning overview', \ 'details': 'warning details', \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } }, \ 'type': 'warning', \ 'file': ale#util#Tempname() . '/Module.elm', \ } \ ]), \ json_encode([ \ { \ 'tag': 'TYPE MISMATCH', \ 'overview': 'error overview 1', \ 'subregion': { 'start': { 'line': 406, 'column': 5 }, 'end': { 'line': 408, 'column': 18 } }, \ 'details': 'error details 1', \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } }, \ 'type': 'error', \ 'file': ale#util#Tempname() . '/Module.elm', \ }, \ { \ 'tag': 'TYPE MISMATCH', \ 'overview': 'error overview 2', \ 'subregion': { 'start': { 'line': 407, 'column': 12 }, 'end': { 'line': 407, 'column': 17 } }, \ 'details': 'error details 2', \ 'region': { 'start': { 'line': 406, 'column': 5}, 'end': { 'line': 407, 'column': 17 } }, \ 'type':'error', \ 'file': ale#util#Tempname() . '/Module.elm', \ }, \ { \ 'tag': 'TYPE MISMATCH', \ 'overview': 'error overview 3', \ 'subregion': { 'start': { 'line': 406, 'column': 88 }, 'end': { 'line': 406, 'column': 93 } }, \ 'details': 'error details 3', \ 'region': { 'start': { 'line': 406, 'column': 5 }, 'end': { 'line': 406, 'column': 93 } }, \ 'type':'error', \ 'file': ale#util#Tempname() . '/Module.elm', \ } \ ]), \ ]) Execute(The elm-make handler should handle errors in Elm 0.18 imported modules): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': 'src/Module.elm:33 - error overview', \ 'detail': "src/Module.elm:33 ----------\n\nerror overview\n\nerror details" \ } \ ], \ ale_linters#elm#make#Handle(347, [ \ json_encode([ \ { \ 'tag': 'unused import', \ 'overview': 'warning overview', \ 'details': 'warning details', \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } }, \ 'type': 'warning', \ 'file': 'src/Module.elm', \ }, \ { \ 'tag': 'type error', \ 'overview': 'error overview', \ 'details': 'error details', \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } }, \ 'type': 'error', \ 'file': 'src/Module.elm', \ } \ ]), \ ]) " Generic Execute(The elm-make handler should put an error on the first line if a line cannot be parsed): AssertEqual \ [ \ { \ 'lnum': 404, \ 'col': 1, \ 'end_lnum': 408, \ 'end_col': 18, \ 'type': 'E', \ 'text': "error details 1\n\nstyled details" \ }, \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': 'Not JSON', \ 'detail': "Not JSON\nAlso not JSON", \ }, \ ], \ ale_linters#elm#make#Handle(347, [ \ json_encode({ \ 'type': 'compile-errors', \ 'errors': [ \ { \ 'path': ale#util#Tempname() . '/Module.elm', \ 'problems': [ \ { \ 'title': 'TYPE MISMATCH', \ 'message': ["error details 1\n\n", { 'string': 'styled details' }], \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } } \ } \ ] \ } \ ] \ }), \ 'Not JSON', \ 'Also not JSON', \ ]) Execute(The elm-make handler should ignore success lines): AssertEqual \ [], \ ale_linters#elm#make#Handle(347, [ \ 'Successfully generated /dev/null', \ ]) ================================================ FILE: test/handler/test_embertemplatelint_handler.vader ================================================ " Author: Adrian Zalewski Before: runtime autoload/ale/handlers/embertemplatelint.vim After: call ale#linter#Reset() Execute(The ember-template-lint handler should parse lines correctly): let input_lines = split('{ \ "/ember-project/app/templates/application.hbs": [ \ { \ "moduleId": "app/templates/application", \ "rule": "bare-strings", \ "severity": 2, \ "message": "Non-translated string used", \ "line": 1, \ "column": 10, \ "source": " Bare String\n" \ }, \ { \ "moduleId": "app/templates/application", \ "rule": "invalid-interactive", \ "severity": 1, \ "message": "Interaction added to non-interactive element", \ "line": 3, \ "column": 6, \ "source": "" \ } \ ] \ }', '\n') AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 10, \ 'text': 'bare-strings: Non-translated string used', \ 'type': 'E', \ }, \ { \ 'lnum': 3, \ 'col': 6, \ 'text': 'invalid-interactive: Interaction added to non-interactive element', \ 'type': 'W', \ }, \ ], \ ale#handlers#embertemplatelint#Handle(347, input_lines) Execute(The ember-template-lint handler should handle template parsing error correctly): let input_lines = split('{ \ "/ember-project/app/templates/application.hbs": [ \ { \ "fatal": true, \ "moduleId": "app/templates/application", \ "message": "Parse error on line 5 ...", \ "line": 5, \ "column": 3, \ "source": "Error: Parse error on line 5 ...", \ "severity": 2 \ } \ ] \ }', '\n') AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 3, \ 'text': 'Parse error on line 5 ...', \ 'type': 'E', \ }, \ ], \ ale#handlers#embertemplatelint#Handle(347, input_lines) Execute(The ember-template-lint handler should handle no lint errors/warnings): AssertEqual \ [], \ ale#handlers#embertemplatelint#Handle(347, []) AssertEqual \ [], \ ale#handlers#embertemplatelint#Handle(347, ['{}']) ================================================ FILE: test/handler/test_erblint_handler.vader ================================================ Before: runtime ale_linters/eruby/erblint.vim After: call ale#linter#Reset() Execute(The erblint handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 0, \ 'end_col': 0, \ 'text': 'Extra blank line detected.', \ 'code': 'ExtraNewline', \ 'type': 'W', \ }, \ { \ 'lnum': 6, \ 'col': 0, \ 'end_col': 0, \ 'text': 'Remove multiple trailing newline at the end of the file.', \ 'code': 'FinalNewline', \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'col': 9, \ 'end_col': 11, \ 'text': 'Use 1 space after `<%=` instead of 2 spaces.', \ 'code': 'SpaceAroundErbTag', \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'col': 9, \ 'end_col': 11, \ 'text': 'Use 1 space before `%>` instead of 2 spaces.', \ 'code': 'SpaceAroundErbTag', \ 'type': 'W', \ }, \ { \ 'lnum': 5, \ 'col': 6, \ 'end_col': 10, \ 'text': 'Extra whitespace detected at end of line.', \ 'code': 'TrailingWhitespace', \ 'type': 'W', \ }, \ ], \ ale_linters#eruby#erblint#Handle(347, [ \ '{"metadata":{"erb_lint_version":"0.1.1","ruby_engine":"ruby","ruby_version":"3.0.2","ruby_patchlevel":"107","ruby_platform":"arm64-darwin20"},"files":[{"path":"demo.html.erb","offenses":[{"linter":"ExtraNewline","message":"Extra blank line detected.","location":{"start_line":3,"start_column":0,"last_line":4,"last_column":0,"length":1}},{"linter":"FinalNewline","message":"Remove multiple trailing newline at the end of the file.","location":{"start_line":6,"start_column":0,"last_line":8,"last_column":0,"length":2}},{"linter":"SpaceAroundErbTag","message":"Use 1 space after `<%=` instead of 2 spaces.","location":{"start_line":4,"start_column":9,"last_line":4,"last_column":11,"length":2}},{"linter":"SpaceAroundErbTag","message":"Use 1 space before `%>` instead of 2 spaces.","location":{"start_line":4,"start_column":9,"last_line":4,"last_column":11,"length":2}},{"linter":"TrailingWhitespace","message":"Extra whitespace detected at end of line.","location":{"start_line":5,"start_column":6,"last_line":5,"last_column":10,"length":4}}]}],"summary":{"offenses":5,"inspected_files":1,"corrected":0}}' \ ]) Execute(The erblint handler should handle when files are checked and no offenses are found): AssertEqual \ [], \ ale_linters#eruby#erblint#Handle(347, [ \ '{"metadata":{"erb_lint_version":"0.1.1","ruby_engine":"ruby","ruby_version":"3.0.2","ruby_patchlevel":"107","ruby_platform":"arm64-darwin20"},"files":[{"path":"demo.html.erb","offenses":[]}],"summary":{"offenses":0,"inspected_files":1,"corrected":0}}' \ ]) Execute(The erblint handler should handle output without any errors): AssertEqual [], ale_linters#eruby#erblint#Handle(347, ['{}']) AssertEqual [], ale_linters#eruby#erblint#Handle(347, []) ================================================ FILE: test/handler/test_erlang_dialyzer_handler.vader ================================================ Before: runtime ale_linters/erlang/dialyzer.vim After: call ale#linter#Reset() Execute(The dialyzer handler should handle error messages.): AssertEqual \[ \ { \ 'lnum': 3, \ 'lcol': 0, \ 'text': 'Callback info about the provider behaviour is not available', \ 'type': 'W' \ } \], \ ale_linters#erlang#dialyzer#Handle(bufnr(''), ['erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available']) Execute(The dialyzer handler should handle empty input): AssertEqual [], ale_linters#erlang#dialyzer#Handle(bufnr(''), []) AssertEqual [], ale_linters#erlang#dialyzer#Handle(bufnr(''), ['']) ================================================ FILE: test/handler/test_erlang_elvis_handler.vader ================================================ Before: runtime ale_linters/erlang/elvis.vim After: call ale#linter#Reset() Execute(Warning messages should be handled): AssertEqual \ [ \ { \ 'lnum': 11, \ 'text': "Replace the 'if' expression on line 11 with a 'case' expression or function clauses.", \ 'type': 'W', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 20, \ 'text': 'Remove the debug call to io:format/1 on line 20.', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ ], \ ale_linters#erlang#elvis#Handle(bufnr(''), [ \ "src/foo.erl:11:no_if_expression:Replace the 'if' expression on line 11 with a 'case' expression or function clauses.", \ 'src/foo.erl:20:no_debug_call:Remove the debug call to io:format/1 on line 20.', \ ]) Execute(Line length message shouldn't contain the line itself): AssertEqual \ [ \ { \ 'lnum': 24, \ 'text': 'Line 24 is too long.', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ ], \ ale_linters#erlang#elvis#Handle(bufnr(''), [ \ 'src/foo.erl:24:line_length:Line 24 is too long: io:format("Look ma, too long!"),.', \ ]) ================================================ FILE: test/handler/test_eslint_handler.vader ================================================ Before: Save g:ale_javascript_eslint_suppress_eslintignore Save g:ale_javascript_eslint_suppress_missing_config Save g:ale_warn_about_trailing_whitespace Save g:ale_warn_about_trailing_blank_lines let g:ale_javascript_eslint_suppress_eslintignore = 0 let g:ale_javascript_eslint_suppress_missing_config = 0 let g:ale_warn_about_trailing_whitespace = 1 let g:ale_warn_about_trailing_blank_lines = 1 unlet! b:ale_warn_about_trailing_whitespace unlet! b:ale_warn_about_trailing_blank_lines After: Restore unlet! b:ale_javascript_eslint_suppress_eslintignore unlet! b:ale_javascript_eslint_suppress_missing_config unlet! b:ale_warn_about_trailing_whitespace unlet! b:ale_warn_about_trailing_blank_lines unlet! g:config_error_lines Execute(The eslint handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 47, \ 'col': 14, \ 'text': 'Missing trailing comma.', \ 'code': 'comma-dangle', \ 'type': 'W', \ }, \ { \ 'lnum': 56, \ 'col': 41, \ 'text': 'Missing semicolon.', \ 'code': 'semi', \ 'type': 'E', \ }, \ { \ 'lnum': 13, \ 'col': 3, \ 'text': 'Parsing error: Unexpected token', \ 'type': 'E', \ }, \ ], \ ale#handlers#eslint#Handle(bufnr(''), [ \ 'This line should be ignored completely', \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ 'This line should be ignored completely', \ '/path/to/some-filename.js:13:3: Parsing error: Unexpected token', \ ]) Execute(The eslint handler should print a message about a missing configuration file): let g:config_error_lines = [ \ '', \ 'Oops! Something went wrong! :(', \ '', \ 'ESLint couldn''t find a configuration file. To set up a configuration file for this project, please run:', \ ' eslint --init', \ '', \ 'ESLint looked for configuration files in /some/path/or/other and its ancestors.', \ '', \ 'If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://gitter.im/eslint/eslint', \ '', \ ] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should allow the missing config error to be suppressed): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ '', \ 'Oops! Something went wrong! :(', \ '', \ 'ESLint couldn''t find a configuration file. To set up a configuration file for this project, please run:', \ ' eslint --init', \ '', \ 'ESLint looked for configuration files in /some/path/or/other and its ancestors.', \ '', \ 'If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://gitter.im/eslint/eslint', \ '', \ ] AssertEqual \ [], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should print a message for config parsing errors): let g:config_error_lines = [ \ 'Cannot read config file: /some/path/or/other/.eslintrc.js', \ 'Error: Unexpected token <<', \ '/some/path/or/other/.eslintrc.js:1', \ '(function (exports, require, module, __filename, __dirname) { <<<>>>', \ ' ^^', \ 'SyntaxError: Unexpected token <<', \ ' at Object.exports.runInThisContext (vm.js:76:16)', \ ' at Module._compile (module.js:528:28)', \ ' at Object.Module._extensions..js (module.js:565:10)', \ ' at Module.load (module.js:473:32)', \ ' at tryModuleLoad (module.js:432:12)', \ ' at Function.Module._load (module.js:424:3)', \ ' at Module.require (module.js:483:17)', \ ' at require (internal/module.js:20:19)', \ ' at module.exports (/usr/local/lib/node_modules/eslint/node_modules/require-uncached/index.js:14:12)', \ ' at loadJSConfigFile (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:160:16)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(Suppressing missing configs shouldn't suppress parsing errors): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ 'Cannot read config file: /some/path/or/other/.eslintrc.js', \ 'Error: Unexpected token <<', \ '/some/path/or/other/.eslintrc.js:1', \ '(function (exports, require, module, __filename, __dirname) { <<<>>>', \ ' ^^', \ 'SyntaxError: Unexpected token <<', \ ' at Object.exports.runInThisContext (vm.js:76:16)', \ ' at Module._compile (module.js:528:28)', \ ' at Object.Module._extensions..js (module.js:565:10)', \ ' at Module.load (module.js:473:32)', \ ' at tryModuleLoad (module.js:432:12)', \ ' at Function.Module._load (module.js:424:3)', \ ' at Module.require (module.js:483:17)', \ ' at require (internal/module.js:20:19)', \ ' at module.exports (/usr/local/lib/node_modules/eslint/node_modules/require-uncached/index.js:14:12)', \ ' at loadJSConfigFile (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:160:16)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should print a message for invalid configuration settings): let g:config_error_lines = [ \ '/home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ 'Error: /home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ ' at validateRuleOptions (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:115:15)', \ ' at /usr/local/lib/node_modules/eslint/lib/config/config-validator.js:162:13', \ ' at Array.forEach (native)', \ ' at Object.validate (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:161:35)', \ ' at Object.load (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:522:19)', \ ' at loadConfig (/usr/local/lib/node_modules/eslint/lib/config.js:63:33)', \ ' at getLocalConfig (/usr/local/lib/node_modules/eslint/lib/config.js:130:29)', \ ' at Config.getConfig (/usr/local/lib/node_modules/eslint/lib/config.js:256:22)', \ ' at processText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:224:33)', \ ' at CLIEngine.executeOnText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:756:26)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(Suppressing missing configs shouldn't suppress invalid config errors): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ '/home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ 'Error: /home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ ' at validateRuleOptions (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:115:15)', \ ' at /usr/local/lib/node_modules/eslint/lib/config/config-validator.js:162:13', \ ' at Array.forEach (native)', \ ' at Object.validate (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:161:35)', \ ' at Object.load (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:522:19)', \ ' at loadConfig (/usr/local/lib/node_modules/eslint/lib/config.js:63:33)', \ ' at getLocalConfig (/usr/local/lib/node_modules/eslint/lib/config.js:130:29)', \ ' at Config.getConfig (/usr/local/lib/node_modules/eslint/lib/config.js:256:22)', \ ' at processText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:224:33)', \ ' at CLIEngine.executeOnText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:756:26)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should print a message when import is not used in a module): let g:config_error_lines = [ \ 'ImportDeclaration should appear when the mode is ES6 and in the module context.', \ 'AssertionError: ImportDeclaration should appear when the mode is ES6 and in the module context.', \ ' at Referencer.ImportDeclaration (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:597:9)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Referencer.Visitor.visitChildren (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:101:38)', \ ' at Referencer.Program (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:449:14)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Object.analyze (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/index.js:138:16)', \ ' at EventEmitter.module.exports.api.verify (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/eslint.js:887:40)', \ ' at processText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:278:31)', \ ' at CLIEngine.executeOnText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:734:26)', \ ' at Object.execute (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli.js:171:42) ', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(Suppressing missing configs shouldn't suppress module import errors): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ 'ImportDeclaration should appear when the mode is ES6 and in the module context.', \ 'AssertionError: ImportDeclaration should appear when the mode is ES6 and in the module context.', \ ' at Referencer.ImportDeclaration (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:597:9)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Referencer.Visitor.visitChildren (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:101:38)', \ ' at Referencer.Program (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:449:14)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Object.analyze (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/index.js:138:16)', \ ' at EventEmitter.module.exports.api.verify (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/eslint.js:887:40)', \ ' at processText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:278:31)', \ ' at CLIEngine.executeOnText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:734:26)', \ ' at Object.execute (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli.js:171:42) ', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#Handle(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should output end_col values where appropriate): AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 3, \ 'end_col': 15, \ 'text': 'Parsing error: Unexpected token ''some string''', \ 'type': 'E', \ }, \ { \ 'lnum': 70, \ 'col': 3, \ 'end_col': 5, \ 'text': '''foo'' is not defined.', \ 'code': 'no-undef', \ 'type': 'E', \ }, \ { \ 'lnum': 71, \ 'col': 2, \ 'end_col': 6, \ 'text': 'Unexpected `await` inside a loop.', \ 'code': 'no-await-in-loop', \ 'type': 'E', \ }, \ { \ 'lnum': 72, \ 'col': 6, \ 'end_col': 10, \ 'text': 'Redundant use of `await` on a return value.', \ 'code': 'no-return-await', \ 'type': 'E', \ }, \ { \ 'lnum': 73, \ 'col': 4, \ 'end_col': 10, \ 'text': 'Unexpected console statement', \ 'code': 'no-console', \ 'type': 'E', \ }, \ { \ 'lnum': 74, \ 'col': 4, \ 'end_col': 11, \ 'text': 'Unexpected ''debugger'' statement.', \ 'code': 'no-debugger', \ 'type': 'E', \ }, \ ], \ ale#handlers#eslint#Handle(bufnr(''), [ \ 'app.js:4:3: Parsing error: Unexpected token ''some string'' [Error]', \ 'app.js:70:3: ''foo'' is not defined. [Error/no-undef]', \ 'app.js:71:2: Unexpected `await` inside a loop. [Error/no-await-in-loop]', \ 'app.js:72:6: Redundant use of `await` on a return value. [Error/no-return-await]', \ 'app.js:73:4: Unexpected console statement [Error/no-console]', \ 'app.js:74:4: Unexpected ''debugger'' statement. [Error/no-debugger]', \ ]) Execute(The eslint hint about using typescript-eslint-parser): silent! noautocmd file foo.ts AssertEqual \ [ \ { \ 'lnum': 451, \ 'col': 2, \ 'end_col': 2, \ 'text': 'Parsing error (You may need configure typescript-eslint-parser): Unexpected token )', \ 'type': 'E', \ }, \ ], \ ale#handlers#eslint#Handle(bufnr(''), [ \ 'foo.ts:451:2: Parsing error: Unexpected token ) [Error]', \ ]) Execute(eslint should warn about ignored files by default): AssertEqual \ [{ \ 'lnum': 0, \ 'col': 0, \ 'type': 'W', \ 'text': 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.' \ }], \ ale#handlers#eslint#Handle(bufnr(''), [ \ '/path/to/some/ignored.js:0:0: File ignored because of a matching ignore pattern. Use "--no-ignore" to override. [Warning]', \ ]) AssertEqual \ [{ \ 'lnum': 0, \ 'col': 0, \ 'type': 'W', \ 'text': 'File ignored by default. Use "--ignore-pattern ''!node_modules/*''" to override.', \ }], \ ale#handlers#eslint#Handle(bufnr(''), [ \ '/path/to/some/ignored.js:0:0: File ignored by default. Use "--ignore-pattern ''!node_modules/*''" to override. [Warning]', \ ]) Execute(eslint should not warn about ignored files when explicitly disabled): let g:ale_javascript_eslint_suppress_eslintignore = 1 AssertEqual \ [], \ ale#handlers#eslint#Handle(bufnr(''), [ \ '/path/to/some/ignored.js:0:0: File ignored because of a matching ignore pattern. Use "--no-ignore" to override. [Warning]', \ ]) AssertEqual \ [], \ ale#handlers#eslint#Handle(bufnr(''), [ \ '/path/to/some/ignored.js:0:0: File ignored by default. Use "--ignore-pattern ''!node_modules/*''" to override. [Warning]', \ ]) Execute(eslint should handle react errors correctly): AssertEqual \ [ \ { \ 'lnum': 59, \ 'col': 9, \ 'type': 'E', \ 'text': 'Property should be placed on the same line as the component declaration', \ 'code': 'react/jsx-first-prop-new-line', \ }, \ ], \ 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', \ ]) Execute(Disabling warnings about trailing spaces should work): silent! noautocmd file foo.ts AssertEqual \ [ \ { \ 'lnum': 182, \ 'col': 22, \ 'code': 'no-trailing-spaces', \ 'type': 'E', \ 'text': 'Trailing spaces not allowed.', \ }, \ ], \ ale#handlers#eslint#Handle(bufnr(''), [ \ 'foo.js:182:22: Trailing spaces not allowed. [Error/no-trailing-spaces]', \ ]) let g:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [], \ ale#handlers#eslint#Handle(bufnr(''), [ \ 'foo.js:182:22: Trailing spaces not allowed. [Error/no-trailing-spaces]', \ ]) let g:ale_warn_about_trailing_whitespace = 1 let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [], \ ale#handlers#eslint#Handle(bufnr(''), [ \ 'foo.js:182:22: Trailing spaces not allowed. [Error/no-trailing-spaces]', \ ]) ================================================ FILE: test/handler/test_eslint_json_handler.vader ================================================ Before: Save g:ale_javascript_eslint_suppress_eslintignore Save g:ale_javascript_eslint_suppress_missing_config Save g:ale_warn_about_trailing_whitespace Save g:ale_warn_about_trailing_blank_lines let g:ale_javascript_eslint_suppress_eslintignore = 0 let g:ale_javascript_eslint_suppress_missing_config = 0 let g:ale_warn_about_trailing_whitespace = 1 let g:ale_warn_about_trailing_blank_lines = 1 unlet! b:ale_warn_about_trailing_whitespace unlet! b:ale_warn_about_trailing_blank_lines After: Restore unlet! b:ale_javascript_eslint_suppress_eslintignore unlet! b:ale_javascript_eslint_suppress_missing_config unlet! b:ale_warn_about_trailing_whitespace unlet! b:ale_warn_about_trailing_blank_lines unlet! g:config_error_lines Execute(The eslint handler should parse json correctly): call ale#test#SetFilename('foo.js') AssertEqual \ [ \ { \ 'lnum': 1, \ 'end_lnum': 1, \ 'col': 7, \ 'end_col': 14, \ 'text': '''variable'' is assigned a value but never used.', \ 'code': 'no-unused-vars', \ 'type': 'W', \ }, \ { \ 'lnum': 5, \ 'col': 15, \ 'text': 'Missing semicolon.', \ 'code': 'semi', \ 'type': 'W', \ }, \ { \ 'lnum': 7, \ 'end_lnum': 7, \ 'col': 7, \ 'end_col': 14, \ 'text': '''variable'' is already defined.', \ 'code': 'no-redeclare', \ 'type': 'E', \ }, \ ], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"foo.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"''variable'' is assigned a value but never used.","line":1,"column":7,"nodeType":"Identifier","endLine":1,"endColumn":15},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":5,"column":15,"nodeType":"ExpressionStatement","fix":{"range":[46,46],"text":";"}},{"ruleId":"no-redeclare","severity":2,"message":"''variable'' is already defined.","line":7,"column":7,"nodeType":"Identifier","endLine":7,"endColumn":15}],"errorCount":1,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":1,"source":"const variable = {\n a: 3\n};\n\nconsole.log(1)\n\nclass variable {\n}\n"}]' \ ]) Execute(The eslint handler should suppress deprecation warnings): call ale#test#SetFilename('foo.js') AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 9, \ 'text': 'Parsing error: Unexpected token Controller', \ 'type': 'E', \ } \ ], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"foo.js","messages":[{"ruleId":null,"fatal":true,"severity":2 ,"message":"Parsing error: Unexpected token Controller","line":1,"column":9}],"errorCount":1,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount": 0,"source":"i:mport Controller from \"@ember/controller\";\nimport listViewControllerMixin from \"elearning/mixins/list-view-controller\";\nimport { inject as service } from \"@ember/service\";\n\nexport default Controller.extend(listViewControllerMixin(), {\n modelName: \"notification\",\n intl: service(),\n\n flatpickrLocale: computed(\"intl.locale\", function() {\n return this.intl.locale.firstObject.split(\"-\")[0];\n })\n});\n"}]', '(node:616989) [ESLINT_LEGACY_OBJECT_REST_SPREAD] DeprecationWarning: The ''parserOptions.ecmaFeatures.experimentalObjectRestSpread'' option is deprecated. Use ''parser Options.ecmaVersion'' instead. (found in "node_modules/eslint-plugin-ember/lib/config/base.js")]' \ ]) Execute(The eslint handler should print a message about a missing configuration file): let g:config_error_lines = [ \ '', \ 'Oops! Something went wrong! :(', \ '', \ 'ESLint couldn''t find a configuration file. To set up a configuration file for this project, please run:', \ ' eslint --init', \ '', \ 'ESLint looked for configuration files in /some/path/or/other and its ancestors.', \ '', \ 'If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://gitter.im/eslint/eslint', \ '', \ ] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should allow the missing config error to be suppressed): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ '', \ 'Oops! Something went wrong! :(', \ '', \ 'ESLint couldn''t find a configuration file. To set up a configuration file for this project, please run:', \ ' eslint --init', \ '', \ 'ESLint looked for configuration files in /some/path/or/other and its ancestors.', \ '', \ 'If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://gitter.im/eslint/eslint', \ '', \ ] AssertEqual \ [], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should print a message for config parsing errors): let g:config_error_lines = [ \ 'Cannot read config file: /some/path/or/other/.eslintrc.js', \ 'Error: Unexpected token <<', \ '/some/path/or/other/.eslintrc.js:1', \ '(function (exports, require, module, __filename, __dirname) { <<<>>>', \ ' ^^', \ 'SyntaxError: Unexpected token <<', \ ' at Object.exports.runInThisContext (vm.js:76:16)', \ ' at Module._compile (module.js:528:28)', \ ' at Object.Module._extensions..js (module.js:565:10)', \ ' at Module.load (module.js:473:32)', \ ' at tryModuleLoad (module.js:432:12)', \ ' at Function.Module._load (module.js:424:3)', \ ' at Module.require (module.js:483:17)', \ ' at require (internal/module.js:20:19)', \ ' at module.exports (/usr/local/lib/node_modules/eslint/node_modules/require-uncached/index.js:14:12)', \ ' at loadJSConfigFile (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:160:16)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(Suppressing missing configs shouldn't suppress parsing errors): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ 'Cannot read config file: /some/path/or/other/.eslintrc.js', \ 'Error: Unexpected token <<', \ '/some/path/or/other/.eslintrc.js:1', \ '(function (exports, require, module, __filename, __dirname) { <<<>>>', \ ' ^^', \ 'SyntaxError: Unexpected token <<', \ ' at Object.exports.runInThisContext (vm.js:76:16)', \ ' at Module._compile (module.js:528:28)', \ ' at Object.Module._extensions..js (module.js:565:10)', \ ' at Module.load (module.js:473:32)', \ ' at tryModuleLoad (module.js:432:12)', \ ' at Function.Module._load (module.js:424:3)', \ ' at Module.require (module.js:483:17)', \ ' at require (internal/module.js:20:19)', \ ' at module.exports (/usr/local/lib/node_modules/eslint/node_modules/require-uncached/index.js:14:12)', \ ' at loadJSConfigFile (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:160:16)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should print a message for invalid configuration settings): let g:config_error_lines = [ \ '/home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ 'Error: /home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ ' at validateRuleOptions (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:115:15)', \ ' at /usr/local/lib/node_modules/eslint/lib/config/config-validator.js:162:13', \ ' at Array.forEach (native)', \ ' at Object.validate (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:161:35)', \ ' at Object.load (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:522:19)', \ ' at loadConfig (/usr/local/lib/node_modules/eslint/lib/config.js:63:33)', \ ' at getLocalConfig (/usr/local/lib/node_modules/eslint/lib/config.js:130:29)', \ ' at Config.getConfig (/usr/local/lib/node_modules/eslint/lib/config.js:256:22)', \ ' at processText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:224:33)', \ ' at CLIEngine.executeOnText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:756:26)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(Suppressing missing configs shouldn't suppress invalid config errors): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ '/home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ 'Error: /home/w0rp/git/wazoku/wazoku-spotlight/.eslintrc.js:', \ ' Configuration for rule "indent" is invalid:', \ ' Value "off" is the wrong type.', \ '', \ ' at validateRuleOptions (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:115:15)', \ ' at /usr/local/lib/node_modules/eslint/lib/config/config-validator.js:162:13', \ ' at Array.forEach (native)', \ ' at Object.validate (/usr/local/lib/node_modules/eslint/lib/config/config-validator.js:161:35)', \ ' at Object.load (/usr/local/lib/node_modules/eslint/lib/config/config-file.js:522:19)', \ ' at loadConfig (/usr/local/lib/node_modules/eslint/lib/config.js:63:33)', \ ' at getLocalConfig (/usr/local/lib/node_modules/eslint/lib/config.js:130:29)', \ ' at Config.getConfig (/usr/local/lib/node_modules/eslint/lib/config.js:256:22)', \ ' at processText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:224:33)', \ ' at CLIEngine.executeOnText (/usr/local/lib/node_modules/eslint/lib/cli-engine.js:756:26)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should print a message when import is not used in a module): let g:config_error_lines = [ \ 'ImportDeclaration should appear when the mode is ES6 and in the module context.', \ 'AssertionError: ImportDeclaration should appear when the mode is ES6 and in the module context.', \ ' at Referencer.ImportDeclaration (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:597:9)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Referencer.Visitor.visitChildren (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:101:38)', \ ' at Referencer.Program (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:449:14)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Object.analyze (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/index.js:138:16)', \ ' at EventEmitter.module.exports.api.verify (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/eslint.js:887:40)', \ ' at processText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:278:31)', \ ' at CLIEngine.executeOnText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:734:26)', \ ' at Object.execute (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli.js:171:42) ', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(Suppressing missing configs shouldn't suppress module import errors): let b:ale_javascript_eslint_suppress_missing_config = 1 let g:config_error_lines = [ \ 'ImportDeclaration should appear when the mode is ES6 and in the module context.', \ 'AssertionError: ImportDeclaration should appear when the mode is ES6 and in the module context.', \ ' at Referencer.ImportDeclaration (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:597:9)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Referencer.Visitor.visitChildren (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:101:38)', \ ' at Referencer.Program (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/referencer.js:449:14)', \ ' at Referencer.Visitor.visit (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/esrecurse/esrecurse.js:122:34)', \ ' at Object.analyze (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint-scope/lib/index.js:138:16)', \ ' at EventEmitter.module.exports.api.verify (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/eslint.js:887:40)', \ ' at processText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:278:31)', \ ' at CLIEngine.executeOnText (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli-engine.js:734:26)', \ ' at Object.execute (/home/w0rp/git/wazoku/wazoku-spotlight/spotlight/static/node_modules/eslint/lib/cli.js:171:42) ', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'eslint configuration error (type :ALEDetail for more information)', \ 'detail': join(g:config_error_lines, "\n"), \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), g:config_error_lines[:]) Execute(The eslint handler should hint about using typescript-eslint-parser): call ale#test#SetFilename('foo.ts') AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'Parsing error (You may need configure typescript-eslint-parser): The keyword ''interface'' is reserved', \ 'type': 'E', \ }, \ ], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"foo.ts","messages":[{"ruleId":null,"fatal":true,"severity":2,"message":"Parsing error: The keyword ''interface'' is reserved","line":2,"column":1}],"errorCount":1,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\ninterface test {}\n"}]', \ ]) Execute(eslint should warn about ignored files by default): AssertEqual \ [{ \ 'lnum': 0, \ 'type': 'W', \ 'text': 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.' \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"/path/to/some/ignored/file.js","messages":[{"fatal":false,"severity":1,"message":"File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override."}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0}]', \ ]) AssertEqual \ [{ \ 'lnum': 0, \ 'type': 'W', \ 'text': 'File ignored by default. Use "--ignore-pattern ''!node_modules/*''" to override.', \ }], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"/path/to/some/ignored/file.js","messages":[{"fatal":false,"severity":1,"message":"File ignored by default. Use \"--ignore-pattern ''!node_modules/*''\" to override."}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0}]', \ ]) Execute(eslint should not warn about ignored files when explicitly disabled): let g:ale_javascript_eslint_suppress_eslintignore = 1 AssertEqual \ [], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"/path/to/some/ignored/file.js","messages":[{"fatal":false,"severity":1,"message":"File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override."}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0}]', \ ]) AssertEqual \ [], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"/path/to/some/ignored/file.js","messages":[{"fatal":false,"severity":1,"message":"File ignored by default. Use \"--ignore-pattern ''!node_modules/*''\" to override."}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0}]', \ ]) 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#HandleJSON(bufnr(''), [ \ 'Could not connect', \ ]) Execute(Disabling warnings about trailing spaces should work): call ale#test#SetFilename('foo.js') AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 16, \ 'code': 'no-trailing-spaces', \ 'type': 'W', \ 'text': 'Trailing spaces not allowed.', \ }, \ ], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"foo.js","messages":[{"ruleId":"no-trailing-spaces","severity":1,"message":"Trailing spaces not allowed.","line":2,"column":16,"nodeType":"Program","fix":{"range":[16,17],"text":""}}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":1,"source":"\nconsole.log(1); \n"}]' \ ]) let g:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"foo.js","messages":[{"ruleId":"no-trailing-spaces","severity":1,"message":"Trailing spaces not allowed.","line":2,"column":16,"nodeType":"Program","fix":{"range":[16,17],"text":""}}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":1,"source":"\nconsole.log(1); \n"}]' \ ]) let g:ale_warn_about_trailing_whitespace = 1 let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [], \ ale#handlers#eslint#HandleJSON(bufnr(''), [ \ '[{"filePath":"foo.js","messages":[{"ruleId":"no-trailing-spaces","severity":1,"message":"Trailing spaces not allowed.","line":2,"column":16,"nodeType":"Program","fix":{"range":[16,17],"text":""}}],"errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":1,"source":"\nconsole.log(1); \n"}]' \ ]) ================================================ FILE: test/handler/test_fecs_handler.vader ================================================ Before: runtime autoload/ale/handlers/fecs.vim After: call ale#linter#Reset() Execute(fecs should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 20, \ 'col': 25, \ 'text': 'Unexpected console statement.', \ 'code': 'no-console', \ 'type': 'W', \ }, \ { \ 'lnum': 24, \ 'col': 36, \ 'text': 'Missing radix parameter.', \ 'code': 'radix', \ 'type': 'E', \ }, \ { \ 'lnum': 25, \ 'col': 6, \ 'text': 'Missing static property value.', \ 'type': 'E', \ }, \ ], \ ale#handlers#fecs#Handle(347, [ \ 'fecs WARN → line 20, col 25: Unexpected console statement. (no-console)', \ 'fecs ERROR → line 24, col 36: Missing radix parameter. (radix)', \ 'fecs ERROR → line 25, col 6: Missing static property value.', \ ]) ================================================ FILE: test/handler/test_fish_handler.vader ================================================ Before: runtime ale_linters/fish/fish.vim After: call ale#linter#Reset() Execute(The fish handler should handle basic warnings and syntax errors): AssertEqual \ [ \ { \ 'lnum': 20, \ 'col': 23, \ 'text': "Unsupported use of '||'. In fish, please use 'COMMAND; or COMMAND'.", \ }, \ { \ 'lnum': 26, \ 'col': 7, \ 'text': "Illegal command name '(prompt_pwd)'", \ }, \ { \ 'lnum': 36, \ 'col': 1, \ 'text': "'end' outside of a block", \ }, \ ], \ ale_linters#fish#fish#Handle(1, [ \ "fish_prompt.fish (line 20): Unsupported use of '||'. In fish, please use 'COMMAND; or COMMAND'.", \ 'if set -q SSH_CLIENT || set -q SSH_TTY', \ ' ^', \ "fish_prompt.fish (line 26): Illegal command name '(prompt_pwd)'", \ ' (prompt_pwd) \', \ ' ^', \ "fish_prompt.fish (line 36): 'end' outside of a block", \ 'end', \ '^', \ 'config.fish (line 45):', \ "abbr --add p 'cd ~/Projects'", \ '^', \ ]) Execute(The fish handler should handle problems where the problem before before the line with the line number): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 23, \ 'text': 'Unsupported use of ''||''. In fish, please use ''COMMAND; or COMMAND''.', \ }, \ { \ 'lnum': 5, \ 'col': 1, \ 'text': 'wat', \ }, \ ], \ ale_linters#fish#fish#Handle(bufnr(''), [ \ 'Unsupported use of ''||''. In fish, please use ''COMMAND; or COMMAND''.', \ '/tmp/vLz620o/258/test.fish (line 2): if set -q SSH_CLIENT || set -q SSH_TTY', \ ' ^', \ '/tmp/vLz620o/258/test.fish (line 5): wat', \ ' ^', \ ]) ================================================ FILE: test/handler/test_flake8_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_blank_lines Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_blank_lines = 1 let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/flake8.vim After: Restore unlet! b:ale_warn_about_trailing_blank_lines unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute(The flake8 handler should handle basic warnings and syntax errors): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 6, \ 'vcol': 1, \ 'type': 'E', \ 'text': 'indentation is not a multiple of four', \ 'code': 'E111', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 7, \ 'col': 6, \ 'vcol': 1, \ 'type': 'W', \ 'text': 'some warning', \ 'code': 'W123', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 8, \ 'col': 3, \ 'vcol': 1, \ 'type': 'E', \ 'text': 'SyntaxError: invalid syntax', \ 'code': 'E999', \ }, \ ], \ ale_linters#python#flake8#Handle(1, [ \ 'stdin:6:6: E111 indentation is not a multiple of four', \ 'stdin:7:6: W123 some warning', \ 'stdin:8:3: E999 SyntaxError: invalid syntax', \ ]) Execute(The flake8 handler should set end column indexes for certain errors): AssertEqual \ [ \ { \ 'lnum': 25, \ 'col': 1, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 3, \ 'text': 'undefined name ''foo''', \ 'code': 'F821', \ }, \ { \ 'lnum': 28, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 9, \ 'text': 'hello may be undefined, or defined from star imports: x', \ 'code': 'F405', \ }, \ { \ 'lnum': 104, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 12, \ 'text': '''continue'' not properly in loop', \ 'code': 'F999', \ }, \ { \ 'lnum': 106, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 9, \ 'text': '''break'' outside loop', \ 'code': 'F999', \ }, \ { \ 'lnum': 109, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 8, \ 'text': 'local variable ''test'' is assigned to but never used', \ 'code': 'F841', \ }, \ ], \ ale_linters#python#flake8#Handle(1, [ \ 'foo.py:25:1: F821 undefined name ''foo''', \ 'foo.py:28:5: F405 hello may be undefined, or defined from star imports: x', \ 'foo.py:104:5: F999 ''continue'' not properly in loop', \ 'foo.py:106:5: F999 ''break'' outside loop', \ 'foo.py:109:5: F841 local variable ''test'' is assigned to but never used', \ ]) Execute(The flake8 handler should handle stack traces): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': 'ImportError: No module named parser (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "/usr/local/bin/flake8", line 7, in ', \ ' from flake8.main.cli import main', \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/cli.py", line 2, in ', \ ' from flake8.main import application', \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/application.py", line 17, in ', \ ' from flake8.plugins import manager as plugin_manager', \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/plugins/manager.py", line 5, in ', \ ' import pkg_resources', \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', \ ' import email.parser', \ 'ImportError: No module named parser', \ ], "\n"), \ }, \ ], \ ale_linters#python#flake8#Handle(42, [ \ 'Traceback (most recent call last):', \ ' File "/usr/local/bin/flake8", line 7, in ', \ ' from flake8.main.cli import main', \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/cli.py", line 2, in ', \ ' from flake8.main import application', \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/main/application.py", line 17, in ', \ ' from flake8.plugins import manager as plugin_manager', \ ' File "/usr/local/lib/python2.7/dist-packages/flake8/plugins/manager.py", line 5, in ', \ ' import pkg_resources', \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', \ ' import email.parser', \ 'ImportError: No module named parser', \ ]) Execute(The flake8 handler should handle names with spaces): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 6, \ 'vcol': 1, \ 'type': 'E', \ 'text': 'indentation is not a multiple of four', \ 'code': 'E111', \ 'sub_type': 'style', \ }, \ ], \ ale_linters#python#flake8#Handle(42, [ \ 'C:\something\with spaces.py:6:6: E111 indentation is not a multiple of four', \ ]) Execute(Warnings about trailing whitespace should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'W291', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'who cares', \ }, \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'W293', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'who cares', \ }, \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: W291 who cares', \ 'foo.py:6:1: W293 who cares', \ ]) Execute(Disabling trailing whitespace warnings should work): let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: W291 who cares', \ 'foo.py:6:1: W293 who cares', \ ]) Execute(Warnings about trailing blank lines should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'W391', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'blank line at end of file', \ }, \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) Execute(Disabling trailing blank line warnings should work): let b:ale_warn_about_trailing_blank_lines = 0 AssertEqual \ [ \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) Execute(F401 should be a warning): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'F401', \ 'type': 'W', \ 'text': 'module imported but unused', \ }, \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: F401 module imported but unused', \ ]) Execute(E112 should be a syntax error): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'E112', \ 'type': 'E', \ 'text': 'expected an indented block', \ }, \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: E112 expected an indented block', \ ]) Execute(Compatibility with hacking which uses older style flake8): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'H306', \ 'type': 'W', \ 'text': 'imports not in alphabetical order (smtplib, io)', \ }, \ ], \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: H306: imports not in alphabetical order (smtplib, io)', \ ]) ================================================ FILE: test/handler/test_flakehell_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_blank_lines Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_blank_lines = 1 let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/flakehell.vim After: Restore unlet! b:ale_warn_about_trailing_blank_lines unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute(The flakehell handler should handle basic warnings and syntax errors): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 6, \ 'vcol': 1, \ 'type': 'E', \ 'text': 'indentation is not a multiple of four', \ 'code': 'E111', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 7, \ 'col': 6, \ 'vcol': 1, \ 'type': 'W', \ 'text': 'some warning', \ 'code': 'W123', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 8, \ 'col': 3, \ 'vcol': 1, \ 'type': 'E', \ 'text': 'SyntaxError: invalid syntax', \ 'code': 'E999', \ }, \ ], \ ale_linters#python#flakehell#Handle(1, [ \ 'stdin:6:6: E111 indentation is not a multiple of four', \ 'stdin:7:6: W123 some warning', \ 'stdin:8:3: E999 SyntaxError: invalid syntax', \ ]) Execute(The flakehell handler should set end column indexes for certain errors): AssertEqual \ [ \ { \ 'lnum': 25, \ 'col': 1, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 3, \ 'text': 'undefined name ''foo''', \ 'code': 'F821', \ }, \ { \ 'lnum': 28, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 9, \ 'text': 'hello may be undefined, or defined from star imports: x', \ 'code': 'F405', \ }, \ { \ 'lnum': 104, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 12, \ 'text': '''continue'' not properly in loop', \ 'code': 'F999', \ }, \ { \ 'lnum': 106, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 9, \ 'text': '''break'' outside loop', \ 'code': 'F999', \ }, \ { \ 'lnum': 109, \ 'col': 5, \ 'vcol': 1, \ 'type': 'E', \ 'end_col': 8, \ 'text': 'local variable ''test'' is assigned to but never used', \ 'code': 'F841', \ }, \ ], \ ale_linters#python#flakehell#Handle(1, [ \ 'foo.py:25:1: F821 undefined name ''foo''', \ 'foo.py:28:5: F405 hello may be undefined, or defined from star imports: x', \ 'foo.py:104:5: F999 ''continue'' not properly in loop', \ 'foo.py:106:5: F999 ''break'' outside loop', \ 'foo.py:109:5: F841 local variable ''test'' is assigned to but never used', \ ]) Execute(The flakehell handler should handle stack traces): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': 'ImportError: No module named parser (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "/usr/local/bin/flakehell", line 7, in ', \ ' from flakehell.main.cli import main', \ ' File "/usr/local/lib/python2.7/dist-packages/flakehell/main/cli.py", line 2, in ', \ ' from flakehell.main import application', \ ' File "/usr/local/lib/python2.7/dist-packages/flakehell/main/application.py", line 17, in ', \ ' from flakehell.plugins import manager as plugin_manager', \ ' File "/usr/local/lib/python2.7/dist-packages/flakehell/plugins/manager.py", line 5, in ', \ ' import pkg_resources', \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', \ ' import email.parser', \ 'ImportError: No module named parser', \ ], "\n"), \ }, \ ], \ ale_linters#python#flakehell#Handle(42, [ \ 'Traceback (most recent call last):', \ ' File "/usr/local/bin/flakehell", line 7, in ', \ ' from flakehell.main.cli import main', \ ' File "/usr/local/lib/python2.7/dist-packages/flakehell/main/cli.py", line 2, in ', \ ' from flakehell.main import application', \ ' File "/usr/local/lib/python2.7/dist-packages/flakehell/main/application.py", line 17, in ', \ ' from flakehell.plugins import manager as plugin_manager', \ ' File "/usr/local/lib/python2.7/dist-packages/flakehell/plugins/manager.py", line 5, in ', \ ' import pkg_resources', \ ' File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 35, in ', \ ' import email.parser', \ 'ImportError: No module named parser', \ ]) Execute(The flakehell handler should handle names with spaces): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 6, \ 'vcol': 1, \ 'type': 'E', \ 'text': 'indentation is not a multiple of four', \ 'code': 'E111', \ 'sub_type': 'style', \ }, \ ], \ ale_linters#python#flakehell#Handle(42, [ \ 'C:\something\with spaces.py:6:6: E111 indentation is not a multiple of four', \ ]) Execute(Warnings about trailing whitespace should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'W291', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'who cares', \ }, \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'W293', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'who cares', \ }, \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: W291 who cares', \ 'foo.py:6:1: W293 who cares', \ ]) Execute(Disabling trailing whitespace warnings should work): let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: W291 who cares', \ 'foo.py:6:1: W293 who cares', \ ]) Execute(Warnings about trailing blank lines should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'W391', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'blank line at end of file', \ }, \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) Execute(Disabling trailing blank line warnings should work): let b:ale_warn_about_trailing_blank_lines = 0 AssertEqual \ [ \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) Execute(F401 should be a warning): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'F401', \ 'type': 'W', \ 'text': 'module imported but unused', \ }, \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: F401 module imported but unused', \ ]) Execute(E112 should be a syntax error): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'E112', \ 'type': 'E', \ 'text': 'expected an indented block', \ }, \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: E112 expected an indented block', \ ]) Execute(Compatibility with hacking which uses older style flakehell): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'vcol': 1, \ 'code': 'H306', \ 'type': 'W', \ 'text': 'imports not in alphabetical order (smtplib, io)', \ }, \ ], \ ale_linters#python#flakehell#Handle(bufnr(''), [ \ 'foo.py:6:1: H306: imports not in alphabetical order (smtplib, io)', \ ]) ================================================ FILE: test/handler/test_flawfinder_handler.vader ================================================ Before: Save b:ale_c_flawfinder_error_severity runtime ale_linters/c/flawfinder.vim After: Restore call ale#linter#Reset() Execute(The Flawfinder handler should work): AssertEqual \ [ \ { \ 'lnum': 31, \ 'col': 4, \ 'type': 'W', \ 'text': "(buffer) strncpy: Easily used incorrectly", \ }, \ ], \ ale#handlers#flawfinder#HandleFlawfinderFormat(347, [ \ ':31:4: [1] (buffer) strncpy:Easily used incorrectly', \ 'foo', \ 'bar', \ 'baz', \ ]) Execute(The Flawfinder error severity level should be configurable): let b:ale_c_flawfinder_error_severity = 2 AssertEqual \ [ \ { \ 'lnum': 12, \ 'col': 4, \ 'type': 'E', \ 'text': "(buffer) char: Statically-sized arrays can be bad", \ }, \ { \ 'lnum': 31, \ 'col': 4, \ 'type': 'W', \ 'text': "(buffer) strncpy: Easily used incorrectly", \ }, \ ], \ ale#handlers#flawfinder#HandleFlawfinderFormat(bufnr(''), [ \ ':12:4: [2] (buffer) char:Statically-sized arrays can be bad', \ ':31:4: [1] (buffer) strncpy:Easily used incorrectly', \ ]) ================================================ FILE: test/handler/test_flow_handler.vader ================================================ Before: runtime ale_linters/javascript/flow.vim After: unlet! g:flow_output unlet! g:expected unlet! g:actual call ale#linter#Reset() Execute(The flow handler should throw away non-JSON lines): AssertEqual \ [], \ ale_linters#javascript#flow#Handle(bufnr(''), [ \ 'Already up-to-date.', \ '{"flowVersion":"0.50.0","errors":[],"passed":true}', \ ]) AssertEqual \ [], \ ale_linters#javascript#flow#Handle(bufnr(''), [ \ 'foo', \ 'bar', \ 'baz', \ '{"flowVersion":"0.50.0","errors":[],"passed":true}', \ ]) Execute(The flow handler should process errors correctly.): silent! noautocmd file /home/w0rp/Downloads/graphql-js/src/language/parser.js let g:flow_output = { \ "flowVersion": "0.39.0", \ "errors": [ \ { \ "kind": "infer", \ "level": "error", \ "message": [ \ { \ "context": " return 1", \ "descr": "number", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 417, \ "column": 10, \ "offset": 9503 \ }, \ "end": { \ "line": 417, \ "column": 10, \ "offset": 9504 \ } \ }, \ "path": expand('%:p'), \ "line": 417, \ "endline": 417, \ "start": 10, \ "end": 10 \ }, \ { \ "context": v:null, \ "descr": "This type is incompatible with the expected return type of", \ "type": "Comment", \ "path": "", \ "line": 0, \ "endline": 0, \ "start": 1, \ "end": 0 \ }, \ { \ "context": "function parseArguments(lexer: Lexer<*>): Array {", \ "descr": "array type", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 416, \ "column": 43, \ "offset": 9472 \ }, \ "end": { \ "line": 416, \ "column": 61, \ "offset": 9491 \ } \ }, \ "path": expand('%:p'), \ "line": 416, \ "endline": 416, \ "start": 43, \ "end": 61 \ } \ ] \ }, \ { \ "kind": "infer", \ "level": "warning", \ "message": [ \ { \ "context": " return peek(lexer, TokenKind.PAREN_L) ?", \ "descr": "unreachable code", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 419, \ "column": 3, \ "offset": 9508 \ }, \ "end": { \ "line": 421, \ "column": 7, \ "offset": 9626 \ } \ }, \ "path": expand('%:p'), \ "line": 419, \ "endline": 421, \ "start": 3, \ "end": 7 \ } \ ] \ } \ ], \ "passed": v:false \} let g:actual = ale_linters#javascript#flow#Handle(bufnr(''), [json_encode(g:flow_output)]) let g:expected = [ \ { \ 'lnum': 417, \ 'type': 'E', \ 'col': 10, \ 'text': 'number: This type is incompatible with the expected return type of array type', \ }, \ { \ 'lnum': 419, \ 'type': 'W', \ 'col': 3, \ 'text': 'unreachable code:', \ }, \] AssertEqual g:expected, g:actual Execute(The flow handler should fetch the correct location for the currently opened file, even when it's not in the first message.): silent! noautocmd file /Users/rav/Projects/vim-ale-flow/index.js let g:flow_output = { \ "flowVersion": "0.44.0", \ "errors": [{ \ "operation": { \ "context": " , document.getElementById('foo')", \ "descr": "React element `Foo`", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 6, \ "column": 3, \ "offset": 92 \ }, \ "end": { \ "line": 6, \ "column": 18, \ "offset": 108 \ } \ }, \ "path": expand('%:p'), \ "line": 6, \ "endline": 6, \ "start": 3, \ "end": 18 \ }, \ "kind": "infer", \ "level": "error", \ "message": [{ \ "context": "module.exports = function(props: Props) {", \ "descr": "property `bar`", \ "type": "Blame", \ "loc": { \ "source": "/Users/rav/Projects/vim-ale-flow/foo.js", \ "type": "SourceFile", \ "start": { \ "line": 9, \ "column": 34, \ "offset": 121 \ }, \ "end": { \ "line": 9, \ "column": 38, \ "offset": 126 \ } \ }, \ "path": "/Users/rav/Projects/vim-ale-flow/foo.js", \ "line": 9, \ "endline": 9, \ "start": 34, \ "end": 38 \ }, { \ "context": v:null, \ "descr": "Property not found in", \ "type": "Comment", \ "path": "", \ "line": 0, \ "endline": 0, \ "start": 1, \ "end": 0 \ }, { \ "context": " , document.getElementById('foo')", \ "descr": "props of React element `Foo`", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 6, \ "column": 3, \ "offset": 92 \ }, \ "end": { \ "line": 6, \ "column": 18, \ "offset": 108 \ } \ }, \ "path": expand('%:p'), \ "line": 6, \ "endline": 6, \ "start": 3, \ "end": 18 \ }] \ }], \ "passed": v:false \} let g:actual = ale_linters#javascript#flow#Handle(bufnr(''), [json_encode(g:flow_output)]) let g:expected = [ \ { \ 'lnum': 6, \ 'col': 3, \ 'type': 'E', \ 'text': 'property `bar`: Property not found in props of React element `Foo` See also: React element `Foo`', \ } \] AssertEqual g:expected, g:actual Execute(The flow handler should handle relative paths): silent! noautocmd file /Users/rav/Projects/vim-ale-flow/index.js let g:flow_output = { \ "flowVersion": "0.44.0", \ "errors": [{ \ "operation": { \ "context": " , document.getElementById('foo')", \ "descr": "React element `Foo`", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 6, \ "column": 3, \ "offset": 92 \ }, \ "end": { \ "line": 6, \ "column": 18, \ "offset": 108 \ } \ }, \ "path": expand('%:p'), \ "line": 6, \ "endline": 6, \ "start": 3, \ "end": 18 \ }, \ "kind": "infer", \ "level": "error", \ "message": [{ \ "context": "module.exports = function(props: Props) {", \ "descr": "property `bar`", \ "type": "Blame", \ "loc": { \ "source": "vim-ale-flow/foo.js", \ "type": "SourceFile", \ "start": { \ "line": 9, \ "column": 34, \ "offset": 121 \ }, \ "end": { \ "line": 9, \ "column": 38, \ "offset": 126 \ } \ }, \ "path": "vim-ale-flow/foo.js", \ "line": 9, \ "endline": 9, \ "start": 34, \ "end": 38 \ }, { \ "context": v:null, \ "descr": "Property not found in", \ "type": "Comment", \ "path": "", \ "line": 0, \ "endline": 0, \ "start": 1, \ "end": 0 \ }, { \ "context": " , document.getElementById('foo')", \ "descr": "props of React element `Foo`", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 6, \ "column": 3, \ "offset": 92 \ }, \ "end": { \ "line": 6, \ "column": 18, \ "offset": 108 \ } \ }, \ "path": expand('%:p'), \ "line": 6, \ "endline": 6, \ "start": 3, \ "end": 18 \ }] \ }], \ "passed": v:false \} let g:actual = ale_linters#javascript#flow#Handle(bufnr(''), [json_encode(g:flow_output)]) let g:expected = [ \ { \ 'lnum': 6, \ 'col': 3, \ 'type': 'E', \ 'text': 'property `bar`: Property not found in props of React element `Foo` See also: React element `Foo`', \ } \] AssertEqual g:expected, g:actual Execute(The flow handler should handle extra errors): silent! noautocmd file /Users/rav/Projects/vim-ale-flow/index.js let g:flow_output = { \ "flowVersion": "0.54.0", \ "errors": [{ \ "extra": [{ \ "message": [{ \ "context": v:null, \ "descr": "Property \`setVector\` is incompatible:", \ "type": "Blame ", \ "path": "", \ "line": 0, \ "endline": 0, \ "start": 1, \ "end": 0 \ }], \ "children": [{ \ "message": [{ \ "context": "setVector = \{2\}", \ "descr": "number ", \ "type": "Blame ", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile ", \ "start": { \ "line": 90, \ "column": 30, \ "offset": 2296 \ }, \ "end": { \ "line": 90, \ "column": 30, \ "offset": 2297 \ } \ }, \ "path": expand('%:p'), \ "line": 90, \ "endline": 90, \ "start": 30, \ "end": 30 \ }, { \ "context": v:null, \ "descr": "This type is incompatible with ", \ "type": "Comment ", \ "path": "", \ "line": 0, \ "endline": 0, \ "start": 1, \ "end": 0 \ }, { \ "context": "setVector: VectorType => void,", \ "descr": "function type ", \ "type": "Blame ", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 9, \ "column": 14, \ "offset": 252 \ }, \ "end": { \ "line": 9, \ "column": 31, \ "offset": 270 \ } \ }, \ "path": expand('%:p'), \ "line": 9, \ "endline": 9, \ "start": 14, \ "end": 31 \ }] \ }] \ }], \ "kind": "infer", \ "level": "error", \ "suppressions": [], \ "message": [{ \ "context": " < New ", \ "descr": "props of React element `New`", \ "type": "Blame", \ "loc": { \ "source": "vim-ale-flow/foo.js", \ "type": "SourceFile", \ "start": { \ "line": 89, \ "column": 17, \ "offset": 2262 \ }, \ "end": { \ "line": 94, \ "column": 18, \ "offset": 2488 \ } \ }, \ "path": "", \ "line": 89, \ "endline": 94, \ "start": 17, \ "end": 18 \ }, { \ "context": v:null, \ "descr": "This type is incompatible with", \ "type": "Comment", \ "path": "", \ "line": 0, \ "endline": 0, \ "start": 1, \ "end": 0 \ }, { \ "context": "class New extends React.Component < NewProps,NewState > {", \ "descr": "object type", \ "type": "Blame", \ "loc": { \ "source": expand('%:p'), \ "type": "SourceFile", \ "start": { \ "line": 20, \ "column": 35, \ "offset": 489 \ }, \ "end": { \ "line": 20, \ "column": 42, \ "offset": 497 \ } \ }, \ "path": expand('%:p'), \ "line": 20, \ "endline": 20, \ "start": 35, \ "end": 42 \ }] \ }], \ "passed": v:false \} let g:actual = ale_linters#javascript#flow#Handle(bufnr(''), [json_encode(g:flow_output)]) let g:expected = [ \ { \ 'lnum': 20, \ 'col': 35, \ 'type': 'E', \ 'text': 'props of React element `New`: This type is incompatible with object type', \ 'detail': 'props of React element `New`: This type is incompatible with object type' \ . "\nProperty `setVector` is incompatible: number This type is incompatible with function type ", \ } \] AssertEqual g:expected, g:actual ================================================ FILE: test/handler/test_foodcritic_handler.vader ================================================ Before: runtime ale_linters/chef/foodcritic.vim After: call ale#linter#Reset() Execute(Basic warnings should be handled): AssertEqual \ [ \ { \ 'lnum': 1, \ 'code': 'CINK001', \ 'type': 'W', \ 'text': 'Missing CHANGELOG in markdown format', \ 'filename': '/foo/bar/CHANGELOG.md', \ }, \ { \ 'lnum': 1, \ 'code': 'FC011', \ 'type': 'W', \ 'text': 'Missing README in markdown format', \ 'filename': '/foo/bar/README.md', \ }, \ { \ 'lnum': 1, \ 'code': 'FC031', \ 'type': 'W', \ 'text': 'Cookbook without metadata.rb file', \ 'filename': '/foo/bar/metadata.rb', \ }, \ { \ 'lnum': 1, \ 'code': 'FC071', \ 'type': 'W', \ 'text': 'Missing LICENSE file', \ 'filename': '/foo/bar/LICENSE', \ }, \ ], \ ale_linters#chef#foodcritic#Handle(bufnr(''), [ \ 'CINK001: Missing CHANGELOG in markdown format: /foo/bar/CHANGELOG.md:1', \ 'FC011: Missing README in markdown format: /foo/bar/README.md:1', \ 'FC031: Cookbook without metadata.rb file: /foo/bar/metadata.rb:1', \ 'FC071: Missing LICENSE file: /foo/bar/LICENSE:1', \ ]) ================================================ FILE: test/handler/test_fortitude_handler.vader ================================================ Before: runtime ale_linters/fortran/fortitude.vim After: call ale#linter#Reset() Execute(Simple fortitude handler run): AssertEqual \ [ \ { \ 'lnum': 3, \ 'end_lnum': 3, \ 'col': 5, \ 'end_col': 18, \ 'text': '''implicit none'' missing ''external''', \ 'type': 'W', \ 'code': 'C003', \ }, \ { \ 'col': 13, \ 'end_col': 14, \ 'end_lnum': 7, \ 'lnum': 7, \ 'text': 'Syntax error', \ 'type': 'E', \ 'code': 'E001', \ }, \ ], \ ale_linters#fortran#fortitude#Handle(bufnr(''), [ \ '[', \ json_encode({ \ 'code': 'C003', \ 'end_location': {'column': 18, 'row': 3}, \ 'filename': '/home/user/documents/somefortranfile.f90', \ 'fix': { \ 'applicability': 'unsafe', \ 'edits': [ \ { \ 'content': ' (type, external)', \ 'end_location': {'column': 18, 'row': 3}, \ 'location': {'column': 18, 'row': 3}, \ }, \ ], \ 'message': 'Add `(external)` to ''implicit none''', \ }, \ 'location': {'column': 5, 'row': 3}, \ 'message': '''implicit none'' missing ''external''' \ }), \ ',', \ json_encode({ \ 'code': 'E001', \ 'end_location': {'column': 14, 'row': 7}, \ 'filename': '/home/user/documents/somefortranfile.f90', \ 'fix': v:null, \ 'location': {'column': 13, 'row': 7}, \ 'message': 'Syntax error', \ }), \ ']', \ ]) ================================================ FILE: test/handler/test_fortran_handler.vader ================================================ Before: runtime ale_linters/fortran/gcc.vim After: call ale#linter#Reset() Execute(The fortran handler should parse lines from GCC 6.3.1 correctly): AssertEqual \ [ \ { \ 'bufnr': 337, \ 'lnum': 3, \ 'col': 12, \ 'text': "Symbol ‘a’ at (1) has no IMPLICIT type", \ 'type': 'E', \ }, \ { \ 'bufnr': 337, \ 'lnum': 4, \ 'col': 12, \ 'text': "Symbol ‘b’ at (1) has no IMPLICIT type", \ 'type': 'E', \ }, \ ], \ ale_linters#fortran#gcc#Handle(337, [ \ ":3:12:", \ "", \ "Error: Symbol ‘a’ at (1) has no IMPLICIT type", \ ":4:12:", \ "", \ "Error: Symbol ‘b’ at (1) has no IMPLICIT type", \ ]) ================================================ FILE: test/handler/test_gawk_handler.vader ================================================ Before: runtime ale_linters/awk/gawk.vim After: call ale#linter#Reset() Execute(gawk syntax errors should be parsed correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 0, \ 'text': "invalid char ''' in expression", \ 'code': 0, \ 'type': 'E', \ }, \ { \ 'lnum': 5, \ 'col': 0, \ 'text': 'unterminated string', \ 'code': 0, \ 'type': 'E', \ }, \ { \ 'lnum': 10, \ 'col': 0, \ 'text': "escape sequence `\u' treated as plain `u'", \ 'code': 0, \ 'type': 'W', \ }, \ ], \ ale#handlers#gawk#HandleGawkFormat(347, [ \ "gawk: something.awk:1: BEGIN { system('touch aaaaaaaaa') }", \ "gawk: something.awk:1: ^ invalid char ''' in expression", \ 'gawk: something.awk:5: { x = "aaaaaaaaaaa', \ 'gawk: something.awk:5: ^ unterminated string', \ "gawk: something.awk:10: warning: escape sequence `\u' treated as plain `u'", \ ]) ================================================ FILE: test/handler/test_gcc_handler.vader ================================================ Execute(The GCC handler should ignore other lines of output): AssertEqual \ [], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, ['foo', 'bar', 'baz']) Execute(GCC errors from included files should be parsed correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'filename': 'broken.h', \ '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 :3:2:', \ 'broken.h:1:1: error: expected identifier or ''('' before ''{'' token', \ ' {{{', \ ' ^', \ ], "\n"), \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ 'In file included from :3:2:', \ 'broken.h:1:1: error: expected identifier or ''('' before ''{'' token', \ ' {{{', \ ' ^', \ 'compilation terminated.', \ ]) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'filename': 'b.h', \ '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 :5:', \ 'b.h:1:1: error: expected identifier or ''('' before ''{'' token', \ ' {{{', \ ' ^', \ ], "\n"), \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ 'In file included from a.h:1:0,', \ ' from :5:', \ 'b.h:1:1: error: expected identifier or ''('' before ''{'' token', \ ' {{{', \ ' ^', \ 'compilation terminated.', \ ]) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'filename': 'b.h', \ 'type': 'E', \ 'text': 'unknown type name ''bad_type''', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'filename': 'b.h', \ '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 :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#HandleGCCFormatWithIncludes(347, [ \ 'In file included from a.h:1:0,', \ ' from :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): silent file! test.h AssertEqual \ [], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ':1:1: warning: #pragma once in main file [enabled by default]', \ ]) silent file! test.hpp AssertEqual \ [], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ':1:1: warning: #pragma once in main file [enabled by default]', \ ]) Execute(The GCC handler should handle syntax errors): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 12, \ 'type': 'E', \ 'text': 'invalid suffix "p" on integer constant' \ }, \ { \ 'lnum': 17, \ 'col': 5, \ 'type': 'E', \ 'text': 'invalid suffix "n" on integer constant' \ }, \ { \ 'lnum': 4, \ 'type': 'E', \ 'text': 'variable or field ''foo'' declared void' \ }, \ { \ 'lnum': 4, \ 'type': 'E', \ 'text': '''cat'' was not declared in this scope' \ }, \ { \ 'lnum': 12, \ 'type': 'E', \ 'text': 'expected '';'' before ''o''' \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ':6:12: error: invalid suffix "p" on integer constant', \ ':17:5: error: invalid suffix "n" on integer constant', \ ':4: error: variable or field ''foo'' declared void', \ ':4: error: ''cat'' was not declared in this scope', \ ':12: error: expected `;'' before ''o''', \ ]) Execute(The GCC handler should handle notes with no previous message): AssertEqual \ [], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ':1:1: note: x', \ ':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:1:1: note: x", \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ '-:6:12: error: Some error', \ ':1:1: note: x', \ ]) Execute(The GCC handler should interpret - as being the current file): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 12, \ 'type': 'E', \ 'text': 'Some error', \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ '-:6:12: error: Some error', \ ]) Execute(The GCC handler should handle fatal error messages due to missing files): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 12, \ 'type': 'E', \ 'text': 'foo.h: No such file or directory' \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ':3:12: fatal error: foo.h: No such file or directory', \ ]) Execute(The GCC handler should handle errors for inlined header functions): AssertEqual \ [ \ { \ 'lnum': 50, \ 'col': 4, \ 'filename': '/usr/include/bits/fcntl2.h', \ 'type': 'E', \ 'text': 'call to ''__open_missing_mode'' declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments', \ }, \ { \ 'lnum': 44, \ 'col': 5, \ 'filename': '/usr/include/bits/fcntl2.h', \ 'type': 'E', \ 'text': 'call to ''__open_too_many_args'' declared with attribute error: open can be called either with 2 or 3 arguments, not more', \ }, \ { \ 'lnum': 7, \ 'col': 10, \ 'type': 'E', \ 'text': 'call to ''__open_missing_mode'' declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments', \ }, \ { \ 'lnum': 13, \ 'col': 11, \ 'type': 'E', \ 'text': 'call to ''__open_too_many_args'' declared with attribute error: open can be called either with 2 or 3 arguments, not more', \ }, \ { \ 'lnum': 1, \ 'text': 'Error found in header. See :ALEDetail', \ 'detail': join([ \ 'In file included from /usr/include/fcntl.h:328,', \ ' from :1:', \ 'In function ‘open’,', \ ' inlined from ‘main’ at :7:10:', \ '/usr/include/bits/fcntl2.h:50:4: error: call to ‘__open_missing_mode’ declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments', \ ' __open_missing_mode ();', \ ' ^~~~~~~~~~~~~~~~~~~~~~', \ 'In function ‘open’,', \ ' inlined from ‘main’ at :13:11:', \ '/usr/include/bits/fcntl2.h:44:5: error: call to ‘__open_too_many_args’ declared with attribute error: open can be called either with 2 or 3 arguments, not more', \ ' __open_too_many_args ();', \ ], "\n") \ }, \], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ 'In file included from /usr/include/fcntl.h:328,', \ ' from :1:', \ 'In function ‘open’,', \ ' inlined from ‘main’ at :7:10:', \ '/usr/include/bits/fcntl2.h:50:4: error: call to ‘__open_missing_mode’ declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments', \ ' __open_missing_mode ();', \ ' ^~~~~~~~~~~~~~~~~~~~~~', \ 'In function ‘open’,', \ ' inlined from ‘main’ at :13:11:', \ '/usr/include/bits/fcntl2.h:44:5: error: call to ‘__open_too_many_args’ declared with attribute error: open can be called either with 2 or 3 arguments, not more', \ ' __open_too_many_args ();', \ ' ^~~~~~~~~~~~~~~~~~~~~~~', \ ]) Execute(The GCC handler should handle macro expansion errors in current file): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 19, \ 'type': 'E', \ 'text': 'error message', \ 'detail': "error message\n:1:19: note: in expansion of macro 'TEST'", \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ': error: error message', \ ':1:19: note: in expansion of macro ‘TEST’', \ ' 1 | std::string str = TEST;', \ ' | ^~~~', \ ]) Execute(The GCC handler should handle macro expansion errors in other files): AssertEqual \ [ \ { \ 'lnum': 0, \ 'type': 'E', \ 'text': 'Error found in macro expansion. See :ALEDetail', \ 'detail': "error message\ninc.h:1:19: note: in expansion of macro 'TEST'", \ }, \ ], \ ale#handlers#gcc#HandleGCCFormatWithIncludes(347, [ \ ': error: error message', \ 'inc.h:1:19: note: in expansion of macro ‘TEST’', \ ' 1 | std::string str = TEST;', \ ' | ^~~~', \ ]) ================================================ FILE: test/handler/test_ghc_handler.vader ================================================ After: unlet! g:detail Execute(The ghc handler should handle hdevtools output): call ale#test#SetFilename('foo.hs') AssertEqual \ [ \ { \ 'lnum': 147, \ 'type': 'W', \ 'col': 62, \ 'text': "• Couldn't match type ‘a -> T.Text’ with ‘T.Text’ Expected type: [T.Text]", \ 'detail': join([ \ "• Couldn't match type ‘a -> T.Text’ with ‘T.Text’", \ ' Expected type: [T.Text]', \ ], "\n"), \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ 'foo.hs:147:62: warning:', \ "• Couldn't match type ‘a -> T.Text’ with ‘T.Text’", \ ' Expected type: [T.Text]', \ ]) Execute(The ghc handler should handle ghc 8 output): call ale#test#SetFilename('src/Appoint/Lib.hs') AssertEqual \ [ \ { \ 'lnum': 6, \ 'type': 'E', \ 'col': 1, \ 'text': 'Failed to load interface for ‘GitHub.Data’ Use -v to see a list of the files searched for.', \ 'detail': join([ \ ' Failed to load interface for ‘GitHub.Data’', \ ' Use -v to see a list of the files searched for.', \ ], "\n"), \ }, \ { \ 'lnum': 7, \ 'type': 'W', \ 'col': 1, \ 'text': 'Failed to load interface for ‘GitHub.Endpoints.PullRequests’ Use -v to see a list of the files searched for.', \ 'detail': join([ \ ' Failed to load interface for ‘GitHub.Endpoints.PullRequests’', \ ' Use -v to see a list of the files searched for.', \ ], "\n"), \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ '', \ ale#path#Simplify('src/Appoint/Lib.hs') . ':6:1: error:', \ ' Failed to load interface for ‘GitHub.Data’', \ ' Use -v to see a list of the files searched for.', \ '', \ ale#path#Simplify('src/Appoint/Lib.hs') . ':7:1: warning:', \ ' Failed to load interface for ‘GitHub.Endpoints.PullRequests’', \ ' Use -v to see a list of the files searched for.', \ ]) Execute(The ghc handler should handle ghc 7 output): call ale#test#SetFilename('src/Main.hs') AssertEqual \ [ \ { \ 'lnum': 168, \ 'type': 'E', \ 'col': 1, \ 'text': 'parse error (possibly incorrect indentation or mismatched brackets)', \ 'detail': join([ \ ' parse error (possibly incorrect indentation or mismatched brackets)', \ ], "\n"), \ }, \ { \ 'lnum': 84, \ 'col': 1, \ 'type': 'W', \ 'text': 'Top-level binding with no type signature: myLayout :: Choose Tall (Choose (Mirror Tall) Full) a', \ 'detail': join([ \ ' Top-level binding with no type signature:', \ ' myLayout :: Choose Tall (Choose (Mirror Tall) Full) a', \ ], "\n"), \ }, \ { \ 'lnum': 94, \ 'col': 5, \ 'type': 'E', \ 'text': 'Some other error', \ 'detail': join([ \ ' Some other error', \ ], "\n"), \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ ale#path#Simplify('src/Main.hs') . ':168:1:', \ ' parse error (possibly incorrect indentation or mismatched brackets)', \ ale#path#Simplify('src/Main.hs') . ':84:1:Warning:', \ ' Top-level binding with no type signature:', \ ' myLayout :: Choose Tall (Choose (Mirror Tall) Full) a', \ ale#path#Simplify('src/Main.hs') . ':94:5:Error:', \ ' Some other error', \ ]) Execute(The ghc handler should handle stack 1.5.1 output): call ale#test#SetFilename('src/Main.hs') AssertEqual \ [ \ { \ 'lnum': 160, \ 'col': 14, \ 'type': 'E', \ 'text': '• Expecting one fewer arguments to ‘Exp’ Expected kind ‘k0 -> *’, but ‘Exp’ has kind ‘*’ • In the type ‘Exp a’ | 160 | pattern F :: Exp a | ^^^^^', \ 'detail': join([ \ ' • Expecting one fewer arguments to ‘Exp’', \ ' Expected kind ‘k0 -> *’, but ‘Exp’ has kind ‘*’', \ ' • In the type ‘Exp a’', \ ' |', \ ' 160 | pattern F :: Exp a', \ ' | ^^^^^', \ ], "\n"), \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ ' ' . ale#path#Simplify('src/Main.hs') . ':160:14: error:', \ ' • Expecting one fewer arguments to ‘Exp’', \ ' Expected kind ‘k0 -> *’, but ‘Exp’ has kind ‘*’', \ ' • In the type ‘Exp a’', \ ' |', \ ' 160 | pattern F :: Exp a', \ ' | ^^^^^', \ ]) Execute(The ghc handler should handle ghc panic): let g:detail = [ \ '[15 of 15] Compiling SizedTypes.List', \ 'ghc: panic! (the ''impossible'' happened)', \ ' (GHC version 8.10.3:', \ ' src/SizedTypes/List.hs:(46,19)-(50,0) Specified type does not refine Haskell type for `SizedTypes.List.out` (Plugged Init types new)', \ ' The Liquid type', \ ' .', \ ' GHC.Types.Int -> (SizedTypes.List.List a) -> (_, (SizedTypes.List.List a))', \ ' .', \ ' is inconsistent with the Haskell type', \ ' .', \ ' forall p a ->', \ 'p -> SizedTypes.List.List a -> (a, SizedTypes.List.List a)', \ ' .', \ ' defined at src/SizedTypes/List.hs:52:1-3', \ ' .', \ ' Specifically, the Liquid component', \ ' .', \ ' {VV##0 : GHC.Types.Int | VV##0 >= 0}', \ ' .', \ ' is inconsistent with the Haskell component', \ ' .', \ ' p', \ ' .', \ ' ', \ ' HINT: Use the hole ''_'' instead of the mismatched component (in the Liquid specification)', \ '', \ 'Please report this as a GHC bug: https://www.haskell.org/ghc/reportabug', \ '', \ '' \ ] AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': 'ghc panic!', \ 'detail': join(g:detail[1:-3], "\n"), \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), g:detail) unlet g:detail ================================================ FILE: test/handler/test_ghc_mod_handler.vader ================================================ Execute(HandleGhcFormat should handle ghc-mod problems): call ale#test#SetFilename('check2.hs') AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Failed to load interface for ‘Missing’Use -v to see a list of the files searched for.', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Suggestion: Use camelCaseFound: my_variable = ...Why not: myVariable = ...', \ }, \ { \ 'lnum': 6, \ 'col': 1, \ 'type': 'W', \ 'text': 'Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ', \ }, \ { \ 'lnum': 28, \ 'col': 28, \ 'type': 'W', \ 'text': 'Defaulting the following constraints to type ‘Integer’ (Num a0) arising from the literal ‘3’ at check2.hs:28:28 (Eq a0) arising from a use of ‘lookup’ at check2.hs:28:21-28 • In the first argument of ‘lookup’, namely ‘3’ In the expression: lookup 3 In the second argument of ‘fmap’, namely ‘(lookup 3 $ zip [1, 2, 3] [4, 5, 6])''’' \ }, \ ], \ ale#handlers#haskell#HandleGHCFormat(bufnr(''), [ \ 'check2.hs:2:1:Failed to load interface for ‘Missing’Use -v to see a list of the files searched for.', \ 'check2.hs:2:1: Suggestion: Use camelCaseFound: my_variable = ...Why not: myVariable = ...', \ 'check2.hs:6:1: Warning: Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ', \ 'xxx.hs:6:1: Warning: Eta reduceFound: myFunc x = succ xWhy not: myFunc = succ', \ printf("check2.hs:28:28: Warning: Defaulting the following constraints to type ‘Integer’ (Num a0) arising from the literal ‘3’ at %s/check2.hs:28:28 (Eq a0) arising from a use of ‘lookup’ at %s/check2.hs:28:21-28 • In the first argument of ‘lookup’, namely ‘3’ In the expression: lookup 3 In the second argument of ‘fmap’, namely ‘(lookup 3 $ zip [1, 2, 3] [4, 5, 6])'’", tempname(), tempname()), \ ]) ================================================ FILE: test/handler/test_ghdl_handler.vader ================================================ Before: runtime ale_linters/vhdl/ghdl.vim After: call ale#linter#Reset() Execute(The ghdl handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 41, \ 'col' : 5, \ 'type': 'E', \ 'text': "error: 'begin' is expected instead of 'if'" \ }, \ { \ 'lnum': 12, \ 'col' : 8, \ 'type': 'E', \ 'text': ' no declaration for "i0"' \ }, \ ], \ ale_linters#vhdl#ghdl#Handle(bufnr(''), [ \ "dff_en.vhd:41:5:error: 'begin' is expected instead of 'if'", \ '/path/to/file.vhdl:12:8: no declaration for "i0"', \ ]) ================================================ FILE: test/handler/test_gitlablint_handler.vader ================================================ Before: runtime! ale_linters/yaml/gitlablint.vim After: call ale#linter#Reset() Execute(Problems should be parsed correctly for gitlablint): AssertEqual \ [ \ { \ 'lnum': 0, \ 'col': 0, \ 'type': 'E', \ 'text': 'root config contains unknown keys: efore_script', \ }, \ { \ 'lnum': 77, \ 'col': 3, \ 'type': 'E', \ 'text': '(): could not find expected : while scanning a simple key', \ }, \ { \ 'lnum': 0, \ 'col': 0, \ 'type': 'E', \ 'text': 'build:dev:rest job: undefined need: chck:dev', \ }, \ ], \ ale_linters#yaml#gitlablint#Handle(bufnr(''), [ \ 'GitLab CI configuration is invalid', \ 'root config contains unknown keys: efore_script', \ '(): could not find expected : while scanning a simple key at line 77 column 3', \ 'build:dev:rest job: undefined need: chck:dev', \ ]) ================================================ FILE: test/handler/test_gitlint_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/gitcommit/gitlint.vim After: Restore unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute(The gitlint handler should handle basic warnings and syntax errors): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': 'Body message is missing', \ 'code': 'B6', \ }, \ { \ 'lnum': 2, \ 'type': 'E', \ 'text': 'Second line is not empty: "to send to upstream"', \ 'code': 'B4', \ }, \ { \ 'lnum': 3, \ 'type': 'E', \ 'text': 'Body message is too short (19<20): "to send to upstream"', \ 'code': 'B5', \ }, \ { \ 'lnum': 8, \ 'type': 'E', \ 'text': 'Title exceeds max length (92>72): "some very long commit subject line where the author can''t wait to explain what he just fixed"', \ 'code': 'T1', \ }, \ ], \ ale_linters#gitcommit#gitlint#Handle(1, [ \ '1: B6 Body message is missing', \ '2: B4 Second line is not empty: "to send to upstream"', \ '3: B5 Body message is too short (19<20): "to send to upstream"', \ '8: T1 Title exceeds max length (92>72): "some very long commit subject line where the author can''t wait to explain what he just fixed"' \ ]) Execute(Disabling trailing whitespace warnings should work): AssertEqual \ [ \ { \ 'lnum': 8, \ 'type': 'E', \ 'text': 'Trailing whitespace', \ 'code': 'T2', \ }, \ ], \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [ \ '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 \ [], \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [ \ '8: T2 Trailing whitespace', \ ]) AssertEqual \ [], \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [ \ '8: B2 Trailing whitespace', \ ]) ================================================ FILE: test/handler/test_glslang_handler.vader ================================================ Before: runtime ale_linters/glsl/glslang.vim Execute(The glsl glslang handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 0, \ 'type': 'E', \ 'text': '''gl_ModelViewProjectionMatrix'' : undeclared identifier', \ }, \ { \ 'lnum': 121, \ 'col': 0, \ 'type': 'W', \ 'text': '''switch'' : last case/default label not followed by statements', \ }, \ ], \ ale_linters#glsl#glslang#Handle(bufnr(''), [ \ 'ERROR: 0:4: ''gl_ModelViewProjectionMatrix'' : undeclared identifier', \ 'WARNING: 0:121: ''switch'' : last case/default label not followed by statements', \ 'ERROR: 2 compilation errors. No code generated.', \ ]) Execute(The glsl glslang handler should parse lines with options -V or -G correctly): AssertEqual \ [ \ { \ 'lnum': 7, \ 'col': 0, \ 'type': 'E', \ 'text': '''non-opaque uniforms outside a block'' : not allowed when using GLSL for Vulkan', \ }, \ { \ 'lnum': 14, \ 'col': 0, \ 'type': 'W', \ 'text': '''__shininess'' : identifiers containing consecutive underscores ("__") are reserved', \ }, \ ], \ ale_linters#glsl#glslang#Handle(bufnr(''), [ \ 'shader.vert', \ 'ERROR: shader.vert:7: ''non-opaque uniforms outside a block'' : not allowed when using GLSL for Vulkan', \ 'WARNING: shader.vert:14: ''__shininess'' : identifiers containing consecutive underscores ("__") are reserved', \ 'ERROR: 1 compilation errors. No code generated.', \ 'SPIR-V is not generated for failed compile or link', \ ]) ================================================ FILE: test/handler/test_go_generic_handler.vader ================================================ Execute(The golang handler should return the correct filenames): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 0, \ 'text': 'some error', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'), \ }, \ { \ 'lnum': 27, \ 'col': 5, \ 'text': 'some error with a column', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/other.go'), \ }, \ { \ 'lnum': 18, \ 'col': 0, \ 'text': 'random error', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/go1.14.go'), \ }, \ { \ 'lnum': 36, \ 'col': 2, \ 'text': 'another random error', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/anothergo1.14.go'), \ }, \ ], \ ale#handlers#go#Handler(bufnr(''), [ \ 'test.go:27: some error', \ 'other.go:27:5: some error with a column', \ 'vet: go1.14.go:18:0: random error', \ 'vet: anothergo1.14.go:36:2: another random error', \ ]) ================================================ FILE: test/handler/test_gobuild_handler.vader ================================================ Before: runtime ale_linters/go/gobuild.vim After: call ale#linter#Reset() Execute (The gobuild 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', \ '27', \ '', \ 'missing argument for Printf("%s"): format reads arg 2, have only 1 args', \ ], \ [ \ 'C:\something\file with spaces.go', \ '5', \ '2', \ 'expected declaration, found ''STRING'' "log"', \ ], \ ], \ map(ale_linters#go#gobuild#GetMatches([ \ 'C:\something\file with spaces.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args', \ 'C:\something\file with spaces.go:5:2: expected declaration, found ''STRING'' "log"', \ ]), 'v:val[1:4]') Execute (The gobuild handler should handle relative paths correctly): call ale#test#SetFilename('app/test.go') AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 0, \ 'text': 'missing argument for Printf("%s"): format reads arg 2, have only 1 args', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'), \ }, \ ], \ ale_linters#go#gobuild#Handler(bufnr(''), [ \ 'test.go:27: missing argument for Printf("%s"): format reads arg 2, have only 1 args', \ ]) ================================================ FILE: test/handler/test_golangci_lint_handler.vader ================================================ Before: runtime ale_linters/go/golangci_lint.vim After: call ale#linter#Reset() Execute (The golangci-lint handler should handle only typecheck lines as errors): call ale#test#SetFilename('app/main.go') AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 0, \ 'text': 'typecheck - found packages main (main.go) and validator (validation.go) in ', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/main.go'), \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'typecheck - package validator_test; expected package main_test', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/validation_encoder_test.go'), \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'typecheck - package validator_test; expected package main_test', \ 'type': 'E', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/validation_error_test.go'), \ }, \ { \ 'lnum': 505, \ 'col': 75, \ 'text': 'gomnd - Magic number: 404, in detected', \ 'type': 'W', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/main.go'), \ } \ ], \ ale_linters#go#golangci_lint#Handler(bufnr(''), [ \ '{', \ ' "Issues": [', \ ' {', \ ' "FromLinter": "typecheck",', \ ' "Text": "found packages main (main.go) and validator (validation.go) in ",', \ ' "Severity": "",', \ ' "SourceLines": [', \ ' "package main"', \ ' ],', \ ' "Pos": {', \ ' "Filename": "main.go",', \ ' "Offset": 0,', \ ' "Line": 1,', \ ' "Column": 0', \ ' },', \ ' "ExpectNoLint": false,', \ ' "ExpectedNoLintLinter": ""', \ ' },', \ ' {', \ ' "FromLinter": "typecheck",', \ ' "Text": "package validator_test; expected package main_test",', \ ' "Severity": "",', \ ' "SourceLines": [', \ ' "package validator_test"', \ ' ],', \ ' "Pos": {', \ ' "Filename": "validation_encoder_test.go",', \ ' "Offset": 0,', \ ' "Line": 1,', \ ' "Column": 1', \ ' },', \ ' "ExpectNoLint": false,', \ ' "ExpectedNoLintLinter": ""', \ ' },', \ ' {', \ ' "FromLinter": "typecheck",', \ ' "Text": "package validator_test; expected package main_test",', \ ' "Severity": "",', \ ' "SourceLines": [', \ ' "package validator_test"', \ ' ],', \ ' "Pos": {', \ ' "Filename": "validation_error_test.go",', \ ' "Offset": 0,', \ ' "Line": 1,', \ ' "Column": 1', \ ' },', \ ' "ExpectNoLint": false,', \ ' "ExpectedNoLintLinter": ""', \ ' },', \ ' {', \ ' "FromLinter": "gomnd",', \ ' "Text": "Magic number: 404, in detected",', \ ' "Severity": "",', \ ' "SourceLines": [', \ ' "package validator_test"', \ ' ],', \ ' "Pos": {', \ ' "Filename": "main.go",', \ ' "Offset": 0,', \ ' "Line": 505,', \ ' "Column": 75', \ ' },', \ ' "ExpectNoLint": false,', \ ' "ExpectedNoLintLinter": ""', \ ' }', \ ' ]', \ '}', \ ]) Execute (The golangci-lint handler should set proper filename): call ale#test#SetFilename('app/cmd/server/main.go') AssertEqual \ [ \ { \ 'lnum': 198, \ 'col': 19, \ 'text': 'funlen - Function getConfig has too many statements (51 > 50)', \ 'type': 'W', \ 'filename': ale#path#Simplify(expand('%:p:h') . '/main.go'), \ }, \ ], \ ale_linters#go#golangci_lint#Handler(bufnr(''), [ \ '{', \ ' "Issues": [', \ ' {', \ ' "FromLinter": "funlen",', \ ' "Text": "Function getConfig has too many statements (51 > 50)",', \ ' "Severity": "",', \ ' "SourceLines": [', \ ' "package main"', \ ' ],', \ ' "Pos": {', \ ' "Filename": "cmd/server/main.go",', \ ' "Offset": 5374,', \ ' "Line": 198,', \ ' "Column": 19', \ ' },', \ ' "ExpectNoLint": false,', \ ' "ExpectedNoLintLinter": ""', \ ' }', \ ' ]', \ '}', \ ]) ================================================ FILE: test/handler/test_hadolint.vader ================================================ Before: runtime ale_linters/dockerfile/hadolint.vim After: call ale#linter#Reset() Execute(The hadolint handler should handle an empty string response): AssertEqual \ [], \ ale_linters#dockerfile#hadolint#Handle(bufnr(''), []) Execute(The hadolint handler should handle a normal example): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 0, \ 'type': 'W', \ 'code': 'DL3006', \ 'text': 'Always tag the version of an image explicitly', \ 'detail': "DL3006 ( https://github.com/hadolint/hadolint/wiki/DL3006 )\n\nAlways tag the version of an image explicitly", \ }, \ { \ 'lnum': 4, \ 'col': 0, \ 'type': 'W', \ 'code': 'DL3033', \ 'text': 'Specify version with `yum install -y -`.', \ 'detail': "DL3033 ( https://github.com/hadolint/hadolint/wiki/DL3033 )\n\nSpecify version with `yum install -y -`.", \ }, \ { \ 'lnum': 12, \ 'col': 0, \ 'type': 'W', \ 'code': 'SC2039', \ 'text': 'In POSIX sh, brace expansion is undefined.', \ 'detail': "SC2039 ( https://github.com/koalaman/shellcheck/wiki/SC2039 )\n\nIn POSIX sh, brace expansion is undefined.", \ }, \ ], \ ale_linters#dockerfile#hadolint#Handle(bufnr(''), [ \ '-:1 DL3006 warning: Always tag the version of an image explicitly', \ '-:4 DL3033 warning: Specify version with `yum install -y -`.', \ '-:12 SC2039 warning: In POSIX sh, brace expansion is undefined.', \ ]) Execute(The hadolint handler should handle parsing errors): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': "unexpected 'b' expecting '#', ADD, ARG, CMD, COPY, ENTRYPOINT, ENV, EXPOSE, FROM, HEALTHCHECK, LABEL, MAINTAINER, ONBUILD, RUN, SHELL, STOPSIGNAL, USER, VOLUME, WORKDIR, or end of input", \ 'detail': "hadolint could not parse the file because of a syntax error.", \ }, \ ], \ ale_linters#dockerfile#hadolint#Handle(bufnr(''), [ \ '/dev/stdin:1:1 unexpected ''b'' expecting ''#'', ADD, ARG, CMD, COPY, ENTRYPOINT, ENV, EXPOSE, FROM, HEALTHCHECK, LABEL, MAINTAINER, ONBUILD, RUN, SHELL, STOPSIGNAL, USER, VOLUME, WORKDIR, or end of input', \ ]) ================================================ FILE: test/handler/test_haskell_stack_handler.vader ================================================ 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') ================================================ FILE: test/handler/test_hlint_handler.vader ================================================ Before: runtime! ale_linters/haskell/hlint.vim After: call ale#linter#Reset() Execute(The hlint handler should parse items correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 4, \ 'end_lnum': 3, \ 'end_col': 2, \ 'text': 'Error: Do something. Found: [Char] Why not: String', \ 'type': 'E', \ }, \ { \ 'lnum': 2, \ 'col': 4, \ 'end_lnum': 7, \ 'end_col': 2, \ 'text': 'Warning: Do something. Found: [Char] Why not: String', \ 'type': 'W', \ }, \ { \ 'lnum': 73, \ 'col': 25, \ 'end_lnum': 73, \ 'end_col': 31, \ 'text': 'Suggestion: Use String. Found: [Char] Why not: String', \ 'type': 'I', \ }, \ ], \ ale_linters#haskell#hlint#Handle(bufnr(''), [json_encode([ \ { \ 'module': 'Main', \ 'decl': 'foo', \ 'severity': 'Error', \ 'hint': 'Do something', \ 'file': '-', \ 'startLine': 1, \ 'startColumn': 4, \ 'endLine': 3, \ 'endColumn': 2, \ 'from': '[Char]', \ 'to': 'String', \ }, \ { \ 'module': 'Main', \ 'decl': 'foo', \ 'severity': 'Warning', \ 'hint': 'Do something', \ 'file': '-', \ 'startLine': 2, \ 'startColumn': 4, \ 'endLine': 7, \ 'endColumn': 2, \ 'from': '[Char]', \ 'to': 'String', \ }, \ { \ 'module': 'Main', \ 'decl': 'myFocusedBorderColor', \ 'severity': 'Suggestion', \ 'hint': 'Use String', \ 'file': '-', \ 'startLine': 73, \ 'startColumn': 25, \ 'endLine': 73, \ 'endColumn': 31, \ 'from': '[Char]', \ 'to': 'String', \ }, \ ])]) Execute(The hlint handler should handle empty output): AssertEqual \ [], \ ale_linters#haskell#hlint#Handle(bufnr(''), []) ================================================ FILE: test/handler/test_hurlfmt_handler.vader ================================================ Before: runtime ale_linters/hurl/hurlfmt.vim After: call ale#linter#Reset() Execute(The hurlfmt handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 11, \ 'bufnr': 345, \ 'col': 48, \ 'end_col': 48, \ 'text': 'Parsing space : expecting a space ', \ 'type': 'E', \ }, \ ], \ ale_linters#hurl#hurlfmt#HandleOutput(345, [ \ 'error: Parsing space', \ '--> test.hurl:11:48', \ ' |', \ '8 " | header "Content-Type"= "application/json; charset=utf-8"', \ ' | ^ expecting a space', \ ' |', \ ]) Execute(The rubocop handler should handle empty output): AssertEqual [], ale_linters#hurl#hurlfmt#HandleOutput(347, []) ================================================ FILE: test/handler/test_ibm_openapi_validator_handler.vader ================================================ Before: runtime! ale_linters/openapi/ibm_validator.vim After: call ale#linter#Reset() Execute(Problems should be parsed correctly for openapi-ibm-validator): AssertEqual \ [ \ { \ 'lnum': 54, \ 'col': 0, \ 'type': 'E', \ 'text': 'Items with a description must have content in it.', \ }, \ { \ 'lnum': 24, \ 'col': 0, \ 'type': 'W', \ 'text': 'Operations must have a non-empty `operationId`.', \ }, \ { \ 'lnum': 40, \ 'col': 0, \ 'type': 'W', \ 'text': 'operationIds must follow case convention: lower_snake_case', \ }, \ ], \ ale_linters#openapi#ibm_validator#Handle(bufnr(''), [ \ '', \ '[Warning] No .validaterc file found. The validator will run in default mode.', \ 'To configure the validator, create a .validaterc file.', \ '', \ 'errors', \ '', \ ' Message : Items with a description must have content in it.', \ ' Path : paths./settings.patch.description', \ ' Line : 54', \ '', \ 'warnings', \ '', \ ' Message : Operations must have a non-empty `operationId`.', \ ' Path : paths./stats.get.operationId', \ ' Line : 24', \ '', \ ' Message : operationIds must follow case convention: lower_snake_case', \ ' Path : paths./settings.get.operationId', \ ' Line : 40' \ ]) ================================================ FILE: test/handler/test_idris_handler.vader ================================================ Before: Save $TMPDIR " Set TMPDIR so the temporary file checks work. let $TMPDIR = '/tmp' runtime ale_linters/idris/idris.vim After: Restore call ale#linter#Reset() Execute(The idris handler should parse messages that reference a single column): if has('win32') call ale#test#SetFilename($TEMP . '\foo.idr') else call ale#test#SetFilename('/tmp/foo.idr') endif AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 5, \ 'type': 'E', \ 'text': 'When checking right hand side of main with expected type IO () When checking an application of function Prelude.Monad.>>=: Type mismatch between IO () (Type of putStrLn _) and _ -> _ (Is putStrLn _ applied to too many arguments?) Specifically: Type mismatch between IO and \uv => _ -> uv' \ } \ ], \ ale_linters#idris#idris#Handle(bufnr(''), [ \ expand('%:p') . ':4:5:', \ 'When checking right hand side of main with expected type', \ ' IO ()', \ '', \ 'When checking an application of function Prelude.Monad.>>=:', \ ' Type mismatch between', \ ' IO () (Type of putStrLn _)', \ ' and', \ ' _ -> _ (Is putStrLn _ applied to too many arguments?)', \ '', \ ' Specifically:', \ ' Type mismatch between', \ ' IO', \ ' and', \ ' \uv => _ -> uv', \ ]) Execute(The idris handler should parse messages that reference a column range): call ale#test#SetFilename('/tmp/foo.idr') AssertEqual \ [ \ { \ 'lnum': 11, \ 'col': 11, \ 'type': 'E', \ 'text': 'When checking right hand side of Main.case block in main at /tmp/foo.idr:10:10 with expected type IO () Last statement in do block must be an expression' \ } \ ], \ ale_linters#idris#idris#Handle(bufnr(''), [ \ expand('%:p') . ':11:11-13:', \ 'When checking right hand side of Main.case block in main at /tmp/foo.idr:10:10 with expected type', \ ' IO ()', \ '', \ 'Last statement in do block must be an expression', \ ]) ================================================ FILE: test/handler/test_inko_handler.vader ================================================ Before: runtime ale_linters/inko/inko.vim After: call ale#linter#Reset() Execute(The inko handler should parse errors correctly): AssertEqual \ [ \ { \ 'filename': ale#path#Simplify('/tmp/foo.inko'), \ 'lnum': 4, \ 'col': 5, \ 'text': 'this is an error', \ 'type': 'E', \ } \ ], \ ale#handlers#inko#Handle(bufnr(''), [ \ '[', \ ' {', \ ' "file": "/tmp/foo.inko",', \ ' "line": 4,', \ ' "column": 5,', \ ' "message": "this is an error",', \ ' "level": "error"', \ ' }', \ ']' \ ]) Execute(The inko handler should parse warnings correctly): AssertEqual \ [ \ { \ 'filename': ale#path#Simplify('/tmp/foo.inko'), \ 'lnum': 4, \ 'col': 5, \ 'text': 'this is a warning', \ 'type': 'W', \ } \ ], \ ale#handlers#inko#Handle(bufnr(''), [ \ '[', \ ' {', \ ' "file": "/tmp/foo.inko",', \ ' "line": 4,', \ ' "column": 5,', \ ' "message": "this is a warning",', \ ' "level": "warning"', \ ' }', \ ']' \ ]) Execute(The inko handler should handle empty output): AssertEqual [], ale#handlers#inko#Handle(bufnr(''), []) ================================================ FILE: test/handler/test_ispc_ispc_handler.vader ================================================ 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', \ ' ^~~~~~~~~~', \ '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];', \ ' ^^^^^^', \ '', \ ]) ================================================ FILE: test/handler/test_javac_handler.vader ================================================ Before: runtime ale_linters/java/javac.vim call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.java') After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The javac handler should handle cannot find symbol errors): AssertEqual \ [ \ { \ 'filename': ale#path#Simplify('/tmp/vLPr4Q5/33/foo.java'), \ 'lnum': 1, \ 'text': 'error: some error', \ 'type': 'E', \ }, \ { \ 'filename': ale#path#Simplify('/tmp/vLPr4Q5/33/foo.java'), \ 'lnum': 2, \ 'col': 5, \ 'text': 'error: cannot find symbol: BadName', \ 'type': 'E', \ }, \ { \ 'filename': ale#path#Simplify('/tmp/vLPr4Q5/33/foo.java'), \ 'lnum': 34, \ 'col': 5, \ 'text': 'error: cannot find symbol: BadName2', \ 'type': 'E', \ }, \ { \ 'filename': ale#path#Simplify('/tmp/vLPr4Q5/33/foo.java'), \ 'lnum': 37, \ 'text': 'warning: some warning', \ 'type': 'W', \ }, \ { \ 'filename': ale#path#Simplify('/tmp/vLPr4Q5/33/foo.java'), \ 'lnum': 42, \ 'col': 11, \ 'text': 'error: cannot find symbol: bar()', \ 'type': 'E', \ }, \ { \ 'filename': ale#path#Simplify('/tmp/vLPr4Q5/33/foo.java'), \ 'lnum': 58, \ 'col': 19, \ 'text': 'error: incompatible types: Bar cannot be converted to Foo', \ 'type': 'E', \ }, \ ], \ ale_linters#java#javac#Handle(bufnr(''), [ \ '/tmp/vLPr4Q5/33/foo.java:1: error: some error', \ '/tmp/vLPr4Q5/33/foo.java:2: error: cannot find symbol', \ ' BadName foo() {', \ ' ^', \ ' symbol: class BadName', \ ' location: class Bar', \ '/tmp/vLPr4Q5/33/foo.java:34: error: cannot find symbol', \ ' BadName2 foo() {', \ ' ^', \ ' symbol: class BadName2', \ ' location: class Bar', \ '/tmp/vLPr4Q5/33/foo.java:37: warning: some warning', \ '/tmp/vLPr4Q5/33/foo.java:42: error: cannot find symbol', \ ' this.bar();', \ ' ^', \ ' symbol: method bar()', \ '/tmp/vLPr4Q5/33/foo.java:58: error: incompatible types: Bar cannot be converted to Foo', \ ' this.setFoo(bar);', \ ' ^', \ '6 errors', \ ]) Execute(The javac handler should resolve files from different directories): AssertEqual \ [ \ { \ 'filename': ale#path#Simplify(g:dir . '/Foo.java'), \ 'lnum': 1, \ 'text': 'error: some error', \ 'type': 'E', \ }, \ { \ 'filename': ale#path#Simplify(g:dir . '/Bar.java'), \ 'lnum': 1, \ 'text': 'error: some error', \ 'type': 'E', \ }, \ ], \ ale_linters#java#javac#Handle(bufnr(''), [ \ './Foo.java:1: error: some error', \ './Bar.java:1: error: some error', \ ]) ================================================ FILE: test/handler/test_jq_handler.vader ================================================ Before: runtime ale_linters/json/jq.vim After: call ale#linter#Reset() Execute (Should parse error correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 9, \ 'text': 'Expected another array element', \ } \ ], \ ale_linters#json#jq#Handle(0, [ \ 'parse error: Expected another array element at line 1, column 9' \ ]) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 9, \ 'text': 'Expected another array element', \ } \ ], \ ale_linters#json#jq#Handle(0, [ \ 'jq: parse error: Expected another array element at line 1, column 9' \ ]) ================================================ FILE: test/handler/test_jscs_handler.vader ================================================ Before: runtime ale_linters/javascript/jscs.vim After: call ale#linter#Reset() Execute(jscs should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 7, \ 'text': 'Variable declarations should use `let` or `const` not `var`', \ 'code': 'disallowVar', \ }, \ { \ 'lnum': 3, \ 'col': 21, \ 'text': 'Illegal trailing whitespace', \ 'code': 'disallowTrailingWhitespace', \ }, \ { \ 'lnum': 5, \ 'col': 9, \ 'text': 'Variable `hello` is not used', \ 'code': 'disallowUnusedVariables', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'Expected indentation of 1 characters', \ }, \ ], \ ale_linters#javascript#jscs#Handle(347, [ \ 'foobar.js: line 1, col 7, disallowVar: Variable declarations should use `let` or `const` not `var`', \ 'foobar.js: line 3, col 21, disallowTrailingWhitespace: Illegal trailing whitespace', \ 'foobar.js: line 5, col 9, disallowUnusedVariables: Variable `hello` is not used', \ 'foobar.js: line 2, col 1, Expected indentation of 1 characters', \ ]) ================================================ FILE: test/handler/test_ktlint_handler.vader ================================================ Before: Save g:ale_kotlin_ktlint_rulesets let g:ale_kotlin_ktlint_rulesets = [] After: Restore Execute(The ktlint handler method GetRulesets should properly parse custom rulesets): let g:ale_kotlin_ktlint_rulesets = ['/path/to/custom/ruleset.jar', '/path/to/other/ruleset.jar'] AssertEqual \ '--ruleset /path/to/custom/ruleset.jar --ruleset /path/to/other/ruleset.jar', \ ale#handlers#ktlint#GetRulesets(bufnr('')) Execute(The ktlint handler method GetRulesets should return an empty string when no rulesets have been configured): let g:ale_kotlin_ktlint_rulesets = [] AssertEqual \ '', \ ale#handlers#ktlint#GetRulesets(bufnr('')) ================================================ FILE: test/handler/test_lacheck_handler.vader ================================================ Before: runtime ale_linters/tex/lacheck.vim call ale#test#SetDirectory('/testplugin/test/handler') After: call ale#linter#Reset() call ale#test#RestoreDirectory() Execute(The lacheck handler should parse lines correctly): call ale#test#SetFilename('../test-files/tex/sample1.tex') AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'W', \ 'text': 'perhaps you should insert a `~'' before "\ref"' \ } \ ], \ ale_linters#tex#lacheck#Handle(bufnr(''), [ \ "** sample1:", \ "\"sample1.tex\", line 1: perhaps you should insert a `~' before \"\\ref\"" \ ]) Execute(The lacheck handler should ignore errors from input files): call ale#test#SetFilename('ale_test.tex') AssertEqual \ [ \ ], \ ale_linters#tex#lacheck#Handle(255, [ \ "** ale_input:", \ "\"ale_input.tex\", line 1: perhaps you should insert a `~' before \"\\ref\"" \ ]) ================================================ FILE: test/handler/test_languagetool_handler.vader ================================================ Before: runtime! ale_linters/text/languagetool.vim After: call ale#linter#Reset() Execute(languagetool handler should report 3 errors): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 19, \ 'end_col': 20, \ 'text': 'This sentence does not start with an uppercase letter', \ 'type': 'W', \ 'code': 'UPPERCASE_SENTENCE_START', \ }, \ { \ 'lnum': 3, \ 'col': 36, \ 'end_col': 42, \ 'text': "Did you mean 'to see'?", \ 'type': 'W', \ 'code': 'TOO_TO[1]', \ }, \ { \ 'lnum': 3, \ 'col': 44, \ 'end_col': 45, \ 'text': "Use 'a' instead of 'an' if the following word doesn't start with a vowel sound, e.g. 'a sentence', 'a university'", \ 'type': 'W', \ 'code': 'EN_A_VS_AN', \ } \ ], \ ale#handlers#languagetool#HandleOutput(bufnr(''), [ \ '1.) Line 3, column 19, Rule ID: UPPERCASE_SENTENCE_START', \ 'Message: This sentence does not start with an uppercase letter', \ 'Suggestion: Or', \ '...red phrases for details on potential errors. or use this text too see an few of of the probl...', \ ' ^^ ', \ '', \ '2.) Line 3, column 36, Rule ID: TOO_TO[1]', \ "Message: Did you mean 'to see'?", \ 'Suggestion: to see', \ '...etails on potential errors. or use this text too see an few of of the problems that LanguageTool ...', \ ' ^^^^^^^ ', \ '', \ '3.) Line 3, column 44, Rule ID: EN_A_VS_AN', \ "Message: Use 'a' instead of 'an' if the following word doesn't start with a vowel sound, e.g. 'a sentence', 'a university'", \ 'Suggestion: a', \ '...n potential errors. or use this text too see an few of of the problems that LanguageTool can...', \ ' ^^ ', \ 'Time: 2629ms for 8 sentences (3.0 sentences/sec)' \ ]) Execute(languagetool handler should report no errors on empty input): AssertEqual \ [], \ ale#handlers#languagetool#HandleOutput(bufnr(''), [ \ '', \ 'Time: 2629ms for 8 sentences (3.0 sentences/sec)' \ ]) ================================================ FILE: test/handler/test_lessc_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') call ale#test#SetFilename('testfile.less') runtime ale_linters/less/lessc.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The lessc handler should handle errors for the current file correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Unrecognised input. Possibly missing something', \ }, \ ], \ ale_linters#less#lessc#Handle(bufnr(''), [ \ 'ParseError: Unrecognised input. Possibly missing something in - on line 2, column 1:', \ '1 vwewww', \ '2 ', \]) Execute(The lessc handler should handle errors for other files in the same directory correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Unrecognised input. Possibly missing something', \ 'filename': ale#path#Simplify(g:dir . '/imported.less') \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Unrecognised input. Possibly missing something', \ 'filename': ale#path#Simplify(g:dir . '/imported.less') \ }, \ ], \ ale_linters#less#lessc#Handle(bufnr(''), [ \ 'ParseError: Unrecognised input. Possibly missing something in imported.less on line 2, column 1:', \ '1 vwewww', \ '2 ', \ 'ParseError: Unrecognised input. Possibly missing something in ./imported.less on line 2, column 1:', \ '1 vwewww', \ '2 ', \]) Execute(The lessc handler should handle errors for files in directories above correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'Unrecognised input. Possibly missing something', \ 'filename': ale#path#Simplify(g:dir . '/../imported2.less') \ }, \ ], \ ale_linters#less#lessc#Handle(bufnr(''), [ \ 'ParseError: Unrecognised input. Possibly missing something in ../imported2.less on line 2, column 1:', \ '1 vwewww', \ '2 ', \]) ================================================ FILE: test/handler/test_llc_handler.vader ================================================ Before: runtime! ale_linters/llvm/llc.vim After: call ale#linter#Reset() Execute(llc handler should parse errors output for STDIN): AssertEqual \ [ \ { \ 'lnum': 10, \ 'col': 7, \ 'text': "error: value doesn't match function result type 'i32'", \ 'type': 'E', \ }, \ { \ 'lnum': 10, \ 'col': 13, \ 'text': "error: use of undefined value '@foo'", \ 'type': 'E', \ }, \ ], \ ale_linters#llvm#llc#HandleErrors(bufnr(''), [ \ "llc: :10:7: error: value doesn't match function result type 'i32'", \ 'ret i64 0', \ ' ^', \ '', \ "llc: :10:13: error: use of undefined value '@foo'", \ 'call void @foo(i64 %0)', \ ' ^', \ ]) Execute(llc handler should parse errors output for some file): call ale#test#SetFilename('test.ll') AssertEqual \ [ \ { \ 'lnum': 10, \ 'col': 7, \ 'text': "error: value doesn't match function result type 'i32'", \ 'type': 'E', \ }, \ { \ 'lnum': 10, \ 'col': 13, \ 'text': "error: use of undefined value '@foo'", \ 'type': 'E', \ }, \ ], \ ale_linters#llvm#llc#HandleErrors(bufnr(''), [ \ "llc: /path/to/test.ll:10:7: error: value doesn't match function result type 'i32'", \ 'ret i64 0', \ ' ^', \ '', \ "llc: /path/to/test.ll:10:13: error: use of undefined value '@foo'", \ 'call void @foo(i64 %0)', \ ' ^', \ ]) ================================================ FILE: test/handler/test_llvm_mc_handler.vader ================================================ Before: runtime ale_linters/asm/llvm_mc.vim After: call ale#linter#Reset() Execute(The asm llvm-mc handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 10, \ 'col' : 15, \ 'text': "invalid operand for instruction", \ 'type': 'E', \ }, \ { \ 'lnum': 11, \ 'col' : 2, \ 'text': "invalid instruction mnemonic 'lpaq'", \ 'type': 'E', \ }, \ ], \ ale_linters#asm#llvm_mc#Handle(357, [ \ "xorq %rbp, %rbp", \ "{standard_input}:10:15: error: invalid operand for instruction", \ "{standard input}:11:2: error: invalid instruction mnemonic 'lpaq'", \ ]) ================================================ FILE: test/handler/test_lua_selene_handler.vader ================================================ Before: runtime ale_linters/lua/selene.vim After: Restore call ale#linter#Reset() Execute(The selene handler for Lua should parse input correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'end_lnum': 2, \ 'col': 1, \ 'end_col': 3, \ 'text': 'empty if block', \ 'code': 'empty_if', \ 'type': 'W', \ }, \ { \ 'lnum': 1, \ 'end_lnum': 1, \ 'col': 4, \ 'end_col': 11, \ 'text': 'comparing things to nan directly is not allowed', \ 'code': 'compare_nan', \ 'type': 'E', \ 'detail': "comparing things to nan directly is not allowed\n\ntry: `x ~= x` instead" \ }, \ ], \ ale_linters#lua#selene#Handle(0, [ \ '{"severity":"Warning","code":"empty_if","message":"empty if block","primary_label":{"span":{"start":0,"start_line":0,"start_column":0,"end":20,"end_line":1,"end_column":3},"message":""},"notes":[],"secondary_labels":[]}', \ '{"severity":"Error","code":"compare_nan","message":"comparing things to nan directly is not allowed","primary_label":{"span":{"start":3,"start_line":0,"start_column":3,"end":11,"end_line":0,"end_column":11},"message":""},"notes":["try: `x ~= x` instead"],"secondary_labels":[]}', \ 'Results:', \ '1 errors', \ '1 warnings', \ '0 parse errors', \ ]) ================================================ FILE: test/handler/test_luac_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/lua/luac.vim After: Restore call ale#linter#Reset() Execute(The luac handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': 'line contains trailing whitespace', \ 'type': 'E', \ }, \ { \ 'lnum': 3, \ 'text': 'unexpected symbol near ''-''', \ 'type': 'E', \ }, \ { \ 'lnum': 5, \ 'text': '''='' expected near '')''', \ 'type': 'E', \ }, \ ], \ ale_linters#lua#luac#Handle(347, [ \ 'luac /file/path/here.lua:1: line contains trailing whitespace', \ 'luac /file/path/here.lua:3: unexpected symbol near ''-''', \ 'luac /file/path/here.lua:5: ''='' expected near '')''', \ ]) ================================================ FILE: test/handler/test_luacheck_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/lua/luacheck.vim After: Restore call ale#linter#Reset() Execute(The luacheck handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 8, \ 'text': 'line contains trailing whitespace', \ 'code': 'W612', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'text': 'unused loop variable ''k''', \ 'code': 'W213', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'col': 19, \ 'text': 'accessing undefined variable ''x''', \ 'code': 'W113', \ 'type': 'W', \ }, \ ], \ ale_linters#lua#luacheck#Handle(347, [ \ ' /file/path/here.lua:1:8: (W612) line contains trailing whitespace', \ ' /file/path/here.lua:3:5: (W213) unused loop variable ''k''', \ ' /file/path/here.lua:3:19: (W113) accessing undefined variable ''x''', \ ]) Execute(The luacheck handler should respect the warn_about_trailing_whitespace option): let g:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 43, \ 'text': 'unused argument ''g''', \ 'code': 'W212', \ 'type': 'W', \ } \ ], \ ale_linters#lua#luacheck#Handle(347, [ \ '/file/path/here.lua:15:97: (W614) trailing whitespace in a comment', \ '/file/path/here.lua:16:60: (W612) line contains trailing whitespace', \ '/file/path/here.lua:17:1: (W611) line contains only whitespace', \ '/file/path/here.lua:27:57: (W613) trailing whitespace in a string', \ '/file/path/here.lua:5:43: (W212) unused argument ''g''', \ ]) ================================================ FILE: test/handler/test_markdownlint_handler.vader ================================================ Before: runtime ale_linters/markdown/markdownlint.vim After: call ale#linter#Reset() Execute(The Markdownlint handler should parse output with a column correctly): AssertEqual \ [ \ { \ 'lnum': 10, \ 'col': 20, \ 'code': 'MD013/line-length', \ 'text': 'Line length [Expected: 80; Actual: 114]', \ 'type': 'W' \ } \ ], \ ale#handlers#markdownlint#Handle(0, [ \ 'README.md:10:20 MD013/line-length Line length [Expected: 80; Actual: 114]' \ ]) Execute(The Markdownlint handler should parse output with multiple slashes in rule name correctly): AssertEqual \ [ \ { \ 'lnum': 10, \ 'code': 'MD022/blanks-around-headings/blanks-around-headers', \ 'text': 'Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Above] [Context: "### something"]', \ 'type': 'W' \ } \ ], \ ale#handlers#markdownlint#Handle(0, [ \ 'README.md:10 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Above] [Context: "### something"]' \ ]) Execute(The Markdownlint handler should parse output with error severity (0.47.0+)): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 1, \ 'code': 'MD051/link-fragments', \ 'text': 'Link fragments should be valid [Context: "[Installation](#installation)"]', \ 'type': 'E' \ } \ ], \ ale#handlers#markdownlint#Handle(0, [ \ 'test.md:3:1 error MD051/link-fragments Link fragments should be valid [Context: "[Installation](#installation)"]' \ ]) Execute(The Markdownlint handler should parse output with warning severity (0.47.0+)): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 1, \ 'code': 'MD051/link-fragments', \ 'text': 'Link fragments should be valid [Context: "[Installation](#installation)"]', \ 'type': 'W' \ } \ ], \ ale#handlers#markdownlint#Handle(0, [ \ 'test.md:3:1 warning MD051/link-fragments Link fragments should be valid [Context: "[Installation](#installation)"]' \ ]) ================================================ FILE: test/handler/test_mcs_handler.vader ================================================ Before: runtime ale_linters/cs/mcs.vim After: call ale#linter#Reset() Execute(The mcs handler should handle cannot find symbol errors): AssertEqual \ [ \ { \ 'lnum': 12, \ 'col' : 29, \ 'text': '; expected', \ 'code': 'CS1001', \ 'type': 'E', \ }, \ { \ 'lnum': 101, \ 'col': 0, \ 'text': 'Unexpected processor directive (no #if for this #endif)', \ 'code': 'CS1028', \ 'type': 'E', \ }, \ { \ 'lnum': 10, \ 'col': 12, \ 'text': 'some warning', \ 'code': 'CS0123', \ 'type': 'W', \ }, \ ], \ ale_linters#cs#mcs#Handle(347, [ \ 'Tests.cs(12,29): error CS1001: ; expected', \ 'Tests.cs(101,0): error CS1028: Unexpected processor directive (no #if for this #endif)', \ 'Tests.cs(10,12): warning CS0123: some warning', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) ================================================ FILE: test/handler/test_mcsc_handler.vader ================================================ Before: Save g:ale_cs_mcsc_source unlet! g:ale_cs_mcsc_source call ale#test#SetDirectory('/testplugin/test/handler') call ale#test#SetFilename('Test.cs') runtime ale_linters/cs/mcsc.vim After: unlet! g:ale_cs_mcsc_source call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The mcs handler should work with the default of the buffer's directory): AssertEqual \ [ \ { \ 'lnum': 12, \ 'col' : 29, \ 'text': '; expected', \ 'code': 'CS1001', \ 'type': 'E', \ 'filename': ale#path#Simplify(g:dir . '/Test.cs'), \ }, \ ], \ ale_linters#cs#mcsc#Handle(bufnr(''), [ \ 'Test.cs(12,29): error CS1001: ; expected', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) Execute(The mcs handler should handle cannot find symbol errors): let g:ale_cs_mcsc_source = '/home/foo/project/bar' AssertEqual \ [ \ { \ 'lnum': 12, \ 'col' : 29, \ 'text': '; expected', \ 'code': 'CS1001', \ 'type': 'E', \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ { \ 'lnum': 101, \ 'col': 0, \ 'text': 'Unexpected processor directive (no #if for this #endif)', \ 'code': 'CS1028', \ 'type': 'E', \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ { \ 'lnum': 10, \ 'col': 12, \ 'text': 'some warning', \ 'code': 'CS0123', \ 'type': 'W', \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ ], \ ale_linters#cs#mcsc#Handle(bufnr(''), [ \ 'Test.cs(12,29): error CS1001: ; expected', \ 'Test.cs(101,0): error CS1028: Unexpected processor directive (no #if for this #endif)', \ 'Test.cs(10,12): warning CS0123: some warning', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) Execute(The mcsc handler should handle non file specific compiler errors without reporting overal status report as error): let g:ale_cs_mcsc_source = '/home/foo/project/bar' AssertEqual \ [ \ { \ 'lnum': -1, \ 'col' : -1, \ 'text': 'No files to compile were specified', \ 'code': 'CS2008', \ 'type': 'E', \ 'filename': '', \ }, \ ], \ ale_linters#cs#mcsc#Handle(bufnr(''), [ \ 'error CS2008: No files to compile were specified', \ 'Compilation failed: 1 error(s), 0 warnings', \ ]) ================================================ FILE: test/handler/test_mdl_handler.vader ================================================ Before: runtime ale_linters/markdown/mdl.vim After: call ale#linter#Reset() Execute(The mdl handler should parse output correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'code': 'MD002/first-header-h1', \ 'text': 'First header should be a top level header', \ 'type': 'W' \ }, \ { \ 'lnum': 18, \ 'code': 'MD033/no-inline-html', \ 'text': 'Inline HTML', \ 'type': 'W' \ } \ ], \ ale_linters#markdown#mdl#Handle(0, [ \ '[{"filename":"README.md","line":1,"rule":"MD002","aliases":["first-header-h1"],"description":"First header should be a top level header"},{"filename":"README.md","line":18,"rule":"MD033","aliases":["no-inline-html"],"description":"Inline HTML"}]' \ ]) ================================================ FILE: test/handler/test_mercury_mmc_handler.vader ================================================ Before: runtime ale_linters/mercury/mmc.vim After: call ale#linter#Reset() Execute(The mmc handler should handle syntax errors): AssertEqual \ [ \ { \ 'lnum': 3, \ 'type': 'E', \ 'text': "Syntax error at token ',': operator precedence error." \ } \ ], \ ale_linters#mercury#mmc#Handle(1, [ \ "file_name.m:003: Syntax error at token ',': operator precedence error." \ ]) Execute(The mmc handler should handle warnings): AssertEqual \ [ \ { \ 'lnum': 10, \ 'type': 'W', \ 'text': 'Warning: reference to uninitialized state variable !.X.' \ }, \ { \ 'lnum': 12, \ 'type': 'W', \ 'text': 'warning: determinism declaration could be tighter.' \ } \ ], \ ale_linters#mercury#mmc#Handle(1, [ \ 'file_name.m:010: Warning: reference to uninitialized state variable !.X.', \ "file_name.m:012: In `some_predicate':", \ 'file_name.m:012: warning: determinism declaration could be tighter.' \ ]) Execute(The mmc handler should handle semantic errors): AssertEqual \ [ \ { \ 'lnum': 7, \ 'type': 'E', \ 'text': "error: undefined type `bar'/0." \ }, \ { \ 'lnum': 15, \ 'type': 'E', \ 'text': "Error: circular equivalence type `file_name.foo'/0." \ } \ ], \ ale_linters#mercury#mmc#Handle(1, [ \ "file_name.m:007: In clause for predicate `foldit'/4:", \ "file_name.m:007: error: undefined type `bar'/0.", \ "file_name.m:015: Error: circular equivalence type `file_name.foo'/0." \ ]) ================================================ FILE: test/handler/test_mix_handler.vader ================================================ Before: runtime ale_linters/elixir/mix.vim After: call ale#linter#Reset() Execute(The mix handler should parse lines correctly): AssertEqual \ [ \ { \ 'bufnr': 347, \ 'lnum': 87, \ 'col': 0, \ 'text': 'undefined function update_in/4', \ 'type': 'E', \ }, \ ], \ ale_linters#elixir#mix#Handle(347, [ \ '** (CompileError) apps/sim/lib/sim/server.ex:87: undefined function update_in/4' \ ]) ================================================ FILE: test/handler/test_msgfmt_hander.vader ================================================ Before: runtime ale_linters/po/msgfmt.vim After: call ale#linter#Reset() Execute(Duplicate messages should be made easier to navigate): AssertEqual \ [ \ {'lnum': 14, 'col': 0, 'type': 'W', 'text': 'some other thing'}, \ {'lnum': 1746, 'col': 0, 'type': 'W', 'text': 'duplicate of message at line 262'}, \ {'lnum': 262, 'col': 0, 'type': 'W', 'text': 'first location of duplicate of message at line 1746'}, \ {'lnum': 666, 'col': 0, 'type': 'W', 'text': 'duplicate message definition...'}, \ {'lnum': 888, 'col': 0, 'type': 'W', 'text': 'some other thing'}, \ {'lnum': 999, 'col': 0, 'type': 'W', 'text': '...this is the location of the first definition'}, \ ], \ ale_linters#po#msgfmt#Handle(bufnr(''), [ \ '/tmp/v6GMUFf/16/foo.po:14: some other thing', \ '/tmp/v6GMUFf/16/foo.po:1746: duplicate message definition...', \ '/tmp/v6GMUFf/16/foo.po:262: ...this is the location of the first definition', \ '/tmp/v6GMUFf/16/foo.po:666: duplicate message definition...', \ '/tmp/v6GMUFf/16/foo.po:888: some other thing', \ '/tmp/v6GMUFf/16/foo.po:999: ...this is the location of the first definition', \ ]) ================================================ FILE: test/handler/test_mypy_handler.vader ================================================ Before: Save g:ale_python_mypy_ignore_invalid_syntax Save g:ale_python_mypy_show_notes unlet! g:ale_python_mypy_show_notes unlet! g:ale_python_mypy_ignore_invalid_syntax runtime ale_linters/python/mypy.vim call ale#test#SetDirectory('/testplugin/test/handler') After: Restore call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The mypy handler should parse lines correctly): call ale#test#SetFilename('__init__.py') let g:ale_python_mypy_show_notes = 0 AssertEqual \ [ \ { \ 'lnum': 768, \ 'col': 38, \ 'filename': ale#path#Simplify(g:dir . '/baz.py'), \ 'type': 'E', \ 'text': 'Cannot determine type of ''SOME_SYMBOL''', \ }, \ { \ 'lnum': 821, \ 'col': 38, \ 'filename': ale#path#Simplify(g:dir . '/baz.py'), \ 'type': 'E', \ 'text': 'Cannot determine type of ''SOME_SYMBOL''', \ }, \ { \ 'lnum': 38, \ 'col': 44, \ 'filename': ale#path#Simplify(g:dir . '/other.py'), \ 'type': 'E', \ 'text': 'Cannot determine type of ''ANOTHER_SYMBOL''', \ }, \ { \ 'lnum': 15, \ 'col': 3, \ 'filename': ale#path#Simplify(g:dir . '/__init__.py'), \ 'type': 'E', \ 'text': 'Argument 1 to "somefunc" has incompatible type "int"; expected "str"' \ }, \ { \ 'lnum': 72, \ 'col': 1, \ 'filename': ale#path#Simplify(g:dir . '/__init__.py'), \ 'type': 'W', \ 'text': 'Some warning', \ }, \ ], \ ale_linters#python#mypy#Handle(bufnr(''), [ \ 'baz.py: note: In class "SomeClass":', \ 'baz.py:768:38: error: Cannot determine type of ''SOME_SYMBOL''', \ 'baz.py: note: In class "AnotherClass":', \ 'baz.py:821:38: error: Cannot determine type of ''SOME_SYMBOL''', \ '__init__.py:92: note: In module imported here:', \ 'other.py: note: In class "YetAnotherClass":', \ 'other.py:38:44: error: Cannot determine type of ''ANOTHER_SYMBOL''', \ '__init__.py: note: At top level:', \ '__init__.py:15:3: error: Argument 1 to "somefunc" has incompatible type "int"; expected "str"', \ 'another_module/bar.py:14: note: In module imported here,', \ 'another_module/__init__.py:16: note: ... from here,', \ '__init__.py:72:1: warning: Some warning', \ ]) Execute(The mypy handler should show notes if enabled): call ale#test#SetFilename('__init__.py') AssertEqual \ [ \ { \ 'lnum': 72, \ 'col': 1, \ 'filename': ale#path#Simplify(g:dir . '/__init__.py'), \ 'type': 'I', \ 'text': 'A note', \ }, \ ], \ ale_linters#python#mypy#Handle(bufnr(''), [ \ '__init__.py:72:1: note: A note', \ ]) let g:ale_python_mypy_show_notes = 0 AssertEqual \ [], \ ale_linters#python#mypy#Handle(bufnr(''), [ \ '__init__.py:72:1: note: A note', \ ]) Execute(The mypy handler should handle Windows names with spaces): " This test works on Unix, where this is seen as a single filename silent file C:\\something\\with\ spaces.py AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 0, \ 'filename': ale#path#GetAbsPath(getcwd(), 'C:\something\with spaces.py'), \ 'type': 'E', \ 'text': 'No library stub file for module ''django.db''', \ }, \ ], \ ale_linters#python#mypy#Handle(bufnr(''), [ \ 'C:\something\with spaces.py:4: error: No library stub file for module ''django.db''', \ ]) Execute(The mypy syntax errors shouldn't be ignored by default): AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 0, \ 'filename': ale#path#Simplify(g:dir . '/foo.py'), \ 'type': 'E', \ 'text': 'invalid syntax', \ }, \ ], \ ale_linters#python#mypy#Handle(bufnr(''), [ \ 'foo.py:4: error: invalid syntax', \ ]) Execute(The mypy syntax errors should be ignored when the option is on): let g:ale_python_mypy_ignore_invalid_syntax = 1 AssertEqual \ [], \ ale_linters#python#mypy#Handle(bufnr(''), [ \ 'foo.py:4: error: invalid syntax', \ ]) ================================================ FILE: test/handler/test_naga_handler.vader ================================================ Before: runtime ale_linters/wgsl/naga.vim After: call ale#linter#Reset() Execute(Error handler should parse error message and position from input): let example_output = [ \ "error: expected global item ('struct', 'let', 'var', 'type', ';', 'fn') or the end of the file, found '['", \ " ┌─ wgsl:5:1", \ " │", \ "5 │ [[group(1), binding(0)]]", \ " │ ^ expected global item ('struct', 'let', 'var', 'type', ';', 'fn') or the end of the file", \ "Could not parse WGSL", \ ] let actual = ale#handlers#naga#Handle(0, example_output) let expected = [{ \ "text": "expected global item ('struct', 'let', 'var', 'type', ';', 'fn') or the end of the file, found '['", \ "lnum": 5, \ "col": 1, \ "type": "E", \ }] AssertEqual actual, expected ================================================ FILE: test/handler/test_nagelfar_handler.vader ================================================ Before: runtime ale_linters/tcl/nagelfar.vim After: call ale#linter#Reset() Execute(The nagelfar handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 5, \ 'type': 'W', \ 'text': 'Found constant "bepa" which is also a variable.' \ }, \ { \ 'lnum': 7, \ 'type': 'E', \ 'text': 'Unknown variable "cep"' \ }, \ { \ 'lnum': 7, \ 'type': 'W', \ 'text': 'Unknown command "se"' \ }, \ { \ 'lnum': 8, \ 'type': 'E', \ 'text': 'Unknown variable "epa"' \ }, \ { \ 'lnum': 10, \ 'type': 'E', \ 'text': 'Unknown variable "depa"' \ }, \ { \ 'lnum': 10, \ 'type': 'W', \ 'text': 'Suspicious variable name "$depa"' \ }, \ { \ 'lnum': 11, \ 'type': 'W', \ 'text': 'Suspicious variable name "$cepa"' \ }, \ { \ 'lnum': 13, \ 'type': 'E', \ 'text': 'Wrong number of arguments (3) to "set"' \ }, \ { \ 'lnum': 13, \ 'type': 'W', \ 'text': 'Found constant "bepa" which is also a variable.' \ }, \ { \ 'lnum': 13, \ 'type': 'W', \ 'text': 'Found constant "cepa" which is also a variable.' \ }, \ { \ 'lnum': 18, \ 'type': 'E', \ 'text': 'Badly formed if statement' \ }, \ { \ 'lnum': 24, \ 'type': 'E', \ 'text': 'Unknown subcommand "gurka" to "info"' \ }, \ { \ 'lnum': 31, \ 'type': 'W', \ 'text': 'Switch pattern starting with #. This could be a bad comment.' \ }, \ { \ 'lnum': 31, \ 'type': 'W', \ 'text': 'Unknown command "This"' \ }, \ { \ 'lnum': 31, \ 'type': 'W', \ 'text': 'Unknown command "bad"' \ }, \ { \ 'lnum': 34, \ 'type': 'W', \ 'text': 'Unknown command "miffo"' \ }, \ { \ 'lnum': 55, \ 'type': 'W', \ 'text': 'Suspicious variable name "$bepa"' \ }, \ { \ 'lnum': 56, \ 'type': 'W', \ 'text': 'Suspicious variable name "$apa"' \ }, \ { \ 'lnum': 61, \ 'type': 'E', \ 'text': 'Could not complete statement.' \ }, \ { \ 'lnum': 67, \ 'type': 'E', \ 'text': 'Could not complete statement.' \ }, \ { \ 'lnum': 70, \ 'type': 'E', \ 'text': 'Wrong number of arguments (4) to "proc"' \ }, \ { \ 'lnum': 72, \ 'type': 'E', \ 'text': 'Wrong number of arguments (1) to "if"' \ }, \ { \ 'lnum': 75, \ 'type': 'E', \ 'text': 'Unbalanced close brace found' \ }, \ { \ 'lnum': 82, \ 'type': 'E', \ 'text': 'Unbalanced close brace found' \ }, \ { \ 'lnum': 88, \ 'type': 'E', \ 'text': 'Could not complete statement.' \ }, \ { \ 'lnum': 90, \ 'type': 'E', \ 'text': 'Wrong number of arguments (1) to "if"' \ }, \ { \ 'lnum': 93, \ 'type': 'W', \ 'text': 'Close brace not aligned with line 90 (4 0)' \ }, \ ], \ ale_linters#tcl#nagelfar#Handle(bufnr(''), [ \ 'Line 5: W Found constant "bepa" which is also a variable.', \ 'Line 7: E Unknown variable "cep"', \ 'Line 7: W Unknown command "se"', \ 'Line 8: E Unknown variable "epa"', \ 'Line 10: E Unknown variable "depa"', \ 'Line 10: N Suspicious variable name "$depa"', \ 'Line 11: N Suspicious variable name "$cepa"', \ 'Line 13: E Wrong number of arguments (3) to "set"', \ 'Line 13: W Found constant "bepa" which is also a variable.', \ 'Line 13: W Found constant "cepa" which is also a variable.', \ 'Line 18: E Badly formed if statement', \ 'Line 24: E Unknown subcommand "gurka" to "info"', \ 'Line 31: W Switch pattern starting with #. This could be a bad comment.', \ 'Line 31: W Unknown command "This"', \ 'Line 31: W Unknown command "bad"', \ 'Line 34: W Unknown command "miffo"', \ 'Line 55: N Suspicious variable name "$bepa"', \ 'Line 56: N Suspicious variable name "$apa"', \ 'Line 61: E Could not complete statement.', \ 'Line 67: E Could not complete statement.', \ 'Line 70: E Wrong number of arguments (4) to "proc"', \ 'Line 72: E Wrong number of arguments (1) to "if"', \ 'Line 75: E Unbalanced close brace found', \ 'Line 82: E Unbalanced close brace found', \ 'Line 88: E Could not complete statement.', \ 'Line 90: E Wrong number of arguments (1) to "if"', \ 'Line 93: N Close brace not aligned with line 90 (4 0)', \ ]) ================================================ FILE: test/handler/test_nasm_handler.vader ================================================ Before: runtime ale_linters/nasm/nasm.vim After: call ale#linter#Reset() Execute(The nasm handler should parse GCC style output from nasm correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'text': "label alone on a line without a colon might be in error", \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'text': "invalid combination of opcode and operands", \ 'type': 'E', \ }, \ { \ 'lnum': 7, \ 'text': "unable to open include file `bar.asm'", \ 'type': 'E', \ }, \ ], \ ale_linters#nasm#nasm#Handle(bufnr(''), [ \ "tmp.asm:2: warning: label alone on a line without a colon might be in error", \ "tmp.asm:4: error: invalid combination of opcode and operands", \ "tmp.asm:7: fatal: unable to open include file `bar.asm'" \ ]) ================================================ FILE: test/handler/test_nim_handler.vader ================================================ Before: runtime ale_linters/nim/nimcheck.vim After: call ale#linter#Reset() Execute(Parsing nim errors should work): silent file foobar.nim AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 8, \ 'text': 'use {.base.} for base methods; baseless methods are deprecated', \ 'code': 'UseBase', \ 'type': 'W', \ }, \ { \ 'lnum': 12, \ 'col': 2, \ 'text': 'identifier expected, but found ''a.barfoo''', \ 'type': 'E', \ 'end_col': 9, \ }, \ { \ 'lnum': 2, \ 'col': 5, \ 'text': '''NotUsed'' is declared but not used', \ 'code': 'XDeclaredButNotUsed', \ 'type': 'W', \ 'end_col': 11, \ }, \ { \ 'lnum': 12, \ 'col': 2, \ 'text': 'with : character', \ 'type': 'E', \ }, \ { \ 'lnum': 1, \ 'col': 8, \ 'text': 'imported and not used: ''strutils''', \ 'code': 'UnusedImport', \ 'type': 'W', \ 'end_col': 15, \ }, \ { \ 'lnum': 12, \ 'col': 9, \ 'text': 'undeclared identifier: ''total''', \ 'type': 'E', \ 'end_col': 13, \ }, \ { \ 'lnum': 14, \ 'col': 1, \ 'text': '''sum'' cannot be assigned to', \ 'type': 'E', \ 'end_col': 3, \ }, \ { \ 'lnum': 15, \ 'col': 1, \ 'text': 'redefinition of ''getName''; previous declaration here: /nested/folder/foobar.nim(14, 6)', \ 'type': 'E', \ 'end_col': 7, \ }, \ ], \ ale_linters#nim#nimcheck#Handle(bufnr(''), [ \ 'Line with wrong( format)', \ 'foobar.nim(8, 8) Warning: use {.base.} for base methods; baseless methods are deprecated [UseBase]', \ 'foobar.nim(12, 2) Error: identifier expected, but found ''a.barfoo''', \ '/nested/folder/foobar.nim(2, 5) Hint: ''NotUsed'' is declared but not used [XDeclaredButNotUsed]', \ 'foobar.nim(12, 2) Error: with : character', \ 'foobar.nim(1, 8) Warning: imported and not used: ''strutils'' [UnusedImport]', \ 'foobar.nim(12, 9) Error: undeclared identifier: ''total''', \ 'foobar.nim(14, 1) Error: ''sum'' cannot be assigned to', \ 'foobar.nim(15, 1) Error: redefinition of ''getName''; previous declaration here: /nested/folder/foobar.nim(14, 6)', \ ]) ================================================ FILE: test/handler/test_nix_handler.vader ================================================ Before: runtime ale_linters/nix/nix.vim After: call ale#linter#Reset() Execute(The nix handler should parse nix-instantiate error messages correctly): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 3, \ 'type': 'E', \ 'text': "syntax error, unexpected ']', expecting ';'", \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'type': 'E', \ 'text': "undefined variable 'foo'", \ }, \ \ ], \ ale_linters#nix#nix#Handle(bufnr(''), [ \ "@nix {\"line\":6,\"column\":3,\"raw_msg\":\"syntax error, unexpected ']', expecting ';'\"}", \ "@nix {\"line\":3,\"column\":5,\"raw_msg\":\"undefined variable 'foo'\"}", \ "@nix {\"unrelated\":\"message\"}" \ ]) Execute(The nix handler should parse nix-instantiate error messages with ANSI color codes correctly): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 5, \ 'type': 'E', \ 'text': "undefined variable 'foo'", \ }, \ \ ], \ ale_linters#nix#nix#Handle(bufnr(''), [ \ "@nix {\"line\":3,\"column\":5,\"raw_msg\":\"undefined variable '\\u001b[35;1mfoo\\u001b[0m'\"}", \ "@nix {\"unrelated\":\"message\"}" \ ]) Execute(The nix handler should parse message from old nix-instantiate correctly): AssertEqual \ [ \ { \ 'lnum': 23, \ 'col': 14, \ 'text': 'error: syntax error, unexpected IN', \ 'type': 'E', \ }, \ { \ 'lnum': 3, \ 'col': 12, \ 'text': 'error: syntax error, unexpected ''='', expecting '';''', \ 'type': 'E', \ }, \ \ ], \ ale_linters#nix#nix#Handle(47, [ \ 'This line should be ignored', \ 'error: syntax error, unexpected IN, at /path/to/filename.nix:23:14', \ 'error: syntax error, unexpected ''='', expecting '';'', at /path/to/filename.nix:3:12', \ ]) Execute(The nix command should not add 'log-format' option for nix version 2.3): AssertEqual \ 'nix-instantiate --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.3.0'], '') Execute(The nix command should add 'log-format' option for nix version 2.4): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.4.1'], '') Execute(The nix command should add 'log-format' option for nix version 2.5): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.5.0pre20211206_d1aaa7e'], '') Execute(The nix command should add 'log-format' option for nix version 2.6): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.6.0pre20211206_ignored'], '') Execute(The nix command should add 'log-format' option for nix version 2.7): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.7.0pre20211206_ignored'], '') Execute(The nix command should add 'log-format' option for nix version 2.8): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.8.0pre20211206_ignored'], '') Execute(The nix command should add 'log-format' option for nix version 2.9): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.9.0pre20211206_ignored'], '') Execute(The nix command should add 'log-format' option for nix version 2.10): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.10.0pre20221221_ignored'], '') Execute(The nix command should add 'log-format' option for nix version 2.20): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 2.20.0pre20221221_ignored'], '') Execute(The nix command should add 'log-format' option for nix version 3.0): AssertEqual \ 'nix-instantiate --log-format internal-json --parse -', \ ale_linters#nix#nix#Command('', ['nix-instantiate (Nix) 3.0.0pre20211206_ignored'], '') ================================================ FILE: test/handler/test_npmgroovylint_handler.vader ================================================ Before: runtime ale_linters/groovy/npmgroovylint.vim After: call ale#linter#Reset() Execute(The npm-groovy-lint handler should parse JSON): AssertEqual \ [ \ { \ 'col': 0, \ 'end_col': 1, \ 'end_lnum': 2, \ 'filename': 'test2.groovy', \ 'lnum': 2, \ 'text': 'Some error message', \ 'type': 'E', \ }, \ { \ 'filename': 'test.groovy', \ 'lnum': 1, \ 'text': 'Some warning message', \ 'type': 'W', \ }, \ ], \ ale_linters#groovy#npmgroovylint#Handle(bufnr(''), [ \ '{', \ ' "files" : {', \ ' "test.groovy" : {', \ ' "errors" : [', \ ' {', \ ' "id" : 0,', \ ' "line" : 1,', \ ' "msg" : "Some warning message",', \ ' "rule" : "SomeRule",', \ ' "severity" : "warning"', \ ' }', \ ' ]', \ ' },', \ ' "test2.groovy": {', \ ' "errors": [', \ ' {', \ ' "id" : 1,', \ ' "line" : 2,', \ ' "msg" : "Some error message",', \ ' "range" : {', \ ' "end" : {', \ ' "character" : 1,', \ ' "line" : 2', \ ' },', \ ' "start" : {', \ ' "character" : 0,', \ ' "line" : 2', \ ' }', \ ' },', \ ' "rule" : "SomeOtherRule",', \ ' "severity" : "error"', \ ' }', \ ' ]', \ ' }', \ ' }', \ '}', \ ]) ================================================ FILE: test/handler/test_openscad_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') " Load sca2d runtime ale_linters/openscad/sca2d.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The openscad handler should handle sca2d output): AssertEqual \ [ \ { \ 'filename': ale#path#Simplify(g:dir . '/awesome_project.scad'), \ 'lnum': 7, \ 'type': 'E', \ 'col': 42, \ 'text': 'Module `corcle` used but never defined.', \ 'detail': 'E2002: Module `corcle` used but never defined.', \ }, \ ], \ ale#handlers#openscad#SCA2D_callback(bufnr(''), [ \ 'awesome_project.scad:7:42: E2002: Module `corcle` used but never defined.', \ '', \ 'SCA2D message summary', \ '=====================', \ 'Fatal errors: 0', \ 'Errors: 1', \ 'Warnings: 0', \ 'Info: 0', \ 'Depreciated 0', \ ]) AssertEqual \ [ \ { \ 'filename': ale#path#Simplify(g:dir . '/awesome_project.scad'), \ 'lnum': 1, \ 'type': 'E', \ 'col': 37, \ 'text': 'Cannot read file due to syntax error: - No terminal matches ''}'' in the current parser context', \ 'detail': 'F0001: Cannot read file due to syntax error: - No terminal matches ''}'' in the current parser context', \ }, \ ], \ ale#handlers#openscad#SCA2D_callback(bufnr(''), [ \ 'awesome_project.scad:1:1: F0001: Cannot read file due to syntax error:', \ ' - No terminal matches ''}'' in the current parser context, at line 1 col 37', \ ' - ', \ ' - translate([ 0, 0, 0 ]) { circle(10) }', \ ' - ^', \ ' - Expected one of: ', \ ' - * IF', \ ' - * LET', \ ' - * FOR', \ ' - * FUNC_CALL_NAME', \ ' - * TERMINATION', \ ' - * STAR', \ ' - * LBRACE', \ ' - * BANG', \ ' - * ASSIGN', \ ' - * PERCENT', \ ' - * HASH', \ ' - * INTERSECTION_FOR', \ ' - ', \ 'If you believe this is a bug in SCA2D please report it to us.', \ '', \ '', \ 'SCA2D message summary', \ '=====================', \ 'Fatal errors: 1', \ 'Errors: 0', \ 'Warnings: 0', \ 'Info: 0', \ 'Depreciated 0', \ ]) ================================================ FILE: test/handler/test_packwerk_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') cd .. runtime ale_linters/ruby/packwerk.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The packwerk handler should parse lines correctly): call ale#test#SetFilename('test-files/ruby/valid_rails_app/app/models/thing.rb') AssertEqual \ [ \ { \ 'lnum': 36, \ 'col': 100, \ 'text': 'Dependency violation: ::Edi::Source belongs to ''edi'', but ''billing'' does not specify a dependency on ''edi''.', \ } \ ], \ ale_linters#ruby#packwerk#Handle(bufnr(''), [ \ '/Users/JaneDoe/src/github.com/sample-project/billing/app/jobs/document_processing_job.rb:36:100', \ 'Dependency violation: ::Edi::Source belongs to ''edi'', but ''billing'' does not specify a dependency on ''edi''.', \ 'Are we missing an abstraction?', \ 'Is the code making the reference, and the referenced constant, in the right packages?', \ '', \ 'Inference details: ''Edi::Source'' refers to ::Edi::Source which seems to be defined in edi/app/models/edi/source.rb.', \ ]) ================================================ FILE: test/handler/test_perl6_handler.vader ================================================ 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" : "", \ "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 $_ = 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 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 $_ = 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 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"', \ '}', \ '}', \ ]) ================================================ FILE: test/handler/test_perl_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') runtime ale_linters/perl/perl.vim 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') AssertEqual \ [ \ {'lnum': '2', 'type': 'E', 'text': 'Compilation failed in require'}, \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ 'syntax error at ' . ale#path#Simplify(g:dir . '/foo.pm') . ' line 4, near "aklsdfjmy "', \ 'Compilation failed in require at ' . ale#path#Simplify(g:dir . '/bar.pl') . ' line 2.', \ 'BEGIN failed--compilation aborted at ' . ale#path#Simplify(g:dir . '/bar.pl') . ' line 2.', \ ]) Execute(The Perl linter should complain about failing to locate modules): AssertEqual \ [ \ { \ 'lnum': '23', \ 'type': 'E', \ 'text': 'Can''t locate JustOneDb.pm in @INC (you may need to install the JustOneDb module) (@INC contains: /home/local/sean/work/PostgreSQL/6616/../../../../lib /home/local/sean/work/PostgreSQL/6616/lib lib /etc/perl /usr/local/lib/perl/5.18.2 /usr/local/share/perl/5.18.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.18 /usr/share/perl/5.18 /usr/local/lib/site_perl .)', \ }, \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ 'Can''t locate JustOneDb.pm in @INC (you may need to install the JustOneDb module) (@INC contains: /home/local/sean/work/PostgreSQL/6616/../../../../lib /home/local/sean/work/PostgreSQL/6616/lib lib /etc/perl /usr/local/lib/perl/5.18.2 /usr/local/share/perl/5.18.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.18 /usr/share/perl/5.18 /usr/local/lib/site_perl .) at - line 23.', \ 'BEGIN failed--compilation aborted at - line 23.', \ ]) Execute(The Perl linter should complain about failing to locate modules): AssertEqual \ [ \ {'lnum': '8', 'type': 'E', 'text': 'BEGIN failed--compilation aborted'}, \ {'lnum': '10', 'type': 'E', 'text': 'BEGIN failed--compilation aborted'} \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ 'Unable to build `ro` accessor for slot `path` in `App::CPANFileUpdate` because the slot cannot be found. at /extlib/Method/Traits.pm line 189.', \ 'BEGIN failed--compilation aborted at - line 8.', \ 'Unable to build `ro` accessor for slot `path` in `App::CPANFileUpdate` because the slot cannot be found. at /extlib/Method/Traits.pm line 189.', \ 'BEGIN failed--compilation aborted at - line 10.', \ ]) Execute(The Perl linter should not report warnings as errors): AssertEqual \ [ \ {'lnum': '5', 'type': 'W', 'text': '"my" variable $foo masks earlier declaration in same scope'}, \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ '"my" variable $foo masks earlier declaration in same scope at - line 5.', \ 't.pl syntax OK', \ ]) Execute(The Perl linter does not default to reporting generic error): AssertEqual \ [ \ {'lnum': '8', 'type': 'E', 'text': 'Missing right curly or square bracket'}, \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ 'Missing right curly or square bracket at - line 8, at end of line', \ 'syntax error at - line 8, at EOF', \ 'Execution of t.pl aborted due to compilation errors.', \ ]) " The first "error" is actually a warning, but the current implementation " doesn't have a good way of teasing out the warnings from amongst the " errors. If we're able to do this in future, then we'll want to switch " the first "E" to a "W". Execute(The Perl linter reports errors even when mixed with warnings): AssertEqual \ [ \ {'lnum': '5', 'type': 'E', 'text': '"my" variable $foo masks earlier declaration in same scope'}, \ {'lnum': '8', 'type': 'E', 'text': 'Missing right curly or square bracket'}, \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ '"my" variable $foo masks earlier declaration in same scope at - line 5.', \ 'Missing right curly or square bracket at - line 8, at end of line', \ 'syntax error at - line 8, at EOF', \ 'Execution of t.pl aborted due to compilation errors.', \ ]) Execute(The Perl linter reports errors even when an additional file location is included): AssertEqual \ [ \ {'lnum': '5', 'type': 'E', 'text': '"my" variable $foo masks earlier declaration in same scope'}, \ {'lnum': '6', 'type': 'E', 'text': '"my" variable $foo masks earlier declaration in same scope'}, \ {'lnum': '11', 'type': 'E', 'text': 'Global symbol "$asdf" requires explicit package name (did you forget to declare "my $asdf"?)'}, \ {'lnum': '12', 'type': 'E', 'text': 'Global symbol "$asdf" requires explicit package name (did you forget to declare "my $asdf"?)'}, \ ], \ ale_linters#perl#perl#Handle(bufnr(''), [ \ '"my" variable $foo masks earlier declaration in same scope at - line 5.', \ '"my" variable $foo masks earlier declaration in same scope at - line 6, at line 1.', \ 'Global symbol "$asdf" requires explicit package name (did you forget to declare "my $asdf"?) at - line 11.', \ 'Global symbol "$asdf" requires explicit package name (did you forget to declare "my $asdf"?) at - line 12, line 1.', \ 'Execution of t.pl aborted due to compilation errors.', \ ]) ================================================ FILE: test/handler/test_perlcritic_handler.vader ================================================ Before: runtime ale_linters/perl/perlcritic.vim After: call ale#linter#Reset() Execute(The Perl::Critic handler should create all issues as warnings): AssertEqual \ [ \ { \ 'lnum': '21', \ 'col': '17', \ 'text': 'Regular expression without "/m" flag', \ 'type': 'W', \ } \ ], \ ale_linters#perl#perlcritic#Handle(99, [ \ '21:17 Regular expression without "/m" flag' \ ]) ================================================ FILE: test/handler/test_php_handler.vader ================================================ Before: runtime ale_linters/php/php.vim After: call ale#linter#Reset() Given (Some invalid lines of PHP): [foo;] class Foo { / } $foo) ['foo' 'bar'] function count() {} Execute(The php handler should calculate column numbers): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 5, \ 'end_col': 5, \ 'text': "syntax error, unexpected ';', expecting ']'", \ }, \ { \ 'lnum': 2, \ 'col': 13, \ 'end_col': 13, \ 'text': "syntax error, unexpected '/', expecting function (T_FUNCTION) or const (T_CONST)", \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'end_col': 5, \ 'text': "syntax error, unexpected ')'", \ }, \ { \ 'lnum': 4, \ 'col': 8, \ 'end_col': 12, \ 'text': "syntax error, unexpected ''bar'' (T_CONSTANT_ENCAPSED_STRING), expecting ']'", \ }, \ ], \ ale_linters#php#php#Handle(347, [ \ "This line should be ignored completely", \ "Parse error: syntax error, unexpected ';', expecting ']' in - on line 1", \ "Parse error: syntax error, unexpected '/', expecting function (T_FUNCTION) or const (T_CONST) in - on line 2", \ "Parse error: syntax error, unexpected ')' in - on line 3", \ "Parse error: syntax error, unexpected ''bar'' (T_CONSTANT_ENCAPSED_STRING), expecting ']' in - on line 4", \ ]) Execute (The php handler should ignore lines starting with 'PHP Parse error'): AssertEqual \ [], \ ale_linters#php#php#Handle(347, [ \ "PHP Parse error: syntax error, This line should be ignored completely in - on line 1", \ ]) Execute (The php handler should handle lines containing 'Standard input code'): AssertEqual \ [ \ { \ 'lnum': 47, \ 'col': 0, \ 'text': "Invalid numeric literal", \ }, \ ], \ ale_linters#php#php#Handle(347, [ \ "Parse error: Invalid numeric literal in Standard input code on line 47", \ ]) Execute (The php handler should parse lines without column indication): AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 0, \ 'text': "Cannot redeclare count()", \ }, \ { \ 'lnum': 21, \ 'col': 0, \ 'text': "syntax error, unexpected end of file", \ }, \ { \ 'lnum': 47, \ 'col': 0, \ 'text': "Invalid numeric literal", \ }, \ ], \ ale_linters#php#php#Handle(347, [ \ "This line should be ignored completely", \ "Fatal error: Cannot redeclare count() in - on line 5", \ "Parse error: syntax error, unexpected end of file in - on line 21", \ "Parse error: Invalid numeric literal in - on line 47", \ ]) ================================================ FILE: test/handler/test_php_phan_handler.vader ================================================ Before: runtime ale_linters/php/phan.vim After: call ale#linter#Reset() Execute(The php static analyzer handler should parse errors from phan): AssertEqual \ [ \ { \ 'lnum': 25, \ 'type': 'W', \ 'text': 'Return type of getValidator is undeclared type \Respect\Validation\Validator', \ 'filename': 'example.php', \ }, \ { \ 'lnum': 66, \ 'type': 'W', \ 'text': 'Call to method string from undeclared class \Respect\Validation\Validator', \ 'filename': 'example.php', \ }, \ ], \ ale_linters#php#phan#Handle(347, [ \ "example.php:25 PhanUndeclaredTypeReturnType Return type of getValidator is undeclared type \\Respect\\Validation\\Validator", \ "example.php:66 PhanUndeclaredClassMethod Call to method string from undeclared class \\Respect\\Validation\\Validator", \ ]) ================================================ FILE: test/handler/test_php_phpmd_handler.vader ================================================ Before: runtime ale_linters/php/phpmd.vim After: call ale#linter#Reset() Execute(The php static analyzer handler should parse errors from phpmd): AssertEqual \ [ \ { \ 'lnum': 22, \ 'type': 'W', \ 'text': "Avoid unused local variables such as '$response'.", \ }, \ { \ 'lnum': 14, \ 'type': 'W', \ 'text': "The method test uses an else expression. Else is never necessary and you can simplify the code to work without else.", \ }, \ ], \ ale_linters#php#phpmd#Handle(347, [ \ "example.php:22 Avoid unused local variables such as '$response'.", \ "example.php:14 The method test uses an else expression. Else is never necessary and you can simplify the code to work without else.", \ ]) ================================================ FILE: test/handler/test_phpcs_handler.vader ================================================ Before: runtime ale_linters/php/phpcs.vim After: call ale#linter#Reset() Execute(phpcs errors should be handled): AssertEqual \ [ \ { \ 'lnum': 18, \ 'col': 3, \ 'type': 'E', \ 'sub_type': 'style', \ 'text': 'Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)', \ }, \ { \ 'lnum': 22, \ 'col': 3, \ 'type': 'E', \ 'sub_type': 'style', \ 'text': 'All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks)', \ }, \ ], \ ale_linters#php#phpcs#Handle(bufnr(''), [ \ '/path/to/some-filename.php:18:3: error - Line indented incorrectly; expected 4 spaces, found 2 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)', \ "/path/to/some-filename.php:22:3: error - All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '\"\n'.", \ ]) ================================================ FILE: test/handler/test_phpstan_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/php/phpstan.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Output without errors should be parsed correctly): call ale#test#SetFilename('phpstan-test-files/foo/test.php') AssertEqual \ [], \ ale_linters#php#phpstan#Handle(bufnr(''), [ \ '{"totals":{"errors":0,"file_errors":0},"files":[],"errors":[]}', \ ]) Execute(Output with some errors should be parsed correctly): call ale#test#SetFilename('phpstan-test-files/foo/test.php') AssertEqual \ [ \ { \ 'lnum': 9, \ 'text': 'Call to method format() on an unknown class DateTimeImutable.', \ 'type': 'E' \ }, \ { \ 'lnum': 16, \ 'text': 'Sample message.', \ 'type': 'E' \ }, \ { \ 'lnum': 192, \ 'text': 'Invalid command testCommand.', \ 'type': 'E' \ } \ ], \ ale_linters#php#phpstan#Handle(bufnr(''), [json_encode( \ { \ "totals":{"errors": 0, "file_errors": 11}, \ "files":{expand('%:p'): {"errors": 3, "messages": [ \ {"message": "Call to method format() on an unknown class DateTimeImutable.", "line":9}, \ {"message": "Sample message.", "line":16}, \ {"message": "Invalid command testCommand.", "line": 192} \ ]}} \ }, \)]) ================================================ FILE: test/handler/test_pmd_handler.vader ================================================ Before: runtime ale_linters/java/pmd.vim After: call ale#linter#Reset() Execute(The pmd handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 18, \ 'text': 'Each class should declare at least one constructor', \ 'code': 'Code Style - AtLeastOneConstructor', \ 'type': 'W', \ }, \ { \ 'lnum': 36, \ 'text': 'Local variable ''node'' could be declared final', \ 'code': 'Code Style - LocalVariableCouldBeFinal', \ 'type': 'W', \ }, \ ], \ ale_linters#java#pmd#Handle(666, [ \ '"Problem","Package","File","Priority","Line","Description","Rule set","Rule"', \ '"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"' \ ]) ================================================ FILE: test/handler/test_pony_handler.vader ================================================ Execute(The pony handler should handle ponyc output): call ale#test#SetFilename('foo.pony') AssertEqual \ [ \ { \ 'filename': '/home/projects/Wombat.pony', \ 'lnum': 22, \ 'type': 'E', \ 'col': 30, \ 'text': 'can''t lookup private fields from outside the type', \ }, \ ], \ ale#handlers#pony#HandlePonycFormat(bufnr(''), [ \ 'Building builtin -> /usr/lib/pony/0.21.3/packages/builtin', \ 'Building . -> /home/projects', \ 'Error:', \ '/home/projects/Wombat.pony:22:30: can''t lookup private fields from outside the type', \ ' env.out.print(defaultWombat._hunger_level)', \ ' ^', \ ]) ================================================ FILE: test/handler/test_powershell_handler.vader ================================================ Before: runtime ale_linters/powershell/powershell.vim After: call ale#linter#Reset() Execute(The powershell handler should process syntax errors from parsing a powershell script): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 29, \ 'type': 'E', \ 'text': 'Missing closing ''}'' in statement block or type definition.', \ 'code': 'ParseException', \ }, \ ], \ ale_linters#powershell#powershell#Handle(bufnr(''), [ \ "At line:8 char:29", \ "+ Invoke-Command -ScriptBlock {", \ "+ ~", \ "Missing closing '}' in statement block or type definition.", \ "At /home/harrisj/tester.ps1:5 char:5", \ "+ [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Contents);", \ "+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", \ "+ CategoryInfo : NotSpecified: (:) [], ParseException", \ "+ FullyQualifiedErrorId : ParseException" \ ]) Execute(The powershell handler should process multiple syntax errors from parsing a powershell script): AssertEqual \ [ \ { \ 'lnum': 11, \ 'col': 31, \ 'type': 'E', \ 'text': 'The string is missing the terminator: ".', \ 'code': 'ParseException' \ }, \ { \ 'lnum': 3, \ 'col': 16, \ 'type': 'E', \ 'text': 'Missing closing ''}'' in statement block or type definition.', \ 'code': 'ParseException' \ }, \ ], \ ale_linters#powershell#powershell#Handle(bufnr(''), [ \ 'At line:11 char:31', \ '+ write-verbose ''deleted''', \ '+ ~', \ 'The string is missing the terminator: ".', \ 'At line:3 char:16', \ '+ invoke-command {', \ '+ ~', \ 'Missing closing ''}'' in statement block or type definition.', \ 'At /var/folders/qv/15ybvt050v9cgwrm7c95x4r4zc4qsg/T/vwhzIc8/1/script.ps1:1 char:150', \ '+ ... ontents); [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Con ...', \ '+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~', \ '+ CategoryInfo : NotSpecified: (:) [], ParseException', \ '+ FullyQualifiedErrorId : ParseException' \ ]) Execute(The powershell handler should process unexecpected token that contains a newline character): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 8, \ 'type': 'E', \ 'text': 'The string is missing the terminator: ".', \ 'code': 'ParseException' \ }, \ { \ 'lnum': 2, \ 'col': 8, \ 'type': 'E', \ 'text': 'Unexpected token ''"', \ 'code': 'ParseException' \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': 'Missing closing ''}'' in statement block or type definition.', \ 'code': 'ParseException' \ } \ ], \ ale_linters#powershell#powershell#Handle(bufnr(''), [ \ 'At line:2 char:8', \ '+ "" "', \ '+ ~', \ 'The string is missing the terminator: ".', \ 'At line:2 char:8', \ '+ "" "', \ '+ ~', \ 'Unexpected token ''"', \ '', \ ' }'' in expression or statement.', \ '', \ 'At line:1 char:1', \ '+ {', \ '+ ~', \ 'Missing closing ''}'' in statement block or type definition.', \ 'At C:\Users\jpharris\AppData\Local\Temp\VIAA777.tmp\script.ps1:1 char:150', \ '+ ... ontents); [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Con ...', \ '+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~', \ ' + CategoryInfo : NotSpecified: (:) [], ParseException', \ ' + FullyQualifiedErrorId : ParseException' \ ]) ================================================ FILE: test/handler/test_prospector_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/prospector.vim After: Restore call ale#linter#Reset() Execute(Basic prospector errors should be handle): AssertEqual \ [ \ { \ 'lnum': 20, \ 'col': 1, \ 'text': 'Trailing whitespace', \ 'code': '(pylint) trailing-whitespace', \ 'type': 'E', \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Missing module docstring', \ 'code': '(pylint) missing-docstring', \ 'type': 'E', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'Missing function docstring', \ 'code': '(pylint) missing-docstring', \ 'type': 'E', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'text': '''break'' not properly in loop', \ 'code': '(pylint) not-in-loop', \ 'type': 'E', \ }, \ { \ 'lnum': 4, \ 'col': 5, \ 'text': 'Unreachable code', \ 'code': '(pylint) unreachable', \ 'type': 'E', \ }, \ { \ 'lnum': 7, \ 'col': 33, \ 'text': 'No exception type(s) specified', \ 'code': '(pylint) bare-except', \ 'type': 'E', \ }, \ ], \ ale_linters#python#prospector#Handle(bufnr(''), [ \ '{', \ ' "messages": [', \ ' {', \ ' "source": "pylint",', \ ' "code": "trailing-whitespace",', \ ' "message": "Trailing whitespace",', \ ' "location": {', \ ' "character": 0,', \ ' "line": 20', \ ' }', \ ' },', \ ' {', \ ' "source": "pylint",', \ ' "code": "missing-docstring",', \ ' "message": "Missing module docstring",', \ ' "location": {', \ ' "character": 0,', \ ' "line": 1', \ ' }', \ ' },', \ ' {', \ ' "source": "pylint",', \ ' "code": "missing-docstring",', \ ' "message": "Missing function docstring",', \ ' "location": {', \ ' "character": 0,', \ ' "line": 2', \ ' }', \ ' },', \ ' {', \ ' "source": "pylint",', \ ' "code": "not-in-loop",', \ ' "message": "''break'' not properly in loop",', \ ' "location": {', \ ' "character": 4,', \ ' "line": 3', \ ' }', \ ' },', \ ' {', \ ' "source": "pylint",', \ ' "code": "unreachable",', \ ' "message": "Unreachable code",', \ ' "location": {', \ ' "character": 4,', \ ' "line": 4', \ ' }', \ ' },', \ ' {', \ ' "source": "pylint",', \ ' "code": "bare-except",', \ ' "message": "No exception type(s) specified",', \ ' "location": {', \ ' "character": 32,', \ ' "line": 7', \ ' }', \ ' }', \ ' ]', \ '}', \ ]) Execute(Ignoring trailing whitespace messages should work): let g:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Missing module docstring', \ 'code': '(pylint) missing-docstring', \ 'type': 'E', \ }, \ ], \ ale_linters#python#prospector#Handle(bufnr(''), [ \ '{', \ ' "messages": [', \ ' {', \ ' "source": "pylint",', \ ' "code": "trailing-whitespace",', \ ' "message": "Trailing whitespace",', \ ' "location": {', \ ' "character": 0,', \ ' "line": 4', \ ' }', \ ' },', \ ' {', \ ' "source": "pylint",', \ ' "code": "missing-docstring",', \ ' "message": "Missing module docstring",', \ ' "location": {', \ ' "character": 0,', \ ' "line": 1', \ ' }', \ ' }', \ ' ]', \ '}', \ ]) Execute(The prospector handler should handle empty output): AssertEqual \ [], \ ale_linters#python#prospector#Handle(bufnr(''), []) ================================================ FILE: test/handler/test_psscriptanalyzer_handler.vader ================================================ Before: runtime ale_linters/powershell/psscriptanalyzer.vim After: call ale#linter#Reset() Execute(The psscriptanalyzer handler should handle basic information or warnings): AssertEqual \ [ \ { \ 'lnum': 1, \ 'type': 'I', \ 'text': 'The cmdlet ''Get-GithubRepo'' does not have a help comment.', \ 'code': 'PSProvideCommentHelp', \ }, \ { \ 'lnum': 9, \ 'type': 'W', \ 'text': '''%'' is an alias of ''ForEach-Object''. Alias can introduce possible problems and make scripts hard to maintain. Please consider changing alias to its full content.', \ 'code': 'PSAvoidUsingCmdletAliases', \ }, \ { \ 'lnum': 23, \ 'type': 'E', \ 'text': 'The ComputerName parameter of a cmdlet should not be hardcoded as this will expose sensitive information about the system.', \ 'code': 'PSAvoidUsingComputerNameHardcoded', \ }, \ ], \ ale_linters#powershell#psscriptanalyzer#Handle(bufnr(''), [ \ '1', \ 'Information', \ 'The cmdlet ''Get-GithubRepo'' does not have a help comment.', \ 'PSProvideCommentHelp', \ '9', \ 'Warning', \ '''%'' is an alias of ''ForEach-Object''. Alias can introduce possible problems and make scripts hard to maintain. Please consider changing alias to its full content.', \ 'PSAvoidUsingCmdletAliases', \ '23', \ 'Error', \ 'The ComputerName parameter of a cmdlet should not be hardcoded as this will expose sensitive information about the system.', \ 'PSAvoidUsingComputerNameHardcoded', \ ]) ================================================ FILE: test/handler/test_puglint_handler.vader ================================================ Before: runtime ale_linters/pug/puglint.vim After: call ale#linter#Reset() Execute(Regular errors should be handled): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 5, \ 'type': 'E', \ 'text': 'Static attribute "class" must be written as class literal', \ }, \ ], \ ale_linters#pug#puglint#Handle(0, [ \ '/tmp/vwYwsJA/233/test.pug:1:5 Static attribute "class" must be written as class literal', \ ]) Execute(syntax errors in the configuration file should be handled): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': 'puglint configuration error (type :ALEDetail for more information)', \ 'detail': join( \ [ \ 'undefined:2', \ ' disallowClassAttributeWithStaticValue: true', \ ' ^', \ 'SyntaxError: Unexpected token d in JSON at position 4', \ ' at JSON.parse ()', \ ], \ "\n" \ ), \ }, \ ], \ ale_linters#pug#puglint#Handle(0, [ \ 'undefined:2', \ ' disallowClassAttributeWithStaticValue: true', \ ' ^', \ 'SyntaxError: Unexpected token d in JSON at position 4', \ ' at JSON.parse ()', \ ]) ================================================ FILE: test/handler/test_puppet_handler.vader ================================================ Before: runtime ale_linters/puppet/puppet.vim After: call ale#linter#Reset() Execute(The puppet handler should parse lines correctly when no column is supplied): " Line Error AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 0, \ 'text': "Syntax error at '='; expected '}'" \ }, \ { \ 'lnum': 3, \ 'col': 0, \ 'text': "Syntax error at '='; expected '}'" \ }, \ ], \ ale_linters#puppet#puppet#Handle(255, [ \ "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 '='; expected '}' at C:/puppet/modules/pancakes/manifests/init.pp:3", \ ]) Execute(The puppet handler should parse lines and column correctly): " Line Error AssertEqual \ [ \ { \ 'lnum': 43, \ 'col': 12, \ 'text': "Syntax error at ':'" \ }, \ { \ 'lnum': 54, \ 'col': 9, \ 'text': "Syntax error at ':'" \ }, \ { \ 'lnum': 45, \ 'col': 12, \ 'text': "Syntax error at 'parameter1'" \ }, \ ], \ ale_linters#puppet#puppet#Handle(255, [ \ "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 ':' at C:/puppet/modules/nginx/manifests/init.pp:54:9", \ "Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 45, column: 12)", \ ]) Execute(The puppet handler should correctly parse errors that are reported before even trying to parse for an environment): " Line Error AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 11, \ 'text': "Illegal attempt to assign to 'a Name'. Not an assignable reference" \ }, \ ], \ ale_linters#puppet#puppet#Handle(255, [ \ "Error: Illegal attempt to assign to 'a Name'. Not an assignable reference (file: /tmp/modules/waffles/manifests/syrup.pp, line: 5, column: 11)", \ ]) Execute(The puppet handler should parse lines when end of input is the location): AssertEqual \ [ \ { \ 'lnum': 0, \ 'col': 0, \ 'text': "Syntax error at end of input" \ }, \ ], \ ale_linters#puppet#puppet#Handle(255, [ \ "Error: Could not parse for environment production: Syntax error at end of input (file: /tmp//modules/test/manifests/init.pp)", \ ]) ================================================ FILE: test/handler/test_pycodestyle_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_blank_lines Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_blank_lines = 1 let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/pycodestyle.vim After: Restore unlet! b:ale_warn_about_trailing_blank_lines unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute(The pycodestyle handler should parse output): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 3, \ 'type': 'E', \ 'text': 'SyntaxError: invalid syntax', \ 'code': 'E999', \ }, \ { \ 'lnum': 69, \ 'col': 11, \ 'text': 'multiple imports on one line', \ 'code': 'E401', \ 'type': 'E', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 77, \ 'col': 1, \ 'text': 'expected 2 blank lines, found 1', \ 'code': 'E302', \ 'type': 'E', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 88, \ 'col': 5, \ 'text': 'expected 1 blank line, found 0', \ 'code': 'E301', \ 'type': 'E', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 222, \ 'col': 34, \ 'text': 'deprecated form of raising exception', \ 'code': 'W602', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ { \ 'lnum': 544, \ 'col': 21, \ 'text': '.has_key() is deprecated, use ''in''', \ 'code': 'W601', \ 'type': 'W', \ 'sub_type': 'style', \ }, \ ], \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'stdin:8:3: E999 SyntaxError: invalid syntax', \ 'stdin:69:11: E401 multiple imports on one line', \ 'stdin:77:1: E302 expected 2 blank lines, found 1', \ 'stdin:88:5: E301 expected 1 blank line, found 0', \ 'stdin:222:34: W602 deprecated form of raising exception', \ 'example.py:544:21: W601 .has_key() is deprecated, use ''in''', \ ]) Execute(Warnings about trailing whitespace should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'code': 'W291', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'who cares', \ }, \ { \ 'lnum': 6, \ 'col': 1, \ 'code': 'W293', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'who cares', \ }, \ ], \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'foo.py:6:1: W291 who cares', \ 'foo.py:6:1: W293 who cares', \ ]) Execute(Disabling trailing whitespace warnings should work): let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ ], \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'foo.py:6:1: W291 who cares', \ 'foo.py:6:1: W293 who cares', \ ]) Execute(Warnings about trailing blank lines should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'code': 'W391', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'blank line at end of file', \ }, \ ], \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) Execute(Disabling trailing blank line warnings should work): let b:ale_warn_about_trailing_blank_lines = 0 AssertEqual \ [ \ ], \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) Execute(E112 should be a syntax error): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'code': 'E112', \ 'type': 'E', \ 'text': 'expected an indented block', \ }, \ ], \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'foo.py:6:1: E112 expected an indented block', \ ]) ================================================ FILE: test/handler/test_pydocstyle_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/pydocstyle.vim After: Restore call ale#linter#Reset() silent file something_else.py " File sample.py " # sample.py file " " def main(): " """ " This is a multi-line description that should produce multiple errors to be " tested by the handler " """ " return False " " " if __name__ == '__main__': " main() " " The command to generate the handler input is: " " $ python -m pydocstyle --verbose --source --explain sample.py " [...] " $ Execute(Basic pydocstyle warnings should be handled): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Missing docstring in public module', \ 'code': 'D100', \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'col': 1, \ 'text': '1 blank line required between summary line and description (found 0)', \ 'code': 'D205', \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'col': 1, \ 'text': 'First line should end with a period (not ''e'')', \ 'code': 'D400', \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'col': 1, \ 'text': 'First line should be in imperative mood; try rephrasing (found ''This'')', \ 'code': 'D401', \ 'type': 'W', \ }, \ ], \ ale_linters#python#pydocstyle#Handle(bufnr(''), [ \ 'Checking file ' . fnamemodify(bufname(bufnr('')), ':p') . '.', \ './mydir/myfile.py:1 at module level:', \ ' D100: Missing docstring in public module', \ '', \ ' All modules should normally have docstrings. [...] all functions and', \ ' classes exported by a module should also have docstrings. Public', \ ' methods (including the __init__ constructor) should also have', \ ' docstrings.', \ ' Note: Public (exported) definitions are either those with names listed', \ ' in __all__ variable (if present), or those that do not start', \ ' with a single underscore.', \ '', \ ' 1: # 2: 3: s 4: a 5: m 6: p 7: l ...', \ '', \ '', \ 'C:\mydir\myfile.py:4 in public function `main`:', \ ' D205: 1 blank line required between summary line and description (found 0)', \ '', \ ' Multi-line docstrings consist of a summary line just like a one-line', \ ' docstring, followed by a blank line, followed by a more elaborate', \ ' description. The summary line may be used by automatic indexing tools;', \ ' it is important that it fits on one line and is separated from the', \ ' rest of the docstring by a blank line.', \ '', \ ' 3: d 4: e 5: f 6: 7: m 8: a 9: i ...', \ '', \ '', \ 'myfile.py:4 in public function `main`:', \ ' D400: First line should end with a period (not ''e'')', \ '', \ ' The [first line of a] docstring is a phrase ending in a period.', \ '', \ ' 3: d 4: e 5: f 6: 7: m 8: a 9: i ...', \ '', \ '', \ ale#Escape(fnamemodify(bufname(bufnr('')), ':t')) . ':4 in public function `main`:', \ ' D401: First line should be in imperative mood; try rephrasing (found ''This'')', \ '', \ ' [Docstring] prescribes the function or method''s effect as a command:', \ ' ("Do this", "Return that"), not as a description; e.g. don''t write', \ ' "Returns the pathname ...".', \ '', \ ' 3: d 4: e 5: f 6: 7: m 8: a 9: i ...', \ ]) Execute(Handler should handle empty output): AssertEqual \ [], \ ale_linters#python#pydocstyle#Handle(bufnr(''), []) ================================================ FILE: test/handler/test_pyflakes_handler.vader ================================================ Before: runtime ale_linters/python/pyflakes.vim After: call ale#linter#Reset() Execute(The pyflakes handler should handle basic errors): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 0, \ 'text': 'undefined name ''foo''', \ }, \ { \ 'lnum': 1, \ 'col': 7, \ 'text': 'invalid syntax', \ }, \ ], \ ale_linters#python#pyflakes#Handle(bufnr(''), [ \ 'test.py:1: undefined name ''foo''', \ 'test.py:1:7: invalid syntax', \ ]) ================================================ FILE: test/handler/test_pylama_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/pylama.vim After: Restore call ale#linter#Reset() silent file something_else.py Execute(The pylama handler should handle no messages with version older than 8.1.4): AssertEqual [], ale_linters#python#pylama#Handle(bufnr(''), [8, 0, 5], []) Execute(The pylama handler should handle no messages with version newer or equal than 8.1.4): AssertEqual [], ale_linters#python#pylama#Handle(bufnr(''), [8, 2, 0], []) Execute(The pylama handler should handle basic warnings and syntax errors with version older than 8.1.4): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 1, \ 'code': 'W0611', \ 'type': 'W', \ 'sub_type': '', \ 'text': '''foo'' imported but unused [pyflakes]', \ }, \ { \ 'lnum': 8, \ 'col': 0, \ 'code': 'E0401', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'Unable to import ''foo'' [pylint]', \ }, \ { \ 'lnum': 10, \ 'col': 1, \ 'code': 'E302', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'expected 2 blank lines, found 1 [pycodestyle]', \ }, \ { \ 'lnum': 11, \ 'col': 1, \ 'code': 'D401', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'First line should be in imperative mood (''Get'', not ''Gets'') [pydocstyle]', \ }, \ { \ 'lnum': 15, \ 'col': 81, \ 'code': 'E501', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'line too long (96 > 80 characters) [pycodestyle]', \ }, \ { \ 'lnum': 16, \ 'col': 1, \ 'code': 'D203', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': '1 blank line required before class docstring (found 0) [pydocstyle]', \ }, \ { \ 'lnum': 18, \ 'col': 1, \ 'code': 'D107', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'Missing docstring in __init__ [pydocstyle]', \ }, \ { \ 'lnum': 20, \ 'col': 0, \ 'code': 'C4001', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'Invalid string quote ", should be '' [pylint]', \ }, \ ], \ ale_linters#python#pylama#Handle(bufnr(''), [8, 0, 5], [ \ 'No config file found, using default configuration', \ 'index.py:8:1: W0611 ''foo'' imported but unused [pyflakes]', \ 'index.py:8:0: E0401 Unable to import ''foo'' [pylint]', \ 'index.py:10:1: E302 expected 2 blank lines, found 1 [pycodestyle]', \ 'index.py:11:1: D401 First line should be in imperative mood (''Get'', not ''Gets'') [pydocstyle]', \ 'index.py:15:81: E501 line too long (96 > 80 characters) [pycodestyle]', \ 'index.py:16:1: D203 1 blank line required before class docstring (found 0) [pydocstyle]', \ 'index.py:18:1: D107 Missing docstring in __init__ [pydocstyle]', \ 'index.py:20:0: C4001 Invalid string quote ", should be '' [pylint]', \ ]) Execute(The pylama handler should handle basic warnings and syntax errors with version newer than 8.1.4): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 1, \ 'code': 'W0611', \ 'type': 'W', \ 'sub_type': '', \ 'text': '''foo'' imported but unused [pyflakes]', \ }, \ { \ 'lnum': 8, \ 'col': 0, \ 'code': 'E0401', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'Unable to import ''foo'' [pylint]', \ }, \ { \ 'lnum': 10, \ 'col': 1, \ 'code': 'E302', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'expected 2 blank lines, found 1 [pycodestyle]', \ }, \ { \ 'lnum': 11, \ 'col': 1, \ 'code': 'D401', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'First line should be in imperative mood (''Get'', not ''Gets'') [pydocstyle]', \ }, \ { \ 'lnum': 15, \ 'col': 81, \ 'code': 'E501', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'line too long (96 > 80 characters) [pycodestyle]', \ }, \ { \ 'lnum': 16, \ 'col': 1, \ 'code': 'D203', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': '1 blank line required before class docstring (found 0) [pydocstyle]', \ }, \ { \ 'lnum': 18, \ 'col': 1, \ 'code': 'D107', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'Missing docstring in __init__ [pydocstyle]', \ }, \ { \ 'lnum': 20, \ 'col': 0, \ 'code': 'C4001', \ 'type': 'W', \ 'sub_type': 'style', \ 'text': 'Invalid string quote ", should be '' [pylint]', \ }, \ ], \ ale_linters#python#pylama#Handle(bufnr(''), [8, 2, 0], [ \ '[{"source":"pyflakes","col":1,"lnum":8,"etype":"W","message":"''foo'' imported but unused","filename":"index.py","number":"W0611"},{"source":"pylint","col":0,"lnum":8,"etype":"E","message":"Unable to import ''foo''","filename":"index.py","number":"E0401"},{"source":"pycodestyle","col":1,"lnum":10,"etype":"E","message":"expected 2 blank lines, found 1","filename":"index.py","number":"E302"},{"source":"pydocstyle","col":1,"lnum":11,"etype":"D","message":"First line should be in imperative mood (''Get'', not ''Gets'')","filename":"index.py","number":"D401"},{"source":"pycodestyle","col":81,"lnum":15,"etype":"E","message":"line too long (96 > 80 characters)","filename":"index.py","number":"E501"},{"source":"pydocstyle","col":1,"lnum":16,"etype":"D","message":"1 blank line required before class docstring (found 0)","filename":"index.py","number":"D203"},{"source":"pydocstyle","col":1,"lnum":18,"etype":"D","message":"Missing docstring in __init__","filename":"index.py","number":"D107"},{"source":"pylint","col":0,"lnum":20,"etype":"C","message":"Invalid string quote \", should be ''","filename":"index.py","number":"C4001"}]', \ ]) Execute(The pylama handler should handle tracebacks with parsable messages with version older than 8.1.4): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': 'ParseError: Cannot parse file. (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "/usr/local/lib/python2.7/site-packages/pylama/core.py", line 66, in run', \ ' path, code=code, ignore=ignore, select=select, params=lparams)', \ ' File "/usr/local/lib/python2.7/site-packages/pylama/lint/pylama_pydocstyle.py", line 37, in run', \ ' } for e in PyDocChecker().check_source(*check_source_args)]', \ ' File "/usr/local/lib/python2.7/site-packages/pydocstyle/checker.py", line 64, in check_source', \ ' module = parse(StringIO(source), filename)', \ ' File "/usr/local/lib/python2.7/site-packages/pydocstyle/parser.py", line 340, in __call__', \ ' return self.parse(*args, **kwargs)', \ ' File "/usr/local/lib/python2.7/site-packages/pydocstyle/parser.py", line 328, in parse', \ ' six.raise_from(ParseError(), error)', \ ' File "/usr/local/lib/python2.7/site-packages/six.py", line 737, in raise_from', \ ' raise value', \ 'ParseError: Cannot parse file.', \ ], "\n"), \ }, \ { \ 'lnum': 11, \ 'col': 1, \ 'code': 'E302', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'expected 2 blank lines, found 1 [pycodestyle]', \ }, \ { \ 'lnum': 16, \ 'col': 81, \ 'code': 'E501', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'line too long (96 > 80 characters) [pycodestyle]', \ }, \ ], \ ale_linters#python#pylama#Handle(bufnr(''), [8, 0, 5], [ \ 'Traceback (most recent call last):', \ ' File "/usr/local/lib/python2.7/site-packages/pylama/core.py", line 66, in run', \ ' path, code=code, ignore=ignore, select=select, params=lparams)', \ ' File "/usr/local/lib/python2.7/site-packages/pylama/lint/pylama_pydocstyle.py", line 37, in run', \ ' } for e in PyDocChecker().check_source(*check_source_args)]', \ ' File "/usr/local/lib/python2.7/site-packages/pydocstyle/checker.py", line 64, in check_source', \ ' module = parse(StringIO(source), filename)', \ ' File "/usr/local/lib/python2.7/site-packages/pydocstyle/parser.py", line 340, in __call__', \ ' return self.parse(*args, **kwargs)', \ ' File "/usr/local/lib/python2.7/site-packages/pydocstyle/parser.py", line 328, in parse', \ ' six.raise_from(ParseError(), error)', \ ' File "/usr/local/lib/python2.7/site-packages/six.py", line 737, in raise_from', \ ' raise value', \ 'ParseError: Cannot parse file.', \ '', \ 'index.py:11:1: E302 expected 2 blank lines, found 1 [pycodestyle]', \ 'index.py:16:81: E501 line too long (96 > 80 characters) [pycodestyle]', \ ]) " Note: This is probably a bug, since all pylama plugins produce codes, but " should be handled for compatibility. " Note: The pylama isort plugin is distributed in the isort package. Execute(The pylama handler should handle messages without codes with version older than 8.1.4): AssertEqual \ [ \ { \ 'lnum': 0, \ 'col': 0, \ 'code': '', \ 'type': 'W', \ 'sub_type': '', \ 'text': 'Incorrectly sorted imports. [isort]' \ }, \ ], \ ale_linters#python#pylama#Handle(bufnr(''), [8, 0, 5], [ \ 'index.py:0:0: Incorrectly sorted imports. [isort]', \ ]) " Note: This is a pylama bug, but should be handled for compatibility. " See https://github.com/klen/pylama/pull/146 Execute(The pylama handler should handle message codes followed by a colon with version older than 8.1.4): AssertEqual \ [ \ { \ 'lnum': 31, \ 'col': 1, \ 'code': 'E800', \ 'type': 'E', \ 'sub_type': '', \ 'text': 'Found commented out code: # needs_sphinx = ''1.0'' [eradicate]', \ }, \ ], \ ale_linters#python#pylama#Handle(bufnr(''), [8, 0, 5], [ \ 'index.py:31:1: E800: Found commented out code: # needs_sphinx = ''1.0'' [eradicate]', \ ]) ================================================ FILE: test/handler/test_pylint_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/pylint.vim After: Restore call ale#linter#Reset() silent file something_else.py Execute(Basic pylint errors should be handle): AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 1, \ 'text': 'Trailing whitespace', \ 'code': 'trailing-whitespace', \ 'type': 'W', \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Missing module docstring', \ 'code': 'missing-docstring', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'Missing function docstring', \ 'code': 'missing-docstring', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'text': '''break'' not properly in loop', \ 'code': 'not-in-loop', \ 'type': 'E', \ }, \ { \ 'lnum': 4, \ 'col': 5, \ 'text': 'Unreachable code', \ 'code': 'unreachable', \ 'type': 'W', \ }, \ { \ 'lnum': 7, \ 'col': 33, \ 'text': 'No exception type(s) specified', \ 'code': 'bare-except', \ 'type': 'W', \ }, \ ], \ ale_linters#python#pylint#Handle(bufnr(''), [ \ 'No config file found, using default configuration', \ '************* Module test', \ 'test.py:4:0: C0303 (trailing-whitespace) Trailing whitespace', \ 'test.py:1:0: C0111 (missing-docstring) Missing module docstring', \ 'test.py:2:0: C0111 (missing-docstring) Missing function docstring', \ 'test.py:3:4: E0103 (not-in-loop) ''break'' not properly in loop', \ 'test.py:4:4: W0101 (unreachable) Unreachable code', \ 'test.py:7:32: W0702 (bare-except) No exception type(s) specified', \ '', \ '------------------------------------------------------------------', \ 'Your code has been rated at 0.00/10 (previous run: 2.50/10, -2.50)', \ ]) Execute(Ignoring trailing whitespace messages should work): let g:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Missing module docstring', \ 'code': 'missing-docstring', \ 'type': 'W', \ }, \ ], \ ale_linters#python#pylint#Handle(bufnr(''), [ \ 'No config file found, using default configuration', \ '************* Module test', \ 'test.py:4:0: C0303 (trailing-whitespace) Trailing whitespace', \ 'test.py:1:0: C0111 (missing-docstring) Missing module docstring', \ '', \ '------------------------------------------------------------------', \ 'Your code has been rated at 0.00/10 (previous run: 2.50/10, -2.50)', \ ]) Execute(The pylint handler should parse Windows filenames): AssertEqual \ [ \ { \ 'lnum': 13, \ 'col': 6, \ 'text': 'Undefined variable ''x''', \ 'code': 'undefined-variable', \ 'type': 'E', \ }, \ ], \ ale_linters#python#pylint#Handle(bufnr(''), [ \ '************* Module test', \ 'D:\acm\github\vim\tools\test.py:13:5: E0602 (undefined-variable) Undefined variable ''x''', \ '', \ '------------------------------------------------------------------', \ 'Your code has been rated at 5.83/10 (previous run: 5.83/10, +0.00)', \ ]) Execute(Use msg_id): let g:ale_python_pylint_use_msg_id = 1 AssertEqual \ [ \ { \ 'lnum': 13, \ 'col': 6, \ 'text': 'Undefined variable ''x''', \ 'code': 'E0602', \ 'type': 'E', \ }, \ ], \ ale_linters#python#pylint#Handle(bufnr(''), [ \ '************* Module test', \ 'D:\acm\github\vim\tools\test.py:13:5: E0602 (undefined-variable) Undefined variable ''x''', \ '', \ '------------------------------------------------------------------', \ 'Your code has been rated at 5.83/10 (previous run: 5.83/10, +0.00)', \ ]) ================================================ FILE: test/handler/test_pyrex_cython_handler.vader ================================================ Before: runtime ale_linters/pyrex/cython.vim After: call ale#linter#Reset() Execute(The cython handler should handle warnings and errors): AssertEqual \ [ \ { \ 'lnum': 42, \ 'col': 7, \ 'text': 'some warning', \ 'type': 'W', \ }, \ { \ 'lnum': 777, \ 'col': 21, \ 'text': 'some error', \ 'type': 'E', \ }, \ ], \ ale_linters#pyrex#cython#Handle(347, [ \ 'warning: file:42:7: some warning', \ 'file:777:21: some error', \ ]) ================================================ FILE: test/handler/test_qmlfmt_handler.vader ================================================ Before: runtime ale_linters/qml/qmlfmt.vim After: call ale#linter#Reset() Execute(The qmlfmt handler should parse error messages correctly): AssertEqual \ [ \ { \ 'lnum': 22, \ 'col': 1, \ 'type': 'E', \ 'text': 'Expected token ''}''.' \ } \ ], \ ale_linters#qml#qmlfmt#Handle(1, [ \ 'Error:22:1: Expected token ''}''.' \ ]) ================================================ FILE: test/handler/test_qmllint_handler.vader ================================================ Before: runtime ale_linters/qml/qmllint.vim After: call ale#linter#Reset() Execute(The qmllint handler should parse error messages correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 0, \ 'type': 'E', \ 'text': 'Expected token ''}''' \ } \ ], \ ale_linters#qml#qmllint#Handle(1, [ \ '/tmp/ab34cd56/Test.qml:2 : Expected token ''}''' \ ]) ================================================ FILE: test/handler/test_raco_handler.vader ================================================ Before: runtime ale_linters/racket/raco.vim After: call ale#linter#Reset() Execute(The raco handler should handle errors for the current file correctly): AssertEqual \ [ \ { \ 'filename': 'foo.rkt', \ 'lnum': 4, \ 'col': 1, \ 'type': 'E', \ 'text': 'dfine: unbound identifier in modulemessage', \ }, \ ], \ ale_linters#racket#raco#Handle(bufnr(''), [ \ 'foo.rkt:4:1: dfine: unbound identifier in modulemessage', \ ' in: dfine', \ ' context...:', \ ' /usr/local/Cellar/racket/6.5/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt:34:15: loop', \ ' /usr/local/Cellar/racket/6.5/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt:10:2: show-program', \ ' /usr/local/Cellar/racket/6.5/share/racket/pkgs/compiler-lib/compiler/commands/expand.rkt: [running body]', \ ' /usr/local/Cellar/minimal-racket/6.6/share/racket/collects/raco/raco.rkt: [running body]', \ ' /usr/local/Cellar/minimal-racket/6.6/share/racket/collects/raco/main.rkt: [running body]', \ ]) ================================================ FILE: test/handler/test_rails_best_practices_handler.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test/handler') cd .. runtime ale_linters/ruby/rails_best_practices.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The rails_best_practices handler should parse JSON correctly): call ale#test#SetFilename('test-files/ruby/valid_rails_app/app/models/thing.rb') AssertEqual \ [ \ { \ 'lnum': 5, \ 'text': 'use local variable', \ 'type': 'W', \ }, \ { \ 'lnum': 10, \ 'text': 'other advice', \ 'type': 'W', \ } \ ], \ ale_linters#ruby#rails_best_practices#Handle(bufnr(''), [ \ '[', \ '{', \ '"message": "use local variable",', \ '"line_number": "5",', \ printf('"filename": "%s"', substitute(expand('%:p'), '\\', '\\\\', 'g')), \ '},{', \ '"message": "other advice",', \ '"line_number": "10",', \ printf('"filename": "%s"', substitute(expand('%:p'), '\\', '\\\\', 'g')), \ '}', \ ']' \ ]) Execute(The rails_best_practices handler should parse JSON correctly when there is no output from the tool): AssertEqual \ [], \ ale_linters#ruby#rails_best_practices#Handle(347, [ \ ]) Execute(The rails_best_practices handler should handle garbage output): AssertEqual \ [], \ ale_linters#ruby#rails_best_practices#Handle(347, [ \ 'No such command in 2.4.1 of ruby', \ ]) ================================================ FILE: test/handler/test_redpen_handler.vader ================================================ Before: runtime! ale_linters/markdown/redpen.vim After: call ale#linter#Reset() Execute(redpen handler should handle errors output): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 10, \ 'end_lnum': 1, \ 'end_col': 15, \ 'text': 'Found possibly misspelled word "plugin".', \ 'type': 'W', \ 'code': 'Spelling', \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Found possibly misspelled word "NeoVim".', \ 'type': 'W', \ 'code': 'Spelling', \ }, \ { \ 'lnum': 1, \ 'col': 35, \ 'end_lnum': 1, \ 'end_col': 55, \ 'text': 'Found possibly misspelled word "コードチェック".', \ 'type': 'W', \ 'code': 'Spelling', \ }, \ ], \ ale#handlers#redpen#HandleRedpenOutput(bufnr(''), [ \ '[', \ ' {', \ ' "document": "test.md",', \ ' "errors": [', \ ' {', \ ' "sentence": "ALE is a plugin for providing linting in NeoVim and Vim 8 while you edit your text files.",', \ ' "endPosition": {', \ ' "offset": 15,', \ ' "lineNum": 1', \ ' },', \ ' "validator": "Spelling",', \ ' "lineNum": 1,', \ ' "sentenceStartColumnNum": 0,', \ ' "message": "Found possibly misspelled word \"plugin\".",', \ ' "startPosition": {', \ ' "offset": 9,', \ ' "lineNum": 1', \ ' }', \ ' },', \ ' {', \ ' "sentence": "ALE is a plugin for providing linting in NeoVim and Vim 8 while you edit your text files.",', \ ' "validator": "Spelling",', \ ' "lineNum": 1,', \ ' "sentenceStartColumnNum": 0,', \ ' "message": "Found possibly misspelled word \"NeoVim\"."', \ ' },', \ ' {', \ ' "sentence": "ALEはNeoVimとVim8で非同期のコードチェックを実現するプラグインです。",', \ ' "endPosition": {', \ ' "offset": 27,', \ ' "lineNum": 1', \ ' },', \ ' "validator": "Spelling",', \ ' "lineNum": 1,', \ ' "sentenceStartColumnNum": 0,', \ ' "message": "Found possibly misspelled word \"コードチェック\".",', \ ' "startPosition": {', \ ' "offset": 20,', \ ' "lineNum": 1', \ ' }', \ ' }', \ ' ]', \ ' }', \ ']', \ ]) Execute(The redpen handler should handle an empty error list): AssertEqual \ [], \ ale#handlers#redpen#HandleRedpenOutput(bufnr(''), [ \ '[', \ ' {', \ ' "document": "test.md",', \ ' "errors": []', \ ' }', \ ']', \ ]) Execute(The redpen handler should handle totally empty output): AssertEqual \ [], \ ale#handlers#redpen#HandleRedpenOutput(bufnr(''), []) ================================================ FILE: test/handler/test_reek_handler.vader ================================================ Before: Save g:ale_ruby_reek_show_context Save g:ale_ruby_reek_show_wiki_link let g:ale_ruby_reek_show_context = 0 let g:ale_ruby_reek_show_wiki_link = 0 runtime ale_linters/ruby/reek.vim After: Restore call ale#linter#Reset() Execute(The reek handler should parse JSON correctly, with only context enabled): let g:ale_ruby_reek_show_context = 1 AssertEqual \ [ \ { \ 'lnum': 12, \ 'text': 'Context#method violates rule number one', \ 'code': 'Rule1', \ 'type': 'W', \ }, \ { \ 'lnum': 34, \ 'text': 'Context#method violates rule number two', \ 'code': 'Rule2', \ 'type': 'W', \ }, \ { \ 'lnum': 56, \ 'text': 'Context#method violates rule number two', \ 'code': 'Rule2', \ 'type': 'W', \ }, \ ], \ ale_linters#ruby#reek#Handle(347, [ \ '[{"context":"Context#method","lines":[12],"message":"violates rule number one","smell_type":"Rule1","source":"/home/user/file.rb","parameter":"bad parameter","wiki_link":"https://example.com/Rule1.md"},{"context":"Context#method","lines":[34, 56],"message":"violates rule number two","smell_type":"Rule2","source":"/home/user/file.rb","name":"bad code","count":2,"wiki_link":"https://example.com/Rule1.md"}]' \ ]) Execute(The reek handler should parse JSON correctly, with no context or wiki links): AssertEqual \ [ \ { \ 'lnum': 12, \ 'text': 'violates rule number one', \ 'code': 'Rule1', \ 'type': 'W', \ }, \ ], \ ale_linters#ruby#reek#Handle(347, [ \ '[{"context":"Context#method","lines":[12],"message":"violates rule number one","smell_type":"Rule1","source":"/home/user/file.rb","parameter":"bad parameter","wiki_link":"https://example.com/Rule1.md"}]' \ ]) Execute(The reek handler should parse JSON correctly, with both context and wiki links): let g:ale_ruby_reek_show_context = 1 let g:ale_ruby_reek_show_wiki_link = 1 AssertEqual \ [ \ { \ 'lnum': 12, \ 'text': 'Context#method violates rule number one [https://example.com/Rule1.md]', \ 'code': 'Rule1', \ 'type': 'W', \ }, \ ], \ ale_linters#ruby#reek#Handle(347, [ \ '[{"context":"Context#method","lines":[12],"message":"violates rule number one","smell_type":"Rule1","source":"/home/user/file.rb","parameter":"bad parameter","wiki_link":"https://example.com/Rule1.md"}]' \ ]) Execute(The reek handler should parse JSON correctly when there is no output from reek): AssertEqual \ [], \ ale_linters#ruby#reek#Handle(347, [ \ ]) Execute(The reek handler should handle garbage output): AssertEqual \ [], \ ale_linters#ruby#reek#Handle(347, [ \ 'No such command in 2.4.1 of ruby', \ ]) ================================================ FILE: test/handler/test_remark_lint_handler.vader ================================================ Before: runtime ale_linters/markdown/remark_lint.vim After: call ale#linter#Reset() Execute(Warning and error messages should be handled correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 4, \ 'type': 'W', \ 'text': 'Incorrect list-item indent: add 1 space list-item-indent remark-lint', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'type': 'E', \ 'text': 'Incorrect list-item indent: remove 1 space list-item-indent remark-lint', \ }, \ { \ 'lnum': 18, \ 'col': 71, \ 'end_lnum': 19, \ 'end_col': 1, \ 'type': 'E', \ 'text': 'Missing new line after list item list-item-spacing remark-lint', \ }, \ ], \ ale_linters#markdown#remark_lint#Handle(1, [ \ 'foo.md', \ ' 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint', \ ' 3:5 error Incorrect list-item indent: remove 1 space list-item-indent remark-lint', \ ' 18:71-19:1 error Missing new line after list item list-item-spacing remark-lint', \ '', \ '⚠ 1 warnings', \ '✘ 2 errors', \]) ================================================ FILE: test/handler/test_rflint_handler.vader ================================================ Before: runtime ale_linters/robot/rflint.vim After: call ale#linter#Reset() Execute(Warning and error messages should be handled correctly): AssertEqual \ [ \ { \ 'bufnr': 1, \ 'filename': 'test.robot', \ 'type': 'W', \ 'lnum': 1, \ 'col': 2, \ 'text': 'RequireSuiteDocumentation', \ 'detail': 'No suite documentation', \ }, \ { \ 'bufnr': 1, \ 'filename': 'test.robot', \ 'type': 'E', \ 'lnum': 3, \ 'col': 4, \ 'text': 'RequireTestDocumentation', \ 'detail': 'No testcase documentation', \ }, \ ], \ ale_linters#robot#rflint#Handle(1, [ \ 'test.robot:W:1:2:RequireSuiteDocumentation:No suite documentation', \ 'test.robot:E:3:4:RequireTestDocumentation:No testcase documentation' \]) ================================================ FILE: test/handler/test_rpmlint_handler.vader ================================================ Before: runtime ale_linters/spec/rpmlint.vim After: call ale#linter#Reset() Execute(The rpmlint handler should parse error messages correctly): AssertEqual \ [ \ { \ 'bufnr': 42, \ 'lnum': 23, \ 'text': 'macro-in-comment %version', \ 'type': 'W', \ }, \ { \ 'bufnr': 42, \ 'lnum': 17, \ 'text': 'hardcoded-library-path in %_prefix/lib/%name', \ 'type': 'E', \ }, \ { \ 'bufnr': 42, \ 'lnum': 1, \ 'text': 'specfile-error warning: bogus date in %changelog: Mon Oct 1 2005 - Foo', \ 'type': 'E', \ }, \ ], \ ale_linters#spec#rpmlint#Handle(42, [ \ 'cyrus-imapd.spec:23: W: macro-in-comment %version', \ 'cyrus-imapd.spec:17: E: hardcoded-library-path in %_prefix/lib/%name', \ 'apcupsd.spec: E: specfile-error warning: bogus date in %changelog: Mon Oct 1 2005 - Foo', \ ]) ================================================ FILE: test/handler/test_rstcheck_lint_handler.vader ================================================ Before: runtime ale_linters/rst/rstcheck.vim After: call ale#linter#Reset() Execute(Warning and error messages should be handled correctly): " For some reason we can't set the directory such that the filenames are " correct here when running the tests from the Docker image, so we have to " just check the basenames of the files instead. AssertEqual \ [ \ { \ 'filename': 'bad_python.rst', \ 'lnum': 7, \ 'col': 0, \ 'type': 'W', \ 'text': '(python) unexpected EOF while parsing', \ }, \ { \ 'filename': 'bad_cpp.rst', \ 'lnum': 9, \ 'col': 0, \ 'type': 'W', \ 'text': '(cpp) error: ''x'' was not declared in this scope', \ }, \ { \ 'filename': 'bad_rst.rst', \ 'lnum': 1, \ 'col': 0, \ 'type': 'E', \ 'text': 'Title overline & underline mismatch.', \ }, \ ], \ map( \ ale_linters#rst#rstcheck#Handle(1, [ \ 'bad_python.rst:7: (ERROR/3) (python) unexpected EOF while parsing', \ 'bad_cpp.rst:9: (ERROR/3) (cpp) error: ''x'' was not declared in this scope', \ 'bad_rst.rst:1: (SEVERE/4) Title overline & underline mismatch.', \ ]), \ 'extend(v:val, {''filename'': fnamemodify(v:val.filename, '':t'')})' \ ) ================================================ FILE: test/handler/test_rubocop_handler.vader ================================================ Before: runtime ale_linters/ruby/rubocop.vim After: call ale#linter#Reset() Execute(The rubocop handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 83, \ 'col': 29, \ 'end_col': 35, \ 'text': 'Prefer single-quoted strings...', \ 'code': 'Style/SomeCop', \ 'type': 'W', \ }, \ { \ 'lnum': 12, \ 'col': 2, \ 'end_col': 2, \ 'text': 'Some error', \ 'code': 'Style/SomeOtherCop', \ 'type': 'E', \ }, \ { \ 'lnum': 10, \ 'col': 5, \ 'end_col': 12, \ 'text': 'Regular warning', \ 'code': 'Style/WarningCop', \ 'type': 'W', \ }, \ { \ 'lnum': 11, \ 'col': 1, \ 'end_col': 1, \ 'text': 'Another error', \ 'code': 'Style/SpaceBeforeBlockBraces', \ 'type': 'E', \ }, \ ], \ ale#ruby#HandleRubocopOutput(347, [ \ '{"metadata":{"rubocop_version":"0.47.1","ruby_engine":"ruby","ruby_version":"2.1.5","ruby_patchlevel":"273","ruby_platform":"x86_64-linux-gnu"},"files":[{"path":"my_great_file.rb","offenses":[{"severity":"convention","message":"Prefer single-quoted strings...","cop_name":"Style/SomeCop","corrected":false,"location":{"line":83,"column":29,"length":7}},{"severity":"fatal","message":"Some error","cop_name":"Style/SomeOtherCop","corrected":false,"location":{"line":12,"column":2,"length":1}},{"severity":"warning","message":"Regular warning","cop_name":"Style/WarningCop","corrected":false,"location":{"line":10,"column":5,"length":8}},{"severity":"error","message":"Another error","cop_name":"Style/SpaceBeforeBlockBraces","corrected":false,"location":{"line":11,"column":1,"length":1}}]}],"summary":{"offense_count":4,"target_file_count":1,"inspected_file_count":1}}' \ ]) Execute(The rubocop handler should handle when files are checked and no offenses are found): AssertEqual \ [], \ ale#ruby#HandleRubocopOutput(347, [ \ '{"metadata":{"rubocop_version":"0.47.1","ruby_engine":"ruby","ruby_version":"2.1.5","ruby_patchlevel":"273","ruby_platform":"x86_64-linux-gnu"},"files":[{"path":"my_great_file.rb","offenses":[]}],"summary":{"offense_count":0,"target_file_count":1,"inspected_file_count":1}}' \ ]) Execute(The rubocop handler should handle when no files are checked): AssertEqual \ [], \ ale#ruby#HandleRubocopOutput(347, [ \ '{"metadata":{"rubocop_version":"0.47.1","ruby_engine":"ruby","ruby_version":"2.1.5","ruby_patchlevel":"273","ruby_platform":"x86_64-linux-gnu"},"files":[],"summary":{"offense_count":0,"target_file_count":0,"inspected_file_count":0}}' \ ]) Execute(The rubocop handler should handle empty output): AssertEqual [], ale#ruby#HandleRubocopOutput(347, ['{}']) AssertEqual [], ale#ruby#HandleRubocopOutput(347, []) ================================================ FILE: test/handler/test_ruby_handler.vader ================================================ Before: runtime ale_linters/ruby/ruby.vim After: call ale#linter#Reset() Execute(The ruby handler should parse lines correctly and add the column if it can): " Point Error " Warning " Line Error AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 13, \ 'type': 'E', \ 'text': 'syntax error, unexpected '';''' \ }, \ { \ 'lnum': 9, \ 'col': 0, \ 'type': 'W', \ 'text': 'warning: statement not reached' \ }, \ { \ 'lnum': 12, \ 'col': 0, \ 'type': 'E', \ 'text': 'syntax error, unexpected end-of-input, expecting keyword_end' \ } \ ], \ ale#handlers#ruby#HandleSyntaxErrors(255, [ \ "test.rb:6: syntax error, unexpected ';'", \ " t = ;", \ " ^", \ "test.rb:9: warning: statement not reached", \ "test.rb:12: syntax error, unexpected end-of-input, expecting keyword_end", \ ]) ================================================ FILE: test/handler/test_ruff_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_blank_lines Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_blank_lines = 1 let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/python/ruff.vim After: Restore unlet! b:ale_warn_about_trailing_blank_lines unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute(We should handle basic output of ruff correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'code': 'F821', \ 'type': 'W', \ 'end_col': 7, \ 'end_lnum': 2, \ 'text': 'Undefined name example', \ }, \ ], \ ale_linters#python#ruff#Handle(bufnr(''), [ \ '{"cell":null,"code":"F821","end_location":{"column":8,"row":2},"filename":"/home/eduardo/Code/Python/test.py","fix":null,"location":{"column":1,"row":2},"message":"Undefined name example","noqa_row":2,"url":"https://docs.astral.sh/ruff/rules/undefined-name"}', \ ]) Execute(We should handle totally broken output from ruff): AssertEqual [], ale_linters#python#ruff#Handle(bufnr(''), ['ERROR: oh noes!']) Execute(We should handle mixed error lines and JSON output from ruff): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'code': 'F821', \ 'type': 'W', \ 'end_col': 7, \ 'end_lnum': 2, \ 'text': 'Undefined name example', \ }, \ ], \ ale_linters#python#ruff#Handle(bufnr(''), [ \ 'ERROR: oh noes!', \ '{"cell":null,"code":"F821","end_location":{"column":8,"row":2},"filename":"/home/eduardo/Code/Python/test.py","fix":null,"location":{"column":1,"row":2},"message":"Undefined name example","noqa_row":2,"url":"https://docs.astral.sh/ruff/rules/undefined-name"}', \ ]) Execute(Warnings about trailing whitespace should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'end_lnum': 6, \ 'end_col': 1, \ 'code': 'W291', \ 'type': 'W', \ 'text': 'who cares', \ }, \ { \ 'lnum': 6, \ 'col': 1, \ 'end_lnum': 6, \ 'end_col': 1, \ 'code': 'W293', \ 'type': 'W', \ 'text': 'who cares', \ }, \ ], \ ale_linters#python#ruff#Handle(bufnr(''), [ \ '{"cell":null,"code":"W291","end_location":{"column":2,"row":6},"filename":"/test.py","fix":null,"location":{"column":1,"row":6},"message":"who cares","noqa_row":2,"url":""}', \ '{"cell":null,"code":"W293","end_location":{"column":2,"row":6},"filename":"/test.py","fix":null,"location":{"column":1,"row":6},"message":"who cares","noqa_row":2,"url":""}', \ ]) Execute(Disabling trailing whitespace warnings should work): let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [], \ ale_linters#python#ruff#Handle(bufnr(''), [ \ '{"cell":null,"code":"W291","end_location":{"column":2,"row":6},"filename":"/test.py","fix":null,"location":{"column":1,"row":6},"message":"who cares","noqa_row":2,"url":""}', \ '{"cell":null,"code":"W293","end_location":{"column":2,"row":6},"filename":"/test.py","fix":null,"location":{"column":1,"row":6},"message":"who cares","noqa_row":2,"url":""}', \ ]) Execute(Warnings about trailing blank lines should be reported by default): AssertEqual \ [ \ { \ 'lnum': 6, \ 'col': 1, \ 'end_lnum': 6, \ 'end_col': 1, \ 'code': 'W391', \ 'type': 'W', \ 'text': 'blank line at end of file', \ }, \ ], \ ale_linters#python#ruff#Handle(bufnr(''), [ \ '{"cell":null,"code":"W391","end_location":{"column":2,"row":6},"filename":"/test.py","fix":null,"location":{"column":1,"row":6},"message":"blank line at end of file","noqa_row":2,"url":""}', \ ]) Execute(Disabling trailing blank line warnings should work): let b:ale_warn_about_trailing_blank_lines = 0 AssertEqual \ [], \ ale_linters#python#ruff#Handle(bufnr(''), [ \ '{"cell":null,"code":"W391","end_location":{"column":2,"row":6},"filename":"/test.py","fix":null,"location":{"column":1,"row":6},"message":"blank line at end of file","noqa_row":2,"url":""}', \ ]) ================================================ FILE: test/handler/test_rust_handler.vader ================================================ Before: Save g:ale_rust_ignore_secondary_spans let g:ale_rust_ignore_secondary_spans = 0 After: Restore Execute(The Rust handler should handle rustc output): call ale#test#SetFilename('src/playpen.rs') AssertEqual \ [ \ { \ 'lnum': 15, \ 'end_lnum': 15, \ 'type': 'E', \ 'col': 5, \ 'end_col': 7, \ 'text': 'expected one of `.`, `;`, `?`, `}`, or an operator, found `for`', \ }, \ { \ 'lnum': 13, \ 'end_lnum': 13, \ 'type': 'E', \ 'col': 7, \ 'end_col': 9, \ 'text': 'no method named `wat` found for type `std::string::String` in the current scope', \ }, \ ], \ ale#handlers#rust#HandleRustErrors(bufnr(''), [ \ '', \ 'ignore this', \ json_encode({ \ 'message': 'expected one of `.`, `;`, `?`, `}`, or an operator, found `for`', \ 'code': v:null, \ 'level': 'error', \ 'spans': [ \ { \ 'file_name': '', \ 'byte_start': 418, \ 'byte_end': 421, \ 'line_start': 15, \ 'line_end': 15, \ 'column_start': 5, \ 'column_end': 8, \ 'is_primary': v:true, \ 'label': v:null, \ }, \ ], \ }), \ json_encode({ \ 'message': 'main function not found', \ 'code': v:null, \ 'level': 'error', \ 'spans': [], \ }), \ json_encode({ \ 'code': v:null, \ 'level': 'error', \ 'message': 'no method named `wat` found for type `std::string::String` in the current scope', \ 'spans': [ \ { \ 'byte_end': 410, \ 'byte_start': 407, \ 'column_end': 10, \ 'column_start': 7, \ 'file_name': '', \ 'is_primary': v:true, \ 'label': v:null, \ 'line_end': 13, \ 'line_start': 13, \ } \ ] \ }), \ json_encode({ \ 'code': v:null, \ 'level': 'error', \ 'message': 'aborting due to previous error', \ 'spans': [ \ ] \ }), \ ]) Execute(The Rust handler should handle cargo output): call ale#test#SetFilename('src/playpen.rs') AssertEqual \ [ \ { \ 'lnum': 15, \ 'end_lnum': 15, \ 'type': 'E', \ 'col': 5, \ 'end_col': 7, \ 'text': 'expected one of `.`, `;`, `?`, `}`, or an operator, found `for`', \ }, \ { \ 'lnum': 13, \ 'end_lnum': 13, \ 'type': 'E', \ 'col': 7, \ 'end_col': 9, \ 'text': 'no method named `wat` found for type `std::string::String` in the current scope', \ }, \ ], \ ale#handlers#rust#HandleRustErrors(bufnr(''), [ \ '', \ 'ignore this', \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'expected one of `.`, `;`, `?`, `}`, or an operator, found `for`', \ 'spans': [ \ { \ 'byte_end': 11508, \ 'byte_start': 11505, \ 'column_end': 8, \ 'column_start': 5, \ 'file_name': ale#path#Simplify('src/playpen.rs'), \ 'is_primary': v:true, \ 'label': v:null, \ 'line_end': 15, \ 'line_start': 15, \ } \ ] \ }, \ }), \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'no method named `wat` found for type `std::string::String` in the current scope', \ 'spans': [ \ { \ 'byte_end': 11497, \ 'byte_start': 11494, \ 'column_end': 10, \ 'column_start': 7, \ 'file_name': ale#path#Simplify('src/playpen.rs'), \ 'is_primary': v:true, \ 'label': v:null, \ 'line_end': 13, \ 'line_start': 13, \ } \ ] \ }, \ }), \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'aborting due to previous error', \ 'spans': [ \ ] \ }, \ }), \ ]) Execute(The Rust handler should should errors from expansion spans): AssertEqual \ [ \ { \ 'lnum': 4, \ 'end_lnum': 4, \ 'type': 'E', \ 'col': 21, \ 'end_col': 22, \ 'text': 'mismatched types: expected bool, found integral variable', \ }, \ ], \ ale#handlers#rust#HandleRustErrors(bufnr(''), [ \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'mismatched types', \ 'spans': [ \ { \ 'byte_end': 1, \ 'byte_start': 1, \ 'column_end': 1, \ 'column_start': 1, \ 'file_name': ale#path#Simplify('src/other.rs'), \ 'is_primary': v:true, \ 'label': 'some other error', \ 'line_end': 4, \ 'line_start': 4, \ 'expansion': { \ 'span': { \ 'byte_end': 54, \ 'byte_start': 52, \ 'column_end': 23, \ 'column_start': 21, \ 'file_name': ale#path#Simplify('src/playpen.rs'), \ 'is_primary': v:true, \ 'label': 'expected bool, found integral variable', \ 'line_end': 4, \ 'line_start': 4, \ } \ } \ } \ ] \ }, \ }), \ ]) Execute(The Rust handler should show detailed errors): call ale#test#SetFilename('src/playpen.rs') AssertEqual \ [ \ { \ 'lnum': 4, \ 'end_lnum': 4, \ 'type': 'E', \ 'col': 21, \ 'end_col': 22, \ 'text': 'mismatched types: expected bool, found integral variable', \ }, \ ], \ ale#handlers#rust#HandleRustErrors(bufnr(''), [ \ '', \ 'ignore this', \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'mismatched types', \ 'spans': [ \ { \ 'byte_end': 54, \ 'byte_start': 52, \ 'column_end': 23, \ 'column_start': 21, \ 'expansion': v:null, \ 'file_name': ale#path#Simplify('src/playpen.rs'), \ 'is_primary': v:true, \ 'label': 'expected bool, found integral variable', \ 'line_end': 4, \ 'line_start': 4, \ } \ ] \ }, \ }), \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'aborting due to previous error(s)', \ 'spans': [ \ ] \ }, \ }), \ ]) Execute(The Rust handler should show detailed clippy errors with rendered field if it's available): call ale#test#SetFilename('src/playpen.rs') AssertEqual \ [ \ { \ 'lnum': 4, \ 'end_lnum': 4, \ 'type': 'E', \ 'col': 21, \ 'end_col': 22, \ 'text': 'mismatched types: expected bool, found integral variable', \ 'detail': 'this is a detailed description', \ }, \ ], \ ale#handlers#rust#HandleRustErrors(bufnr(''), [ \ '', \ 'ignore this', \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'mismatched types', \ 'rendered': 'this is a detailed description', \ 'spans': [ \ { \ 'byte_end': 54, \ 'byte_start': 52, \ 'column_end': 23, \ 'column_start': 21, \ 'expansion': v:null, \ 'file_name': ale#path#Simplify('src/playpen.rs'), \ 'is_primary': v:true, \ 'label': 'expected bool, found integral variable', \ 'line_end': 4, \ 'line_start': 4, \ } \ ] \ }, \ }), \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'aborting due to previous error(s)', \ 'spans': [ \ ] \ }, \ }), \ ]) Execute(The Rust handler should find correct files): call ale#test#SetFilename('src/noerrors/mod.rs') AssertEqual \ [], \ ale#handlers#rust#HandleRustErrors(bufnr(''), [ \ '', \ 'ignore this', \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'unresolved import `Undefined`', \ 'spans': [ \ { \ 'byte_end': 103, \ 'byte_start': 94, \ 'column_end': 14, \ 'column_start': 5, \ 'file_name': 'src/haserrors/mod.rs', \ 'is_primary': v:true, \ 'label': 'no `Undefined` in the root', \ 'line_end': 1, \ 'line_start': 1, \ } \ ] \ }, \ }), \ json_encode({ \ 'message': { \ 'code': v:null, \ 'level': 'error', \ 'message': 'aborting due to previous error', \ 'spans': [ \ ] \ }, \ }), \ ]) Execute(The Rust handler should remove secondary spans if set): call ale#test#SetFilename('src/noerrors/mod.rs') AssertEqual \ [ \ { \ 'lnum': 1, \ 'end_lnum': 1, \ 'type': 'E', \ 'end_col': 20, \ 'col': 1, \ 'text': 'this function takes 1 parameter but 0 were supplied: defined here', \ }, \ { \ 'lnum': 1, \ 'end_lnum': 1, \ 'type': 'E', \ 'end_col': 45, \ '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': '', \ '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': 45, \ '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': '', \ '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': [] \ }, \ }), \ ]) ================================================ FILE: test/handler/test_salt_salt_lint.vader ================================================ Before: runtime ale_linters/salt/salt_lint.vim After: call ale#linter#Reset() Execute(The salt handler should parse lines correctly and show error in severity HIGH): AssertEqual \ [ \ { \ 'lnum': 5, \ 'code': 207, \ 'text': 'File modes should always be encapsulated in quotation marks', \ 'type': 'E' \ } \ ], \ ale_linters#salt#salt_lint#Handle(255, [ \ '[{"id": "207", "message": "File modes should always be encapsulated in quotation marks", "filename": "test.sls", "linenumber": 5, "line": " - mode: 0755", "severity": "HIGH"}]' \ ]) Execute(The salt handler should parse lines correctly and show error in severity not HIGH): AssertEqual \ [ \ { \ 'lnum': 27, \ 'code': 204, \ 'text': 'Lines should be no longer that 160 chars', \ 'type': 'W' \ } \ ], \ ale_linters#salt#salt_lint#Handle(255, [ \ '[{"id": "204", "message": "Lines should be no longer that 160 chars", "filename": "test2.sls", "linenumber": 27, "line": "this line is definitely longer than 160 chars, this line is definitely longer than 160 chars, this line is definitely longer than 160 chars", "severity": "VERY_LOW"}]' \ ]) ================================================ FILE: test/handler/test_scala_handler.vader ================================================ Execute(The handler should return an empty list with empty input): AssertEqual [], ale#handlers#scala#HandleScalacLintFormat(bufnr(''), []) Execute(The handler should correctly parse error messages): AssertEqual \ [ \ { \ 'lnum': 4, \ 'col': 8, \ 'text': ''':'' expected but identifier found.', \ 'type': 'E' \ }, \ { \ 'lnum': 6, \ 'col': 2, \ 'text': 'identifier expected but eof found.', \ 'type': 'E' \ } \ ], \ ale#handlers#scala#HandleScalacLintFormat(bufnr(''), \ [ \ "hi.scala:4: error: ':' expected but identifier found.", \ " Some stupid scala code", \ " ^", \ "hi.scala:6: error: identifier expected but eof found.", \ ")", \ " ^", \ "two errors found", \ ]) ================================================ FILE: test/handler/test_scalastyle_handler.vader ================================================ Before: runtime! ale_linters/scala/scalastyle.vim After: call ale#linter#Reset() Execute(The scalastyle handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 190, \ 'text': 'Missing or badly formed ScalaDoc: Missing @param str', \ 'type': 'W', \ }, \ { \ 'lnum': 200, \ 'col': 34, \ 'text': 'There should be a space before the plus (+) sign', \ 'type': 'E', \ }, \ { \ 'lnum': 200, \ 'col': 1, \ 'text': 'There should be a space before the plus (+) sign', \ 'type': 'E', \ }, \ ], \ ale_linters#scala#scalastyle#Handle(347, [ \ 'Starting scalastyle', \ 'start file /home/test/Doop.scala', \ 'warning file=/home/test/Doop.scala message=Missing or badly formed ScalaDoc: Missing @param str line=190', \ 'error file=/home/test/Doop.scala message=There should be a space before the plus (+) sign line=200 column=33', \ 'error file=/home/test/Doop.scala message=There should be a space before the plus (+) sign line=200 column=0', \ 'end file /home/test/Doop.scala', \ 'Processed 1 file(s)', \ 'Found 0 errors', \ 'Found 3 warnings', \ 'Finished in 934 ms', \ ]) Execute(The scalastyle linter should complain when there is no configuration file): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': '(See :help ale-scala-scalastyle) No scalastyle configuration file was found.', \ }, \ ], \ ale_linters#scala#scalastyle#Handle(347, [ \ 'scalastyle 1.0.0', \ 'Usage: scalastyle [options] ', \ ' -c, --config FILE configuration file (required)', \ ]) ================================================ FILE: test/handler/test_scarb_handler.vader ================================================ Before: runtime ale_linters/cairo/scarb.vim After: call ale#linter#Reset() Execute(Check scarb output parsing): AssertEqual \ [ \ { \ 'lnum': 40, \ 'col': 48, \ 'text': 'Skipped tokens. Expected: Const/Module/Use/FreeFunction/ExternFunction/ExternType/Trait/Impl/Struct/Enum/TypeAlias/InlineMacro or an attribute.', \ 'type': 'E', \ }, \ ], \ ale#handlers#cairo#HandleCairoErrors(bufnr(''), [ \ 'error: Skipped tokens. Expected: Const/Module/Use/FreeFunction/ExternFunction/ExternType/Trait/Impl/Struct/Enum/TypeAlias/InlineMacro or an attribute.', \ ' --> /path/to/file.cairo:40:48', \ ]) ================================================ FILE: test/handler/test_shell_handler.vader ================================================ Before: runtime ale_linters/sh/shell.vim After: call ale#linter#Reset() Execute(The shell handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 13, \ 'text': 'syntax error near unexpected token d', \ }, \ { \ 'lnum': 7, \ 'text': 'line 42: line 36:', \ }, \ { \ 'lnum': 11, \ 'text': 'Syntax error: "(" unexpected', \ }, \ { \ 'lnum': 95, \ 'text': 'parse error near `out=$(( $1 / 1024. )...', \ }, \ { \ 'lnum': 22, \ 'text': ':11: :33: :44:', \ }, \ { \ 'lnum': 9, \ 'text': '`done'' unexpected', \ }, \ ], \ ale_linters#sh#shell#Handle(347, [ \ 'bash: line 13: syntax error near unexpected token d', \ 'bash: line 7: line 42: line 36:', \ 'sh: 11: Syntax error: "(" unexpected', \ 'qfm:95: parse error near `out=$(( $1 / 1024. )...', \ 'qfm:22: :11: :33: :44:', \ 'foo.sh: syntax error at line 9: `done'' unexpected', \ ]) Execute(The shell handler should parse Simplified Chinese lines correctly): AssertEqual \ [ \ { \ 'lnum': 0, \ 'text': '未预期的符号“done”附近有语法错误', \ }, \ { \ 'lnum': 90, \ 'text': '寻找匹配的“"”时遇到了未预期的文件结束符', \ }, \ { \ 'lnum': 111, \ 'text': '语法错误: 未预期的文件结尾', \ }, \ { \ 'lnum': 22, \ 'text': ':11: :33: :44:', \ }, \ ], \ ale_linters#sh#shell#Handle(347, [ \ '/tmp/nvimWL5sOL/2/a.sh:行0: 未预期的符号“done”附近有语法错误', \ '/tmp/nvimWL5sOL/2/a.sh:行90: 寻找匹配的“"”时遇到了未预期的文件结束符', \ '/tmp/nvimWL5sOL/2/a.sh:行111: 语法错误: 未预期的文件结尾', \ '/tmp/nvimWL5sOL/2/a.sh:行22: :11: :33: :44:', \ ]) Execute(The shell handler should parse Traditional Chinese lines correctly): AssertEqual \ [ \ { \ 'lnum': 0, \ 'text': '未預期的字組「(」附近有語法錯誤', \ }, \ { \ 'lnum': 90, \ 'text': '尋找匹配的「"」時遇到了未預期的檔案結束符', \ }, \ { \ 'lnum': 111, \ 'text': '語法錯誤: 未預期的檔案結尾', \ }, \ { \ 'lnum': 22, \ 'text': ':11: :33: :44:', \ }, \ ], \ ale_linters#sh#shell#Handle(347, [ \ '/tmp/nvimWL5sOL/2/a.sh: 列 0: 未預期的字組「(」附近有語法錯誤', \ '/tmp/nvimWL5sOL/2/a.sh: 列 90: 尋找匹配的「"」時遇到了未預期的檔案結束符', \ '/tmp/nvimWL5sOL/2/a.sh: 列 111: 語法錯誤: 未預期的檔案結尾', \ '/tmp/nvimWL5sOL/2/a.sh: 列 22: :11: :33: :44:', \ ]) Execute(The shell handler should parse Japanese lines correctly): AssertEqual \ [ \ { \ 'lnum': 0, \ 'text': "予期しないトークン `(' 周辺に構文エラーがあります", \ }, \ { \ 'lnum': 90, \ 'text': "予期しないトークン `done' 周辺に構文エラーがあります", \ }, \ { \ 'lnum': 111, \ 'text': "対応する `\"' を探索中に予期しないファイル終了 (EOF) です", \ }, \ { \ 'lnum': 22, \ 'text': ':11: :33: :44:', \ }, \ ], \ ale_linters#sh#shell#Handle(347, [ \ "/tmp/nvimWL5sOL/2/a.sh: 行 0: 予期しないトークン `(' 周辺に構文エラーがあります", \ "/tmp/nvimWL5sOL/2/a.sh: 行 90: 予期しないトークン `done' 周辺に構文エラーがあります", \ "/tmp/nvimWL5sOL/2/a.sh: 行 111: 対応する `\"' を探索中に予期しないファイル終了 (EOF) です", \ "/tmp/nvimWL5sOL/2/a.sh: 行 22: :11: :33: :44:", \ ]) Execute(The shell handler should parse Greek lines correctly): AssertEqual \ [ \ { \ 'lnum': 0, \ 'text': 'συντακτικό σφάλμα κοντά στο μη αναμενόμενο σύμβολο «done»', \ }, \ { \ 'lnum': 90, \ 'text': 'syntax error: μη αναμενόμενο τέλος αρχείου', \ }, \ { \ 'lnum': 111, \ 'text': 'μη αναμενόμενο EOF κατά την αναζήτηση «"»', \ }, \ { \ 'lnum': 22, \ 'text': ':11: :33: :44:', \ }, \ ], \ ale_linters#sh#shell#Handle(347, [ \ '/tmp/nvimWL5sOL/2/a.sh: γραμμή 0: συντακτικό σφάλμα κοντά στο μη αναμενόμενο σύμβολο «done»', \ '/tmp/nvimWL5sOL/2/a.sh: γραμμή 90: syntax error: μη αναμενόμενο τέλος αρχείου', \ '/tmp/nvimWL5sOL/2/a.sh: γραμμή 111: μη αναμενόμενο EOF κατά την αναζήτηση «"»', \ "/tmp/nvimWL5sOL/2/a.sh: γραμμή 22: :11: :33: :44:", \ ]) Execute(The shell handler should parse Russian lines correctly): AssertEqual \ [ \ { \ 'lnum': 0, \ 'text': 'синтаксическая ошибка рядом с неожиданным маркером «done»', \ }, \ { \ 'lnum': 90, \ 'text': 'синтаксическая ошибка: неожиданный конец файла', \ }, \ { \ 'lnum': 111, \ 'text': 'неожиданный конец файла во время поиска «"»', \ }, \ { \ 'lnum': 22, \ 'text': ':11: :33: :44:', \ }, \ ], \ ale_linters#sh#shell#Handle(347, [ \ '/tmp/nvimWL5sOL/2/a.sh: строка 0: синтаксическая ошибка рядом с неожиданным маркером «done»', \ '/tmp/nvimWL5sOL/2/a.sh: строка 90: синтаксическая ошибка: неожиданный конец файла', \ '/tmp/nvimWL5sOL/2/a.sh: строка 111: неожиданный конец файла во время поиска «"»', \ '/tmp/nvimWL5sOL/2/a.sh: строка 22: :11: :33: :44:', \ ]) ================================================ FILE: test/handler/test_shellcheck_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace After: Restore Execute(The shellcheck handler should handle basic errors or warnings <0.7.0): AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'W', \ 'text': 'In POSIX sh, ''let'' is not supported.', \ 'code': 'SC2039', \ 'detail': 'In POSIX sh, ''let'' is not supported.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC2039', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'type': 'E', \ 'text': 'Don''t put spaces around the = in assignments.', \ 'code': 'SC1068', \ 'detail': 'Don''t put spaces around the = in assignments.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC1068', \ }, \ ], \ ale#handlers#shellcheck#Handle(bufnr(''), [0, 6, 0], [ \ '-:2:1: warning: In POSIX sh, ''let'' is not supported. [SC2039]', \ '-:2:3: error: Don''t put spaces around the = in assignments. [SC1068]', \ ]) Execute(The shellcheck handler should handle notes <0.7.0): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 3, \ 'type': 'I', \ 'text': 'Double quote to prevent globbing and word splitting.', \ 'code': 'SC2086', \ 'detail': 'Double quote to prevent globbing and word splitting.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC2086', \ }, \ ], \ ale#handlers#shellcheck#Handle(bufnr(''), [0, 6, 0], [ \ '-:3:3: note: Double quote to prevent globbing and word splitting. [SC2086]', \ ]) Execute(The shellcheck handler should handle basic errors or warnings >=0.7.0): AssertEqual \ [ \ { \ 'lnum': 2, \ 'end_lnum': 3, \ 'col': 1, \ 'end_col': 1, \ 'type': 'W', \ 'text': 'In POSIX sh, ''let'' is not supported.', \ 'code': 'SC2039', \ 'detail': 'In POSIX sh, ''let'' is not supported.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC2039', \ }, \ { \ 'lnum': 2, \ 'end_lnum': 3, \ 'col': 3, \ 'end_col': 3, \ 'type': 'E', \ 'text': 'Don''t put spaces around the = in assignments.', \ 'code': 'SC1068', \ 'detail': 'Don''t put spaces around the = in assignments.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC1068', \ }, \ ], \ ale#handlers#shellcheck#Handle(bufnr(''), [0, 7, 0], [ \ '{ \ "comments": [ \ { \ "file":"-", \ "line":2, \ "endLine":3, \ "column":1, \ "endColumn":2, \ "level":"warning", \ "code":2039, \ "message":"In POSIX sh, ''let'' is not supported.", \ "fix": null \ }, \ { \ "file":"-", \ "line":2, \ "endLine":3, \ "column":3, \ "endColumn":4, \ "level":"error", \ "code":1068, \ "message":"Don''t put spaces around the = in assignments.", \ "fix": null \ } \ ] \ }' \ ]) Execute(The shellcheck handler should handle info and style >=0.7.0): AssertEqual \ [ \ { \ 'lnum': 3, \ 'end_lnum': 5, \ 'col': 3, \ 'end_col': 4, \ 'type': 'I', \ 'text': 'Double quote to prevent globbing and word splitting.', \ 'code': 'SC2086', \ 'detail': 'Double quote to prevent globbing and word splitting.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC2086', \ }, \ { \ 'lnum': 13, \ 'end_lnum': 13, \ 'col': 17, \ 'end_col': 27, \ 'type': 'I', \ 'text': '$/${} is unnecessary on arithmetic variables.', \ 'code': 'SC2004', \ 'detail': '$/${} is unnecessary on arithmetic variables.' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC2004', \ } \ ], \ ale#handlers#shellcheck#Handle(bufnr(''), [0, 7, 0], [ \ '{ \ "comments": [ \ { \ "file": "-", \ "line": 3, \ "endLine": 5, \ "column": 3, \ "endColumn": 5, \ "level": "info", \ "code": 2086, \ "message": "Double quote to prevent globbing and word splitting.", \ "fix": null \ }, \ { \ "file": "-", \ "line": 13, \ "endLine": 13, \ "column": 17, \ "endColumn": 28, \ "level": "style", \ "code": 2004, \ "message": "$/${} is unnecessary on arithmetic variables.", \ "fix": null \ } \ ] \ }' \ ]) Execute(shellcheck errors for trailing whitespace should show by default): AssertEqual \ [ \ { \ 'lnum': 8, \ 'col': 12, \ 'code': 'SC1101', \ 'end_lnum': 8, \ 'type': 'E', \ 'end_col': 11, \ 'text': 'Delete trailing spaces after \ to break line (or use quotes for literal space).', \ 'detail': 'Delete trailing spaces after \ to break line (or use quotes for literal space).' . "\n\nFor more information:\n https://www.shellcheck.net/wiki/" . 'SC1101', \ }, \ ], \ ale#handlers#shellcheck#Handle(bufnr(''), [0, 7, 0], [ \ '{ \ "comments": [ \ { \ "file": "-", \ "line": 8, \ "endLine": 8, \ "column": 12, \ "endColumn": 12, \ "level": "error", \ "code":1101, \ "message":"Delete trailing spaces after \\ to break line (or use quotes for literal space).", \ "fix":null \ } \ ] \ }', \ ]) Execute(shellcheck errors for trailing whitepsace should be able to be silenced by ale_warn_about_trailing_whitespace): let g:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [], \ ale#handlers#shellcheck#Handle(bufnr(''), [0, 7, 0], [ \ '{ \ "comments": [ \ { \ "file": "-", \ "line": 8, \ "endLine": 8, \ "column": 12, \ "endColumn": 12, \ "level": "error", \ "code":1101, \ "message":"Delete trailing spaces after \\ to break line (or use quotes for literal space).", \ "fix":null \ } \ ] \ }', \ ]) ================================================ FILE: test/handler/test_sierra_handler.vader ================================================ Before: runtime ale_linters/cairo/sierra.vim After: call ale#linter#Reset() Execute(The starknet handler should handle error messages correctly): AssertEqual \ [ \ { \ 'lnum': 16, \ 'col': 25, \ 'text': 'Plugin diagnostic: Type not found', \ 'type': 'E', \ }, \ ], \ ale_linters#cairo#sierra#Handle(bufnr(''), [ \ 'error: Plugin diagnostic: Type not found', \ ' --> lib.cairo:16:25', \ ]) ================================================ FILE: test/handler/test_slang_handler.vader ================================================ Before: runtime ale_linters/verilog/slang.vim After: call ale#linter#Reset() Execute(The slang handler should parse lines correctly): AssertEqual \ [ \ { \ 'filename' : 'foo.sv', \ 'lnum': 11, \ 'col': 1, \ 'type': 'W', \ 'text': 'extra '';'' has no effect [-Wempty-member]', \ }, \ { \ 'filename' : 'bar.sv', \ 'lnum': 24, \ 'col': 12, \ 'type': 'E', \ 'text': 'cannot mix continuous and procedural assignments to variable ''data_o''', \ }, \ ], \ ale_linters#verilog#slang#Handle(bufnr(''), [ \ 'foo.sv:11:1: warning: extra '';'' has no effect [-Wempty-member]', \ 'bar.sv:24:12: error: cannot mix continuous and procedural assignments to variable ''data_o''', \ ]) ================================================ FILE: test/handler/test_slim_handler.vader ================================================ " Author: Markus Doits Before: runtime ale_linters/slim/slimlint.vim After: call ale#linter#Reset() Execute(The slim handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'text': '`div` is redundant when class attribute shortcut is present', \ 'code': 'RedundantDiv', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'text': 'Line is too long. [136/80]', \ 'code': 'LineLength', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'text': 'Invalid syntax', \ 'type': 'E', \ }, \ ], \ ale_linters#slim#slimlint#Handle(347, [ \ 'inv.slim:1 [W] RedundantDiv: `div` is redundant when class attribute shortcut is present', \ 'inv.slim:2 [W] LineLength: Line is too long. [136/80]', \ 'inv.slim:3 [E] Invalid syntax', \ ]) ================================================ FILE: test/handler/test_sml_handler.vader ================================================ Execute (Testing on EOF error): AssertEqual [ \ { \ 'filename': 'a.sml', \ 'lnum': 2, \ 'col': 15, \ 'type': 'E', \ 'text': 'Error: syntax error found at EOF', \ }, \], \ ale#handlers#sml#Handle(42, [ \ "Standard ML of New Jersey v110.78 [built: Thu Jul 23 11:21:58 2015]", \ "[opening a.sml]", \ "a.sml:2.16 Error: syntax error found at EOF", \ '/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Compile with "syntax error" raised at ../compiler/Parse/main/smlfile.sml:15.24-15.46', \]) Execute (Testing if the handler can handle multiple errors on the same line): AssertEqual [ \ { \ 'filename': 'a.sml', \ 'lnum': 1, \ 'col': 5, \ 'type': 'E', \ 'text': "Error: can't find function arguments in clause", \ }, \ { \ 'filename': 'a.sml', \ 'lnum': 1, \ 'col': 12, \ 'type': 'E', \ 'text': 'Error: unbound variable or constructor: wow', \ }, \], \ ale#handlers#sml#Handle(42, [ \ "Standard ML of New Jersey v110.78 [built: Thu Jul 23 11:21:58 2015]", \ "[opening test.sml]", \ "a.sml:1.6-1.10 Error: can't find function arguments in clause", \ "a.sml:1.13-1.16 Error: unbound variable or constructor: wow", \ "/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0", \ "raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27", \]) Execute (Testing rarer errors): AssertEqual [ \ { \ 'filename': 'a.sml', \ 'lnum': 5, \ 'col': 18, \ 'type': 'E', \ 'text': "Error: syntax error found at ID", \ }, \ { \ 'filename': 'a.sml', \ 'lnum': 7, \ 'col': 0, \ 'type': 'E', \ 'text': "Error: value type in structure doesn't match signature spec", \ }, \], \ ale#handlers#sml#Handle(42, [ \ "Standard ML of New Jersey v110.78 [built: Thu Jul 23 11:21:58 2015]", \ "[opening test.sml]", \ "a.sml:5.19 Error: syntax error found at ID", \ "a.sml:7.1-9.27 Error: value type in structure doesn't match signature spec", \ "/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0", \ "raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27", \]) Execute (Testing a warning): AssertEqual [ \ { \ 'filename': 'a.sml', \ 'lnum': 4, \ 'col': 4, \ 'type': 'W', \ 'text': "Warning: match nonexhaustive", \ }, \], \ ale#handlers#sml#Handle(42, [ \ "Standard ML of New Jersey v110.78 [built: Thu Jul 23 11:21:58 2015]", \ "[opening a.sml]", \ "a.sml:4.5-4.12 Warning: match nonexhaustive", \ "0 => ...", \ "val f = fn : int -> int", \ "-", \]) Execute (Testing stdIn): AssertEqual [ \ { \ 'bufnr': 42, \ 'lnum': 1, \ 'col': 5, \ 'type': 'E', \ 'text': "Error: operator and operand don't agree [overload conflict]", \ }, \ { \ 'bufnr': 42, \ 'lnum': 2, \ 'col': 4, \ 'type': 'E', \ 'text': "Error: operator and operand don't agree [overload conflict]", \ }, \], \ ale#handlers#sml#Handle(42, [ \ "Standard ML of New Jersey v110.79 [built: Sat Oct 26 12:27:04 2019]", \ "- = stdIn:1.6-1.21 Error: operator and operand don't agree [overload conflict]", \ " operator domain: [+ ty] * [+ ty]", \ " operand: string * [int ty]", \ " in expression:", \ ' "abc" + 123', \ "stdIn:2.5-2.20 Error: operator and operand don't agree [overload conflict]", \ " operator domain: [+ ty] * [+ ty]", \ " operand: [+ ty] * string", \ " in expression:", \ ' 890 + "xyz"', \ "-", \]) ================================================ FILE: test/handler/test_solc_handler.vader ================================================ Before: runtime ale_linters/solidity/solc.vim After: call ale#linter#Reset() Execute(Check solc output parsing): AssertEqual \ [ \ { \ 'lnum': 40, \ 'col': 48, \ 'text': 'This declaration shadows an existing declaration.', \ 'type': 'W', \ }, \ { \ 'lnum': 23, \ 'col': 16, \ 'text': 'Member "getSinleSignature" not found or not visible after argument-dependent lookup in type(contract OneToN).', \ 'type': 'E', \ }, \ ], \ ale_linters#solidity#solc#Handle(bufnr(''), [ \ 'Warning: This declaration shadows an existing declaration.', \ ' --> /path/to/file.sol:40:48:', \ ' |', \ '40 | function decimals() external view returns (uint8 decimals);', \ ' | ^------------^', \ 'Error: Member "getSinleSignature" not found or not visible after argument-dependent lookup in type(contract OneToN).', \ ' --> /path/to/file.sol:23:16: ', \ ' | ', \ '23 | return OneToN.getSinleSignature(signatures, i);', \ ' | ^----------------------^', \ ]) ================================================ FILE: test/handler/test_solhint_handler.vader ================================================ Before: runtime ale_linters/solidity/solhint.vim After: call ale#linter#Reset() Execute(The solhint handler should parse linter error messages correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 17, \ 'text': 'Compiler version must be fixed', \ 'code': 'compiler-fixed', \ 'type': 'W', \ }, \ { \ 'lnum': 4, \ 'col': 8, \ 'text': 'Use double quotes for string literals', \ 'code': 'quotes', \ 'type': 'E', \ }, \ { \ 'lnum': 5, \ 'col': 8, \ 'text': 'Use double quotes for string literals', \ 'code': 'quotes', \ 'type': 'E', \ }, \ { \ 'lnum': 13, \ 'col': 3, \ 'text': 'Expected indentation of 4 spaces but found 2', \ 'code': 'indent', \ 'type': 'E', \ }, \ { \ 'lnum': 14, \ 'col': 3, \ 'text': 'Expected indentation of 4 spaces but found 2', \ 'code': 'indent', \ 'type': 'E', \ }, \ { \ 'lnum': 47, \ 'col': 3, \ 'text': 'Function order is incorrect, public function can not go after internal function.', \ 'code': 'func-order', \ 'type': 'E', \ }, \ ], \ ale_linters#solidity#solhint#Handle(bufnr(''), [ \ 'contracts/Bounty.sol:1:17: Compiler version must be fixed [Warning/compiler-fixed]', \ 'contracts/Bounty.sol:4:8: Use double quotes for string literals [Error/quotes]', \ 'contracts/Bounty.sol:5:8: Use double quotes for string literals [Error/quotes]', \ 'contracts/Bounty.sol:13:3: Expected indentation of 4 spaces but found 2 [Error/indent]', \ 'contracts/Bounty.sol:14:3: Expected indentation of 4 spaces but found 2 [Error/indent]', \ 'contracts/Bounty.sol:47:3: Function order is incorrect, public function can not go after internal function. [Error/func-order]', \ ]) Execute(The solhint handler should parse syntax error messages correctly): AssertEqual \ [ \ { \ 'lnum': 30, \ 'col': 4, \ 'text': "missing ';' at 'uint248'", \ 'code': 'Parse error', \ 'type': 'E', \ }, \ { \ 'lnum': 203, \ 'col': 4, \ 'text': "no viable alternative at input '_loserStakeMultiplier}'", \ 'code': 'Parse error', \ 'type': 'E', \ }, \ ], \ ale_linters#solidity#solhint#Handle(bufnr(''), [ \ "contracts/Bounty.sol:30:4: Parse error: missing ';' at 'uint248' [Error]", \ "contracts/Bounty.sol:203:4: Parse error: no viable alternative at input '_loserStakeMultiplier}' [Error]", \ ]) ================================================ FILE: test/handler/test_spectral_handler.vader ================================================ Before: runtime ale_linters/yaml/spectral.vim After: call ale#linter#Reset() Execute(spectral handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'code': 'oas3-api-servers', \ 'text': 'OpenAPI `servers` must be present and non-empty array.', \ 'type': 'W' \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'code': 'oas3-schema', \ 'text': 'Object should have required property `paths`.', \ 'type': 'E' \ }, \ { \ 'lnum': 1, \ 'col': 1, \ 'code': 'openapi-tags', \ 'text': 'OpenAPI object should have non-empty `tags` array.', \ 'type': 'W' \ }, \ { \ 'lnum': 3, \ 'col': 6, \ 'code': 'info-contact', \ 'text': 'Info object should contain `contact` object.', \ 'type': 'W' \ }, \ { \ 'lnum': 3, \ 'col': 6, \ 'code': 'oas3-schema', \ 'text': '`info` property should have required property `version`.', \ 'type': 'E' \ }, \ ], \ ale#handlers#spectral#HandleSpectralOutput(bufnr(''), [ \ 'openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array."', \ 'openapi.yml:1:1 error oas3-schema "Object should have required property `paths`."', \ 'openapi.yml:1:1 warning openapi-tags "OpenAPI object should have non-empty `tags` array."', \ 'openapi.yml:3:6 warning info-contact "Info object should contain `contact` object."', \ 'openapi.yml:3:6 error oas3-schema "`info` property should have required property `version`."', \ ]) ================================================ FILE: test/handler/test_sql_sqlfluff_handler.vader ================================================ Before: runtime ale_linters/sql/sqlfluff.vim After: call ale#linter#Reset() Execute(The sqlfluff handler should handle basic warnings with version older than 3.0.0): AssertEqual \ [ \ { \ 'filename': 'schema.sql', \ 'lnum': 1, \ 'col': 8, \ 'type': 'W', \ 'code': 'L010', \ 'text': 'Keywords must be consistently upper case.', \ }, \ { \ 'filename': 'schema.sql', \ 'lnum': 13, \ 'col': 2, \ 'type': 'W', \ 'code': 'L003', \ 'text': 'Expected 1 indentation, found 0 [compared to line 12]', \ }, \ { \ 'filename': 'schema.sql', \ 'lnum': 16, \ 'col': 1, \ 'type': 'W', \ 'code': 'L009', \ 'text': 'Files must end with a single trailing newline.', \ }, \ ], \ ale_linters#sql#sqlfluff#Handle(bufnr(''), [2, 3, 5], [ \ '[{"filepath": "schema.sql", "violations": [{"line_no": 1, "line_pos": 8, "code": "L010", "description": "Keywords must be consistently upper case."}, {"line_no": 13, "line_pos": 2, "code": "L003", "description": "Expected 1 indentation, found 0 [compared to line 12]"}, {"line_no": 16, "line_pos": 1, "code": "L009", "description": "Files must end with a single trailing newline."}]}]', \ ]) Execute(The sqlfluff handler should handle basic warnings with version newer than 3.0.0): AssertEqual \ [ \ { \ 'filename': 'schema.sql', \ 'lnum': 1, \ 'end_lnum': 1, \ 'col': 8, \ 'end_col': 12, \ 'type': 'W', \ 'code': 'L010', \ 'text': 'Keywords must be consistently upper case.', \ }, \ { \ 'filename': 'schema.sql', \ 'lnum': 13, \ 'end_lnum': 13, \ 'col': 2, \ 'end_col': 20, \ 'type': 'W', \ 'code': 'L003', \ 'text': 'Expected 1 indentation, found 0 [compared to line 12]', \ }, \ { \ 'filename': 'schema.sql', \ 'lnum': 16, \ 'end_lnum': 16, \ 'col': 1, \ 'end_col': 5, \ 'type': 'W', \ 'code': 'L009', \ 'text': 'Files must end with a single trailing newline.', \ }, \ { \ 'filename': 'schema.sql', \ 'lnum': 3, \ 'col': 21, \ 'type': 'W', \ 'code': 'TMP', \ 'text': "Undefined jinja template variable: 'a_jinja_templated_table'", \ }, \ ], \ ale_linters#sql#sqlfluff#Handle(bufnr(''), [3, 0, 0], [ \ '[{"filepath": "schema.sql", "violations": [{"start_line_no": 1, "end_line_no":1, "start_line_pos": 8, "end_line_pos":12, "code": "L010", "description": "Keywords must be consistently upper case."}, {"start_line_no": 13, "end_line_no":13, "start_line_pos": 2, "end_line_pos":20, "code": "L003", "description": "Expected 1 indentation, found 0 [compared to line 12]"}, {"start_line_no": 16, "end_line_no":16, "start_line_pos": 1, "end_line_pos":5, "code": "L009", "description": "Files must end with a single trailing newline."}, {"start_line_no": 3, "start_line_pos": 21, "code": "TMP", "description": "Undefined jinja template variable: ''a_jinja_templated_table''"}]}]', \ ]) ================================================ FILE: test/handler/test_sqlint_handler.vader ================================================ Before: runtime! ale_linters/sql/sqlint.vim After: call ale#linter#Reset() Execute(The sqlint handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 1, \ 'text': 'syntax error at or near "WIBBLE"', \ 'type': 'E', \ }, \ { \ 'lnum': 47, \ 'col': 11, \ 'text': 'unterminated quoted string at or near "''', \ 'type': 'E', \ }, \ { \ 'lnum': 50, \ 'col': 12, \ 'text': 'some warning at end of input', \ 'type': 'W', \ }, \ ], \ ale_linters#sql#sqlint#Handle(347, [ \ 'This line should be ignored completely', \ 'stdin:3:1:ERROR syntax error at or near "WIBBLE"', \ 'stdin:47:11:ERROR unterminated quoted string at or near "''', \ 'stdin:50:12:WARNING some warning at end of input', \ ]) ================================================ FILE: test/handler/test_sqllint_handler.vader ================================================ Before: " Load the file which defines the linter. runtime ale_linters/sql/sqllint.vim After: " Unload all linters again. call ale#linter#Reset() Execute (The output should be correct): " Test that the right loclist items are parsed from the handler. AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 0, \ 'type': '', \ 'text': 'stdin:1 [ER_NO_DB_ERROR] No database selected' \ }, \ ], \ ale_linters#sql#sqllint#Handle(bufnr(''), [ \ 'stdin:1 [ER_NO_DB_ERROR] No database selected' \ ]) ================================================ FILE: test/handler/test_standard_handler.vader ================================================ Before: Save g:ale_javascript_eslint_suppress_eslintignore let g:ale_javascript_eslint_suppress_eslintignore = 0 After: Restore Execute(The standard handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 47, \ 'col': 14, \ 'text': 'Expected indentation of 2 spaces but found 4.', \ 'type': 'E', \ }, \ { \ 'lnum': 56, \ 'col': 41, \ 'text': 'Strings must use singlequote.', \ 'type': 'E', \ }, \ { \ 'lnum': 13, \ 'col': 3, \ 'text': 'Parsing error: Unexpected token', \ 'type': 'E', \ }, \ ], \ ale#handlers#eslint#Handle(347, [ \ 'This line should be ignored completely', \ '/path/to/some-filename.js:47:14: Expected indentation of 2 spaces but found 4.', \ '/path/to/some-filename.js:56:41: Strings must use singlequote.', \ 'This line should be ignored completely', \ '/path/to/some-filename.js:13:3: Parsing error: Unexpected token', \ ]) ================================================ FILE: test/handler/test_starknet_handler.vader ================================================ Before: runtime ale_linters/cairo/starknet.vim After: call ale#linter#Reset() Execute(The starknet handler should handle error messages correctly): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col': 6, \ 'text': 'Could not find module "starkware.cairo.commo.cairo_builtins". Searched in the following paths:', \ 'type': 'E', \ }, \ ], \ ale_linters#cairo#starknet#Handle(bufnr(''), [ \ 'contract.cairo:3:6: Could not find module "starkware.cairo.commo.cairo_builtins". Searched in the following paths:', \ 'from starkware.cairo.commo.cairo_builtins import HashBuiltin', \ ' ^**********************************^', \ ]) AssertEqual \ [ \ { \ 'lnum': 21, \ 'col': 2, \ 'text': 'Unsupported decorator: "vie".', \ 'type': 'E', \ }, \ ], \ ale_linters#cairo#starknet#Handle(bufnr(''), [ \ 'contract.cairo:21:2: Unsupported decorator: "vie".', \ '@vie', \ ' ^*^', \ ]) ================================================ FILE: test/handler/test_statix_handler.vader ================================================ Execute(The statix handler should handle statix output): call ale#test#SetFilename('flake.nix') AssertEqual \ [ \ { \ 'lnum': 46, \ 'type': 'W', \ 'col': 13, \ 'code': '3', \ 'text': 'This assignment is better written with `inherit`' \ }, \ ], \ ale#handlers#statix#Handle(bufnr(''), \ '>46:13:W:3:This assignment is better written with `inherit`' \) ================================================ FILE: test/handler/test_steep_handler.vader ================================================ Before: runtime ale_linters/ruby/steep.vim After: call ale#linter#Reset() Execute(The steep handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 400, \ 'col': 18, \ 'end_col': 45, \ 'text': 'Method parameters are incompatible with declaration `(untyped, untyped, *untyped, **untyped) { () -> untyped } -> untyped`', \ 'code': 'Ruby::MethodArityMismatch', \ 'type': 'E', \ }, \ { \ 'lnum': 20, \ 'col': 9, \ 'end_col': 17, \ 'text': 'Cannot find implementation of method `::Frobz::FooBarBaz#method_name`', \ 'code': 'Ruby::MethodDefinitionMissing', \ 'type': 'W', \ }, \ { \ 'lnum': 30, \ 'col': 9, \ 'end_col': 17, \ 'text': 'Cannot find implementation of method `::Frobz::FooBarBaz#method_name`', \ 'code': 'Ruby::MethodDefinitionMissing', \ 'type': 'I', \ }, \ { \ 'lnum': 40, \ 'col': 9, \ 'end_col': 17, \ 'text': 'Cannot find implementation of method `::Frobz::FooBarBaz#method_name`', \ 'code': 'Ruby::MethodDefinitionMissing', \ 'type': 'I', \ }, \ ], \ ale_linters#ruby#steep#HandleOutput(347, [ \ '# Type checking files:', \ '', \ '...............................................................................................................................F..........F.F...F.', \ '', \ 'lib/frobz/foobar_baz.rb:400:17: [error] Method parameters are incompatible with declaration `(untyped, untyped, *untyped, **untyped) { () -> untyped } -> untyped`', \ '│ Diagnostic ID: Ruby::MethodArityMismatch', \ '│', \ '└ def frobz(obj, suffix, *args, &block)', \ ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~', \ '', \ 'lib/frobz/foobar_baz.rb:20:8: [warning] Cannot find implementation of method `::Frobz::FooBarBaz#method_name`', \ '│ Diagnostic ID: Ruby::MethodDefinitionMissing', \ '│', \ '└ class FooBarBaz', \ ' ~~~~~~~~~', \ '', \ 'lib/frobz/foobar_baz.rb:30:8: [information] Cannot find implementation of method `::Frobz::FooBarBaz#method_name`', \ '│ Diagnostic ID: Ruby::MethodDefinitionMissing', \ '│', \ '└ class FooBarBaz', \ ' ~~~~~~~~~', \ '', \ 'lib/frobz/foobar_baz.rb:40:8: [hint] Cannot find implementation of method `::Frobz::FooBarBaz#method_name`', \ '│ Diagnostic ID: Ruby::MethodDefinitionMissing', \ '│', \ '└ class FooBarBaz', \ ' ~~~~~~~~~', \ '', \ 'Detected 4 problems from 1 file', \ ]) Execute(The steep handler should handle when files are checked and no offenses are found): AssertEqual \ [], \ ale_linters#ruby#steep#HandleOutput(347, [ \ '# Type checking files:', \ '', \ '.............................................................................................................................................', \ '', \ 'No type error detected. 🧉', \ ]) Execute(The steep handler should handle when no files are checked): AssertEqual \ [], \ ale_linters#ruby#steep#HandleOutput(347, [ \ '# Type checking files:', \ '', \ '', \ '', \ 'No type error detected. 🧉', \ ]) Execute(The steep handler should handle empty output): AssertEqual [], ale_linters#ruby#steep#HandleOutput(347, ['']) AssertEqual [], ale_linters#ruby#steep#HandleOutput(347, []) ================================================ FILE: test/handler/test_stylelint_handler.vader ================================================ After: unlet! g:error_lines Execute (stylelint errors should be handled correctly): " Stylelint includes trailing spaces for output. This needs to be taken into " account for parsing errors. AssertEqual \ [ \ { \ 'lnum': 108, \ 'col': 10, \ 'type': 'E', \ 'text': 'Unexpected leading zero', \ 'code': 'number-leading-zero', \ }, \ { \ 'lnum': 116, \ 'col': 20, \ 'type': 'E', \ 'text': 'Expected a trailing semicolon', \ 'code': 'declaration-block-trailing-semicolon', \ }, \ ], \ ale#handlers#css#HandleStyleLintFormat(42, [ \ 'src/main.css', \ ' 108:10 ✖ Unexpected leading zero number-leading-zero ', \ ' 116:20 ✖ Expected a trailing semicolon declaration-block-trailing-semicolon', \ ]) Execute (stylelint should complain when no configuration file is used): let g:error_lines = [ \ 'Error: No configuration provided for /home/w0rp/.vim/bundle/ale/test.stylus', \ ' at module.exports (/home/w0rp/.vim/bundle/ale/node_modules/stylelint/lib/utils/configurationError.js:8:27)', \ ' at stylelint._fullExplorer.load.then.then.config (/home/w0rp/.vim/bundle/ale/node_modules/stylelint/lib/getConfigForFile.js:39:13)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'stylelint exception thrown (type :ALEDetail for more information)', \ 'detail': join(g:error_lines, "\n"), \ }], \ ale#handlers#css#HandleStyleLintFormat(347, g:error_lines[:]) Execute (stylelint should complain but not blow up when SyntaxError is encountered): let g:error_lines = [ \ 'SyntaxError: Unexpected token, expected "," (136:4)', \ ' at constructor (/home/ts-project/node_modules/@babel/parser/lib/index.js:367:19)', \ ' at TypeScriptParserMixin.raise (/home/ts-project/node_modules/@babel/parser/lib/index.js:6630:19)', \ ' at TypeScriptParserMixin.unexpected (/home/ts-project/node_modules/@babel/parser/lib/index.js:6650:16)', \ ' at TypeScriptParserMixin.expect (/home/ts-project/node_modules/@babel/parser/lib/index.js:6930:12)', \ ' at TypeScriptParserMixin.tsParseDelimitedListWorker (/home/ts-project/node_modules/@babel/parser/lib/index.js:7932:14)', \ ' at TypeScriptParserMixin.tsParseDelimitedList (/home/ts-project/node_modules/@babel/parser/lib/index.js:7909:25)', \ ' at /home/ts-project/node_modules/@babel/parser/lib/index.js:9170:19', \ ' at TypeScriptParserMixin.tsInTopLevelContext (/home/ts-project/node_modules/@babel/parser/lib/index.js:8834:14)', \ ' at /home/ts-project/node_modules/@babel/parser/lib/index.js:9168:44', \ ' at TypeScriptParserMixin.tsInType (/home/ts-project/node_modules/@babel/parser/lib/index.js:8841:14)', \] AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'stylelint exception thrown (type :ALEDetail for more information)', \ 'detail': join(g:error_lines, "\n"), \ }], \ ale#handlers#css#HandleStyleLintFormat(347, g:error_lines[:]) ================================================ FILE: test/handler/test_swaglint_handler.vader ================================================ Before: runtime ale_linters/yaml/swaglint.vim After: call ale#linter#Reset() Execute(The swaglint handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'Missing required property: info', \ 'code': 'sway_object_missing_required_property', \ 'type': 'E', \ }, \ { \ 'lnum': 6, \ 'col': 9, \ 'text': 'Not a valid response definition', \ 'code': 'sway_one_of_missing', \ 'type': 'E', \ }, \ { \ 'lnum': 7, \ 'col': 11, \ 'text': 'Missing required property: description', \ 'code': 'sway_object_missing_required_property', \ 'type': 'E', \ }, \ { \ 'lnum': 7, \ 'col': 11, \ 'text': 'Missing required property: $ref', \ 'code': 'sway_object_missing_required_property', \ 'type': 'E', \ }, \ { \ 'lnum': 1, \ 'col': 10, \ 'text': 'Expected type string but found type integer', \ 'code': 'sway_invalid_type', \ 'type': 'E', \ }, \ { \ 'lnum': 1, \ 'col': 10, \ 'text': 'No enum match for: 2', \ 'code': 'sway_enum_mismatch', \ 'type': 'E', \ }, \ { \ 'lnum': 14, \ 'col': 3, \ 'text': 'Definition is not used: #/definitions/Foo', \ 'code': 'sway_unused_definition', \ 'type': 'W', \ }, \ ], \ ale_linters#yaml#swaglint#Handle(347, [ \ 'swagger.yaml: error @ 1:1 - Missing required property: info (sway_object_missing_required_property)', \ 'swagger.yaml: error @ 6:9 - Not a valid response definition (sway_one_of_missing)', \ 'swagger.yaml: error @ 7:11 - Missing required property: description (sway_object_missing_required_property)', \ 'swagger.yaml: error @ 7:11 - Missing required property: $ref (sway_object_missing_required_property)', \ 'swagger.yaml: error @ 1:10 - Expected type string but found type integer (sway_invalid_type)', \ 'swagger.yaml: error @ 1:10 - No enum match for: 2 (sway_enum_mismatch)', \ 'swagger.yaml: warning @ 14:3 - Definition is not used: #/definitions/Foo (sway_unused_definition)', \ ]) ================================================ FILE: test/handler/test_swiftlint_handler.vader ================================================ Before: runtime ale_linters/swift/swiftlint.vim After: call ale#linter#Reset() Execute(The swiftint handler should parse error messages correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 7, \ 'text': 'Operator Usage Whitespace Violation: Operators should be surrounded by a single whitespace when they are being used.', \ 'code': 'operator_usage_whitespace', \ 'type': 'W', \ }, \ { \ 'lnum': 1, \ 'col': 11, \ 'text': 'Operator Usage Whitespace Violation: Operators should be surrounded by a single whitespace when they are being used.', \ 'code': 'operator_usage_whitespace', \ 'type': 'W', \ }, \ \ ], \ ale_linters#swift#swiftlint#Handle(bufnr(''), [ \ 'This line should be ignored', \ ':1:7: warning: Operator Usage Whitespace Violation: Operators should be surrounded by a single whitespace when they are being used. (operator_usage_whitespace)', \ ':1:11: warning: Operator Usage Whitespace Violation: Operators should be surrounded by a single whitespace when they are being used. (operator_usage_whitespace)', \ ]) ================================================ FILE: test/handler/test_swipl_handler.vader ================================================ 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 handle a warning / error of two lines in the new format): 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:', \ 'Warning: 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 join three or more lines with '. ' on latest swipl): 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:', \ 'Warning: Clauses of fib/2 are not together in the source-file', \ 'Warning: Earlier definition at /path/to/test.pl:7', \ 'Warning: Current predicate: f/0', \ 'Warning: Use :- discontiguous fib/2. to suppress this message', \ ]) Execute (The swipl handler should ignore warnings / errors 'No permission to call sandboxed with latest swpl...'): call ale#test#SetFilename('test.pl') AssertEqual \ [], \ ale_linters#prolog#swipl#Handle(bufnr(''), [ \ 'ERROR: /path/to/test.pl:11:', \ 'ERROR: No permission to call sandboxed `''$set_predicate_attribute''(_G3416:_G3417,_G3413,_G3414)''', \ 'ERROR: Reachable from:', \ 'ERROR: system:''$set_pattr''(A,B,C,D)', \ 'ERROR: system:''$set_pattr''(vimscript:A,B,C)', \ 'ERROR: vimscript: (multifile A)', \ 'ERROR: /path/to/test.pl:12:', \ 'ERROR: No permission to call sandboxed `''$set_predicate_attribute''(_G205:_G206,_G202,_G203)''', \ 'ERROR: Reachable from:', \ 'ERROR: system:''$set_pattr''(A,B,C,D)', \ 'ERROR: system:''$set_pattr''(vimscript:A,B,C)', \ 'ERROR: vimscript: (multifile A)', \ 'ERROR: /path/to/test.pl:13:', \ 'ERROR: No permission to call sandboxed `''$set_predicate_attribute''(_G1808:_G1809,_G1805,_G1806)''', \ 'ERROR: Reachable from:', \ 'ERROR: system:''$set_pattr''(A,B,C,D)', \ 'ERROR: system:''$set_pattr''(vimscript:A,B,C)', \ 'ERROR: 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', \ ]) ================================================ FILE: test/handler/test_syntaxerl_handler.vader ================================================ Before: runtime ale_linters/erlang/syntaxerl.vim After: call ale#linter#Reset() Execute (Handle SyntaxErl output): AssertEqual \ [ \ { \ 'lnum': 42, \ 'text': "syntax error before: ','", \ 'type': 'E', \ }, \ { \ 'lnum': 42, \ 'text': 'function foo/0 is unused', \ 'type': 'W', \ }, \ ], \ ale_linters#erlang#syntaxerl#Handle(bufnr(''), [ \ "/tmp/v2wDixk/1/module.erl:42: syntax error before: ','", \ '/tmp/v2wDixk/2/module.erl:42: warning: function foo/0 is unused', \ ]) ================================================ FILE: test/handler/test_systemd_analyze_handler.vader ================================================ Before: runtime ale_linters/systemd/systemd_analyze.vim After: call ale#linter#Reset() Execute(The systemd-analyze handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 9, \ 'col': 1, \ 'type': 'W', \ 'text': 'Unknown key name ''Wat'' in section ''Service'', ignoring.', \ }, \ ], \ ale_linters#systemd#systemd_analyze#Handle(bufnr(''), [ \ '/home/user/.config/systemd/user/foo.service:9: Unknown key name ''Wat'' in section ''Service'', ignoring.', \ ]) ================================================ FILE: test/handler/test_terraform_handler.vader ================================================ Before: " Load the file which defines the linter. runtime ale_linters/terraform/terraform.vim call ale#test#SetDirectory('/testplugin/test/test-files/terraform') call ale#test#SetFilename('providers.tf') After: " Unload all linters again. call ale#linter#Reset() call ale#test#RestoreDirectory() Execute(The output should be correct): AssertEqual \ [ \ { \ 'lnum': 17, \ 'col': 13, \ 'filename': ale#path#Simplify(g:dir . '/providers.tf'), \ 'type': 'W', \ 'text': 'Terraform 0.13 and earlier allowed provider version', \ }, \ { \ 'lnum': 0, \ 'col': 0, \ 'filename': ale#path#Simplify(g:dir . '/providers.tf'), \ 'type': 'E', \ 'text': 'Plugin reinitialization required. Please run "terraform"', \ } \ ], \ ale_linters#terraform#terraform#Handle(bufnr(''), [ \ '{', \ '"valid": false,', \ '"error_count": 1,', \ '"warning_count": 1,', \ '"diagnostics": [', \ ' {', \ ' "severity": "warning",', \ ' "summary": "Version constraints inside provider configuration blocks are deprecated",', \ ' "detail": "Terraform 0.13 and earlier allowed provider version",', \ ' "range": {', \ ' "filename": "providers.tf",', \ ' "start": {', \ ' "line": 17,', \ ' "column": 13,', \ ' "byte": 669', \ ' },', \ ' "end": {', \ ' "line": 17,', \ ' "column": 24,', \ ' "byte": 680', \ ' }', \ ' }', \ ' },', \ ' {', \ ' "severity": "error",', \ ' "summary": "Could not load plugin",', \ ' "detail": "Plugin reinitialization required. Please run \"terraform\""', \ ' }', \ ' ]', \ '}', \ ]) Execute(Should use summary if detail not available): AssertEqual \ [ \ { \ 'lnum': 91, \ 'col': 41, \ 'filename': ale#path#Simplify(g:dir . '/main.tf'), \ 'type': 'E', \ 'text': 'storage_os_disk: required field is not set', \ } \ ], \ ale_linters#terraform#terraform#Handle(bufnr(''), [ \ '{', \ ' "valid": false,', \ ' "error_count": 1,', \ ' "warning_count": 0,', \ ' "diagnostics": [', \ ' {', \ ' "severity": "error",', \ ' "summary": "storage_os_disk: required field is not set",', \ ' "range": {', \ ' "filename": "main.tf",', \ ' "start": {', \ ' "line": 91,', \ ' "column": 41,', \ ' "byte": 2381', \ ' },', \ ' "end": {', \ ' "line": 91,', \ ' "column": 41,', \ ' "byte": 2381', \ ' }', \ ' }', \ ' }', \ ' ]', \ '}' \ ]) Execute(Should use summary if detail available but empty): AssertEqual \ [ \ { \ 'lnum': 91, \ 'col': 41, \ 'filename': ale#path#Simplify(g:dir . '/main.tf'), \ 'type': 'E', \ 'text': 'storage_os_disk: required field is not set', \ } \ ], \ ale_linters#terraform#terraform#Handle(bufnr(''), [ \ '{', \ ' "valid": false,', \ ' "error_count": 1,', \ ' "warning_count": 0,', \ ' "diagnostics": [', \ ' {', \ ' "severity": "error",', \ ' "summary": "storage_os_disk: required field is not set",', \ ' "detail": "",', \ ' "range": {', \ ' "filename": "main.tf",', \ ' "start": {', \ ' "line": 91,', \ ' "column": 41,', \ ' "byte": 2381', \ ' },', \ ' "end": {', \ ' "line": 91,', \ ' "column": 41,', \ ' "byte": 2381', \ ' }', \ ' }', \ ' }', \ ' ]', \ '}' \ ]) ================================================ FILE: test/handler/test_textlint_handler.vader ================================================ Before: runtime! ale_linters/markdown/textlint.vim After: call ale#linter#Reset() Execute(textlint handler should handle errors output): AssertEqual \ [ \ { \ 'lnum': 16, \ 'col': 50, \ 'text': 'Found possibly misspelled word "NeoVim".', \ 'type': 'W', \ 'code': 'preset-japanese/no-doubled-joshi', \ }, \ ], \ ale#handlers#textlint#HandleTextlintOutput(bufnr(''), [ \ '[', \ ' {', \ ' "filePath": "test.md",', \ ' "messages": [', \ ' {', \ ' "type": "lint",', \ ' "ruleId": "preset-japanese/no-doubled-joshi",', \ ' "index": 1332,', \ ' "line": 16,', \ ' "column": 50,', \ ' "severity": 2,', \ ' "message": "Found possibly misspelled word \"NeoVim\"."', \ ' }', \ ' ]', \ ' }', \ ']', \ ]) Execute(textlint handler should no error output): AssertEqual \ [], \ ale#handlers#textlint#HandleTextlintOutput(bufnr(''), []) ================================================ FILE: test/handler/test_tflint_handler.vader ================================================ Before: runtime! ale_linters/terraform/tflint.vim After: call ale#linter#Reset() Execute(The tflint handler should parse items correctly): AssertEqual \ [ \ { \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', \ 'lnum': 1, \ 'col': 30, \ 'end_lnum': 2, \ 'end_col': 1, \ 'text': 'A block definition must have block content delimited by "{" and "}", starting on the same line as the block header.', \ 'code': 'Invalid block definition', \ 'type': 'E', \ }, \ { \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', \ 'lnum': 2, \ 'col': 3, \ 'end_lnum': 2, \ 'end_col': 6, \ 'text': 'An argument named "ami" is not expected here.', \ 'code': 'Unsupported argument', \ 'type': 'E', \ }, \ { \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', \ 'lnum': 3, \ 'col': 3, \ 'end_lnum': 1, \ 'end_col': 6, \ 'text': 'An argument named "instance_type" is not expected here.', \ 'code': 'Unsupported argument', \ 'type': 'E', \ }, \ { \ 'filename': 'github.com/wata727/example-module/aws_db_instance.tf', \ 'lnum': 12, \ 'col': 11, \ 'end_lnum': 12, \ 'end_col': 21, \ 'text': 'be warned, traveller', \ 'code': 'aws_db_instance_readable_password', \ 'type': 'W', \ }, \ { \ 'filename': 'github.com/wata727/example-module/aws_elasticache_cluster.tf', \ 'lnum': 9, \ 'col': 29, \ 'end_lnum': 9, \ 'end_col': 29, \ 'text': 'error message', \ 'code': 'aws_elasticache_cluster_invalid_type', \ 'type': 'E', \ }, \ { \ 'filename': 'github.com/wata727/example-module/aws_instance.tf', \ 'lnum': 5, \ 'col': 15, \ 'end_lnum': 5, \ 'end_col': 25, \ 'text': 'just so ya know', \ 'code': 'aws_instance_not_specified_iam_profile', \ 'type': 'I', \ }, \ ], \ ale_linters#terraform#tflint#Handle(123, [ \ '{"issues":[{"rule":{"name":"aws_db_instance_readable_password","severity":"WARNING","link":"https://github.com/wata727/tflint/blob/master/docs/aws_db_instance_readable_password.md"},"message":"be warned, traveller","range":{"filename":"github.com/wata727/example-module/aws_db_instance.tf","start":{"line":12,"column":11},"end":{"line":12,"column":21},"callers":[]}},{"rule":{"name":"aws_elasticache_cluster_invalid_type","severity":"ERROR","link":"https://github.com/wata727/tflint/blob/master/docs/aws_elasticache_cluster_invalid_type.md"},"message":"error message","range":{"filename":"github.com/wata727/example-module/aws_elasticache_cluster.tf","start":{"line":9,"column":29},"end":{"line":9,"column":29},"callers":[]}},{"rule":{"name":"aws_instance_not_specified_iam_profile","severity":"NOTICE","link":"https://github.com/wata727/tflint/blob/master/docs/aws_instance_not_specified_iam_profile.md"},"message":"just so ya know","range":{"filename":"github.com/wata727/example-module/aws_instance.tf","start":{"line":5,"column":15},"end":{"line":5,"column":25},"callers":[]}}],"errors":[{"message":"github.com/wata727/example-module/aws_instance.tf:1,30-2,1: Invalid block definition; A block definition must have block content delimited by \"{\" and \"}\", starting on the same line as the block header."},{"message":"github.com/wata727/example-module/aws_instance.tf:2,3-6: Unsupported argument; An argument named \"ami\" is not expected here."},{"message":"github.com/wata727/example-module/aws_instance.tf:3,3-16: Unsupported argument; An argument named \"instance_type\" is not expected here."}]}' \ ]) ================================================ FILE: test/handler/test_tfsec_handler.vader ================================================ Before: runtime ale_linters/terraform/tfsec.vim After: call ale#linter#Reset() Execute(The tfsec handler should handle empty output): AssertEqual \ [], \ ale_linters#terraform#tfsec#Handle(bufnr(''), ['{"results": null}']) Execute(The tfsec handler should parse results correctly): AssertEqual \ [ \ { \ 'filename': '/test/main.tf', \ 'lnum': 10, \ 'end_lnum': 12, \ 'text': "IAM policy document uses sensitive action 'iam:PassRole' on wildcarded resource '*'", \ 'code': 'aws-iam-no-policy-wildcards', \ 'type': 'W', \ }, \], \ ale_linters#terraform#tfsec#Handle(bufnr(''), json_encode( \ { \ "results": [ \ { \ "rule_id": "AVD-AWS-0057", \ "long_id": "aws-iam-no-policy-wildcards", \ "rule_description": "IAM policy should avoid use of wildcards and instead apply the principle of least privilege", \ "rule_provider": "aws", \ "rule_service": "iam", \ "impact": "Overly permissive policies may grant access to sensitive resources", \ "resolution": "Specify the exact permissions required, and to which resources they should apply instead of using wildcards.", \ "links": [ \ "https://aquasecurity.github.io/tfsec/v1.28.0/checks/aws/iam/no-policy-wildcards/", \ "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document" \ ], \ "description": "IAM policy document uses sensitive action 'iam:PassRole' on wildcarded resource '*'", \ "severity": "HIGH", \ "warning": v:false, \ "status": 0, \ "resource": "data.aws_iam_policy_document.default", \ "location": { \ "filename": "/test/main.tf", \ "start_line": 10, \ "end_line": 12 \ } \ } \ ] \ } \)) ================================================ FILE: test/handler/test_thrift_handler.vader ================================================ Before: runtime ale_linters/thrift/thrift.vim After: call ale#linter#Reset() Execute(The thrift handler should handle basic warnings and errors): AssertEqual \ [ \ { \ 'lnum': 17, \ 'col': 0, \ 'type': 'W', \ 'text': 'The "byte" type is a compatibility alias for "i8". Use i8" to emphasize the signedness of this type.', \ }, \ { \ 'lnum': 20, \ 'col': 0, \ 'type': 'W', \ 'text': 'Could not find include file include.thrift', \ }, \ { \ 'lnum': 83, \ 'col': 0, \ 'type': 'E', \ 'text': 'Enum FOO is already defined!', \ }, \ ], \ ale_linters#thrift#thrift#Handle(1, [ \ '[WARNING:/path/filename.thrift:17] The "byte" type is a compatibility alias for "i8". Use i8" to emphasize the signedness of this type.', \ '[WARNING:/path/filename.thrift:20] Could not find include file include.thrift', \ '[FAILURE:/path/filename.thrift:83] Enum FOO is already defined!', \ ]) Execute(The thrift handler should handle multiline errors): AssertEqual \ [ \ { \ 'lnum': 75, \ 'col': 0, \ 'type': 'E', \ 'text': 'This integer is too big: "11111111114213213453243"', \ }, \ { \ 'lnum': 76, \ 'col': 0, \ 'type': 'E', \ 'text': 'Implicit field keys are deprecated and not allowed with -strict', \ }, \ { \ 'lnum': 77, \ 'col': 0, \ 'type': 'E', \ 'text': "Unknown error (last token was ';')", \ }, \ ], \ ale_linters#thrift#thrift#Handle(1, [ \ "[ERROR:/path/filename.thrift:75] (last token was '11111111114213213453243')", \ 'This integer is too big: "11111111114213213453243"', \ "[ERROR:/path/filename.thrift:76] (last token was ';')", \ 'Implicit field keys are deprecated and not allowed with -strict', \ "[ERROR:/path/filename.thrift:77] (last token was ';')", \ ]) ================================================ FILE: test/handler/test_thriftcheck_handler.vader ================================================ Before: runtime ale_linters/thrift/thriftcheck.vim After: call ale#linter#Reset() Execute(The thriftcheck handler should handle basic warnings and errors): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': '"py" namespace must match "^idl\\."', \ 'code': 'namespace.pattern', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'type': 'W', \ 'text': '64-bit integer constant -2147483649 may not work in all languages', \ 'code': 'int.64bit', \ }, \ ], \ ale_linters#thrift#thriftcheck#Handle(1, [ \ 'file.thrift:1:1: error: "py" namespace must match "^idl\\." (namespace.pattern)', \ 'file.thrift:3:5: warning: 64-bit integer constant -2147483649 may not work in all languages (int.64bit)', \ ]) ================================================ FILE: test/handler/test_tlint_handler.vader ================================================ Before: runtime ale_linters/php/tlint.vim After: call ale#linter#Reset() Execute(The tlint handler should calculate line numbers): AssertEqual \ [ \ { \ 'lnum': '5', \ 'col': 0, \ 'sub_type': \ 'style', \ 'type': 'W', \ 'text': ['! There should be no unused imports.', 'There should be no unused imports.', '', '', '', '', '', '', '', ''] \ }, \ { \ 'lnum': '15', \ 'col': 0, \ 'sub_type': \ 'style', \ 'type': 'W', \ 'text': ['! There should be no method visibility in test methods.', 'There should be no method visibility in test methods.', '', '', '', '', '', '', '', ''] \ }, \ ], \ ale_linters#php#tlint#Handle(347, [ \ "Lints for /Users/jose/Code/Tighten/tester/tests/Unit/ExampleTest.php", \ "============", \ "! There should be no unused imports.", \ "5 : `use Illuminate\Foundation\Testing\RefreshDatabase;`", \ "! There should be no method visibility in test methods.", \ "15 : ` public function testBasicTest()`", \ ]) ================================================ FILE: test/handler/test_tslint_handler.vader ================================================ Before: Save g:ale_typescript_tslint_ignore_empty_files unlet! g:ale_typescript_tslint_ignore_empty_files unlet! b:ale_typescript_tslint_ignore_empty_files runtime ale_linters/typescript/tslint.vim call ale#test#SetDirectory('/testplugin/test/handler') After: Restore unlet! b:ale_typescript_tslint_ignore_empty_files unlet! b:relative_to_root unlet! b:tempname_suffix unlet! b:relative_tempname call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The tslint handler should parse lines correctly): call ale#test#SetFilename('app/test.ts') AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 15, \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.ts'), \ 'end_lnum': 1, \ 'type': 'E', \ 'end_col': 15, \ 'text': 'Missing semicolon', \ 'code': 'semicolon', \ }, \ { \ 'lnum': 2, \ 'col': 8, \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.ts'), \ 'end_lnum': 3, \ 'type': 'W', \ 'end_col': 12, \ 'text': 'Something else', \ }, \ { \ 'lnum': 2, \ 'col': 8, \ 'filename': ale#path#Simplify(expand('%:p:h') . '/something-else.ts'), \ 'end_lnum': 3, \ 'type': 'W', \ 'end_col': 12, \ 'text': 'Something else', \ 'code': 'something', \ }, \ { \ 'lnum': 31, \ 'col': 9, \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.ts'), \ 'end_lnum': 31, \ 'type': 'E', \ 'end_col': 20, \ 'text': 'Calls to console.log are not allowed.', \ 'code': 'no-console', \ }, \ ] , \ ale_linters#typescript#tslint#Handle(bufnr(''), [json_encode([ \ { \ 'endPosition': { \ 'character': 14, \ 'line': 0, \ 'position': 1000 \ }, \ 'failure': 'Missing semicolon', \ 'fix': { \ 'innerLength': 0, \ 'innerStart': 14, \ 'innerText': ';' \ }, \ 'name': 'test.ts', \ 'ruleName': 'semicolon', \ 'ruleSeverity': 'ERROR', \ 'startPosition': { \ 'character': 14, \ 'line': 0, \ 'position': 1000 \ } \ }, \ { \ 'endPosition': { \ 'character': 11, \ 'line': 2, \ 'position': 1000 \ }, \ 'failure': 'Something else', \ 'fix': { \ 'innerLength': 0, \ 'innerStart': 14, \ 'innerText': ';' \ }, \ 'name': 'test.ts', \ 'ruleSeverity': 'WARNING', \ 'startPosition': { \ 'character': 7, \ 'line': 1, \ 'position': 1000 \ } \ }, \ { \ 'endPosition': { \ 'character': 11, \ 'line': 2, \ 'position': 22 \ }, \ 'failure': 'Something else', \ 'fix': { \ 'innerLength': 0, \ 'innerStart': 14, \ 'innerText': ';' \ }, \ 'name': 'something-else.ts', \ 'ruleName': 'something', \ 'ruleSeverity': 'WARNING', \ 'startPosition': { \ 'character': 7, \ 'line': 1, \ 'position': 14 \ } \ }, \ { \ "endPosition": { \ "character": 19, \ "line": 30, \ "position": 14590 \ }, \ "failure": "Calls to console.log are not allowed.", \ 'name': 'test.ts', \ "ruleName": "no-console", \ "startPosition": { \ "character": 8, \ "line": 30, \ "position": 14579 \ } \ }, \])]) Execute(The tslint handler should handle empty output): AssertEqual \ [], \ ale_linters#typescript#tslint#Handle(bufnr(''), []) Execute(The tslint handler report errors for empty files by default): call ale#test#SetFilename('app/test.ts') AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.ts'), \ 'end_lnum': 2, \ 'type': 'E', \ 'end_col': 1, \ 'text': 'Consecutive blank lines are forbidden', \ 'code': 'no-consecutive-blank-lines', \ }, \ ], \ ale_linters#typescript#tslint#Handle(bufnr(''), [json_encode([{ \ 'endPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ }, \ 'failure': 'Consecutive blank lines are forbidden', \ 'fix': [{ \ 'innerStart': 0, \ 'innerLength': 1, \ 'innerText': '' \ }], \ 'name': 'test.ts', \ 'ruleName': 'no-consecutive-blank-lines', \ 'ruleSeverity': 'ERROR', \ 'startPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ } \ }])]) Execute(The tslint handler should not report errors for empty files when the ignore option is on): let b:ale_typescript_tslint_ignore_empty_files = 1 call ale#test#SetFilename('app/test.ts') AssertEqual \ [ \ ], \ ale_linters#typescript#tslint#Handle(bufnr(''), [json_encode([{ \ 'endPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ }, \ 'failure': 'Consecutive blank lines are forbidden', \ 'fix': [{ \ 'innerStart': 0, \ 'innerLength': 1, \ 'innerText': '' \ }], \ 'name': 'test.ts', \ 'ruleName': 'no-consecutive-blank-lines', \ 'ruleSeverity': 'ERROR', \ 'startPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ } \ }])]) Given typescript(A file with extra blank lines): const x = 3 const y = 4 Execute(The tslint handler should report errors when the ignore option is on, but the file is not empty): let b:ale_typescript_tslint_ignore_empty_files = 1 call ale#test#SetFilename('app/test.ts') AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 1, \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.ts'), \ 'end_lnum': 2, \ 'type': 'E', \ 'end_col': 1, \ 'text': 'Consecutive blank lines are forbidden', \ 'code': 'no-consecutive-blank-lines', \ }, \ ], \ ale_linters#typescript#tslint#Handle(bufnr(''), [json_encode([{ \ 'endPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ }, \ 'failure': 'Consecutive blank lines are forbidden', \ 'fix': [{ \ 'innerStart': 0, \ 'innerLength': 1, \ 'innerText': '' \ }], \ 'name': 'test.ts', \ 'ruleName': 'no-consecutive-blank-lines', \ 'ruleSeverity': 'ERROR', \ 'startPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ } \ }])]) Execute(The tslint handler should not report no-implicit-dependencies errors): call ale#test#SetFilename('app/test.ts') AssertEqual \ [ \ ], \ ale_linters#typescript#tslint#Handle(bufnr(''), [json_encode([{ \ 'endPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ }, \ 'failure': 'this is ignored', \ 'name': 'test.ts', \ 'ruleName': 'no-implicit-dependencies', \ 'ruleSeverity': 'ERROR', \ 'startPosition': { \ 'character': 0, \ 'line': 1, \ 'position': 1 \ }, \ }])]) Execute(The tslint handler should set filename keys for temporary files): " The temporary filename below is hacked into being a relative path so we can " test that we resolve the temporary filename first. let b:relative_to_root = substitute(expand('%:p'), '\v[^/\\]*([/\\])[^/\\]*', '../', 'g') let b:tempname_suffix = substitute(tempname(), '^\v([A-Z]:)?[/\\]', '', '') let b:relative_tempname = substitute(b:relative_to_root . b:tempname_suffix, '\\', '/', 'g') AssertEqual \ [ \ {'lnum': 47, 'col': 1, 'code': 'curly', 'end_lnum': 47, 'type': 'E', 'end_col': 26, 'text': 'if statements must be braced'}, \ ], \ ale_linters#typescript#tslint#Handle(bufnr(''), [json_encode([ \ { \ 'endPosition': { \ 'character':25, \ 'line':46, \ 'position':1383, \ }, \ 'failure': 'if statements must be braced', \ 'name': b:relative_tempname, \ 'ruleName': 'curly', \ 'ruleSeverity':'ERROR', \ 'startPosition': { \ 'character':0, \ 'line':46, \ 'position':1358, \ } \ }, \ ])]) ================================================ FILE: test/handler/test_typecheck_handler.vader ================================================ Before: runtime ale_linters/typescript/typecheck.vim After: call ale#linter#Reset() Execute(The typecheck handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 16, \ 'col': 7, \ 'text': "Type 'A' is not assignable to type 'B'", \ }, \ { \ 'lnum': 7, \ 'col': 41, \ 'text': "Property 'a' does not exist on type 'A'", \ }, \ ], \ ale_linters#typescript#typecheck#Handle(347, [ \ "somets.ts[16, 7]: Type 'A' is not assignable to type 'B'", \ "somets.ts[7, 41]: Property 'a' does not exist on type 'A'", \ ]) ================================================ FILE: test/handler/test_unimport_handler.vader ================================================ Before: runtime ale_linters/python/unimport.vim After: call ale#linter#Reset() Execute(The unimport handler should handle import warnings): AssertEqual \ [ \ { \ 'lnum': 9, \ 'type': 'W', \ 'text': 'unused: urllib.parse', \ }, \ ], \ ale_linters#python#unimport#Handle(1, [ \ 'urllib.parse at path/to/file.py:9', \ ]) ================================================ FILE: test/handler/test_v_handler.vader ================================================ Before: runtime ale_linters/v/v.vim After: call ale#linter#Reset() Execute (The v handler should correctly parse error messages): AssertEqual \ [{ \ 'lnum': 4, \ 'col': 3, \ 'filename': ale#path#GetAbsPath(expand('%:p:h'), 'const ants.v'), \ 'type': 'W', \ 'end_col': 14, \ 'text': 'const names cannot contain uppercase letters, use snake_case instead' \ }, \ { \ 'lnum': 4, \ 'col': 8, \ 'filename': ale#path#GetAbsPath(expand('%:p:h'), 'main.v'), \ 'type': 'W', \ 'end_col': 10, \ 'text': 'module "os" is imported but never used' \ }, \ { \ 'lnum': 20, \ 'col': 10, \ 'filename': ale#path#GetAbsPath(expand('%:p:h'), 'main.v'), \ 'type': 'E', \ 'end_col': 18, \ 'text': 'undefined ident: `win_widt`' \ }], \ ale_linters#v#v#Handler('', [ \ './const ants.v:4:3: warning: const names cannot contain uppercase letters, use snake_case instead', \ ' 2 |', \ ' 3 | const (', \ ' 4 | BUTTON_TEXT = "OK"', \ ' | ~~~~~~~~~~~', \ ' 5 | )', \ './main.v:4:8: warning: module "os" is imported but never used', \ ' 2 |', \ ' 3 | import ui', \ ' 4 | import os', \ ' | ~~', \ ' 5 |', \ ' 6 | const (', \ './main.v:20:10: error: undefined ident: `win_widt`', \ ' 18 | mut app := &App{}', \ ' 19 | app.window = ui.window({', \ ' 20 | width: win_widt', \ ' | ~~~~~~~~', \ ' 21 | height: win_height', \ ' 22 | title: "Counter"', \ ]) ================================================ FILE: test/handler/test_vala_lint_handler.vader ================================================ Before: runtime ale_linters/vala/vala_lint.vim After: call ale#linter#Reset() Execute(The Vala-Lint handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 18, \ 'col': 18, \ 'text': 'Expected space before paren', \ 'code': 'space-before-paren', \ 'type': 'E', \ }, \ { \ 'lnum': 64, \ 'col': 37, \ 'text': 'Expected space before paren', \ 'code': 'space-before-paren', \ 'type': 'W', \ }, \ { \ 'lnum': 73, \ 'col': 37, \ 'text': 'Expected space before paren', \ 'code': 'space-before-paren', \ 'type': 'E', \ }, \ ], \ ale_linters#vala#vala_lint#Handle(bufnr(''), [ \ 'Application.vala', \ ' 18.18 error Expected space before paren space-before-paren', \ ' 64.37 warn Expected space before paren space-before-paren', \ ' 73.37 error Expected space before paren space-before-paren', \ ]) Execute(The Vala-Lint handler should ignore unknown error types): AssertEqual \ [ \ { \ 'lnum': 73, \ 'col': 37, \ 'text': 'Expected space before paren', \ 'code': 'space-before-paren', \ 'type': 'E', \ }, \ ], \ ale_linters#vala#vala_lint#Handle(bufnr(''), [ \ 'Application.vala', \ ' 18.18 test Expected space before paren space-before-paren', \ ' 73.37 error Expected space before paren space-before-paren', \ ]) ================================================ FILE: test/handler/test_vale_handler.vader ================================================ Execute(The vale handler should handle broken JSON): AssertEqual \ [], \ ale#handlers#vale#Handle(bufnr(''), ["{asdf"]) Execute(The vale handler should handle am empty string response): AssertEqual \ [], \ ale#handlers#vale#Handle(bufnr(''), []) Execute(The vale handler should handle an empty result): AssertEqual \ [], \ ale#handlers#vale#Handle(bufnr(''), ["{}"]) Execute(The vale handler should handle a normal example): AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 195, \ 'end_col': 201, \ 'type': 'W', \ 'text': "Consider removing 'usually'", \ 'code': 'vale.Hedging', \ }, \ { \ 'lnum': 7, \ 'col': 1, \ 'end_col': 27, \ 'type': 'E', \ 'text': "'Documentation' is repeated!", \ 'code': 'vale.Repetition', \ }, \ { \ 'lnum': 7, \ 'col': 1, \ 'end_col': 27, \ 'type': 'I', \ 'text': "'Documentation' is repeated!", \ 'code': 'vale.Repetition', \ }, \ ], \ ale#handlers#vale#Handle(bufnr(''), [ \ '{', \ ' "/home/languitar/src/autosuspend/README.md": [', \ ' {', \ ' "Check": "vale.Hedging",', \ ' "Description": "",', \ ' "Line": 5,', \ ' "Link": "",', \ " \"Message\": \"Consider removing 'usually'\",", \ ' "Severity": "warning",', \ ' "Span": [', \ ' 195,', \ ' 201', \ ' ],', \ ' "Hide": false', \ ' },', \ ' {', \ ' "Check": "vale.Repetition",', \ ' "Description": "",', \ ' "Line": 7,', \ ' "Link": "",', \ " \"Message\": \"'Documentation' is repeated!\",", \ ' "Severity": "error",', \ ' "Span": [', \ ' 1,', \ ' 27', \ ' ],', \ ' "Hide": false', \ ' },', \ ' {', \ ' "Check": "vale.Repetition",', \ ' "Description": "",', \ ' "Line": 7,', \ ' "Link": "",', \ " \"Message\": \"'Documentation' is repeated!\",", \ ' "Severity": "suggestion",', \ ' "Span": [', \ ' 1,', \ ' 27', \ ' ],', \ ' "Hide": false', \ ' }', \ ' ]', \ '}', \ ]) ================================================ FILE: test/handler/test_vcom_handler.vader ================================================ Before: runtime ale_linters/vhdl/vcom.vim After: call ale#linter#Reset() Execute(The vcom handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 218, \ 'type': 'W', \ 'text': '(vcom-1236) Shared variables must be of a protected type.' \ }, \ { \ 'lnum': 73, \ 'type': 'E', \ 'text': '(vcom-1136) Unknown identifier "aresetn".' \ }, \ { \ 'lnum': 73, \ 'type': 'E', \ 'text': 'Bad resolution function (STD_LOGIC) for type (error).' \ }, \ { \ 'lnum': 73, \ 'type': 'E', \ 'text': 'near ":": (vcom-1576) expecting ";" or ")".' \ }, \ ], \ ale_linters#vhdl#vcom#Handle(bufnr(''), [ \ '** Warning: ../path/to/file.vhd(218): (vcom-1236) Shared variables must be of a protected type.', \ '** Error: tb_file.vhd(73): (vcom-1136) Unknown identifier "aresetn".', \ '** Error: tb_file.vhd(73): Bad resolution function (STD_LOGIC) for type (error).', \ '** Error: tb_file.vhd(73): near ":": (vcom-1576) expecting ";" or ")".', \ ]) ================================================ FILE: test/handler/test_verilator_handler.vader ================================================ Before: runtime ale_linters/verilog/verilator.vim After: call ale#linter#Reset() Execute (The verilator handler should parse legacy messages with only line numbers): AssertEqual \ [ \ { \ 'lnum': 3, \ 'type': 'E', \ 'text': 'syntax error, unexpected IDENTIFIER', \ 'filename': 'foo.v' \ }, \ { \ 'lnum': 10, \ 'type': 'W', \ 'text': 'Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).', \ 'filename': 'bar.v' \ }, \ ], \ ale_linters#verilog#verilator#Handle(bufnr(''), [ \ '%Error: foo.v:3: syntax error, unexpected IDENTIFIER', \ '%Warning-BLKSEQ: bar.v:10: Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).', \ ]) Execute (The verilator handler should parse new format messages with line and column numbers): AssertEqual \ [ \ { \ 'lnum': 3, \ 'col' : 1, \ 'type': 'E', \ 'text': 'syntax error, unexpected endmodule, expecting ;', \ 'filename': 'bar.v' \ }, \ { \ 'lnum': 4, \ 'col' : 6, \ 'type': 'W', \ 'text': 'Signal is not used: r', \ 'filename': 'foo.v' \ }, \ ], \ ale_linters#verilog#verilator#Handle(bufnr(''), [ \ '%Error: bar.v:3:1: syntax error, unexpected endmodule, expecting ;', \ '%Warning-UNUSED: foo.v:4:6: Signal is not used: r', \ ]) ================================================ FILE: test/handler/test_vint_handler.vader ================================================ Before: runtime ale_linters/vim/vint.vim After: call ale#linter#Reset() Execute(The vint handler should parse error messages correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'filename': 'gcc.vim', \ 'text': 'Use scriptencoding when multibyte char exists (see :help :script encoding)', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'col': 17, \ 'filename': 'gcc.vim', \ 'end_col': 18, \ 'text': 'Use robust operators ''==#'' or ''==?'' instead of ''=='' (see Google VimScript Style Guide (Matching))', \ 'type': 'W', \ }, \ { \ 'lnum': 3, \ 'col': 8, \ 'filename': 'gcc.vim', \ 'end_col': 15, \ 'text': 'Make the scope explicit like ''l:filename'' (see Anti-pattern of vimrc (Scope of identifier))', \ 'type': 'W', \ }, \ { \ 'lnum': 7, \ 'col': 8, \ 'filename': 'gcc.vim', \ 'end_col': 15, \ 'text': 'Undefined variable: filename (see :help E738)', \ 'type': 'W', \ }, \ { \ 'lnum': 8, \ 'col': 11, \ 'filename': 'gcc.vim', \ 'end_col': 16, \ 'text': 'E128: Function name must start with a capital or contain a colon: foobar (see ynkdir/vim-vimlparser)', \ 'type': 'E', \ }, \ { \ 'lnum': 9, \ 'col': 12, \ 'filename': 'gcc.vim', \ 'end_col': 13, \ 'text': 'Use robust operators ''=~#'' or ''=~?'' instead of ''=~'' (see Google VimScript Style Guide (Matching))', \ 'type': 'W', \ }, \ ], \ ale_linters#vim#vint#Handle(bufnr(''), [ \ 'gcc.vim:1:1: warning: Use scriptencoding when multibyte char exists (see :help :script encoding)', \ 'gcc.vim:3:17: warning: Use robust operators `==#` or `==?` instead of `==` (see Google VimScript Style Guide (Matching))', \ 'gcc.vim:3:8: style_problem: Make the scope explicit like `l:filename` (see Anti-pattern of vimrc (Scope of identifier))', \ 'gcc.vim:7:8: warning: Undefined variable: filename (see :help E738)', \ 'gcc.vim:8:11: error: E128: Function name must start with a capital or contain a colon: foobar (see ynkdir/vim-vimlparser)', \ 'gcc.vim:9:12: warning: Use robust operators `=~#` or `=~?` instead of `=~` (see Google VimScript Style Guide (Matching))', \ ]) ================================================ FILE: test/handler/test_vlog_handler.vader ================================================ Before: runtime ale_linters/verilog/vlog.vim After: call ale#linter#Reset() Execute(The vlog handler should parse old-style lines correctly): AssertEqual \ [ \ { \ 'lnum': 7, \ 'type': 'W', \ 'text': '(vlog-2623) Undefined variable: C.', \ 'filename': 'add.v' \ }, \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': '(vlog-13294) Identifier must be declared with a port mode: C.', \ 'filename': 'file.v' \ }, \ ], \ ale_linters#verilog#vlog#Handle(bufnr(''), [ \ '** Warning: add.v(7): (vlog-2623) Undefined variable: C.', \ '** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: C.', \ ]) Execute(The vlog handler should parse new-style lines correctly): AssertEqual \ [ \ { \ 'lnum': 7, \ 'type': 'W', \ 'text': '(vlog-2623) Undefined variable: C.', \ 'filename': 'add.v' \ }, \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': '(vlog-13294) Identifier must be declared with a port mode: C.', \ 'filename': 'file.v' \ }, \ ], \ ale_linters#verilog#vlog#Handle(bufnr(''), [ \ '** Warning: (vlog-2623) add.v(7): Undefined variable: C.', \ '** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C.', \ ]) ================================================ FILE: test/handler/test_vulture_handler.vader ================================================ Before: runtime ale_linters/python/vulture.vim call ale#test#SetDirectory('/testplugin/test/handler') After: Restore call ale#test#RestoreDirectory() call ale#linter#Reset() 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': 'BaddestException: Everything gone wrong (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "/usr/lib/python3.6/site-packages/vulture/__init__.py", line 13, in ', \ ' 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 ', \ ' from .core import stuff', \ 'BaddestException: Everything gone wrong', \ ]) Execute(The vulture handler should handle empty output): AssertEqual \ [], \ ale_linters#python#vulture#Handle(bufnr(''), []) ================================================ FILE: test/handler/test_write_good_handler.vader ================================================ Execute(The write-good handler should handle the example from the write-good README): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'end_col': 2, \ 'type': 'W', \ 'text': '"So" adds no meaning', \ }, \ { \ 'lnum': 1, \ 'col': 12, \ 'end_col': 21, \ 'type': 'W', \ 'text': '"was stolen" may be passive voice', \ }, \ { \ 'lnum': 6, \ 'col': 2, \ 'end_col': 2, \ 'type': 'W', \ 'text': '"foo bar" bla', \ }, \ ], \ ale#handlers#writegood#Handle(bufnr(''), [ \ 'In /tmp/vBYivbZ/6/test.md', \ '=============', \ 'So the cat was stolen.', \ '^^', \ '"So" adds no meaning on line 1 at column 0', \ '-------------', \ 'So the cat was stolen.', \ ' ^^^^^^^^^^', \ '"was stolen" may be passive voice on line 1 at column 11', \ '"foo bar" bla on line 6 at column 1', \ ]) ================================================ FILE: test/handler/test_xmllint_handler.vader ================================================ Before: runtime ale_linters/xml/xmllint.vim After: call ale#linter#Reset() Execute(The xmllint handler should parse error messages correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 22, \ 'type': 'W', \ 'text': 'warning: Unsupported version ''dummy''' \ }, \ { \ 'lnum': 34, \ 'col': 1, \ 'type': 'E', \ 'text': 'parser error : Start tag expected, ''<'' not found' \ } \ ], \ ale_linters#xml#xmllint#Handle(1, [ \ 'path/to/file.xml:1: warning: Unsupported version ''dummy''', \ '', \ ' ^', \ '-:34: parser error : Start tag expected, ''<'' not found', \ 'blahblah>', \ '^' \ ]) ================================================ FILE: test/handler/test_xvhdl_handler.vader ================================================ Before: runtime ale_linters/vhdl/xvhdl.vim After: call ale#linter#Reset() Execute(The xvhdl handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 17, \ 'type': 'E', \ 'text': '[VRFC 10-91] aresetn is not declared ' \ }, \ { \ 'lnum': 128, \ 'type': 'E', \ 'text': '[VRFC 10-91] m_axis_tx_tdata is not declared ' \ }, \ ], \ ale_linters#vhdl#xvhdl#Handle(bufnr(''), [ \ 'ERROR: [VRFC 10-91] aresetn is not declared [/path/to/file.vhd:17]', \ 'ERROR: [VRFC 10-91] m_axis_tx_tdata is not declared [/home/user/tx_data.vhd:128]', \ ]) ================================================ FILE: test/handler/test_xvlog_handler.vader ================================================ Before: runtime ale_linters/verilog/xvlog.vim After: call ale#linter#Reset() Execute(The xvlog handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 5, \ 'type': 'E', \ 'text': '[VRFC 10-1412] syntax error near output ' \ }, \ ], \ ale_linters#verilog#xvlog#Handle(bufnr(''), [ \ 'ERROR: [VRFC 10-1412] syntax error near output [/path/to/file.v:5]', \ ]) ================================================ FILE: test/handler/test_yamllint_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime! ale/handlers/yamllint.vim After: Restore unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute(Problems should be parsed correctly for yamllint): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'W', \ 'text': 'missing document start "---"', \ 'code': 'document-start', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'E', \ 'text': 'syntax error: expected the node content, but found ''''', \ }, \ ], \ ale#handlers#yamllint#Handle(bufnr(''), [ \ 'something.yaml:1:1: [warning] missing document start "---" (document-start)', \ 'something.yml:2:1: [error] syntax error: expected the node content, but found ''''', \ ]) Execute(The yamllint handler should respect ale_warn_about_trailing_whitespace): AssertEqual \ [ \ { \ 'lnum': 5, \ 'col': 18, \ 'type': 'E', \ 'text': 'trailing spaces', \ 'code': 'trailing-spaces', \ }, \ ], \ ale#handlers#yamllint#Handle(bufnr(''), [ \ 'something.yml:5:18: [error] trailing spaces (trailing-spaces)', \ ]) let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ ], \ ale#handlers#yamllint#Handle(bufnr(''), [ \ 'something.yml:5:18: [error] trailing spaces (trailing-spaces)', \ ]) ================================================ FILE: test/handler/test_yosys_handler.vader ================================================ Before: runtime ale_linters/verilog/yosys.vim After: call ale#linter#Reset() Execute(The yosys handler should parse lines correctly): AssertEqual \ [ \ { \ 'lnum': 3, \ 'type': 'E', \ 'text': 'syntax error, unexpected TOK_ID', \ 'filename': 'file.v' \ }, \ { \ 'lnum': 1, \ 'type': 'E', \ 'text': 'internal error', \ }, \ ], \ ale_linters#verilog#yosys#Handle(bufnr(''), [ \ '1. Executing Verilog-2005 frontend: file.v', \ 'ERROR: internal error', \ 'file.v:3: ERROR: syntax error, unexpected TOK_ID', \ ]) ================================================ FILE: test/handler/test_yq_handler.vader ================================================ Before: runtime ale_linters/yaml/yq.vim After: call ale#linter#Reset() Execute (Should parse error correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'text': "did not find expected ',' or ']'", \ } \ ], \ ale_linters#yaml#yq#Handle(bufnr(''), [ \ "Error: bad file '-': yaml: line 2: did not find expected ',' or ']'" \ ]) ================================================ FILE: test/handler/test_zeek_handler.vader ================================================ Before: runtime ale_linters/zeek/zeek.vim After: call ale#linter#Reset() Execute(The zeek handler should parse errors correctly): AssertEqual \ [ \ { \ 'lnum': 2, \ 'text': 'unknown identifier bar, at or near "bar"', \ 'type': 'E', \ }, \ ], \ ale_linters#zeek#zeek#HandleErrors(bufnr(''), [ \ 'error in /tmp/foo.zeek, line 2: unknown identifier bar, at or near "bar"' \ ]) Execute(The zeek handler should parse warnings correctly): AssertEqual \ [ \ { \ 'lnum': 11, \ 'text': 'expression value ignored (c$removal_hooks)', \ 'type': 'W', \ }, \ ], \ ale_linters#zeek#zeek#HandleErrors(bufnr(''), [ \ 'warning in /tmp/bar.zeek, line 11: expression value ignored (c$removal_hooks)' \ ]) ================================================ FILE: test/handler/test_zlint_handler.vader ================================================ Before: runtime ale_linters/zig/zlint.vim After: call ale#linter#Reset() Execute(The zlint handler should parse GitHub Actions format correctly): " Create a temporary buffer let buffer = bufnr('') " Define input lines let input_lines = [ \ '::warning file=test.zig,line=61,col=47,title=unsafe-undefined::`undefined` is missing a safety comment', \ '', \ '::error file=test2.zig,line=4,col=33,title=no-unresolved::Unresolved import to ''test3.zig''', \ '', \ ] " Define expected output let expected_output = [ \ { \ 'filename': 'test.zig', \ 'lnum': 61, \ 'col': 47, \ 'text': '`undefined` is missing a safety comment', \ 'type': 'W', \ 'code': 'unsafe-undefined' \ }, \ { \ 'filename': 'test2.zig', \ 'lnum': 4, \ 'col': 33, \ 'text': 'Unresolved import to ''test3.zig''', \ 'type': 'E', \ 'code': 'no-unresolved' \ }, \ ] " Get actual output let actual_output = ale_linters#zig#zlint#Handle(buffer, input_lines) " Assert equality AssertEqual expected_output, actual_output ================================================ FILE: test/jsonnet_files/testfile.jsonnet ================================================ { foo: bar } ================================================ FILE: test/linter/test_ada_gcc.vader ================================================ 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 %s:h' \ . ' -gnatwa -gnatq %t' let b:ale_ada_gcc_executable = 'foo' AssertLinter 'foo', \ ale#Escape('foo') . ' -x ada -c -gnatc' \ . ' -o ' . b:out_file \ . ' -I %s:h' \ . ' -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 %s:h' \ . ' --foo --bar %t' ================================================ FILE: test/linter/test_adals.vader ================================================ Before: call ale#assert#SetUpLinterTest('ada', 'adals') After: call ale#assert#TearDownLinterTest() Execute(Sets adals executable): let g:ale_ada_adals_executable = '/path/to /Ada' AssertLinter '/path/to /Ada', ale#Escape('/path/to /Ada') Execute(Sets adals encoding): let b:ale_ada_adals_encoding = 'iso-8859-1' AssertLSPConfig {'ada.defaultCharset': 'iso-8859-1', 'ada.projectFile': 'default.gpr'} Execute(Sets adals project): let g:ale_ada_adals_project = 'myproject.gpr' AssertLSPConfig {'ada.defaultCharset': 'utf-8', 'ada.projectFile': 'myproject.gpr'} ================================================ FILE: test/linter/test_alex.vader ================================================ Before: call ale#assert#SetUpLinterTest('tex', 'alex') call ale#test#SetFilename('test_file.tex') After: call ale#assert#TearDownLinterTest() Execute(The global executable should be used when the local one cannot be found): AssertLinter 'alex', \ ale#Escape('alex') . ' --stdin --text', Execute(Should use the node_modules/.bin executable, if available): call ale#test#SetFilename('../test-files/alex/node-modules/test_file.tex') AssertLinter ale#path#Simplify(g:dir . '/../test-files/alex/node-modules/node_modules/.bin/alex'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/alex/node-modules/node_modules/.bin/alex')) \ . ' --stdin --text', Execute(Should use the node_modules/alex executable, if available): call ale#test#SetFilename('../test-files/alex/node-modules-2/test_file.tex') AssertLinter ale#path#Simplify(g:dir . '/../test-files/alex/node-modules-2/node_modules/alex/cli.js'), \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/alex/node-modules-2/node_modules/alex/cli.js')) \ . ' --stdin --text', Execute(Should let users configure a global executable and override local paths): call ale#test#SetFilename('../test-files/write-good/node-modules-2/test_file.tex') let g:ale_alex_executable = '/path/to/custom/alex' let g:ale_alex_use_global = 1 AssertLinter '/path/to/custom/alex', \ ale#Escape('/path/to/custom/alex') . ' --stdin --text' ================================================ FILE: test/linter/test_ameba.vader ================================================ Before: call ale#assert#SetUpLinterTest('crystal', 'ameba') call ale#test#SetFilename('dummy.cr') let g:ale_crystal_ameba_executable = 'bin/ameba' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to bin/ameba): AssertLinter 'bin/ameba', ale#Escape('bin/ameba') \ . ' --format json ' \ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.cr')) Execute(Should be able to set a custom executable): let g:ale_crystal_ameba_executable = 'ameba' AssertLinter 'ameba' , ale#Escape('ameba') \ . ' --format json ' \ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.cr')) ================================================ FILE: test/linter/test_angular.vader ================================================ Before: call ale#assert#SetUpLinterTest('html', 'angular') let g:paths = {} After: call ale#assert#TearDownLinterTest() unlet g:paths Execute(The Angular LSP connection shouldn't be created outside of Angular projects): AssertLSPLanguage 'html' AssertLSPConfig {} AssertLSPProject '' AssertLinterNotExecuted Execute(The default command for Angular should be correct): call ale#test#SetFilename('../test-files/angular/test.html') let g:paths = { \ 'ngserver': ale#test#GetFilename('../test-files/angular/node_modules/@angular/language-server/bin/ngserver'), \ 'service': ale#test#GetFilename('../test-files/angular/node_modules/@angular/language-service'), \ 'typescript': ale#test#GetFilename('../test-files/angular/node_modules/typescript'), \} AssertLSPLanguage 'html' AssertLSPProject ale#test#GetFilename('../test-files/angular') AssertLinter 'node', ale#Escape('node') . ' ' . ale#Escape(g:paths.ngserver) \ . ' --ngProbeLocations ' . ale#Escape(g:paths.service) \ . ' --tsProbeLocations ' . ale#Escape(g:paths.typescript) \ . ' --stdio' ================================================ FILE: test/linter/test_ansible_language_server.vader ================================================ Before: call ale#assert#SetUpLinterTest('ansible', 'language_server') After: call ale#assert#TearDownLinterTest() Execute(The ansible language server command callback should return default string): AssertLinter 'ansible-language-server', ale#Escape('ansible-language-server') . ' --stdio' Execute(The ansible language server executable should be configurable): let g:ale_ansible_language_server_executable = '~/.local/bin/als' AssertLinter '~/.local/bin/als' , ale#Escape('~/.local/bin/als') . ' --stdio' Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_ansible_language_server_config = {'ansible-language-server': {'ansible': {'completion': {'provideRedirectModules': v:false}}}} AssertLSPConfig {'ansible-language-server': {'ansible': {'completion': {'provideRedirectModules': v:false}}}} ================================================ FILE: test/linter/test_ansible_lint.vader ================================================ 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 version <5.0.0 command callback should return default string): GivenCommandOutput ['v4.1.2'] AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' --nocolor -p %t' Execute(The ansible_lint version >=5.0.0 command callback should return default string): GivenCommandOutput ['v5.1.2'] AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' --nocolor --parseable-severity -x yaml %s' Execute(The ansible_lint version >=6.0.0 command callback should return default string): GivenCommandOutput ['v6.0.2'] AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' --nocolor -f json -x yaml %s' Execute(The ansible_lint executable should be configurable): let g:ale_ansible_ansible_lint_executable = '~/.local/bin/ansible-lint' GivenCommandOutput ['v4.1.2'] AssertLinter '~/.local/bin/ansible-lint', \ ale#Escape('~/.local/bin/ansible-lint') . ' --nocolor -p %t' Execute(pipenv is detected when ansible_ansible_lint_auto_pipenv is set): let g:ale_ansible_ansible_lint_auto_pipenv = 1 call ale#test#SetFilename('../test-files/ansible/pipenv/script.yml') GivenCommandOutput ['v25.6.1'] AssertLinterCwd expand('%:p:h') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run ansible-lint --nocolor -f json -x yaml %s' Execute(poetry is detected when ansible_ansible_lint_auto_poetry is set): let g:ale_ansible_ansible_lint_auto_poetry = 1 call ale#test#SetFilename('../test-files/ansible/poetry/script.yml') GivenCommandOutput ['v25.6.1'] AssertLinterCwd expand('%:p:h') AssertLinter 'poetry', ale#Escape('poetry') . ' run ansible-lint --nocolor -f json -x yaml %s' Execute(uv is detected when ansible_ansible_lint_auto_uv is set): let g:ale_ansible_ansible_lint_auto_uv = 1 call ale#test#SetFilename('../test-files/ansible/uv/script.yml') GivenCommandOutput ['v25.6.1'] AssertLinterCwd expand('%:p:h') AssertLinter 'uv', ale#Escape('uv') . ' run ansible-lint --nocolor -f json -x yaml %s' ================================================ FILE: test/linter/test_asciidoc_textlint.vader ================================================ " Author: januswel, w0rp Before: " This is just one language for the linter. call ale#assert#SetUpLinterTest('asciidoc', 'textlint') " The configuration is shared between many languages. Save g:ale_textlint_executable Save g:ale_textlint_use_global Save g:ale_textlint_options let g:ale_textlint_executable = 'textlint' let g:ale_textlint_use_global = 0 let g:ale_textlint_options = '' unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options After: unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'textlint', \ ale#Escape('textlint') . ' -f json --stdin --stdin-filename %s' Execute(The executable and options should be configurable): let b:ale_textlint_executable = 'foobar' let b:ale_textlint_options = '--something' AssertLinter 'foobar', \ ale#Escape('foobar') . ' --something -f json --stdin --stdin-filename %s' Execute(The local executable from .bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_bin_path/foo.txt') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint')) \ . ' -f json --stdin --stdin-filename %s' Execute(The local executable from textlint/bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_textlint_bin_path/foo.txt') if has('win32') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape('node.exe') . ' ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' else AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' endif ================================================ FILE: test/linter/test_asm_gcc.vader ================================================ Before: call ale#assert#SetUpLinterTest('asm', 'gcc') call ale#test#SetFilename('test.cpp') let b:command_tail = ' -x assembler' \ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -Wall -' After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(The executable should be configurable): let b:ale_asm_gcc_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail ================================================ FILE: test/linter/test_avra_avra.vader ================================================ Before: call ale#assert#SetUpLinterTest('avra', 'avra') let b:command_tail = ' %t -o ' . g:ale#util#nul_file let b:command_tail_opt = ' %t --max_errors 20 -o ' . g:ale#util#nul_file After: unlet! b:command_tail unlet! b:command_tail_opt call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'avra', ale#Escape('avra') . b:command_tail, let b:ale_avra_avra_executable = '~/avra' AssertLinter '~/avra', ale#Escape('~/avra') . b:command_tail Execute(The options should be configurable): let b:ale_avra_avra_options = '--max_errors 20' AssertLinter 'avra', ale#Escape('avra') \ . ' %t --max_errors 20 -o ' . g:ale#util#nul_file Execute(The options should be used in command): let b:ale_avra_avra_options = '--max_errors 20' AssertLinter 'avra', ale#Escape('avra') . b:command_tail_opt ================================================ FILE: test/linter/test_bandit.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'bandit') let b:bandit_flags = ' --format custom ' \ . '--msg-template "{line}:{test_id}:{severity}:{msg}" ' After: call ale#assert#TearDownLinterTest() unlet! b:bandit_flags Execute(The bandit command callback should return default string): AssertLinter 'bandit', \ ale#Escape('bandit') \ . b:bandit_flags \ . ' -' Execute(The bandit command callback should allow options): let g:ale_python_bandit_options = '--configfile bandit.yaml' AssertLinter 'bandit', \ ale#Escape('bandit') \ . b:bandit_flags \ . ' --configfile bandit.yaml -' Execute(The bandit executable should be configurable): let g:ale_python_bandit_executable = '~/.local/bin/bandit' AssertLinter '~/.local/bin/bandit', \ ale#Escape('~/.local/bin/bandit') \ . b:bandit_flags \ . ' -' Execute(Setting executable to 'pipenv' appends 'run bandit'): let g:ale_python_bandit_executable = 'path/to/pipenv' AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') \ . ' run bandit' \ . b:bandit_flags \ . ' -' Execute(Pipenv is detected when python_bandit_auto_pipenv is set): let g:ale_python_bandit_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') \ . ' run bandit' \ . b:bandit_flags \ . ' -' Execute(Setting executable to 'poetry' appends 'run bandit'): let g:ale_python_bandit_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') \ . ' run bandit' \ . b:bandit_flags \ . ' -' Execute(Poetry is detected when python_bandit_auto_poetry is set): let g:ale_python_bandit_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') \ . ' run bandit' \ . b:bandit_flags \ . ' -' Execute(uv is used when python_bandit_auto_uv is set): let g:ale_python_bandit_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') \ . ' run bandit' \ . b:bandit_flags \ . ' -' Execute(The bandit command callback should add .bandit by default): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_bandit/namespace/foo/bar.py') let b:config_path = ale#path#Simplify( \ g:dir . '/../test-files/python/with_bandit/.bandit' \) AssertLinter 'bandit', \ ale#Escape('bandit') \ . ' --ini ' . ale#Escape(b:config_path) \ . b:bandit_flags \ . ' -' Execute(The bandit command callback should support not using .bandit): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/with_bandit/subdir/foo/bar.py') let g:ale_python_bandit_use_config = 0 AssertLinter 'bandit', \ ale#Escape('bandit') \ . b:bandit_flags \ . ' -' ================================================ FILE: test/linter/test_bashate.vader ================================================ Before: call ale#assert#SetUpLinterTest('sh', 'bashate') call ale#test#SetFilename('test.sh') After: call ale#assert#TearDownLinterTest() Execute(The default bashate command should be correct): AssertLinter 'bashate', ale#Escape('bashate') . ' %t' Execute(The bashate command should accept options): let b:ale_sh_bashate_options = '-i E310 --max-line-length 100' AssertLinter 'bashate', \ ale#Escape('bashate') . ' -i E310 --max-line-length 100 %t' ================================================ FILE: test/linter/test_bib_bibclean.vader ================================================ Before: call ale#assert#SetUpLinterTest('bib', 'bibclean') let g:ale_ruby_rubocop_executable = 'bibclean' let g:ale_ruby_rubocop_options = '' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to bibclean): AssertLinter 'bibclean', ale#Escape('bibclean') \ . ' -file-position ' Execute(Should be able to set a custom executable): let g:ale_bib_bibclean_executable = 'bin/bibclean' AssertLinter 'bin/bibclean' , ale#Escape('bin/bibclean') \ . ' -file-position ' Execute(Should not include custom options): let g:ale_bib_bibclean_options = '-no-prettryprint' AssertLinter 'bibclean' , ale#Escape('bibclean') \ . ' -file-position ' ================================================ FILE: test/linter/test_bicep_az_bicep.vader ================================================ Before: call ale#assert#SetUpLinterTest('bicep', 'az_bicep') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): if has('win32') AssertLinter 'az', ale#Escape('az') . ' bicep build --outfile NUL --file %s ' else AssertLinter 'az', ale#Escape('az') . ' bicep build --outfile /dev/null --file %s ' endif Execute(The executable should be configurable): let g:ale_bicep_az_bicep_executable = 'foobar' if has('win32') AssertLinter 'foobar', ale#Escape('foobar') . ' bicep build --outfile NUL --file %s ' else AssertLinter 'foobar', ale#Escape('foobar') . ' bicep build --outfile /dev/null --file %s ' endif ================================================ FILE: test/linter/test_bicep_bicep.vader ================================================ Before: call ale#assert#SetUpLinterTest('bicep', 'bicep') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): if has('win32') AssertLinter 'bicep', ale#Escape('bicep') . ' build --outfile NUL %s' else AssertLinter 'bicep', ale#Escape('bicep') . ' build --outfile /dev/null %s' endif Execute(The executable should be configurable): let g:ale_bicep_bicep_executable = 'foobar' if has('win32') AssertLinter 'foobar', ale#Escape('foobar') . ' build --outfile NUL %s' else AssertLinter 'foobar', ale#Escape('foobar') . ' build --outfile /dev/null %s' endif ================================================ FILE: test/linter/test_bindzone_checkzone.vader ================================================ Before: call ale#assert#SetUpLinterTest('bindzone', 'checkzone') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'named-checkzone', \ ale#Escape('named-checkzone') . ' -c IN example.com %t' Execute(The default command should be overridden): let b:ale_bindzone_checkzone_executable = '/bin/bind9-checkzone' AssertLinter '/bin/bind9-checkzone', \ ale#Escape('/bin/bind9-checkzone') . ' -c IN example.com %t' Execute(The default options should be overridden): let b:ale_bindzone_checkzone_options = '-c IN -d' AssertLinter 'named-checkzone', \ ale#Escape('named-checkzone') . ' -c IN -d example.com %t' ================================================ FILE: test/linter/test_bingo.vader ================================================ Before: Save g:ale_go_go111module call ale#assert#SetUpLinterTest('go', 'bingo') After: Restore if isdirectory(g:dir . '/.git') call delete(g:dir . '/.git', 'd') endif unlet! b:ale_completion_enabled unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The default bingo executable and options should be correct): AssertLinter 'bingo', ale#Escape('bingo') . ' --mode stdio' Execute(The bingo executable and options should be configurable): let b:ale_go_bingo_executable = 'boo' let b:ale_go_bingo_options = '--mode stdio --trace' AssertLinter 'boo', ale#Escape('boo') . ' --mode stdio --trace' Execute(should support Go environment variables): call ale#test#SetFilename('../test-files/go/go1/prj1/file.go') let b:ale_go_go111module = 'on' AssertLinter 'bingo', \ ale#Env('GO111MODULE', 'on') . ale#Escape('bingo') . ' --mode stdio' Execute(Should return directory for 'go.mod' if found in parent directory): call ale#test#SetFilename('../test-files/go/test.go') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/go') Execute(Should return nearest directory with '.git' if found in parent directory): call ale#test#SetFilename('test.go') call mkdir(g:dir . '/.git') AssertLSPProject g:dir Execute(Should ignore 'go.mod' and return '.git' dir if modules off): call ale#test#SetFilename('../test-files/go/test.go') let b:ale_go_go111module = 'off' let b:parent_dir = ale#path#Simplify(g:dir . '/..') let b:git_dir = b:parent_dir . '/.git' if !isdirectory(b:git_dir) call mkdir(b:git_dir) endif AssertLSPProject b:parent_dir call delete(b:git_dir, 'd') unlet! b:parent_dir unlet! b:git_dir ================================================ FILE: test/linter/test_biome.vader ================================================ Before: Save g:ale_biome_options Save g:ale_biome_lsp_project_root let g:ale_biome_options = '' let g:ale_biome_lsp_project_root = '' call ale#assert#SetUpLinterTest('typescript', 'biome') call ale#test#SetFilename('test.ts') After: call ale#assert#TearDownLinterTest() Execute(The default biome command should be correct): AssertLinter 'biome', ale#Escape('biome') . ' lsp-proxy' Execute(Uses the filetype as the language): call ale#test#SetFilename('test.ts') set filetype=typescript AssertLSPLanguage 'typescript' call ale#test#SetFilename('test.tsx') set filetype=typescriptreact AssertLSPLanguage 'typescriptreact' call ale#test#SetFilename('test.js') set filetype=javascript AssertLSPLanguage 'javascript' call ale#test#SetFilename('test.jsx') set filetype=javascriptreact AssertLSPLanguage 'javascriptreact' Execute(Should find project root containing biome.json): call ale#test#SetFilename('../test-files/biome/json/src/test.ts') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/biome/json') Execute(Should find project root containing biome.jsonc): call ale#test#SetFilename('../test-files/biome/jsonc/src/test.ts') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/biome/jsonc') Execute(Should use user-specified project root): let g:ale_biome_lsp_project_root = '/' call ale#test#SetFilename('../test-files/biome/jsonc/src/test.ts') AssertLSPProject '/' ================================================ FILE: test/linter/test_bitbake.vader ================================================ Before: call ale#assert#SetUpLinterTest('bitbake', 'oelint_adv') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'oelint-adv', ale#Escape('oelint-adv') . ' --quiet %s' Execute(The executable should be configurable): let b:ale_bitbake_oelint_adv_executable = 'xyz' AssertLinter 'xyz', ale#Escape('xyz') . ' --quiet %s' ================================================ FILE: test/linter/test_brakeman.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'brakeman') After: call ale#assert#TearDownLinterTest() Execute(The brakeman command callback should detect absence of a valid Rails app): call ale#test#SetFilename('../test-files/ruby/not_a_rails_app/test.rb') AssertLinter 'brakeman', '' Execute(The brakeman command callback should find a valid Rails app root): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/db/test.rb') AssertLinter 'brakeman', ale#Escape('brakeman') \ . ' -f json -q -p ' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/ruby/valid_rails_app')) Execute(The brakeman command callback should include configured options): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/db/test.rb') let g:ale_ruby_brakeman_options = '--combobulate' AssertLinter 'brakeman', ale#Escape('brakeman') \ . ' -f json -q --combobulate -p ' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/ruby/valid_rails_app')) Execute(Setting bundle appends 'exec brakeman'): call ale#test#SetFilename('../test-files/ruby/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 . '/../test-files/ruby/valid_rails_app')) ================================================ FILE: test/linter/test_buf_lint.vader ================================================ Before: call ale#assert#SetUpLinterTest('proto', 'buf_lint') call ale#test#SetFilename('test.proto') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'buf', \ ale#Escape('buf') \ . ' lint' \ . ' %s#include_package_files=true' Execute(The callback should include any additional config): let b:ale_proto_buf_lint_executable = '/tmp/buf' let b:ale_proto_buf_lint_config = '/tmp/buf.yaml' AssertLinter '/tmp/buf', \ ale#Escape('/tmp/buf') \ . ' lint' \ . ' --config=' . ale#Escape('/tmp/buf.yaml') \ . ' %s#include_package_files=true' Execute(The callback should include additional options): let b:ale_proto_buf_lint_executable = '/tmp/buf' let b:ale_proto_buf_lint_options = '--disable-symlinks' AssertLinter '/tmp/buf', \ ale#Escape('/tmp/buf') \ . ' lint' \ . ' --disable-symlinks' \ . ' %s#include_package_files=true' ================================================ FILE: test/linter/test_bzl_buildifier.vader ================================================ Before: call ale#assert#SetUpLinterTest('bzl', 'buildifier') After: call ale#assert#TearDownLinterTest() Execute(Should use default command when bazel_buildifier_options are not set): call ale#test#SetDirectory('/testplugin/test/test-files/bzl/bazel-package') call ale#test#SetFilename('BUILD.bazel') let g:ale_bazel_buildifier_executable = 'buildifier' let g:ale_bazel_buildifier_options = '' AssertLinter 'buildifier', \ ale#Escape('buildifier') . ' -mode check -lint warn -path %s' call ale#test#RestoreDirectory() Execute(Should use custom buildifier options when bazel_buildifier_options are set): call ale#test#SetDirectory('/testplugin/test/test-files/bzl/bazel-package') call ale#test#SetFilename('BUILD.bazel') let g:ale_bazel_buildifier_executable = 'buildifier' let g:ale_bazel_buildifier_options = '-v' AssertLinter 'buildifier', \ ale#Escape('buildifier') . ' -mode check -lint warn -path %s -v' call ale#test#RestoreDirectory() ================================================ FILE: test/linter/test_c3_c3lsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('c3', 'c3lsp') After: call ale#assert#TearDownLinterTest() Execute(The default c3lsp settings should be correct): AssertLinter 'c3lsp', ale#Escape('c3lsp') AssertLSPConfig {} Execute(c3lsp should be configurable): let b:ale_c3_c3lsp_executable = 'billy' let b:ale_c3_c3lsp_init_options = {'x': 'y'} AssertLinter 'billy', ale#Escape('billy') AssertLSPConfig {'x': 'y'} ================================================ FILE: test/linter/test_c_cc.vader ================================================ Before: Save g:ale_c_parse_makefile Save g:ale_history_enabled let g:ale_c_parse_makefile = 0 let g:ale_history_enabled = 0 let g:get_cflags_return_value = '' let g:executable_map = {} runtime autoload/ale/c.vim runtime autoload/ale/engine.vim function! ale#engine#IsExecutable(buffer, executable) abort return has_key(g:executable_map, a:executable) endfunction function! ale#c#GetCFlags(buffer, output) abort return g:get_cflags_return_value endfunction call ale#assert#SetUpLinterTest('c', 'cc') let b:command_tail = ' -S -x c' \ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -std=c11 -Wall -' After: unlet! g:get_cflags_return_value unlet! g:executable_map unlet! b:command_tail runtime autoload/ale/c.vim runtime autoload/ale/engine.vim call ale#assert#TearDownLinterTest() Execute(clang should be used instead of gcc, if available): let g:executable_map = {'clang': 1} AssertLinter 'clang', [ale#Escape('clang') . b:command_tail] Execute(The executable should be configurable): AssertLinter 'gcc', [ale#Escape('gcc') . b:command_tail] let b:ale_c_cc_executable = 'foobar' AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail] Execute(The -std flag should be replaced by parsed C flags): let b:command_tail = substitute(b:command_tail, 'c11', 'c99 ', '') let g:get_cflags_return_value = '-std=c99' AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(gcc should not use -x c-header with header files by default): call ale#test#SetFilename('../test-files/c/makefile_project/subdir/test.h') AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(clang should use -x c-header with header files by default): let g:executable_map = {'clang': 1} let b:command_tail = substitute(b:command_tail, '-x c', '-x c-header', '') call ale#test#SetFilename('../test-files/c/makefile_project/subdir/test.h') AssertLinter 'clang', ale#Escape('clang') . b:command_tail Execute(gcc should use -x c-header with header files if configured to do so): let b:ale_c_cc_use_header_lang_flag = 1 let b:command_tail = substitute(b:command_tail, '-x c', '-x c-header', '') call ale#test#SetFilename('../test-files/c/makefile_project/subdir/test.h') AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(clang should not use -x c-header with header files if configured to do so): let g:executable_map = {'clang': 1} let b:ale_c_cc_use_header_lang_flag = 0 call ale#test#SetFilename('../test-files/c/makefile_project/subdir/test.h') AssertLinter 'clang', ale#Escape('clang') . b:command_tail Execute(The header file extensions should be configurable): let g:executable_map = {'clang': 1} let b:command_tail = substitute(b:command_tail, '-x c', '-x c-header', '') call ale#assert#SetUpLinterTest('c', 'cc') let b:ale_c_cc_header_exts = ['json'] call ale#test#SetFilename('../test-files/c/json_project/build/compile_commands.json') AssertLinter 'clang', ale#Escape('clang') . b:command_tail ================================================ FILE: test/linter/test_c_ccls.vader ================================================ " Author: Ye Jingchen , Ben Falconer " Description: A language server for C Before: call ale#assert#SetUpLinterTest('c', 'ccls') Save b:ale_c_build_dir_names Save b:ale_c_ccls_executable Save b:ale_c_ccls_init_options After: call ale#assert#TearDownLinterTest() Execute(The project root should be detected correctly using compile_commands.json file): call ale#test#SetFilename(tempname() . '/dummy.c') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_compile_commands_json/dummy.c') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/with_compile_commands_json') Execute(The project root should be detected correctly using .ccls file): call ale#test#SetFilename(tempname() . '/dummy.c') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_ccls/dummy.c') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/with_ccls') Execute(The project root should be detected correctly using .ccls-root file): call ale#test#SetFilename(tempname() . '/dummy.c') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_ccls-root/dummy.c') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/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' } Execute(The compile command database should be detected correctly): call ale#test#SetFilename('../test-files/ccls/with_ccls/dummy.c') AssertLSPOptions {} call ale#test#SetFilename('../test-files/ccls/with_compile_commands_json/dummy.c') AssertLSPOptions { 'compilationDatabaseDirectory': \ ale#path#Simplify(g:dir . '/../test-files/ccls/with_compile_commands_json') } call ale#test#SetFilename('../test-files/ccls/with_build_dir/dummy.c') let b:ale_c_build_dir_names = ['unusual_build_dir_name'] AssertLSPOptions { 'compilationDatabaseDirectory': \ ale#path#Simplify(g:dir . '/../test-files/ccls/with_build_dir/unusual_build_dir_name') } ================================================ FILE: test/linter/test_c_clang_tidy.vader ================================================ Before: Save g:ale_c_parse_makefile let g:ale_c_parse_makefile = 0 call ale#assert#SetUpLinterTest('c', 'clangtidy') call ale#test#SetFilename('test.c') After: call ale#assert#TearDownLinterTest() Execute(The clangtidy command default should be correct): AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') . ' %s' Execute(You should be able to set other checks for clang-tidy): let b:ale_c_clangtidy_checks = ['-*', 'clang-analyzer-*'] AssertLinter 'clang-tidy', \ ale#Escape('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(You should be able to manually set flags for clang-tidy): let b:ale_c_clangtidy_extra_options = '-config=' AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') . ' ' . ale#Escape('-config=') . ' %s' Execute(The build directory should be configurable): let b:ale_c_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') 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' AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') \ . ' -checks=' . ale#Escape('*') . ' %s' \ . ' -p ' . ale#Escape('/foo/bar') Execute(The build directory should be used 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' AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') \ . ' -checks=' . ale#Escape('*') . ' %s' \ . ' -p ' . ale#Escape('/foo/bar') Execute(The executable should be configurable): let b:ale_c_clangtidy_checks = ['*'] let b:ale_c_clangtidy_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' -checks=' . ale#Escape('*') . ' %s' ================================================ FILE: test/linter/test_c_clangcheck.vader ================================================ # modified from test_cpp_cppcheck.vader Before: call ale#assert#SetUpLinterTest('c', 'clangcheck') After: call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'clang-check', \ ale#Escape('clang-check') \ . ' -analyze %s --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics' let b:ale_c_clangcheck_executable = 'foobar' " The extra arguments in the command are used to prevent .plist files from " being generated. AssertLinter 'foobar', \ ale#Escape('foobar') \ . ' -analyze %s --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics' Execute(The options should be configurable): let b:ale_c_clangcheck_options = '--something' AssertLinter 'clang-check', \ ale#Escape('clang-check') \ . ' -analyze %s' \ . ' --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics' \ . ' --something' Execute(The build directory should be used when set): let b:ale_c_clangcheck_options = '--something' let b:ale_c_build_dir = '/foo/bar' AssertLinter 'clang-check', \ ale#Escape('clang-check') \ . ' -analyze %s --something -p ' . ale#Escape('/foo/bar') ================================================ FILE: test/linter/test_c_clangd.vader ================================================ Before: call ale#assert#SetUpLinterTest('c', 'clangd') Save b:ale_c_clangd_options Save b:ale_c_build_dir Save b:ale_c_build_dir_names Save b:ale_c_parse_compile_commands After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'c' Execute(The default executable should be correct): AssertLinter 'clangd', ale#Escape('clangd') Execute(The project root should be detected correctly): call ale#test#SetFilename(tempname() . '/dummy.c') AssertLSPProject '' call ale#test#SetFilename('../test-files/clangd/with_compile_commands/dummy.c') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/clangd/with_compile_commands') Execute(The executable should be configurable): let g:ale_c_clangd_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') Execute(The options should be configurable): let b:ale_c_clangd_options = '-compile-commands-dir=foo' AssertLinter 'clangd', ale#Escape('clangd') . ' ' . b:ale_c_clangd_options Execute(The compile command database should be detected correctly): call ale#test#SetFilename('../test-files/clangd/with_build_dir/dummy_src/dummy.c') let b:ale_c_clangd_options = '' let b:ale_c_build_dir = '' let b:ale_c_build_dir_names = ['unusual_build_dir_name'] let b:ale_c_parse_compile_commands = 1 AssertLinter 'clangd', ale#Escape('clangd') \ . ' -compile-commands-dir=' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/clangd/with_build_dir/unusual_build_dir_name')) ================================================ FILE: test/linter/test_c_cppcheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('c', 'cppcheck') let b:command_tail = ' -q --language=c --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') . ' --enable=style -I' . ale#Escape(ale#path#Simplify(g:dir)) .' %t' After: unlet! b:rel_file_path unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'cppcheck', ale#Escape('cppcheck') . b:command_tail let b:ale_c_cppcheck_executable = 'foobar' AssertLinterCwd '' AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail Execute(cppcheck for C should detect compile_commands.json files): let b:rel_file_path = '../test-files/cppcheck/one/foo.c' call ale#test#SetFilename(b:rel_file_path) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/cppcheck/one') AssertLinter 'cppcheck', ale#Escape('cppcheck') \ . ' -q --language=c' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --project=' . ale#Escape('compile_commands.json') \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --enable=style' Execute(cppcheck for C should detect compile_commands.json files in build directories): let b:rel_file_path = '../test-files/cppcheck/with_build_dir/foo.c' call ale#test#SetFilename(b:rel_file_path) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/cppcheck/with_build_dir') AssertLinter 'cppcheck', ale#Escape('cppcheck') \ . ' -q --language=c' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --project=' . ale#Escape(ale#path#Simplify('build/compile_commands.json')) \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --enable=style' Execute(cppcheck for C should include file dir if compile_commands.json file is not found): call ale#test#SetFilename('../test-files/cppcheck/foo.c') AssertLinter 'cppcheck', \ ale#Escape('cppcheck') \ . ' -q --language=c' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --enable=style' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cppcheck')) \ . ' %t' Execute(cppcheck for C header should include file dir and not use compile_commands.json): call ale#test#SetFilename('../test-files/cppcheck/one/foo.h') AssertLinter 'cppcheck', \ ale#Escape('cppcheck') \ . ' -q --language=c' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cppcheck/one')) \ . ' --suppress=unusedStructMember' \ . ' --enable=style' \ . ' %t' ================================================ FILE: test/linter/test_c_cquery.vader ================================================ 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): call ale#test#SetFilename(tempname() . '/dummy.c') AssertLSPProject '' call ale#test#SetFilename('../test-files/cquery/dummy.c') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/cquery') Execute(The project root should be detected correctly using .cquery file): call ale#test#SetFilename(tempname() . '/dummy.c') AssertLSPProject '' call ale#test#SetFilename('../test-files/cquery/with_cquery/dummy.c') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/cquery/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'} ================================================ FILE: test/linter/test_c_flawfinder.vader ================================================ Before: call ale#assert#SetUpLinterTest('c', 'flawfinder') After: call ale#assert#TearDownLinterTest() Execute(The default flawfinder command should be correct): AssertLinter 'flawfinder', ale#Escape('flawfinder') . ' -CDQS --minlevel=1 %t' Execute(The minlevel of flawfinder should be configurable): let b:ale_c_flawfinder_minlevel = 8 AssertLinter 'flawfinder', ale#Escape('flawfinder') . ' -CDQS --minlevel=8 %t' Execute(Additional flawfinder options should be configurable): let b:ale_c_flawfinder_executable = 'foo' let b:ale_c_flawfinder_options = '--foobar' AssertLinter 'foo', ale#Escape('foo') . ' -CDQS --foobar --minlevel=1 %t' ================================================ FILE: test/linter/test_c_import_paths.vader ================================================ Before: " Make sure the c.vim file is loaded first. call ale#c#FindProjectRoot(bufnr('')) Save g:ale_c_parse_compile_commands Save g:ale_c_parse_makefile Save g:__ale_c_project_filenames let g:original_project_filenames = g:__ale_c_project_filenames let g:executable_map = {} " 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_compile_commands = 0 let g:ale_c_parse_makefile = 0 runtime autoload/ale/engine.vim function! ale#engine#IsExecutable(buffer, executable) abort return has_key(g:executable_map, a:executable) endfunction After: Restore unlet! g:original_project_filenames unlet! g:executable_map runtime autoload/ale/engine.vim call ale#assert#TearDownLinterTest() Execute(The C cc linter should include 'include' directories for projects with a Makefile): call ale#assert#SetUpLinterTest('c', 'cc') call ale#test#SetFilename('../test-files/c/makefile_project/subdir/file.c') let g:ale_c_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/makefile_project/include')) \ . ' -' Execute(The C cc linter should include 'include' directories for projects with a configure file): call ale#assert#SetUpLinterTest('c', 'cc') call ale#test#SetFilename('../test-files/c/configure_project/subdir/file.c') let g:ale_c_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/configure_project/include')) \ . ' -' Execute(The C cc linter should include root directories for projects with .h files in them): call ale#assert#SetUpLinterTest('c', 'cc') call ale#test#SetFilename('../test-files/c/h_file_project/subdir/file.c') let g:ale_c_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/h_file_project')) \ . ' -' Execute(The C cc linter should include root directories for projects with .hpp files in them): call ale#assert#SetUpLinterTest('c', 'cc') call ale#test#SetFilename('../test-files/c/hpp_file_project/subdir/file.c') let g:ale_c_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/hpp_file_project')) \ . ' -' Execute(The C ClangTidy handler should include 'include' directories for projects with a Makefile): call ale#assert#SetUpLinterTest('c', 'clangtidy') call ale#test#SetFilename('../test-files/c/makefile_project/subdir/file.cpp') let g:ale_c_clangtidy_options = '' AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') \ . ' %s ' \ . '-- -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/makefile_project/include')) Execute(The C++ cc linter should include 'include' directories for projects with a Makefile): call ale#assert#SetUpLinterTest('cpp', 'cc') call ale#test#SetFilename('../test-files/c/makefile_project/subdir/file.cpp') let g:ale_cpp_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/makefile_project/include')) \ . ' -' Execute(The C++ cc linter should include 'include' directories for projects with a configure file): call ale#assert#SetUpLinterTest('cpp', 'cc') call ale#test#SetFilename('../test-files/c/configure_project/subdir/file.cpp') let g:ale_cpp_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/configure_project/include')) \ . ' -' Execute(The C++ cc linter should include root directories for projects with .h files in them): call ale#assert#SetUpLinterTest('cpp', 'cc') call ale#test#SetFilename('../test-files/c/h_file_project/subdir/file.cpp') let g:ale_cpp_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/h_file_project')) \ . ' -' Execute(The C++ cc linter should include root directories for projects with .hpp files in them): call ale#assert#SetUpLinterTest('cpp', 'cc') call ale#test#SetFilename('../test-files/c/hpp_file_project/subdir/file.cpp') let g:ale_cpp_cc_options = '' AssertLinter 'gcc', \ ale#Escape('gcc') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/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-files/c/json_project/subdir/file.cpp') AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') \ . ' %s ' \ . '-p ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/json_project/build')) Execute(The C++ ClangTidy handler should include 'include' directories for projects with a Makefile): call ale#assert#SetUpLinterTest('cpp', 'clangtidy') call ale#test#SetFilename('../test-files/c/makefile_project/subdir/file.cpp') let g:ale_cpp_clangtidy_options = '' AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') \ . ' %s ' \ . '-- -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/c/makefile_project/include')) ================================================ FILE: test/linter/test_cargo.vader ================================================ Before: call ale#assert#SetUpLinterTest('rust', 'cargo') call ale#test#SetFilename('../test-files/cargo/test.rs') let g:cd = 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cargo')) . ' && ' let g:suffix = ' --frozen --message-format=json -q' let g:ale_rust_cargo_avoid_whole_workspace = 0 " Test with version 0.22.0 by default. GivenCommandOutput ['cargo 0.22.0 (3423351a5 2017-10-06)'] After: call ale#assert#TearDownLinterTest() unlet! g:cd unlet! g:suffix Execute(The linter should not be executed when there's no Cargo.toml file): call ale#test#SetFilename('../foo.rs') AssertLinterNotExecuted Execute(The linter should be executed when there is a Cargo.toml file): GivenCommandOutput [] AssertLinter 'cargo', 'cargo build --frozen --message-format=json -q' Execute(`cargo check` should be used when the version is new enough): GivenCommandOutput ['cargo 0.17.0 (3423351a5 2017-10-06)'] AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo check' . g:suffix, \] " We should cache the version check GivenCommandOutput [] AssertLinter 'cargo', ['cargo check' . g:suffix] Execute(`cargo build` should be used when cargo is too old): GivenCommandOutput ['cargo 0.16.0 (3423351a5 2017-10-06)'] AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo build' . g:suffix, \] GivenCommandOutput [] AssertLinter 'cargo', ['cargo build' . g:suffix] Execute(`cargo build` should be used when g:ale_rust_cargo_use_check is set to 0): let g:ale_rust_cargo_use_check = 0 GivenCommandOutput ['cargo 0.24.0 (3423351a5 2017-10-06)'] AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo build' . g:suffix, \] " We should cache the version check GivenCommandOutput [] AssertLinter 'cargo', ['cargo build' . g:suffix] Execute(`cargo check` should be used when the version is new enough): AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo check' . g:suffix, \] " We should cache the version check GivenCommandOutput [] AssertLinter 'cargo', ['cargo check' . g:suffix] Execute(--all-targets should be used when g:ale_rust_cargo_check_all_targets is set to 1): let g:ale_rust_cargo_check_all_targets = 1 AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --all-targets' . g:suffix] " We should cache the version check AssertLinter 'cargo', ['cargo check --all-targets' . g:suffix] Execute(--tests should be used when g:ale_rust_cargo_check_tests is set to 1): let g:ale_rust_cargo_check_tests = 1 AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --tests' . g:suffix] " We should cache the version check GivenCommandOutput [] AssertLinter 'cargo', ['cargo check --tests' . g:suffix] Execute(--examples should be used when g:ale_rust_cargo_check_examples is set to 1): let g:ale_rust_cargo_check_examples = 1 AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --examples' . g:suffix] " We should cache the version check GivenCommandOutput [] AssertLinter 'cargo', ['cargo check --examples' . g:suffix] Execute(--no-default-features should be used when g:ale_rust_cargo_default_feature_behavior is none): let b:ale_rust_cargo_default_feature_behavior = 'none' AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --no-default-features'] Execute(g:ale_rust_cargo_include_features added when g:ale_rust_cargo_default_feature_behavior is none): let b:ale_rust_cargo_default_feature_behavior = 'none' let b:ale_rust_cargo_include_features = 'foo bar' AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --no-default-features --features ' . ale#Escape('foo bar')] Execute(g:ale_rust_cargo_include_features added and escaped): let b:ale_rust_cargo_default_feature_behavior = 'default' let b:ale_rust_cargo_include_features = "foo bar baz" AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --features ' . ale#Escape('foo bar baz')] Execute(--all-features should be used when g:ale_rust_cargo_default_feature_behavior is all): let b:ale_rust_cargo_default_feature_behavior = 'all' " When all features are enabled we should ignore extra features to add " since it won't do anything let b:ale_rust_cargo_include_features = 'foo bar' GivenCommandOutput ['cargo 0.22.0 (3423351a5 2017-10-06)'] AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --all-features'] Execute(Cargo should run from the crate directory when set to avoid the workspace): let g:ale_rust_cargo_avoid_whole_workspace = 1 call ale#test#SetFilename('../test-files/cargo/workspace_paths/subpath/test.rs') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/cargo/workspace_paths/subpath') call ale#semver#ResetVersionCache() AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo check --frozen --message-format=json -q', \] Execute(Cargo should not run from the crate directory when not set to avoid the workspace): let g:ale_rust_cargo_avoid_whole_workspace = 0 call ale#test#SetFilename('../test-files/cargo/workspace_paths/subpath/test.rs') AssertLinterCwd '' call ale#semver#ResetVersionCache() AssertLinter 'cargo', [ \ ale#Escape('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', [ \ ale#Escape('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', [ \ ale#Escape('cargo') . ' --version', \ 'cargo clippy --frozen --message-format=json -q -- -D warnings', \] Execute(Clippy options work without prepending --): let b:ale_rust_cargo_use_clippy = 1 let b:ale_rust_cargo_clippy_options = '-D warnings' AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo clippy --frozen --message-format=json -q -- -D warnings', \] Execute(Build supports all cargo flags): let g:ale_rust_cargo_use_check = 0 let g:ale_rust_cargo_check_all_targets = 1 let g:ale_rust_cargo_check_tests = 1 let g:ale_rust_cargo_check_examples = 1 let b:ale_rust_cargo_default_feature_behavior = 'all' let b:ale_rust_cargo_target_dir = 'target/ale' AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo build --all-targets --examples --tests --target-dir ' . ale#Escape('target/ale') . ' --frozen --message-format=json -q --all-features', \] Execute(Clippy supports all cargo flags): let b:ale_rust_cargo_use_clippy = 1 let g:ale_rust_cargo_check_all_targets = 1 let g:ale_rust_cargo_check_tests = 1 let g:ale_rust_cargo_check_examples = 1 let b:ale_rust_cargo_default_feature_behavior = 'all' let b:ale_rust_cargo_clippy_options = '-D warnings' let b:ale_rust_cargo_target_dir = 'target/ale' AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo clippy --all-targets --examples --tests --target-dir ' . ale#Escape('target/ale') . ' --frozen --message-format=json -q --all-features -- -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', [ \ ale#Escape('cargo') . ' --version', \ 'cargo check --frozen --message-format=json -q', \] Execute(`cargo --target-dir` should be used when the version is new enough and it is set): let b:ale_rust_cargo_target_dir = 'target/ale' GivenCommandOutput ['cargo 0.17.0 (3423351a5 2017-10-06)'] AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo check --target-dir ' . ale#Escape('target/ale') . g:suffix, \] Execute(`cargo --target-dir` should not be used when the version is not new enough and it is set): let b:ale_rust_cargo_target_dir = 'target/ale' GivenCommandOutput ['cargo 0.16.0 (3423351a5 2017-10-06)'] AssertLinter 'cargo', [ \ ale#Escape('cargo') . ' --version', \ 'cargo build' . g:suffix, \] ================================================ FILE: test/linter/test_checkmake.vader ================================================ Before: Save g:ale_make_checkmake_config let g:ale_make_checkmake_config = '' call ale#assert#SetUpLinterTest('make', 'checkmake') " NOTE: the format string must be manually matched that set in the plugin let b:format = '"{{.LineNumber}}:{{.Rule}}:{{.Violation}}{{\"\r\n\"}}"' After: Restore unlet! b:command_tail unlet! b:ale_make_checkmake_config call ale#assert#TearDownLinterTest() Execute(checkmake should run with default format option): let b:command_tail = ' --format=' . b:format . ' %s' AssertLinter 'checkmake', 'checkmake' . b:command_tail Execute(checkmake command should take the config option if it is non-empty): let g:ale_make_checkmake_config = '/path to/checkmake.ini' let b:command_tail = ' --format=' . b:format \ . ' --config="' . g:ale_make_checkmake_config . '"' \ . ' %s' AssertLinter 'checkmake', 'checkmake' . b:command_tail Execute(the local buffer config option takes precedence over global option): let g:ale_make_checkmake_config = '/path/to/checkmake.ini' let b:ale_make_checkmake_config = '/another/checkmake.ini' let b:command_tail = ' --format=' . b:format \ . ' --config="' . b:ale_make_checkmake_config . '"' \ . ' %s' AssertLinter 'checkmake', 'checkmake' . b:command_tail ================================================ FILE: test/linter/test_checkov.vader ================================================ Before: call ale#assert#SetUpLinterTest('terraform', 'checkov') After: call ale#assert#TearDownLinterTest() Execute(The default command should be direct): AssertLinter 'checkov', \ ale#Escape('checkov') . ' -f %t -o json --quiet ' Execute(It should be possible to override the default command): let b:ale_terraform_checkov_executable = '/bin/other/checkov' AssertLinter '/bin/other/checkov', \ ale#Escape('/bin/other/checkov') . ' -f %t -o json --quiet ' ================================================ FILE: test/linter/test_checkstyle.vader ================================================ Before: call ale#assert#SetUpLinterTest('java', 'checkstyle') call ale#test#SetFilename('dummy.java') After: call ale#assert#TearDownLinterTest() Execute(The checkstyle callback should return the correct default value): AssertLinter 'checkstyle', \ ale#Escape('checkstyle') \ . ' -c ' . ale#Escape('/google_checks.xml') \ . ' %s' Execute(The checkstyle executable should be configurable): let b:ale_java_checkstyle_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') \ . ' -c ' . ale#Escape('/google_checks.xml') \ . ' %s' Execute(Custom options should be supported): let b:ale_java_checkstyle_options = '--foobar -cp -classpath /path/to/checkstyle-8.7-all.jar' AssertLinter 'checkstyle', \ ale#Escape('checkstyle') \ . ' --foobar -cp -classpath /path/to/checkstyle-8.7-all.jar' \ . ' -c ' . ale#Escape('/google_checks.xml') \ . ' %s' Execute(configuration files set in _config should be supported): let b:ale_java_checkstyle_config = ale#path#Simplify(g:dir . '/../test-files/checkstyle/other_config.xml') AssertLinter 'checkstyle', \ ale#Escape('checkstyle') \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/checkstyle/other_config.xml')) \ . ' %s' Execute(configuration files set in _options should be preferred over _config): let b:ale_java_checkstyle_config = '/foo.xml' let b:ale_java_checkstyle_options = '-c /bar.xml' AssertLinter 'checkstyle', ale#Escape('checkstyle') . ' -c /bar.xml %s' let b:ale_java_checkstyle_options = '-x -c /bar.xml' AssertLinter 'checkstyle', ale#Escape('checkstyle') . ' -x -c /bar.xml %s' Execute(google_checks.xml should be used by default): call ale#test#SetFilename('../test-files/checkstyle/test.java') AssertLinter 'checkstyle', \ ale#Escape('checkstyle') \ . ' -c ' . ale#Escape('/google_checks.xml') \ . ' %s' Execute(Other relative paths should be supported): let b:ale_java_checkstyle_config = '../test-files/checkstyle/other_config.xml' AssertLinter 'checkstyle', \ ale#Escape('checkstyle') \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/checkstyle/other_config.xml')) \ . ' %s' call ale#test#SetFilename('../test-files/checkstyle/test.java') let b:ale_java_checkstyle_config = 'other_config.xml' AssertLinter 'checkstyle', \ ale#Escape('checkstyle') \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/checkstyle/other_config.xml')) \ . ' %s' ================================================ FILE: test/linter/test_circleci.vader ================================================ Before: call ale#assert#SetUpLinterTest('yaml', 'circleci') After: call ale#assert#TearDownLinterTest() Execute(The linter should not run for every YAML file): AssertLinterNotExecuted Execute(The linter should for YAML files in a .circleci directory): call ale#test#SetFilename('../test-files/.circleci/config.yml') AssertLinter 'circleci', 'circleci --skip-update-check config validate - < %s' ================================================ FILE: test/linter/test_clang_tidy.vader ================================================ Before: Save g:ale_c_parse_makefile let g:ale_c_parse_makefile = 0 call ale#assert#SetUpLinterTest('cpp', 'clangtidy') call ale#test#SetFilename('test.cpp') After: call ale#assert#TearDownLinterTest() Execute(The clangtidy command default should be correct): 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-*'] AssertLinter 'clang-tidy', \ ale#Escape('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(You should be able to manually set flags for clang-tidy): let b:ale_cpp_clangtidy_extra_options = '-config=' AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') . ' ' . ale#Escape('-config=') . ' %s' 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') 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') Execute(The build directory should be used 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' \ . ' -p ' . ale#Escape('/foo/bar') call ale#test#SetFilename('test.hpp') AssertLinter 'clang-tidy', \ ale#Escape('clang-tidy') \ . ' -checks=' . ale#Escape('*') . ' %s' \ . ' -p ' . ale#Escape('/foo/bar') Execute(The executable should be configurable): let b:ale_cpp_clangtidy_checks = ['*'] let b:ale_cpp_clangtidy_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' -checks=' . ale#Escape('*') . ' %s' ================================================ FILE: test/linter/test_clj_kondo.vader ================================================ Before: call ale#assert#SetUpLinterTest('clojure', 'clj_kondo') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'clj-kondo', 'clj-kondo' \ . ' --cache --lint - --filename %s' Execute(Extra options should be supported): let g:ale_clojure_clj_kondo_options = '--config ./clj-kondo/config.edn' AssertLinter 'clj-kondo', 'clj-kondo' \ . ' --config ./clj-kondo/config.edn --lint - --filename %s' ================================================ FILE: test/linter/test_cloudformation_checkov.vader ================================================ Before: call ale#assert#SetUpLinterTest('cloudformation', 'checkov') After: call ale#assert#TearDownLinterTest() Execute(The default command should be direct): AssertLinter 'checkov', \ ale#Escape('checkov') . ' -f %t -o json --quiet --framework cloudformation ' Execute(It should be possible to override the default command): let b:ale_cloudformation_checkov_executable = '/bin/other/checkov' AssertLinter '/bin/other/checkov', \ ale#Escape('/bin/other/checkov') . ' -f %t -o json --quiet --framework cloudformation ' ================================================ FILE: test/linter/test_cmake_cmake_lint.vader ================================================ Before: call ale#assert#SetUpLinterTest('cmake', 'cmake_lint') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'cmake-lint', ale#Escape('cmake-lint') . ' %s' Execute(The executable should be configurable): let g:ale_cmake_cmake_lint_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' %s' ================================================ FILE: test/linter/test_cookstyle.vader ================================================ Before: call ale#assert#SetUpLinterTest('chef', 'cookstyle') After: call ale#assert#TearDownLinterTest() Execute(The default cookstyle command should be correct): AssertLinter 'cookstyle', ale#Escape('cookstyle') . ' --force-exclusion --format json --stdin %s' Execute(The cookstyle executable and options should be configurable): let b:ale_chef_cookstyle_executable = 'foobar' let b:ale_chef_cookstyle_options = '--parallel' AssertLinter 'foobar', ale#Escape('foobar') . ' --parallel --force-exclusion --format json --stdin %s' ================================================ FILE: test/linter/test_cpp_cc.vader ================================================ Before: Save g:ale_c_parse_makefile Save g:ale_history_enabled let g:ale_c_parse_makefile = 0 let g:ale_history_enabled = 0 let g:get_cflags_return_value = '' let g:executable_map = {} runtime autoload/ale/c.vim runtime autoload/ale/engine.vim function! ale#engine#IsExecutable(buffer, executable) abort return has_key(g:executable_map, a:executable) endfunction function! ale#c#GetCFlags(buffer, output) abort return g:get_cflags_return_value endfunction call ale#assert#SetUpLinterTest('cpp', 'cc') let b:command_tail = ' -S -x c++' \ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -iquote %s:h' \ . ' -std=c++14 -Wall -' After: unlet! g:get_cflags_return_value unlet! g:executable_map unlet! b:command_tail runtime autoload/ale/c.vim runtime autoload/ale/engine.vim call ale#assert#TearDownLinterTest() Execute(clang++ should be used instead of gcc, if available): let g:executable_map = {'clang++': 1} AssertLinter 'clang++', [ale#Escape('clang++') . b:command_tail] Execute(The executable should be configurable): AssertLinter 'gcc', [ale#Escape('gcc') . b:command_tail] let b:ale_cpp_cc_executable = 'foobar' AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail] Execute(The -std flag should be replaced by parsed C flags): let b:command_tail = substitute(b:command_tail, 'c++14', 'c++11 ', '') let g:get_cflags_return_value = '-std=c++11' AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(gcc should not use -x c++-header with header files by default): call ale#test#SetFilename('../test-files/c/hpp_file_project/test.hpp') AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(clang++ should use -x c++-header with header files by default): let g:executable_map = {'clang++': 1} let b:command_tail = substitute(b:command_tail, '-x c++', '-x c++-header', '') call ale#test#SetFilename('../test-files/c/hpp_file_project/test.hpp') AssertLinter 'clang++', ale#Escape('clang++') . b:command_tail Execute(gcc should use -x c-header with header files if configured to do so): let b:ale_cpp_cc_use_header_lang_flag = 1 let b:command_tail = substitute(b:command_tail, '-x c++', '-x c++-header', '') call ale#test#SetFilename('../test-files/c/hpp_file_project/test.hpp') AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail Execute(clang should not use -x c-header with header files if configured to do so): let g:executable_map = {'clang++': 1} let b:ale_cpp_cc_use_header_lang_flag = 0 call ale#test#SetFilename('../test-files/c/hpp_file_project/test.hpp') AssertLinter 'clang++', ale#Escape('clang++') . b:command_tail Execute(The header file extensions should be configurable): let g:executable_map = {'clang++': 1} let b:command_tail = substitute(b:command_tail, '-x c++', '-x c++-header', '') call ale#assert#SetUpLinterTest('cpp', 'cc') let b:ale_cpp_cc_header_exts = ['json'] call ale#test#SetFilename('../test-files/c/json_project/build/compile_commands.json') AssertLinter 'clang++', ale#Escape('clang++') . b:command_tail ================================================ FILE: test/linter/test_cpp_ccls.vader ================================================ " Author: Ye Jingchen , Ben Falconer " Description: A language server for C++ Before: call ale#assert#SetUpLinterTest('cpp', 'ccls') Save b:ale_c_build_dir_names Save b:ale_cpp_ccls_executable Save b:ale_cpp_ccls_init_options After: call ale#assert#TearDownLinterTest() Execute(The project root should be detected correctly using compile_commands.json file): call ale#test#SetFilename(tempname() . '/dummy.cpp') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_compile_commands_json/dummy.cpp') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/with_compile_commands_json') Execute(The project root should be detected correctly using .ccls file): call ale#test#SetFilename(tempname() . '/dummy.cpp') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_ccls/dummy.cpp') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/with_ccls') Execute(The project root should be detected correctly using .ccls-root file): call ale#test#SetFilename(tempname() . '/dummy.cpp') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_ccls-root/dummy.cpp') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/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' } Execute(The compile command database should be detected correctly): call ale#test#SetFilename('../test-files/ccls/with_ccls/dummy.c') AssertLSPOptions {} call ale#test#SetFilename('../test-files/ccls/with_compile_commands_json/dummy.c') AssertLSPOptions { 'compilationDatabaseDirectory': \ ale#path#Simplify(g:dir . '/../test-files/ccls/with_compile_commands_json') } call ale#test#SetFilename('../test-files/ccls/with_build_dir/dummy.c') let b:ale_c_build_dir_names = ['unusual_build_dir_name'] AssertLSPOptions { 'compilationDatabaseDirectory': \ ale#path#Simplify(g:dir . '/../test-files/ccls/with_build_dir/unusual_build_dir_name') } ================================================ FILE: test/linter/test_cpp_clangcheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('cpp', 'clangcheck') After: call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'clang-check', \ ale#Escape('clang-check') \ . ' -analyze %s --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics' let b:ale_cpp_clangcheck_executable = 'foobar' " The extra arguments in the command are used to prevent .plist files from " being generated. AssertLinter 'foobar', \ ale#Escape('foobar') \ . ' -analyze %s --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics' Execute(The options should be configurable): let b:ale_cpp_clangcheck_options = '--something' AssertLinter 'clang-check', \ ale#Escape('clang-check') \ . ' -analyze %s' \ . ' --extra-arg=-Xclang --extra-arg=-analyzer-output=text --extra-arg=-fno-color-diagnostics' \ . ' --something' Execute(The build directory should be used when set): let b:ale_cpp_clangcheck_options = '--something' let b:ale_c_build_dir = '/foo/bar' AssertLinter 'clang-check', \ ale#Escape('clang-check') \ . ' -analyze %s --something -p ' . ale#Escape('/foo/bar') ================================================ FILE: test/linter/test_cpp_clazy.vader ================================================ 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 used 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') . ' -p ' . ale#Escape('/foo/bar') . ' %s' call ale#test#SetFilename('test.hpp') AssertLinter 'clazy-standalone', \ ale#Escape('clazy-standalone') \ . ' -checks=' . ale#Escape('level1') . ' -p ' . ale#Escape('/foo/bar') . ' %s' Execute(The executable should be configurable): let b:ale_cpp_clazy_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' -checks=' . ale#Escape('level1') . ' %s' ================================================ FILE: test/linter/test_cpp_cppcheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('cpp', 'cppcheck') let b:command_tail = ' -q --language=c++ --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') . ' --enable=style -I' . ale#Escape(ale#path#Simplify(g:dir)) .' %t' After: " Remove a test file we might open for some tests. if &buftype != 'nofile' set nomodified set buftype=nofile endif unlet! b:rel_file_path unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'cppcheck', ale#Escape('cppcheck') . b:command_tail let b:ale_cpp_cppcheck_executable = 'foobar' AssertLinterCwd '' AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail Execute(cppcheck for C++ should detect compile_commands.json files): let b:rel_file_path = '../test-files/cppcheck/one/foo.cpp' call ale#test#SetFilename(b:rel_file_path) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/cppcheck/one') AssertLinter 'cppcheck', ale#Escape('cppcheck') \ . ' -q --language=c++' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --project=' . ale#Escape('compile_commands.json') \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --enable=style' Execute(cppcheck for C++ should detect compile_commands.json files in build directories): let b:rel_file_path = '../test-files/cppcheck/with_build_dir/foo.cpp' call ale#test#SetFilename(b:rel_file_path) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/cppcheck/with_build_dir') AssertLinter 'cppcheck', ale#Escape('cppcheck') \ . ' -q --language=c++' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --project=' . ale#Escape(ale#path#Simplify('build/compile_commands.json')) \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --enable=style' Execute(cppcheck for C++ should include file dir if compile_commands.json file is not found): call ale#test#SetFilename('../test-files/cppcheck/foo.cpp') AssertLinter 'cppcheck', \ ale#Escape('cppcheck') \ . ' -q --language=c++' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --enable=style' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cppcheck')) \ . ' %t' Execute(cppcheck for C++ header should include file dir and not use compile_commands.json): call ale#test#SetFilename('../test-files/cppcheck/one/foo.hpp') AssertLinter 'cppcheck', \ ale#Escape('cppcheck') \ . ' -q --language=c++' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cppcheck/one')) \ . ' --suppress=unusedStructMember' \ . ' --enable=style' \ . ' %t' Execute(cppcheck for C++ should ignore compile_commands.json file if buffer is modified): call ale#test#SetFilename('../test-files/cppcheck/one/foo.cpp') set buftype= set modified AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/cppcheck/one') AssertLinter 'cppcheck', ale#Escape('cppcheck') \ . ' -q --language=c++' \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --enable=style' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cppcheck/one')) \ . ' %t' ================================================ FILE: test/linter/test_cpp_cquery.vader ================================================ " Author: Ben Falconer " Description: A language server for C++ Before: call ale#assert#SetUpLinterTest('cpp', 'cquery') After: call ale#assert#TearDownLinterTest() Execute(The project root should be detected correctly using compile_commands.json file): call ale#test#SetFilename(tempname() . '/dummy.cpp') AssertLSPProject '' call ale#test#SetFilename('../test-files/cquery/dummy.cpp') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/cquery') Execute(The project root should be detected correctly using .cquery file): call ale#test#SetFilename(tempname() . '/dummy.cpp') AssertLSPProject '' call ale#test#SetFilename('../test-files/cquery/with_cquery/dummy.cpp') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/cquery/with_cquery') Execute(The executable should be configurable): AssertLinter 'cquery', ale#Escape('cquery') let b:ale_cpp_cquery_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') Execute(The cache directory should be configurable): AssertLSPOptions {'cacheDirectory': expand('$HOME/.cache/cquery')} let b:ale_cpp_cquery_cache_directory = '/foo/bar' AssertLSPOptions {'cacheDirectory': '/foo/bar'} ================================================ FILE: test/linter/test_cpp_flawfinder.vader ================================================ Before: call ale#assert#SetUpLinterTest('cpp', 'flawfinder') After: call ale#assert#TearDownLinterTest() Execute(The flawfinder command should be correct): AssertLinter 'flawfinder', \ ale#Escape('flawfinder') . ' -CDQS --minlevel=1 %t' Execute(The minlevel of flawfinder should be configurable): let b:ale_cpp_flawfinder_minlevel = 8 AssertLinter 'flawfinder', \ ale#Escape('flawfinder') . ' -CDQS --minlevel=8 %t' Execute(Additional flawfinder options should be configurable): let b:ale_cpp_flawfinder_options = ' --foobar' AssertLinter 'flawfinder', \ ale#Escape('flawfinder') . ' -CDQS --foobar --minlevel=1 %t' Execute(The flawfinder executable should be configurable): let b:ale_cpp_flawfinder_executable = 'foo/bar' AssertLinter 'foo/bar', ale#Escape('foo/bar') . ' -CDQS --minlevel=1 %t' ================================================ FILE: test/linter/test_cpplint.vader ================================================ Before: call ale#assert#SetUpLinterTest('cpp', 'cpplint') After: call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'cpplint', ale#Escape('cpplint') . ' %s' let b:ale_cpp_cpplint_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' %s' Execute(The options should be configurable): let b:ale_cpp_cpplint_options = '--something' AssertLinter 'cpplint', ale#Escape('cpplint') . ' --something %s' ================================================ FILE: test/linter/test_cs_csc.vader ================================================ Before: call ale#assert#SetUpLinterTest('cs', 'csc') After: call ale#assert#TearDownLinterTest() Execute(The csc linter should return the correct default command): AssertLinterCwd expand('%:p:h') AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') Execute(The options should be be used in the command): let g:ale_cs_csc_options = '' AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') Execute(The source path should be be used in the command): let g:ale_cs_csc_source = '../foo/bar' AssertLinterCwd '../foo/bar' AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') Execute(The list of search paths for assemblies should be be used in the command if not empty): let g:ale_cs_csc_assembly_path = ['/usr/lib/mono', '../foo/bar'] AssertLinter 'csc', 'csc /unsafe' \ . ' /lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar') \ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') let g:ale_cs_csc_assembly_path = [] AssertLinter 'csc', 'csc /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_csc_assemblies = ['foo.dll', 'bar.dll'] AssertLinter 'csc', 'csc /unsafe' \ . ' /r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll') \ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') let g:ale_cs_csc_assemblies = [] AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') ================================================ FILE: test/linter/test_cs_mcs.vader ================================================ Before: call ale#assert#SetUpLinterTest('cs', 'mcs') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'mcs', 'mcs -unsafe --parse %t' Execute(The options should be be used in the command): let b:ale_cs_mcs_options = '-pkg:dotnet' AssertLinter 'mcs', 'mcs -unsafe --parse -pkg:dotnet %t' ================================================ FILE: test/linter/test_cs_mcsc.vader ================================================ Before: call ale#assert#SetUpLinterTest('cs', 'mcsc') After: call ale#assert#TearDownLinterTest() Execute(The mcsc linter should return the correct default command): AssertLinterCwd expand('%:p:h') AssertLinter 'mcs', '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', 'mcs -unsafe -pkg:dotnet -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') Execute(The source path should be be used in the command): let g:ale_cs_mcsc_source = '../foo/bar' AssertLinterCwd '../foo/bar' AssertLinter 'mcs', 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') Execute(The list of search paths 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', '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', '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', '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', 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') ================================================ FILE: test/linter/test_cspell.vader ================================================ Before: call ale#assert#SetUpLinterTest('tex', 'cspell') " We have to manually do our own variable reset because SetUpLinterTest calls " ale#assert#ResetVariables, which specifically only resets variables that " begin with ale__, per https://github.com/dense-analysis/ale/blob/76c2293e68a6cad3b192062743d25b8daa082205/autoload/ale/assert.vim#L256 " " Took a lot of debugging and reading both junegunn/vader.vim and most ALE " files to find this behavior Save g:ale_cspell_executable Save g:ale_cspell_use_global Save g:ale_cspell_options unlet! g:ale_cspell_executable unlet! g:ale_cspell_use_global unlet! g:ale_cspell_options let g:ale_cspell_executable = 'cspell' let g:ale_cspell_use_global = 0 let g:ale_cspell_options = '' set filetype=tex After: call ale#assert#TearDownLinterTest() Execute(The global executable should be used when the local one cannot be found): AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="latex" -- stdin' Execute(Should use the node_modules/.bin executable if available): call ale#test#SetFilename('../test-files/cspell/node-modules/test.tex') AssertLinter \ ale#path#Simplify(g:dir \ . '/../test-files/cspell/node-modules/node_modules/.bin/cspell'), \ ale#Escape(ale#path#Simplify(g:dir \ . '/../test-files/cspell/node-modules/node_modules/.bin/cspell')) \ . ' lint --no-color --no-progress --no-summary --language-id="latex" -- stdin' Execute(Should use the node_modules/cspell executable if available): call ale#test#SetFilename('../test-files/cspell/node-modules-2/test.tex') AssertLinter \ ale#path#Simplify(g:dir \ . '/../test-files/cspell/node-modules-2/node_modules/cspell/bin.js'), \ (has('win32') ? 'node.exe ': '') \ . ale#Escape(ale#path#Simplify(g:dir \ . '/../test-files/cspell/node-modules-2/node_modules/cspell/bin.js')) \ . ' lint --no-color --no-progress --no-summary --language-id="latex" -- stdin' Execute(Should let users configure a global executable and override local paths): let g:ale_cspell_executable = '/path/to/custom/cspell' let g:ale_cspell_use_global = 1 AssertLinter \ '/path/to/custom/cspell', \ ale#Escape('/path/to/custom/cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="latex" -- stdin' Execute(Additional cspell options should be configurable): call ale#test#SetFilename('../test-files/dummy') let g:ale_cspell_options = '--foobar' AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="latex" --foobar -- stdin' Execute(The language id should be tex when filetype is plaintex): set filetype=plaintex AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="tex" -- stdin' Execute(The language id should be equal to filetype when not tex or plaintex): set filetype=markdown AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="markdown" -- stdin' set filetype=asciidoc AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="asciidoc" -- stdin' set filetype=html AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary --language-id="html" -- stdin' Execute(The language id should not specified when filetype is empty): set filetype= AssertLinter \ 'cspell', \ ale#Escape('cspell') \ . ' lint --no-color --no-progress --no-summary -- stdin' ================================================ FILE: test/linter/test_css_csslint.vader ================================================ Before: call ale#assert#SetUpLinterTest('css', 'csslint') After: call ale#assert#TearDownLinterTest() Execute(--config should be set when the .csslintrc file is found): call ale#test#SetFilename('../test-files/csslint/some-app/subdir/testfile.js') AssertLinter 'csslint', 'csslint --format=compact ' \ . '--config=' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/csslint/some-app/.csslintrc')) \ . ' %t' Execute(--config should not be used when no .csslintrc file exists): call ale#test#SetFilename('../test-files/csslint/other-app/testfile.css') AssertLinter 'csslint', 'csslint --format=compact %t' ================================================ FILE: test/linter/test_css_stylelint.vader ================================================ Before: call ale#assert#SetUpLinterTest('css', 'stylelint') unlet! b:executable After: unlet! b:executable call ale#assert#TearDownLinterTest() Execute(node_modules directories should be discovered): call ale#test#SetFilename('../test-files/stylelint/nested/testfile.css') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/stylelint/node_modules/.bin/stylelint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --no-color --stdin-filename %s' Execute(The global override should work): let b:ale_css_stylelint_executable = 'foobar' let b:ale_css_stylelint_use_global = 1 call ale#test#SetFilename('../test-files/stylelint/nested/testfile.css') AssertLinter 'foobar', ale#Escape('foobar') . ' --no-color --stdin-filename %s' Execute(Extra options should be configurable): call ale#test#SetFilename('../test-files/dummy') let b:ale_css_stylelint_options = '--configFile ''/absolute/path/to/file''' AssertLinter 'stylelint', \ ale#Escape('stylelint') . ' --configFile ''/absolute/path/to/file'' --no-color --stdin-filename %s' ================================================ FILE: test/linter/test_cucumber.vader ================================================ Before: call ale#assert#SetUpLinterTest('cucumber', 'cucumber') After: call ale#assert#TearDownLinterTest() Execute(Should require the nearest features dir, if one is found): call ale#test#SetFilename('../test-files/cucumber/features/cuke.feature') AssertLinter 'cucumber', \ 'cucumber --dry-run --quiet --strict --format=json ' \ . '-r ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/cucumber/features/')) . ' %t' Execute(Should require nothing if no features dir is found): call ale#test#SetFilename('something/without/a/features/dir') AssertLinter 'cucumber', \ 'cucumber --dry-run --quiet --strict --format=json %t' ================================================ FILE: test/linter/test_cuda_nvcc.vader ================================================ Before: call ale#assert#SetUpLinterTest('cuda', 'nvcc') After: call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'nvcc', \ ale#Escape('nvcc') . ' -cuda -std=c++11 %s -o ' . g:ale#util#nul_file let b:ale_cuda_nvcc_executable = 'foobar' 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 ================================================ FILE: test/linter/test_cypher_lint.vader ================================================ Before: call ale#assert#SetUpLinterTest('cypher', 'cypher_lint') After: call ale#assert#TearDownLinterTest() Execute(The default command and executable should be correct): AssertLinter 'cypher-lint', 'cypher-lint' ================================================ FILE: test/linter/test_d_dls.vader ================================================ 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' ================================================ FILE: test/linter/test_dart_analysis_server.vader ================================================ Before: call ale#assert#SetUpLinterTest('dart', 'analysis_server') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'dart', ale#Escape('dart') \ . ' language-server --protocol=lsp' Execute(The executable should be configurable): let g:ale_dart_analysis_server_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') \ . ' language-server --protocol=lsp' Execute(Should be able to disable new language-server command): let g:ale_dart_analysis_server_enable_language_server = 0 AssertLinter 'dart', ale#Escape('dart') \ . ' ./snapshots/analysis_server.dart.snapshot --lsp' ================================================ FILE: test/linter/test_dart_language_server.vader ================================================ 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') ================================================ FILE: test/linter/test_desktop_file_validate.vader ================================================ Before: call ale#assert#SetUpLinterTest('desktop', 'desktop_file_validate') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'desktop-file-validate', \ ale#Escape('desktop-file-validate') . ' %t' Execute(Extra options should work): let b:ale_desktop_desktop_file_validate_options = '--warn-kde' AssertLinter 'desktop-file-validate', \ ale#Escape('desktop-file-validate') . ' --warn-kde %t' ================================================ FILE: test/linter/test_dialyxir.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'dialyxir') call ale#test#SetFilename('../test-files/elixir/mix_project/lib/app.ex') After: call ale#assert#TearDownLinterTest() Execute(Builds dialyxir command with a normal project): AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/mix_project') AssertLinter 'mix', 'mix help dialyzer && mix dialyzer' Execute(Builds dialyxir command with an umbrella project): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/mix_project/lib/app.ex') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') AssertLinter 'mix', 'mix help dialyzer && mix dialyzer' ================================================ FILE: test/linter/test_djlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('html', 'djlint') After: call ale#assert#TearDownLinterTest() Execute(The default djlint command should be correct): AssertLinter 'djlint', ale#Escape('djlint') . ' %s' Execute(The executable should be configurable): let g:ale_html_djlint_executable = 'foo bar' let g:ale_html_djlint_options = '--option' AssertLinter 'foo bar', ale#Escape('foo bar') . ' --option %s' Execute(The --profile option should not be overridden): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=htmldjango let g:ale_html_djlint_options = '--profile jinja' AssertLinter 'djlint', ale#Escape(g:ale_html_djlint_executable) \ . ' --profile jinja' \ . ' %s', Execute(Should set --profile for htmlangular): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=htmlangular AssertLinter 'djlint', ale#Escape(g:ale_html_djlint_executable) \ . ' --profile angular' \ . ' %s', Execute(Should set --profile for jinja): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=jinja AssertLinter 'djlint', ale#Escape(g:ale_html_djlint_executable) \ . ' --profile jinja' \ . ' %s', Execute(Should set --profile for Handlebars): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=handlebars AssertLinter 'djlint', ale#Escape(g:ale_html_djlint_executable) \ . ' --profile handlebars' \ . ' %s', Execute(Should set --profile for nunjucks): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=nunjucks AssertLinter 'djlint', ale#Escape(g:ale_html_djlint_executable) \ . ' --profile nunjucks' \ . ' %s', Execute(Should set --profile for Go HTML Templates): call ale#test#SetFilename('../test-files/djlint/testfile.html') set filetype=gohtmltmpl AssertLinter 'djlint', ale#Escape(g:ale_html_djlint_executable) \ . ' --profile golang' \ . ' %s', ================================================ FILE: test/linter/test_dmd_commandline.vader ================================================ Before: runtime ale_linters/d/dmd.vim After: call ale#linter#Reset() Execute(DMD command line should be correct with imports): AssertEqual \ 'dmd ' . \ '-I' . ale#Escape('source') . ' ' . \ '-I' . ale#Escape('/prefix/include/d') . ' ' . \ '-I' . ale#Escape('/home/user/.dub/packages/pkg-0.0.1/pkg/src') . ' ' . \ ' ' . \ ' ' . \ ' ' . \ '-o- -wi -vcolumns -c %t', \ ale_linters#d#dmd#DMDCommand(bufnr(''), [ \ 'source', \ '/prefix/include/d', \ '/home/user/.dub/packages/pkg-0.0.1/pkg/src', \ '', \ '', \ '', \ '', \ '', \ '', \ ], {}) Execute(DMD command line should be correct with imports and version): AssertEqual \ 'dmd ' . \ '-I' . ale#Escape('source') . ' ' . \ '-I' . ale#Escape('/prefix/include/d') . ' ' . \ '-I' . ale#Escape('/home/user/.dub/packages/pkg-0.0.1/pkg/src') . ' ' . \ ' ' . \ '-version=' . ale#Escape('SOME_VERSION') . ' ' . \ ' ' . \ '-o- -wi -vcolumns -c %t', \ ale_linters#d#dmd#DMDCommand(bufnr(''), [ \ 'source', \ '/prefix/include/d', \ '/home/user/.dub/packages/pkg-0.0.1/pkg/src', \ '', \ '', \ '', \ 'SOME_VERSION', \ '', \ '', \ ], {}) Execute(DMD command line should be correct): AssertEqual \ 'dmd ' . \ '-I' . ale#Escape('source') . ' ' . \ '-I' . ale#Escape('/prefix/include/d') . ' ' . \ '-I' . ale#Escape('/home/user/.dub/packages/pkg-0.0.1/pkg/src') . ' ' . \ '-J' . ale#Escape('views') . ' ' . \ '-version=' . ale#Escape('SOME_VERSION') . ' ' . \ '-version=' . ale#Escape('SOME_OTHER_VERSION') . ' ' . \ '-debug=' . ale#Escape('SomeFeature') . ' ' . \ '-o- -wi -vcolumns -c %t', \ ale_linters#d#dmd#DMDCommand(bufnr(''), [ \ 'source', \ '/prefix/include/d', \ '/home/user/.dub/packages/pkg-0.0.1/pkg/src', \ '', \ 'views', \ '', \ 'SOME_VERSION', \ 'SOME_OTHER_VERSION', \ '', \ 'SomeFeature', \ ], {}) Execute(DMD command line should be correct with CR): " on windows, the function is called with carriage return AssertEqual \ 'dmd ' . \ '-I' . ale#Escape('source') . ' ' . \ '-I' . ale#Escape('C:\prefix\include\d') . ' ' . \ '-I' . ale#Escape('C:\Users\user\AppData\Local\Dub\packages\pkg-0.0.1\pkg\src') . ' ' . \ ' ' . \ ' ' . \ ' ' . \ '-o- -wi -vcolumns -c %t', \ ale_linters#d#dmd#DMDCommand(bufnr(''), [ \ "source\r", \ "C:\\prefix\\include\\d\r", \ "C:\\Users\\user\\AppData\\Local\\Dub\\packages\\pkg-0.0.1\\pkg\\src\r", \ "\r", \ "\r", \ "\r", \ "\r", \ "\r", \ "\r", \ ], {}) ================================================ FILE: test/linter/test_dockerfile_lint.vader ================================================ 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' ================================================ FILE: test/linter/test_dockerlinter.vader ================================================ Before: call ale#assert#SetUpLinterTest('dockerfile', 'dockerlinter') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'dockerlinter', ale#Escape('dockerlinter') . ' -j -f %t' Execute(The executable should be configurable): let b:ale_dockerfile_dockerlinter_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' -j -f %t' Execute(The options should be configurable): let b:ale_dockerfile_dockerlinter_options = '-r additional.yaml' AssertLinter 'dockerlinter', ale#Escape('dockerlinter') . ' -r additional.yaml -j -f %t' ================================================ FILE: test/linter/test_dogma.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'dogma') call ale#test#SetFilename('../test-files/elixir/mix_project/lib/app.ex') After: call ale#assert#TearDownLinterTest() Execute(Builds dogma command with a normal project): AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/mix_project') AssertLinter 'mix', 'mix help dogma && mix dogma %s --format=flycheck' Execute(Builds dogma command with an umbrella project): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/mix_project/lib/app.ex') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') AssertLinter 'mix', 'mix help dogma && mix dogma %s --format=flycheck' ================================================ FILE: test/linter/test_eclipselsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('java', 'eclipselsp') call ale#test#SetFilename('dummy.java') let b:ale_java_eclipselsp_path = '/home/user/eclipse.dst.ls' if has('win32') let b:cfg = ale#path#Simplify(g:dir . '/../config_win') elseif has('macunix') let b:cfg = ale#path#Simplify(g:dir . '/../config_mac') else let b:cfg = ale#path#Simplify(g:dir . '/../config_linux') endif After: unlet! b:ale_java_eclipselsp_path unlet! b:cfg call ale#assert#TearDownLinterTest() Execute(VersionCheck should return correct version): " OpenJDK Java 1.8 AssertEqual [1, 8, 0], ale_linters#java#eclipselsp#VersionCheck([ \ 'openjdk version "1.8.0_191"', \ 'OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-0ubuntu0.18.04.1-b12)', \ 'OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)' \]) " OpenJDK Java 10 AssertEqual [10, 0, 2], ale_linters#java#eclipselsp#VersionCheck([ \ 'openjdk version "10.0.2" 2018-07-17', \ 'OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)', \ 'OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4, mixed mode)' \]) " Oracle Java 1.8 AssertEqual [1, 8, 0], ale_linters#java#eclipselsp#VersionCheck([ \ 'java version "1.8.0_161"', \ 'Java(TM) SE Runtime Environment (build 1.8.0_161-b12)', \ 'Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)' \]) " Oracle Java 10 AssertEqual [10, 0, 1], ale_linters#java#eclipselsp#VersionCheck([ \ 'java version "10.0.1" 2018-04-17', \ 'Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10)', \ 'Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)' \]) AssertEqual [], ale_linters#java#eclipselsp#VersionCheck(['x']) AssertEqual [], ale_linters#java#eclipselsp#VersionCheck([]) Execute(The eclipselsp callback should return the correct default value): let cmd = [ ale#Escape('java'), \ '', \ '-Declipse.application=org.eclipse.jdt.ls.core.id1', \ '-Dosgi.bundles.defaultStartLevel=4', \ '-Declipse.product=org.eclipse.jdt.ls.core.product', \ '-Dlog.level=ALL', \ '-noverify', \ '-Xmx1G', \ '-jar', \ ale#Escape(''), \ '-configuration', \ ale#Escape(b:cfg), \ '-data', \ ale#Escape(ale#path#Simplify('')) \] AssertLinter 'java', join(cmd, ' ') Execute(The eclipselsp callback should allow custom executable): let b:ale_java_eclipselsp_executable='/bin/foobar' let cmd = [ ale#Escape('/bin/foobar'), \ '', \ '-Declipse.application=org.eclipse.jdt.ls.core.id1', \ '-Dosgi.bundles.defaultStartLevel=4', \ '-Declipse.product=org.eclipse.jdt.ls.core.product', \ '-Dlog.level=ALL', \ '-noverify', \ '-Xmx1G', \ '-jar', \ ale#Escape(''), \ '-configuration', \ ale#Escape(b:cfg), \ '-data', \ ale#Escape(ale#path#Simplify('')) \] AssertLinter '/bin/foobar', join(cmd, ' ') Execute(The eclipselsp callback should allow custom configuration path and javaagent): let b:ale_java_eclipselsp_config_path = '/home/config' let b:ale_java_eclipselsp_javaagent = '/home/lombok.jar /home/lombok2.jar' let cmd = [ ale#Escape('java'), \ ale#Escape('-javaagent:/home/lombok.jar'), \ ale#Escape('-javaagent:/home/lombok2.jar'), \ '-Declipse.application=org.eclipse.jdt.ls.core.id1', \ '-Dosgi.bundles.defaultStartLevel=4', \ '-Declipse.product=org.eclipse.jdt.ls.core.product', \ '-Dlog.level=ALL', \ '-noverify', \ '-Xmx1G', \ '-jar', \ ale#Escape(''), \ '-configuration', \ ale#Escape(ale#path#Simplify('/home/config')), \ '-data', \ ale#Escape(ale#path#Simplify('')) \] AssertLinter 'java', join(cmd, ' ') ================================================ FILE: test/linter/test_elixir_credo.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'credo') call ale#test#SetFilename('../test-files/elixir/mix_project/lib/app.ex') After: unlet! g:ale_elixir_credo_strict call ale#assert#TearDownLinterTest() Execute(Builds credo command with normal project): AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/mix_project') AssertLinter 'mix', \ 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s' Execute(Builds credo command with umbrella project): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/mix_project/lib/app.ex') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') AssertLinter 'mix', \ 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s' Execute(Builds credo command with --strict mode when set to 1): let g:ale_elixir_credo_strict = 1 AssertLinter 'mix', \ 'mix help credo && mix credo --strict --format=flycheck --read-from-stdin %s' Execute(Builds credo command with suggest mode by default): AssertLinter 'mix', \ 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s' Execute(Builds credo command with suggest mode when set to 0): let g:ale_elixir_credo_strict = 0 AssertLinter 'mix', \ 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s' Execute(Builds credo command with a custom config file): let g:ale_elixir_credo_config_file = '/home/user/custom_credo.exs' AssertLinter 'mix', \ 'mix help credo && mix credo suggest --config-file /home/user/custom_credo.exs --format=flycheck --read-from-stdin %s' ================================================ FILE: test/linter/test_elixir_expert.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'expert') After: call ale#assert#TearDownLinterTest() Execute(should set correct defaults): AssertLinter 'expert', ale#Escape('expert') Execute(The executable should be configurable): let b:ale_elixir_expert_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/app1/lib/app.ex') AssertLSPLanguage 'elixir' AssertLSPOptions {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') ================================================ FILE: test/linter/test_elixir_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'elixir_ls') After: call ale#assert#TearDownLinterTest() Execute(should set correct defaults): if has('win32') AssertLinter 'elixir-ls\language_server.bat', 'elixir-ls\language_server.bat' else AssertLinter 'elixir-ls/language_server.sh', 'elixir-ls/language_server.sh' endif Execute(should configure elixir-ls release location): let b:ale_elixir_elixir_ls_release = 'boo' if has('win32') AssertLinter 'boo\language_server.bat', 'boo\language_server.bat' else AssertLinter 'boo/language_server.sh', 'boo/language_server.sh' endif Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/app1/lib/app.ex') AssertLSPLanguage 'elixir' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') Execute(should accept configuration settings): AssertLSPConfig {} let b:ale_elixir_elixir_ls_config = {'elixirLS': {'dialyzerEnabled': v:false}} AssertLSPConfig {'elixirLS': {'dialyzerEnabled': v:false}} ================================================ FILE: test/linter/test_elixir_mix.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'mix') call ale#test#SetFilename('../test-files/elixir/mix_project/lib/app.ex') let g:env_prefix = ale#Env('MIX_BUILD_PATH', 'TEMP_DIR') After: unlet! g:env_prefix call ale#assert#TearDownLinterTest() Execute(The default mix command should be correct): AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/mix_project') AssertLinter 'mix', g:env_prefix . 'mix compile %s' Execute(Build mix commands with an umbrella root): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/mix_project/lib/app.ex') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') AssertLinter 'mix', g:env_prefix . 'mix compile %s' ================================================ FILE: test/linter/test_elm_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('elm', 'ls') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): call ale#test#SetFilename('../test-files/elm/newapp/src/Main.elm') AssertLinter 'elm-language-server', ale#Escape('elm-language-server') . ' --stdio' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/elm/newapp/src/Main.elm') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/elm/newapp') Execute(Should let users configure a global executable and override local paths): call ale#test#SetFilename('../test-files/elm/newapp/src/Main.elm') let g:ale_elm_ls_executable = '/path/to/custom/elm-language-server' let g:ale_elm_ls_use_global = 1 AssertLinter '/path/to/custom/elm-language-server', \ ale#Escape('/path/to/custom/elm-language-server') . ' --stdio' Execute(The language should be correct): AssertLSPLanguage 'elm' ================================================ FILE: test/linter/test_elm_make.vader ================================================ 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('../test-files/elm/newapp/src/Main.elm') let g:executable = ale#path#Simplify(g:dir . '/../test-files/elm/newapp/node_modules/.bin/elm') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elm/newapp') AssertLinter g:executable, \ ale#Escape(g:executable) . ' make --report=json --output=/dev/null %t' Execute(should get elm-test executable for test code with elm >= 0.19): call ale#test#SetFilename('../test-files/elm/newapp/tests/TestSuite.elm') let g:executable = ale#path#Simplify(g:dir . '/../test-files/elm/newapp/node_modules/.bin/elm-test') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elm/newapp') AssertLinter g:executable, \ ale#Escape(g:executable) . ' make --report=json --output=/dev/null --compiler ' \ . ale#path#Simplify(g:dir . '/../test-files/elm/newapp/node_modules/.bin/elm') . ' %t' Execute(should fallback to elm executable with elm >= 0.19): call ale#test#SetFilename('../test-files/elm/newapp-notests/tests/TestMain.elm') let g:executable = ale#path#Simplify(g:dir . '/../test-files/elm/newapp-notests/node_modules/.bin/elm') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elm/newapp-notests') AssertLinter g:executable, \ ale#Escape(g:executable) . ' make --report=json --output=/dev/null %t' Execute(should get plain elm executable for test code with elm < 0.19): call ale#test#SetFilename('../test-files/elm/oldapp/tests/TestSuite.elm') let g:executable = ale#path#Simplify(g:dir . '/../test-files/elm/oldapp/node_modules/.bin/elm') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elm/oldapp') 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('../test-files/elm/newapp/src/Main.elm') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elm/newapp') 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('../test-files/elm/newapp/src/Main.elm') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/elm/newapp') AssertLinter 'other-elm', \ ale#Escape('other-elm') . ' make --report=json --output=/dev/null %t' ================================================ FILE: test/linter/test_embertemplatelint.vader ================================================ Before: call ale#assert#SetUpLinterTest('handlebars', 'embertemplatelint') After: call ale#assert#TearDownLinterTest() Execute(Runs the right command for ember-template-lint >= 4.x): GivenCommandOutput ['4.0.0'] AssertLinter 'ember-template-lint', \ ale#Escape('ember-template-lint') . ' --format=json --filename %s' Execute(Runs the right command for ember-template-lint < 4.x): GivenCommandOutput ['3.14.0'] AssertLinter 'ember-template-lint', \ ale#Escape('ember-template-lint') . ' --json --filename %s' ================================================ FILE: test/linter/test_erb.vader ================================================ Before: call ale#assert#SetUpLinterTest('eruby', 'erb') After: call ale#assert#TearDownLinterTest() Execute(Executable should not contain any filter code by default): call ale#test#SetFilename('../test-files/ruby/not_a_rails_app/file.rb') AssertLinter 'erb', 'erb -P -T - -x %t | ruby -c' Execute(Executable should filter invalid eRuby when inside a Rails project): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/app/views/my_great_view.html.erb') AssertLinter 'erb', \ 'ruby -r erb -e ' . ale#Escape('puts ERB.new($stdin.read.gsub(%{<%=},%{<%}), trim_mode: %{-}).src') . '< %t | ruby -c' ================================================ FILE: test/linter/test_erblint.vader ================================================ Before: call ale#assert#SetUpLinterTest('eruby', 'erblint') call ale#test#SetFilename('dummy.html.erb') let g:ale_eruby_erblint_executable = 'erblint' let g:ale_eruby_erblint_options = '' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to erblint): AssertLinter 'erblint', ale#Escape('erblint') \ . ' --format json --stdin %s' Execute(Should be able to set a custom executable): let g:ale_eruby_erblint_executable = 'bin/erblint' AssertLinter 'bin/erblint' , ale#Escape('bin/erblint') \ . ' --format json --stdin %s' Execute(Setting bundle appends 'exec erblint'): let g:ale_eruby_erblint_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec erblint' \ . ' --format json --stdin %s' ================================================ FILE: test/linter/test_erlang_dialyzer.vader ================================================ Before: call ale#assert#SetUpLinterTest('erlang', 'dialyzer') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct.): AssertLinter 'dialyzer', \ ale#Escape('dialyzer') \ . ' -n --plt ' . ale#Escape(expand('$HOME/.dialyzer_plt')) \ . ' -Wunmatched_returns' \ . ' -Werror_handling' \ . ' -Wrace_conditions' \ . ' -Wunderspecs' \ . ' %s' Execute(The command should accept configured executable.): let b:ale_erlang_dialyzer_executable = '/usr/bin/dialyzer' AssertLinter '/usr/bin/dialyzer', \ ale#Escape('/usr/bin/dialyzer') \ . ' -n --plt ' . ale#Escape(expand('$HOME/.dialyzer_plt')) \ . ' -Wunmatched_returns' \ . ' -Werror_handling' \ . ' -Wrace_conditions' \ . ' -Wunderspecs' \ . ' %s' Execute(The command should accept configured options.): let b:ale_erlang_dialyzer_options = '-r ' . expand('$HOME') AssertLinter 'dialyzer', \ ale#Escape('dialyzer') \ . ' -n --plt ' . ale#Escape(expand('$HOME/.dialyzer_plt')) \ . ' -r ' . expand('$HOME') \ . ' %s' Execute(The command should accept configured PLT file.): let b:ale_erlang_dialyzer_plt_file = 'custom-plt' AssertLinter 'dialyzer', \ ale#Escape('dialyzer') \ . ' -n --plt ' . ale#Escape(expand('custom-plt')) \ . ' -Wunmatched_returns' \ . ' -Werror_handling' \ . ' -Wrace_conditions' \ . ' -Wunderspecs' \ . ' %s' ================================================ FILE: test/linter/test_erlang_elvis.vader ================================================ Before: call ale#assert#SetUpLinterTest('erlang', 'elvis') After: unlet! b:root call ale#assert#TearDownLinterTest() Execute(Default command should be correct): AssertLinter 'elvis', \ ale#Escape('elvis') . ' rock --output-format=parsable ' \ . ale#Escape(expand('%:.')) Execute(Executable should be configurable): let b:ale_erlang_elvis_executable = '/path/to/elvis' AssertLinter '/path/to/elvis', \ ale#Escape('/path/to/elvis') . ' rock --output-format=parsable ' \ . ale#Escape(expand('%:.')) Execute(Project root should be detected using elvis.config): let b:root = '../test-files/erlang/app_with_elvis_config' call ale#test#SetFilename(b:root . '/src/app.erl') AssertLinter 'elvis', \ ale#Escape('elvis') . ' rock --output-format=parsable ' \ . ale#Escape(ale#path#Simplify('src/app.erl')) AssertLinterCwd ale#test#GetFilename(b:root) Execute(Root of Rebar3 project should be detected): let b:root = '../test-files/erlang/rebar3_app' call ale#test#SetFilename(b:root . '/src/app.erl') AssertLinter 'elvis', \ ale#Escape('elvis') . ' rock --output-format=parsable ' \ . ale#Escape(ale#path#Simplify('src/app.erl')) AssertLinterCwd ale#test#GetFilename(b:root) call ale#test#SetFilename(b:root . '/_checkouts/dep/src/dep.erl') AssertLinter 'elvis', \ ale#Escape('elvis') . ' rock --output-format=parsable ' \ . ale#Escape(ale#path#Simplify('src/dep.erl')) AssertLinterCwd ale#test#GetFilename(b:root . '/_checkouts/dep') Execute(Root of Erlang.mk project should be detected): let b:root = '../test-files/erlang/erlang_mk_app' call ale#test#SetFilename(b:root . '/src/app.erl') AssertLinter 'elvis', \ ale#Escape('elvis') . ' rock --output-format=parsable ' \ . ale#Escape(ale#path#Simplify('src/app.erl')) AssertLinterCwd ale#test#GetFilename(b:root) ================================================ FILE: test/linter/test_erlang_erlang_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('erlang', 'erlang_ls') After: unlet! b:root call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'erlang_ls', \ ale#Escape('erlang_ls') . ' --log-level=' . ale#Escape('info') Execute(Executable should be configurable): let b:ale_erlang_erlang_ls_executable = '/path/to/erlang_ls' AssertLinter '/path/to/erlang_ls', \ ale#Escape('/path/to/erlang_ls') . ' --log-level=' . ale#Escape('info') Execute(Log level should be configurable): let b:ale_erlang_erlang_ls_log_level = 'debug' AssertLinter 'erlang_ls', \ ale#Escape('erlang_ls') . ' --log-level=' . ale#Escape('debug') Execute(Log directory should be configurable): let b:ale_erlang_erlang_ls_log_dir = '/path/to/logs' AssertLinter 'erlang_ls', \ ale#Escape('erlang_ls') \ . ' --log-dir=' . ale#Escape('/path/to/logs') \ . ' --log-level=' . ale#Escape('info') Execute(Project root should be detected using erlang_ls.config): let b:root = '../test-files/erlang/app_with_erlang_ls_config' call ale#test#SetFilename(b:root . '/src/app.erl') AssertLSPProject ale#test#GetFilename(b:root) call ale#test#SetFilename(b:root . '/_build/default/lib/dep/src/dep.erl') AssertLSPProject ale#test#GetFilename(b:root) call ale#test#SetFilename(b:root . '/deps/dep/src/dep.erl') AssertLSPProject ale#test#GetFilename(b:root) Execute(Root of Rebar3 project should be detected): let b:root = '../test-files/erlang/rebar3_app' call ale#test#SetFilename(b:root . '/src/app.erl') AssertLSPProject ale#test#GetFilename(b:root) call ale#test#SetFilename(b:root . '/_build/default/lib/dep/src/dep.erl') AssertLSPProject ale#test#GetFilename(b:root) call ale#test#SetFilename(b:root . '/_checkouts/dep/src/dep.erl') AssertLSPProject ale#test#GetFilename(b:root) Execute(Root of Erlang.mk project should be detected): let b:root = '../test-files/erlang/erlang_mk_app' call ale#test#SetFilename(b:root . '/src/app.erl') AssertLSPProject ale#test#GetFilename(b:root) call ale#test#SetFilename(b:root . '/deps/dep/src/dep.erl') AssertLSPProject ale#test#GetFilename(b:root) Execute(Root of kerl managed Erlang/OTP installation should be detected): let b:root = '../test-files/erlang/kerl_otp_root' call ale#test#SetFilename(b:root . '/lib/stdlib-4.1.1/array.erl') AssertLSPProject ale#test#GetFilename(b:root) ================================================ FILE: test/linter/test_erlang_erlc.vader ================================================ Before: call ale#assert#SetUpLinterTest('erlang', 'erlc') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct.): let g:cmd = ale_linters#erlang#erlc#GetCommand(bufnr('')) let g:regex = 'erlc.\+-o.\+%t' let g:matched = match(g:cmd, g:regex) " match returns -1 if not found AssertNotEqual \ g:matched, \ -1, \ 'Command error: expected [' . g:cmd . '] to match [' . g:regex . ']' Execute(The command should accept configured executable.): let b:ale_erlang_erlc_executable = '/usr/bin/erlc' let g:cmd = ale_linters#erlang#erlc#GetCommand(bufnr('')) let g:regex = '/usr/bin/erlc.\+-o.\+%t' let g:matched = match(g:cmd, g:regex) " match returns -1 if not found AssertNotEqual \ g:matched, \ -1, \ 'Command error: expected [' . g:cmd . '] to match [' . g:regex . ']' Execute(The command should accept configured options.): let b:ale_erlang_erlc_options = '-I include' let g:cmd = ale_linters#erlang#erlc#GetCommand(bufnr('')) let g:regex = 'erlc.\+-o.\+-I include.\+%t' let g:matched = match(g:cmd, g:regex) " match returns -1 if not found AssertNotEqual \ g:matched, \ -1, \ 'Command error: expected [' . g:cmd . '] to match [' . g:regex . ']' Execute(Linter should recognize OTP23 format.): let g:lines = ["t.erl:6: only association operators '=>' are allowed in map construction"] let g:output_text = ale_linters#erlang#erlc#Handle(bufnr(''), g:lines)[0].text let g:expected = "only association operators '=>' are allowed in map construction" AssertEqual \ g:output_text, \ g:expected, \ 'Command error: expected [' . g:output_text . '] to match [' . g:expected . ']' Execute(Linter should recognize OTP24 format.): let g:lines = ["t.erl:6:16: only association operators '=>' are allowed in map construction", \ "% 6| #{ a => A, b := B }.", \ "% | ^"] let g:output_text = ale_linters#erlang#erlc#Handle(bufnr(''), g:lines)[0].text let g:expected = "only association operators '=>' are allowed in map construction" AssertEqual \ g:output_text, \ g:expected, \ 'Command error: expected [' . g:output_text . '] to match [' . g:expected . ']' ================================================ FILE: test/linter/test_erlang_syntaxerl.vader ================================================ Before: call ale#assert#SetUpLinterTest('erlang', 'syntaxerl') After: call ale#assert#TearDownLinterTest() Execute (The default commands should be correct): AssertLinter 'syntaxerl', [ \ ale#Escape('syntaxerl') . ' -h', \ ale#Escape('syntaxerl') . ' %t', \] Execute (The executable should be configurable): let b:ale_erlang_syntaxerl_executable = '/path/to/syntaxerl' AssertLinter '/path/to/syntaxerl', [ \ ale#Escape('/path/to/syntaxerl') . ' -h', \ ale#Escape('/path/to/syntaxerl') . ' %t', \] Execute (The -b option should be used when available): GivenCommandOutput [ \ 'Syntax checker for Erlang (0.14.0)', \ 'Usage: syntaxerl [-d | --debug] ', \ ' syntaxerl <-h | --help>', \ ' -d, --debug Enable debug output', \ ' -h, --help Show this message', \] AssertLinter 'syntaxerl', [ \ ale#Escape('syntaxerl') . ' -h', \ ale#Escape('syntaxerl') . ' %t', \] GivenCommandOutput [ \ 'Syntax checker for Erlang (0.14.0)', \ 'Usage: syntaxerl [-b | --base ] [-d | --debug] ', \ ' syntaxerl <-h | --help>', \ ' -b, --base Set original filename', \ ' -d, --debug Enable debug output', \ ' -h, --help Show this message', \] AssertLinter 'syntaxerl', [ \ ale#Escape('syntaxerl') . ' -h', \ ale#Escape('syntaxerl') . ' -b %s %t', \] ================================================ FILE: test/linter/test_erubi.vader ================================================ Before: call ale#assert#SetUpLinterTest('eruby', 'erubi') After: call ale#assert#TearDownLinterTest() Execute(Executable should not contain any filter code by default): call ale#test#SetFilename('../test-files/ruby/not_a_rails_app/file.rb') AssertLinter 'ruby', [ \ 'ruby -r erubi/capture_end -e ' . ale#Escape('""'), \ 'ruby -r erubi/capture_end -e ' . ale#Escape('puts Erubi::CaptureEndEngine.new($stdin.read).src') . '< %t | ruby -c', \] Execute(Executable should filter invalid eRuby when inside a Rails project): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/app/views/my_great_view.html.erb') AssertLinter 'ruby', [ \ 'ruby -r erubi/capture_end -e ' . ale#Escape('""'), \ 'ruby -r erubi/capture_end -e ' . ale#Escape('puts Erubi::CaptureEndEngine.new($stdin.read.gsub(%{<%=},%{<%}), nil, %{-}).src') . '< %t | ruby -c', \] Execute(Command should be blank if the first command in the chain returns output): GivenCommandOutput [ \ "/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- erubi/capture_end (LoadError)", \ " from /usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'", \] AssertLinter 'ruby', [ \ 'ruby -r erubi/capture_end -e ' . ale#Escape('""'), \ '', \] ================================================ FILE: test/linter/test_erubis.vader ================================================ Before: call ale#assert#SetUpLinterTest('eruby', 'erubis') After: call ale#assert#TearDownLinterTest() Execute(Executable should not contain any filter code by default): call ale#test#SetFilename('../test-files/ruby/not_a_rails_app/file.rb') AssertLinter 'erubis', 'erubis -x %t | ruby -c' Execute(Executable should filter invalid eRuby when inside a Rails project): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/app/views/my_great_view.html.erb') AssertLinter 'erubis', \ 'ruby -r erubis -e ' . ale#Escape('puts Erubis::Eruby.new($stdin.read.gsub(%{<%=},%{<%})).src') . '< %t | ruby -c' ================================================ FILE: test/linter/test_eslint.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'eslint') runtime autoload/ale/handlers/eslint.vim let b:args = ' -f json --stdin --stdin-filename %s' After: unlet! b:args unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinterCwd '' AssertLinter 'eslint', ale#Escape('eslint') . b:args Execute(create-react-app directories should be detected correctly): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.js') let b:executable = ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint/react-app') AssertLinter b:executable, \ (has('win32') ? ale#Escape('node.exe') . ' ' : '') \ . ale#Escape(b:executable) . b:args Execute(use-global should override create-react-app detection): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.js') let g:ale_javascript_eslint_use_global = 1 let g:ale_javascript_eslint_executable = 'eslint_d' let b:executable = 'eslint_d' AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint/react-app') AssertLinter b:executable, ale#Escape(b:executable) . b:args Execute(other app directories should be detected correctly): call ale#test#SetFilename('../test-files/eslint/other-app/subdir/testfile.js') let b:executable = ale#path#Simplify(g:dir . '/../test-files/eslint/node_modules/.bin/eslint') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint') AssertLinter b:executable, ale#Escape(b:executable) . b:args Execute(use-global should override other app directories): call ale#test#SetFilename('../test-files/eslint/other-app/subdir/testfile.js') let g:ale_javascript_eslint_use_global = 1 let g:ale_javascript_eslint_executable = 'eslint_d' let b:executable = 'eslint_d' AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint') AssertLinter b:executable, ale#Escape(b:executable) . b:args Execute(eslint.js executables should be run with node on Windows): call ale#test#SetFilename('../test-files/eslint/react-app/subdir/testfile.js') let b:executable = ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint/react-app') AssertLinter b:executable, \ (has('win32') ? ale#Escape('node.exe') . ' ' : '') \ . ale#Escape(b:executable) . b:args Execute(eslint.js should be run from a containing project with node_modules): call ale#test#SetFilename('../test-files/eslint/react-app/subdir-with-package-json/testfile.js') let b:executable = ale#path#Simplify(g:dir . '/../test-files/eslint/react-app/node_modules/eslint/bin/eslint.js') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint/react-app') AssertLinter b:executable, \ (has('win32') ? ale#Escape('node.exe') . ' ' : '') \ . ale#Escape(b:executable) . b:args Execute(eslint.js should be run from a containing project with .yarn/sdks): call ale#test#SetFilename('../test-files/eslint/yarn2-app/subdir/testfile.js') let b:executable = ale#path#Simplify(g:dir . '/../test-files/eslint/yarn2-app/.yarn/sdks/eslint/bin/eslint.js') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint/yarn2-app') AssertLinter b:executable, \ (has('win32') ? ale#Escape('node.exe') . ' ' : '') \ . ale#Escape(b:executable) . b:args Execute(astro directories should be detected correctly): call ale#test#SetFilename('../test-files/eslint/astro-app/src/pages/index.astro') let b:executable = ale#path#Simplify(g:dir . '/../test-files/eslint/astro-app/node_modules/eslint/bin/eslint.js') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/eslint/astro-app') AssertLinter b:executable, \ (has('win32') ? ale#Escape('node.exe') . ' ' : '') \ . ale#Escape(b:executable) . b:args ================================================ FILE: test/linter/test_fecs.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'fecs') runtime autoload/ale/handlers/fecs.vim After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'fecs', ale#Escape('fecs') . ' check --colors=false --rule=true %t' ================================================ FILE: test/linter/test_flake8.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'flake8') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' GivenCommandOutput ['3.0.0'] After: unlet! b:executable unlet! b:bin_dir call ale#assert#TearDownLinterTest() Execute(The flake8 callbacks should return the correct default values): AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] " The version check should be cached. GivenCommandOutput [] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] " Try with older versions. call ale#semver#ResetVersionCache() GivenCommandOutput ['2.9.9'] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --format=default -', \] Execute(The option for disabling changing directories should work): let g:ale_python_flake8_change_directory = 'off' AssertLinterCwd ['', ''] call ale#semver#ResetVersionCache() AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] let g:ale_python_flake8_change_directory = 0 AssertLinterCwd [''] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] " Invalid options should be considered the same as turning the setting off. let g:ale_python_flake8_change_directory = 'xxx' AssertLinterCwd [''] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] Execute(The option for changing directory to project root should work): call ale#test#SetFilename('../test-files/python/namespace_package_tox/namespace/foo/bar.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) call ale#semver#ResetVersionCache() AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] Execute(The option for changing directory to file dir should work): let g:ale_python_flake8_change_directory = 'file' call ale#test#SetFilename('../test-files/python/namespace_package_tox/namespace/foo/bar.py') AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] let g:ale_python_flake8_change_directory = 1 AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] Execute(The flake8 command callback should let you set options): let g:ale_python_flake8_options = '--some-option' GivenCommandOutput ['3.0.4'] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --some-option' \ . ' --format=default --stdin-display-name %s -', \] call ale#semver#ResetVersionCache() GivenCommandOutput ['2.9.9'] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --some-option --format=default -', \] Execute(You should be able to set a custom executable and it should be escaped): call ale#test#SetFilename('../test-files/dummy') let g:ale_python_flake8_executable = 'executable with spaces' AssertLinterCwd ['%s:h', '%s:h'] call ale#semver#ResetVersionCache() AssertLinter 'executable with spaces', [ \ ale#Escape('executable with spaces') . ' --version', \ ale#Escape('executable with spaces') \ . ' --format=default' \ . ' --stdin-display-name %s -', \] Execute(The flake8 callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/flake8' \) AssertLinter b:executable, [ \ ale#Escape(b:executable) . ' --version', \ ale#Escape(b:executable) \ . ' --format=default' \ . ' --stdin-display-name %s -', \] Execute(FindProjectRoot should detect the project root directory for namespace package via Manifest.in): call ale#test#SetFilename('../test-files/python/namespace_package_manifest/namespace/foo/bar.py') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/python/namespace_package_manifest'), \ ale#python#FindProjectRoot(bufnr('')) Execute(FindProjectRoot should detect the project root directory for namespace package via setup.cf): call ale#test#SetFilename('../test-files/python/namespace_package_setup/namespace/foo/bar.py') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/python/namespace_package_setup'), \ ale#python#FindProjectRoot(bufnr('')) Execute(FindProjectRoot should ignore the location of pytest.ini): call ale#test#SetFilename('../test-files/python/namespace_package_pytest/namespace/foo/bar.py') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/python/namespace_package_pytest/namespace'), \ ale#python#FindProjectRoot(bufnr('')) Execute(FindProjectRoot should detect the project root directory for namespace package via tox.ini): call ale#test#SetFilename('../test-files/python/namespace_package_tox/namespace/foo/bar.py') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/python/namespace_package_tox'), \ ale#python#FindProjectRoot(bufnr('')) Execute(FindProjectRoot should detect the project root directory for non-namespace package): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir'), \ ale#python#FindProjectRoot(bufnr('')) " Some users currently run flake8 this way, so we should support it. Execute(Using `python -m flake8` should be supported for running flake8): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_flake8_executable = 'python' let g:ale_python_flake8_options = '-m flake8 --some-option' GivenCommandOutput ['2.9.9'] AssertLinter 'python', [ \ ale#Escape('python') . ' -m flake8 --version', \ ale#Escape('python') \ . ' -m flake8 --some-option --format=default -' \] call ale#semver#ResetVersionCache() " Leading spaces shouldn't matter let g:ale_python_flake8_options = ' -m flake8 --some-option' GivenCommandOutput ['2.9.9'] AssertLinter 'python', [ \ ale#Escape('python') . ' -m flake8 --version', \ ale#Escape('python') \ . ' -m flake8 --some-option --format=default -' \] Execute(Setting executable to 'pipenv' should append 'run flake8'): let g:ale_python_flake8_executable = 'path/to/pipenv' " FIXME: pipenv should check the version with flake8. GivenCommandOutput [] AssertLinter 'path/to/pipenv', \ 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('../test-files/python/pipenv/whatever.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -' Execute(Setting executable to 'poetry' should append 'run flake8'): let g:ale_python_flake8_executable = 'path/to/poetry' " FIXME: poetry should check the version with flake8. GivenCommandOutput [] AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run flake8 --format=default -' Execute(poetry is detected when python_flake8_auto_poetry is set): let g:ale_python_flake8_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) AssertLinter 'poetry', \ ale#Escape('poetry') . ' run flake8 --format=default --stdin-display-name %s -' Execute(uv is detected when python_flake8_auto_uv is set): let g:ale_python_flake8_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run flake8 --format=default --stdin-display-name %s -' ================================================ FILE: test/linter/test_flakehell.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'flakehell') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' GivenCommandOutput ['0.8.0'] After: unlet! b:executable unlet! b:bin_dir call ale#assert#TearDownLinterTest() Execute(The flakehell callbacks should return the correct default values): AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' --version', \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] " The version check should be cached. GivenCommandOutput [] AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] Execute(The option for disabling changing directories should work): let g:ale_python_flakehell_change_directory = 'off' AssertLinterCwd ['', ''] call ale#semver#ResetVersionCache() AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' --version', \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] let g:ale_python_flakehell_change_directory = 0 AssertLinterCwd [''] AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] " Invalid options should be considered the same as turning the setting off. let g:ale_python_flakehell_change_directory = 'xxx' AssertLinterCwd [''] AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] Execute(The option for changing directory to project root should work): call ale#test#SetFilename('../test-files/python/namespace_package_tox/namespace/foo/bar.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) call ale#semver#ResetVersionCache() AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' --version', \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] Execute(The option for changing directory to file dir should work): let g:ale_python_flakehell_change_directory = 'file' call ale#test#SetFilename('../test-files/python/namespace_package_tox/namespace/foo/bar.py') AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' --version', \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] let g:ale_python_flakehell_change_directory = 1 AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' lint --format=default --stdin-display-name %s -', \] Execute(The flakehell command callback should let you set options): let g:ale_python_flakehell_options = '--some-option' GivenCommandOutput ['0.8.0'] AssertLinter 'flakehell', [ \ ale#Escape('flakehell') . ' --version', \ ale#Escape('flakehell') . ' lint --some-option' \ . ' --format=default --stdin-display-name %s -', \] Execute(You should be able to set a custom executable and it should be escaped): let g:ale_python_flakehell_executable = 'executable with spaces' call ale#test#SetFilename('../test-files/dummy') AssertLinterCwd ['%s:h', '%s:h'] call ale#semver#ResetVersionCache() AssertLinter 'executable with spaces', [ \ ale#Escape('executable with spaces') . ' --version', \ ale#Escape('executable with spaces') \ . ' lint' \ . ' --format=default' \ . ' --stdin-display-name %s -', \] Execute(The flakehell callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/flakehell' \) AssertLinter b:executable, [ \ ale#Escape(b:executable) . ' --version', \ ale#Escape(b:executable) \ . ' lint' \ . ' --format=default' \ . ' --stdin-display-name %s -', \] " Some users currently run flakehell this way, so we should support it. Execute(Using `python -m flakehell` should be supported for running flakehell): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_flakehell_executable = 'python' let g:ale_python_flakehell_options = '--some-option' AssertLinter 'python', [ \ ale#Escape('python') . ' -m flakehell --version', \ ale#Escape('python') \ . ' -m flakehell lint --some-option --format=default --stdin-display-name %s -' \] call ale#semver#ResetVersionCache() " Leading spaces shouldn't matter let g:ale_python_flakehell_options = ' --some-option' AssertLinter 'python', [ \ ale#Escape('python') . ' -m flakehell --version', \ ale#Escape('python') \ . ' -m flakehell lint --some-option --format=default --stdin-display-name %s -' \] Execute(Setting executable to 'pipenv' should append 'run flakehell'): let g:ale_python_flakehell_executable = 'path/to/pipenv' " FIXME: pipenv should check the version with flakehell. GivenCommandOutput [] AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run flakehell lint --format=default -' Execute(Pipenv is detected when python_flakehell_auto_pipenv is set): let g:ale_python_flakehell_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run flakehell lint --format=default --stdin-display-name %s -' Execute(Setting executable to 'poetry' should append 'run flakehell'): let g:ale_python_flakehell_executable = 'path/to/poetry' " FIXME: poetry should check the version with flakehell. GivenCommandOutput [] AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run flakehell lint --format=default -' Execute(poetry is detected when python_flakehell_auto_poetry is set): let g:ale_python_flakehell_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) AssertLinter 'poetry', \ ale#Escape('poetry') . ' run flakehell lint --format=default --stdin-display-name %s -' Execute(uv is detected when python_flakehell_auto_uv is set): let g:ale_python_flakehell_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run flakehell lint --format=default --stdin-display-name %s -' ================================================ FILE: test/linter/test_flow.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'flow') After: call ale#assert#TearDownLinterTest() Execute(flow should return a command to run if a .flowconfig file exists): call ale#test#SetFilename('../test-files/flow/a/sub/dummy') AssertLinter 'flow', \ ale#Escape('flow') \ . ' check-contents --respect-pragma --json --from ale %s < %t' \ . (!has('win32') ? '; echo' : '') Execute(flow should not use the respect pragma argument if the option is off): call ale#test#SetFilename('../test-files/flow/a/sub/dummy') let b:ale_javascript_flow_use_respect_pragma = 0 AssertLinter 'flow', \ ale#Escape('flow') \ . ' check-contents --json --from ale %s < %t' \ . (!has('win32') ? '; echo' : '') Execute(flow should should not use --respect-pragma for old versions): call ale#test#SetFilename('../test-files/flow/a/sub/dummy') GivenCommandOutput [ \ 'Warning: `flow --version` is deprecated in favor of `flow version`', \ 'Flow, a static type checker for JavaScript, version 0.27.0', \] AssertLinter 'flow', [ \ ale#Escape('flow') . ' --version', \ ale#Escape('flow') \ . ' check-contents --json --from ale %s < %t' \ . (!has('win32') ? '; echo' : ''), \] Execute(flow should not return a command to run if no .flowconfig file exists): call ale#test#SetFilename('../test-files/flow/b/sub/dummy') AssertLinterNotExecuted ================================================ FILE: test/linter/test_foodcritic.vader ================================================ Before: call ale#assert#SetUpLinterTest('chef', 'foodcritic') After: call ale#assert#TearDownLinterTest() Execute(The default foodcritic command should be correct): AssertLinter 'foodcritic', ale#Escape('foodcritic') . ' %s' Execute(The foodcritic executable and options should be configurable): let b:ale_chef_foodcritic_executable = 'foobar' " Tides should be escaped let b:ale_chef_foodcritic_options = '-t ~F011' AssertLinter 'foobar', ale#Escape('foobar') . ' -t \~F011 %s' ================================================ FILE: test/linter/test_fortitude.vader ================================================ Before: call ale#assert#SetUpLinterTest('fortran', 'fortitude') After: call ale#assert#TearDownLinterTest() Execute(The default fortitude command should be correct): AssertLinter 'fortitude', ale#Escape('fortitude') \ . ' check --output-format json %s' Execute(fortitude should be configurable): let b:ale_fortran_fortitude_executable = 'custom-exe' let b:ale_fortran_fortitude_options = '--foobar' AssertLinter 'custom-exe', ale#Escape('custom-exe') \ . ' check --output-format json --foobar %s' ================================================ FILE: test/linter/test_fortran_fortls.vader ================================================ Before: call ale#assert#SetUpLinterTest('fortran', 'language_server') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'fortls', ale#Escape('fortls') Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/fortls-project/test.F90') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/fortls-project') Execute(The language should be correct): AssertLSPLanguage 'fortran' ================================================ FILE: test/linter/test_fsc.vader ================================================ Before: call ale#assert#SetUpLinterTest('scala', 'fsc') After: call ale#assert#TearDownLinterTest() Given scala(An empty Scala file): Execute(The default executable and command should be correct): AssertLinter 'fsc', ale#Escape('fsc') . ' -Ystop-after:parser %t' Given scala.sbt(An empty SBT file): Execute(fsc should not be run for sbt files): AssertLinterNotExecuted ================================================ FILE: test/linter/test_fusionlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('fuse', 'fusionlint') After: call ale#assert#TearDownLinterTest() Execute(The fuse fusionlint command callback should return the correct default string): AssertLinter 'fusion-lint', ale#Escape('fusion-lint') . ' --filename %s -i' Execute(The fuse fusionlint command callback should let you set options): let g:ale_fuse_fusionlint_options = '--example-option argument' AssertLinter 'fusion-lint', \ ale#Escape('fusion-lint') . ' --example-option argument --filename %s -i' Execute(The fusionlint executable should be configurable): let g:ale_fuse_fusionlint_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --filename %s -i' ================================================ FILE: test/linter/test_gawk.vader ================================================ Before: call ale#assert#SetUpLinterTest('awk', 'gawk') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'gawk', \ ale#Escape('gawk') . ' --source ' . ale#Escape('BEGIN { exit } END { exit 1 }') \ . ' --lint -f %t /dev/null' Execute(The executable should be configurable): let b:ale_awk_gawk_executable = '/other/gawk' AssertLinter '/other/gawk', \ ale#Escape('/other/gawk') . ' --source ' . ale#Escape('BEGIN { exit } END { exit 1 }') \ . ' --lint -f %t /dev/null' Execute(The options should be configurable): let b:ale_awk_gawk_executable = 'gawk' let b:ale_awk_gawk_options = '--lint=no-ext' AssertLinter 'gawk', \ ale#Escape('gawk') . ' --source ' . ale#Escape('BEGIN { exit } END { exit 1 }') \ . ' --lint --lint=no-ext -f %t /dev/null' ================================================ FILE: test/linter/test_gfortran.vader ================================================ Before: call ale#assert#SetUpLinterTest('fortran', 'gcc') After: call ale#assert#TearDownLinterTest() Execute(The default fortran gcc command should be correct): AssertLinter 'gcc', ale#Escape('gcc') . ' -S -x f95 -fsyntax-only -ffree-form -Wall -' Execute(The fortran gcc executable and command should be configurable): let g:ale_fortran_gcc_executable = 'gfortran' let g:ale_fortran_gcc_options = '-Wotherthings' AssertLinter 'gfortran', ale#Escape('gfortran') \ . ' -S -x f95 -fsyntax-only -ffree-form -Wotherthings -' Execute(The fortran gcc linter should allow you to use -ffixed-form): let g:ale_fortran_gcc_use_free_form = 0 AssertLinter 'gcc', ale#Escape('gcc') . ' -S -x f95 -fsyntax-only -ffixed-form -Wall -' ================================================ FILE: test/linter/test_ghdl.vader ================================================ Before: call ale#assert#SetUpLinterTest('vhdl', 'ghdl') After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'ghdl', ale#Escape('ghdl') . ' -s --std=08 %t' let b:ale_vhdl_ghdl_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' -s --std=08 %t' Execute(The options should be configurable): let b:ale_vhdl_ghdl_options = '--something' AssertLinter 'ghdl', ale#Escape('ghdl') . ' -s --something %t' ================================================ FILE: test/linter/test_gitlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('gitcommit', 'gitlint') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The gitlint callbacks should return the correct default values): AssertLinter 'gitlint', ale#Escape('gitlint') . ' lint' Execute(The gitlint executable should be configurable, and escaped properly): let g:ale_gitcommit_gitlint_executable = 'executable with spaces' AssertLinter 'executable with spaces', \ ale#Escape('executable with spaces') . ' lint' Execute(The gitlint command callback should let you set options): let g:ale_gitcommit_gitlint_options = '--some-option' AssertLinter 'gitlint', ale#Escape('gitlint') . ' --some-option lint' Execute(The gitlint callbacks shouldn't detect virtualenv directories where they don't exist): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/COMMIT_EDITMSG') AssertLinter 'gitlint', ale#Escape('gitlint') . ' lint' Execute(The gitlint callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/COMMIT_EDITMSG') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/gitlint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' lint' Execute(You should able able to use the global gitlint instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/COMMIT_EDITMSG') let g:ale_gitcommit_gitlint_use_global = 1 AssertLinter 'gitlint', ale#Escape('gitlint') . ' lint' ================================================ FILE: test/linter/test_gleam_gleamlsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('gleam', 'gleamlsp') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'gleam', ale#Escape('gleam') . ' lsp' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/gleam/gleam.toml') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/gleam') ================================================ FILE: test/linter/test_glslang.vader ================================================ Before: call ale#assert#SetUpLinterTest('glsl', 'glslang') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'glslangValidator', ale#Escape('glslangValidator') . ' -C %t' Execute(The executable should be configurable): let b:ale_glsl_glslang_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' -C %t' Execute(Options should work): let g:ale_glsl_glslang_options = '--test' AssertLinter 'glslangValidator', \ ale#Escape('glslangValidator') . ' --test -C %t' ================================================ FILE: test/linter/test_glslls.vader ================================================ Before: call ale#assert#SetUpLinterTest('glsl', 'glslls') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'glslls', ale#Escape('glslls') . ' --stdin' Execute(Executable should be configurable): let b:ale_glsl_glslls_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --stdin' Execute(Setting logfile should work): let b:ale_glsl_glslls_logfile = '/tmp/test.log' AssertLinter 'glslls', \ ale#Escape('glslls') . ' --verbose -l /tmp/test.log --stdin' ================================================ FILE: test/linter/test_gobuild.vader ================================================ Before: Save g:ale_go_go_executable call ale#assert#SetUpLinterTest('go', 'gobuild') After: call ale#assert#TearDownLinterTest() Execute(The default go test command should be correct): AssertLinterCwd '%s:h' AssertLinter 'go', ale#Escape('go') . ' test -c -o /dev/null ./' Execute(Go environment variables should be supported): let b:ale_go_go111module = 'on' AssertLinter 'go', ale#Env('GO111MODULE', 'on') \ . ale#Escape('go') . ' test -c -o /dev/null ./' unlet! b:ale_go_go111module Execute(The go test executable and options should be configurable): let g:ale_go_go_executable = 'foobar' let g:ale_go_gobuild_options = '--foo-bar' AssertLinter 'foobar', ale#Escape('foobar') \ . ' test --foo-bar -c -o /dev/null ./' ================================================ FILE: test/linter/test_gofmt.vader ================================================ Before: Save g:ale_go_go111module Save b:ale_go_go111module let b:ale_go_go111module = '' call ale#assert#SetUpLinterTest('go', 'gofmt') call ale#test#SetFilename('../test-files/go/testfile2.go') After: Restore unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The default gofmt command should be correct): AssertLinter 'gofmt', \ ale#Escape('gofmt') . ' -e %t' Execute(The gofmt command should support Go environment variables): let b:ale_go_go111module = 'on' AssertLinter 'gofmt', \ ale#Env('GO111MODULE', 'on') \ . ale#Escape('gofmt') . ' -e %t' ================================================ FILE: test/linter/test_golangci_lint.vader ================================================ Before: Save g:ale_go_go111module call ale#assert#SetUpLinterTest('go', 'golangci_lint') call ale#test#SetFilename('test.go') " Test with version 1.64.8 by default GivenCommandOutput ['golangci-lint has version 1.64.8 built with go1.23.0'] After: Restore unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The golangci-lint defaults should be correct): AssertLinterCwd '%s:h', AssertLinter 'golangci-lint', \ ale#Escape('golangci-lint') . ' run --out-format=json --show-stats=0' Execute(The golangci-lint defaults should be correct with no version info): GivenCommandOutput [] AssertLinterCwd '%s:h', AssertLinter 'golangci-lint', \ ale#Escape('golangci-lint') . ' run --out-format=json --show-stats=0' Execute(The golangci-lint defaults should be correct with version 2): GivenCommandOutput ['golangci-lint has version 2.0.2 built with go1.24.0'] AssertLinterCwd '%s:h', AssertLinter 'golangci-lint', \ ale#Escape('golangci-lint') . ' run --output.json.path stdout --output.text.path stderr --show-stats=0' Execute(The golangci-lint callback should use a configured executable): let b:ale_go_golangci_lint_executable = 'something else' AssertLinter 'something else', \ ale#Escape('something else') \ . ' run --out-format=json --show-stats=0' Execute(The golangci-lint callback should use a configured version 2 executable): GivenCommandOutput ['golangci-lint has version 2.0.0 built with go1.22.0'] let b:ale_go_golangci_lint_executable = 'something else' AssertLinter 'something else', \ ale#Escape('something else') \ . ' run --output.json.path stdout --output.text.path stderr --show-stats=0' Execute(The golangci-lint callback should use configured options): let b:ale_go_golangci_lint_options = '--foobar' AssertLinter 'golangci-lint', \ ale#Escape('golangci-lint') \ . ' run ' \ . '--foobar ' \ . '--out-format=json ' \ . '--show-stats=0' Execute(The golangci-lint callback should support environment variables): let b:ale_go_go111module = 'on' AssertLinter 'golangci-lint', \ ale#Env('GO111MODULE', 'on') \ . ale#Escape('golangci-lint') \ . ' run ' \ . '--out-format=json ' \ . '--show-stats=0' Execute(The golangci-lint `lint_package` option should use the correct command): let b:ale_go_golangci_lint_package = 0 AssertLinter 'golangci-lint', \ ale#Escape('golangci-lint') \ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' --out-format=json --show-stats=0' ================================================ FILE: test/linter/test_golangserver.vader ================================================ Before: Save $GOPATH Save g:ale_completion_enabled Save g:ale_go_go111module let g:ale_completion_enabled = 0 let g:sep = has('win32') ? ';' : ':' call ale#assert#SetUpLinterTest('go', 'langserver') let $GOPATH = ale#path#Simplify(g:dir . '/../test-files/go/go1') \ . g:sep \ . ale#path#Simplify(g:dir . '/../test-files/go/go2') After: Restore unlet! b:ale_completion_enabled unlet! b:ale_go_go111module 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('../test-files/go/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('../test-files/go/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 support Go environment variables): let b:ale_go_go111module = 'on' AssertLinter 'go-langserver', \ ale#Env('GO111MODULE', 'on') . ale#Escape('go-langserver') Execute(should set go-langserver for go app1): call ale#test#SetFilename('../test-files/go/go1/prj1/file.go') AssertLSPLanguage 'go' AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/go/go1') Execute(should set go-langserver for go app2): call ale#test#SetFilename('../test-files/go/go2/prj1/file.go') AssertLSPLanguage 'go' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/go/go2') ================================================ FILE: test/linter/test_gopls.vader ================================================ Before: Save g:ale_go_go111module Save $GOPATH let $GOPATH = '/non/existent/directory' call ale#assert#SetUpLinterTest('go', 'gopls') After: if isdirectory(g:dir . '/.git') call delete(g:dir . '/.git', 'd') endif unlet! b:ale_go_go111module unlet! b:ale_go_go111module unlet! b:ale_completion_enabled call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'gopls', ale#Escape('gopls') . ' --mode stdio' Execute(The executable should be configurable): let b:ale_go_gopls_executable = 'boo' AssertLinter 'boo', ale#Escape('boo') . ' --mode stdio' Execute(gopls should be found in GOPATH): " This is a directory with a fake executable let $GOPATH = ale#test#GetFilename('../test-files/go/gopath') AssertLinter \ ale#test#GetFilename('../test-files/go/gopath/bin/gopls'), \ ale#Escape(ale#test#GetFilename('../test-files/go/gopath/bin/gopls')) \ . ' --mode stdio' Execute(Global settings should be preferre for gopls if use_global = 1): " This is a directory with a fake executable let $GOPATH = ale#test#GetFilename('../test-files/go/gopath') let b:ale_go_gopls_executable = 'boo' let b:ale_go_gopls_use_global = 1 AssertLinter 'boo', ale#Escape('boo') . ' --mode stdio' Execute(Settings options should work): call ale#test#SetFilename('../test-files/go/go1/prj1/file.go') " let b:ale_completion_enabled = 1 let b:ale_go_gopls_options = '' AssertLinter 'gopls', \ ale#Escape('gopls') . '' let b:ale_go_gopls_options = '--mode stdio --trace' AssertLinter 'gopls', \ ale#Escape('gopls') . ' --mode stdio --trace' let b:ale_go_gopls_init_options = {'ui.diagnostic.analyses': {'composites': v:false}} AssertLSPOptions {'ui.diagnostic.analyses': {'composites': v:false}} Execute(Go environment variables should be passed on): let b:ale_go_go111module = 'off' AssertLinter 'gopls', \ ale#Env('GO111MODULE', 'off') . ale#Escape('gopls') . ' --mode stdio' Execute(Project directories should be detected based on 'go.mod' being present): call ale#test#SetFilename('../test-files/go/test.go') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/go') Execute(Project directories with .git should be detected): call ale#test#SetFilename('test.go') if !isdirectory(g:dir . '/.git') call mkdir(g:dir . '/.git') endif AssertLSPProject g:dir Execute('go.mod' should be ignored if modules are off): call ale#test#SetFilename('../test-files/go/test.go') let b:ale_go_go111module = 'off' let b:parent_dir = ale#path#Simplify(g:dir . '/..') let b:git_dir = b:parent_dir . '/.git' if !isdirectory(b:git_dir) call mkdir(b:git_dir) endif AssertLSPProject b:parent_dir call delete(b:git_dir, 'd') unlet! b:parent_dir unlet! b:git_dir Execute(Init options should handle empty and non-empty values correctly): " Regression test for: Invalid settings: invalid options type []interface {} " This ensures empty init_options {} is passed as an object, not array call ale#test#SetFilename('../test-files/go/go1/prj1/file.go') " Test 1: Default empty dict AssertLSPOptions {} " Test 2: Explicitly set to empty let b:ale_go_gopls_init_options = {} AssertLSPOptions {} " Test 3: Non-empty options should be preserved let b:ale_go_gopls_init_options = { \ 'ui.diagnostic.analyses': {'composites': v:false}, \ 'completeUnimported': v:true \} AssertLSPOptions { \ 'ui.diagnostic.analyses': {'composites': v:false}, \ 'completeUnimported': v:true \} ================================================ FILE: test/linter/test_gosimple.vader ================================================ Before: Save g:ale_go_go111module call ale#assert#SetUpLinterTest('go', 'gosimple') call ale#test#SetFilename('../test-files/go/testfile2.go') After: unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The default gosimple command should be correct): AssertLinterCwd '%s:h' AssertLinter 'gosimple', 'gosimple .' Execute(The gosimple command should support Go environment variables): let b:ale_go_go111module = 'on' AssertLinter 'gosimple', ale#Env('GO111MODULE', 'on') . 'gosimple .' ================================================ FILE: test/linter/test_gotype.vader ================================================ Before: Save g:ale_go_go111module call ale#assert#SetUpLinterTest('go', 'gotype') call ale#test#SetFilename('../test-files/go/testfile2.go') After: unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The default gotype command should be correct): AssertLinterCwd '%s:h' AssertLinter 'gotype', 'gotype -e .' Execute(The gotype callback should ignore test files): call ale#test#SetFilename('bla_test.go') AssertLinterNotExecuted Execute(The gotype callback should support Go environment variables): let b:ale_go_go111module = 'on' AssertLinter 'gotype', ale#Env('GO111MODULE', 'on') . 'gotype -e .' ================================================ FILE: test/linter/test_govet.vader ================================================ Before: Save g:ale_go_go_executable Save g:ale_go_govet_options Save g:ale_go_go111module call ale#assert#SetUpLinterTest('go', 'govet') After: Restore unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The default go vet command should be correct): AssertLinter 'go', ale#Escape('go') . ' vet .' AssertLinterCwd '%s:h' Execute(The go vet command and options should be configurable): let g:ale_go_go_executable = 'foobar' let g:ale_go_govet_options = '--foo-bar' AssertLinter 'foobar', ale#Escape('foobar') . ' vet --foo-bar .' Execute(Go environment variables should be supported): let b:ale_go_go111module = 'on' AssertLinter 'go', ale#Env('GO111MODULE', 'on') . ale#Escape('go') . ' vet .' ================================================ FILE: test/linter/test_graphql_gqlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('graphql', 'gqlint') After: call ale#assert#TearDownLinterTest() Execute(The linter should run from the directory of the file in the buffer): AssertLinterCwd '%s:h' AssertLinter 'gqlint', 'gqlint --reporter=simple %t' ================================================ FILE: test/linter/test_hadolint.vader ================================================ Before: call ale#assert#SetUpLinterTest('dockerfile', 'hadolint') After: call ale#assert#TearDownLinterTest() Execute(We should not use Docker by default): AssertLinter 'hadolint', 'hadolint --no-color -' Execute(Options should be passed correctly when docker is disabled): let b:ale_dockerfile_hadolint_options = '--ignore DL3006' AssertLinter 'hadolint', 'hadolint --ignore DL3006 --no-color -' Execute(The command should be correct when using Docker): let b:ale_dockerfile_hadolint_use_docker = 'always' AssertLinter 'docker', 'docker run --rm -i hadolint/hadolint hadolint --no-color -' Execute(The command should be correct when using docker and supplying options): let b:ale_dockerfile_hadolint_use_docker = 'always' let b:ale_dockerfile_hadolint_options = '--ignore DL3006' AssertLinter 'docker', \ 'docker run --rm -i hadolint/hadolint hadolint --ignore DL3006 --no-color -' ================================================ FILE: test/linter/test_haml_hamllint.vader ================================================ Before: call ale#assert#SetUpLinterTest('haml', 'hamllint') let g:default_command = 'haml-lint %t' After: unlet! b:conf unlet! b:conf_hamllint unlet! b:conf_rubocop call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'haml-lint', 'haml-lint %t' Execute(The command should have the .rubocop.yml prepended as an env var if one exists): call ale#test#SetFilename('../test-files/hamllint/rubocop-yml/subdir/file.haml') let b:conf = ale#path#Simplify(g:dir . '/../test-files/hamllint/rubocop-yml/.rubocop.yml') AssertLinter 'haml-lint', \ ale#Env('HAML_LINT_RUBOCOP_CONF', b:conf) . 'haml-lint %t' Execute(The command should have the nearest .haml-lint.yml set as --config if it exists): call ale#test#SetFilename('../test-files/hamllint/haml-lint-yml/subdir/file.haml') let b:conf = ale#path#Simplify(g:dir . '/../test-files/hamllint/haml-lint-yml/.haml-lint.yml') AssertLinter 'haml-lint', \ 'haml-lint --config ' . ale#Escape(b:conf) . ' %t', Execute(The command should include a .rubocop.yml and a .haml-lint if both are found): call ale#test#SetFilename('../test-files/hamllint/haml-lint-and-rubocop/subdir/file.haml') let b:conf_hamllint = ale#path#Simplify(g:dir . '/../test-files/hamllint/haml-lint-and-rubocop/.haml-lint.yml') let b:conf_rubocop = ale#path#Simplify(g:dir . '/../test-files/hamllint/haml-lint-and-rubocop/.rubocop.yml') 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' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'bin/haml-lint', 'bin/haml-lint %t' ================================================ FILE: test/linter/test_haskell_cabal_ghc.vader ================================================ Before: call ale#assert#SetUpLinterTest('haskell', 'cabal_ghc') After: call ale#assert#TearDownLinterTest() Execute(The options should be used in the command): AssertLinterCwd '%s:h' AssertLinter 'cabal', 'cabal exec -- ghc -fno-code -v0 %t' let b:ale_haskell_cabal_ghc_options = 'foobar' AssertLinter 'cabal', 'cabal exec -- ghc foobar %t' ================================================ FILE: test/linter/test_haskell_ghc.vader ================================================ Before: call ale#assert#SetUpLinterTest('haskell', 'ghc') After: call ale#assert#TearDownLinterTest() Execute(The default ghc command should be correct): AssertLinter 'ghc', 'ghc -fno-code -v0 %t' Execute(The ghc options should be configurable): let b:ale_haskell_ghc_options = 'foobar' AssertLinter 'ghc', 'ghc foobar %t' ================================================ FILE: test/linter/test_haskell_ghc_mod.vader ================================================ 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' ================================================ FILE: test/linter/test_haskell_hdevtools.vader ================================================ Before: call ale#assert#SetUpLinterTest('haskell', 'hdevtools') let b:command_tail = ' check -g -Wall -p %s %t' After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'hdevtools', ale#Escape('hdevtools') . b:command_tail let b:ale_haskell_hdevtools_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail ================================================ FILE: test/linter/test_haskell_hie.vader ================================================ Before: call ale#assert#SetUpLinterTest('haskell', 'hie') 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('../test-files/hie_paths/file.hs') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/hie_paths') Execute(The executable should be configurable): let g:ale_haskell_hie_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --lsp' ================================================ FILE: test/linter/test_haskell_hlint.vader ================================================ 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 ================================================ FILE: test/linter/test_haskell_hls.vader ================================================ Before: call ale#assert#SetUpLinterTest('haskell', 'hls') 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 'haskell-language-server-wrapper', \ ale#Escape('haskell-language-server-wrapper') . ' --lsp' Execute(The project root should be detected correctly): AssertLSPProject g:dir call ale#test#SetFilename('hls_paths/file.hs') AssertLSPProject ale#path#Simplify(g:dir . '/hls_paths') Execute(The executable should be configurable): let g:ale_haskell_hls_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --lsp' Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_haskell_hls_config = {'haskell': {'maxCompletions': 250}} AssertLSPConfig {'haskell': {'maxCompletions': 250}} Execute(We should detect the root with cabal.project files, preferred over *.cabal files): call ale#test#SetFilename('../test-files/haskell/haskell-packages-project/package-a/src/folder/dummy.hs') AssertLSPProject ale#test#GetFilename('../test-files/haskell/haskell-packages-project') Execute(We should a project root with *.cabal files): call ale#test#SetFilename('../test-files/haskell/haskell-simple-package/package-a/src/folder/dummy.hs') AssertLSPProject ale#test#GetFilename('../test-files/haskell/haskell-simple-package/package-a') ================================================ FILE: test/linter/test_haskell_stack_build.vader ================================================ 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('../test-files/stack/test.hs') AssertLinter 'stack', 'stack build --fast' ================================================ FILE: test/linter/test_haskell_stack_ghc.vader ================================================ 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('../test-files/stack/test.hs') AssertLinterCwd '%s:h' AssertLinter 'stack', 'stack ghc -- -fno-code -v0 %t' let b:ale_haskell_stack_ghc_options = 'foobar' AssertLinter 'stack', 'stack ghc -- foobar %t' ================================================ FILE: test/linter/test_hdl_checker_options.vader ================================================ Before: call ale#assert#SetUpLinterTest('vhdl', 'hdl_checker') Save g:ale_hdl_checker_executable Save g:ale_hdl_checker_config_file Save g:ale_hdl_checker_options let g:default_config_file = has('unix') ? '.hdl_checker.config' : '_hdl_checker.config' runtime autoload/ale/handlers/hdl_checker.vim After: Restore call ale#assert#TearDownLinterTest() unlet! g:default_config_file unlet! g:call_count runtime autoload/ale/handlers/hdl_checker.vim Execute(Get default initialization dict): AssertEqual \ {'project_file': g:default_config_file}, \ ale#handlers#hdl_checker#GetInitOptions(bufnr('')) Execute(Get custom initialization dict): let g:ale_hdl_checker_config_file = 'some_file_name' AssertEqual \ {'project_file': 'some_file_name'}, \ ale#handlers#hdl_checker#GetInitOptions(bufnr('')) Execute(Get the checker command without extra user parameters): AssertEqual \ ale#Escape('hdl_checker') . ' --lsp', \ ale#handlers#hdl_checker#GetCommand(bufnr('')) Execute(Get the checker command with user configured parameters): let g:ale_hdl_checker_options = '--log-level DEBUG' AssertEqual \ ale#Escape('hdl_checker') . ' --lsp --log-level DEBUG', \ ale#handlers#hdl_checker#GetCommand(bufnr('')) Execute(Customize executable): let g:ale_hdl_checker_executable = '/some/other/path' AssertEqual \ ale#Escape('/some/other/path') . ' --lsp', \ ale#handlers#hdl_checker#GetCommand(bufnr('')) Execute(Get project root based on .git): call ale#test#SetFilename('../test-files/hdl_server/with_git/files/foo.vhd') " Create .git file silent! call mkdir(g:dir . '/../test-files/hdl_server/with_git/.git') AssertNotEqual '', glob(g:dir . '/../test-files/hdl_server/with_git/.git') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/hdl_server/with_git'), \ ale#handlers#hdl_checker#GetProjectRoot(bufnr('')) Execute(Get project root based on config file): call ale#test#SetFilename('../test-files/hdl_server/with_config_file/foo.vhd') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/hdl_server/with_config_file'), \ ale#handlers#hdl_checker#GetProjectRoot(bufnr('')) Execute(Return no project root if neither .git or config file are found): let g:call_count = 0 " Mock this command to avoid the test to find ale's own .git folder function! ale#handlers#hdl_checker#IsDotGit(path) abort let g:call_count += 1 return 0 endfunction call ale#test#SetFilename('../test-files/hdl_server/foo.vhd') AssertEqual \ '', \ ale#handlers#hdl_checker#GetProjectRoot(bufnr('')) AssertEqual g:call_count, 1 unlet! g:call_count ================================================ FILE: test/linter/test_html_stylelint.vader ================================================ 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/linter') 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('../test-files/stylelint/nested/testfile.html') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/stylelint/node_modules/.bin/stylelint' \) AssertEqual b:executable, ale_linters#html#stylelint#GetExecutable(bufnr('')) AssertEqual \ ale#Escape(b:executable) . ' --no-color --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('../test-files/stylelint/nested/testfile.html') AssertEqual 'foobar', ale_linters#html#stylelint#GetExecutable(bufnr('')) AssertEqual \ ale#Escape('foobar') . ' --no-color --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 --no-color --stdin-filename %s', \ ale_linters#html#stylelint#GetCommand(bufnr('')) ================================================ FILE: test/linter/test_htmlhint.vader ================================================ Before: call ale#assert#SetUpLinterTest('html', 'htmlhint') call ale#test#SetFilename('../test-files/htmlhint/test.html') let g:node_executable = ale#path#Simplify( \ g:dir . '/../test-files/htmlhint/node_modules/.bin/htmlhint' \) let g:config_path = ale#path#Simplify( \ g:dir . '/../test-files/htmlhint/with_config/.htmlhintrc' \) After: unlet! g:node_executable unlet! g:config_path call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter g:node_executable, \ ale#Escape(g:node_executable) . ' --format=unix %t' Execute(The global executable should be used if the option is set): let g:ale_html_htmlhint_executable = 'foo' let g:ale_html_htmlhint_use_global = 1 AssertLinter 'foo', ale#Escape('foo') . ' --format=unix %t', " This is so old configurations which might include this still work. Execute(--format=unix should be removed from the options if added): let g:ale_html_htmlhint_options = '--format=unix' AssertLinter g:node_executable, \ ale#Escape(g:node_executable) . ' --format=unix %t' Execute(The configuration file should be automatically detected): call ale#test#SetFilename('../test-files/htmlhint/with_config/test.html') AssertLinter g:node_executable, \ ale#Escape(g:node_executable) \ . ' --config ' . ale#Escape(g:config_path) \ . ' --format=unix %t' " This is so old configurations which might include the config will work. Execute(The configuration file should be configurable through the options variable): call ale#test#SetFilename('../test-files/htmlhint/with_config/test.html') let g:ale_html_htmlhint_options = '--config=/foo/bar/.htmlhintrc' AssertLinter g:node_executable, \ ale#Escape(g:node_executable) \ . ' --config=/foo/bar/.htmlhintrc' \ . ' --format=unix %t' ================================================ FILE: test/linter/test_hurlfmt.vader ================================================ Before: call ale#assert#SetUpLinterTest('hurl', 'hurlfmt') call ale#test#SetFilename('dummy.hurl') let g:ale_ruby_hurlfmt_executable = 'hurlfmt' let g:ale_ruby_hurlfmt_options = '' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to hurlfmt): AssertLinter 'hurlfmt', ale#Escape('hurlfmt') \ . ' --check --no-color ' Execute(Should be able to set a custom executable): let g:ale_hurl_hurlfmt_executable = 'bin/hurlfmt' AssertLinter 'bin/hurlfmt' , ale#Escape('bin/hurlfmt') \ . ' --check --no-color ' ================================================ FILE: test/linter/test_ibm_openapi_validator.vader ================================================ Before: call ale#assert#SetUpLinterTest('openapi', 'ibm_validator') After: call ale#assert#TearDownLinterTest() Execute(The yaml ibm-openapi-validator command callback should return the correct default string): AssertLinter 'lint-openapi', ale#Escape('lint-openapi') . ' %t' Execute(The yaml ibm-openapi-validator command callback should be configurable): let g:ale_openapi_ibm_validator_executable = '~/.local/bin/lint-openapi' let g:ale_openapi_ibm_validator_options = '-c ~/.config' AssertLinter '~/.local/bin/lint-openapi', ale#Escape('~/.local/bin/lint-openapi') \ . ' -c ~/.config %t' ================================================ FILE: test/linter/test_idris.vader ================================================ Before: call ale#assert#SetUpLinterTest('idris', 'idris') After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be used in the command): AssertLinter 'idris', \ ale#Escape('idris') . ' --total --warnpartial --warnreach --warnipkg --check %s' let b:ale_idris_idris_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' --total --warnpartial --warnreach --warnipkg --check %s' Execute(The options should be configurable): let b:ale_idris_idris_options = '--something' AssertLinter 'idris', ale#Escape('idris') . ' --something --check %s' ================================================ FILE: test/linter/test_ink_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('ink', 'ls') set ft=ink After: call ale#assert#TearDownLinterTest() Execute(should set correct defaults): AssertLinter 'ink-language-server', ale#Escape('ink-language-server') . ' --stdio' Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/ink/story/main.ink') AssertLSPLanguage 'ink' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ink/story') Execute(should accept configuration settings): AssertLSPConfig {} let b:ale_ink_ls_initialization_options = {'ink': {'runThroughMono': v:true}} AssertLSPOptions {'ink': {'runThroughMono': v:true}} ================================================ FILE: test/linter/test_inko_inko.vader ================================================ Before: call ale#assert#SetUpLinterTest('inko', 'inko') call ale#test#SetFilename('../test-files/inko/test.inko') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'inko', ale#Escape('inko') . ' build --check --format=json %s' Execute(The inko callback should include tests/ for test paths): call ale#engine#Cleanup(bufnr('')) noautocmd e! ../test-files/inko/tests/test/test_foo.inko call ale#engine#InitBufferInfo(bufnr('')) AssertLinter 'inko', \ ale#Escape('inko') \ . ' build --check --format=json --include ' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/inko/tests/')) \ . ' %s' ================================================ FILE: test/linter/test_ispc_ispc.vader ================================================ Before: call ale#assert#SetUpLinterTest('ispc', 'ispc') After: call ale#assert#TearDownLinterTest() Execute(The default ispc command should be configurable): AssertLinter 'ispc', ale#Escape('ispc') . ' --nowrap %s' Execute(The ispc executable nad options should be configurable): let b:ale_ispc_ispc_executable = 'foo' let g:ale_ispc_ispc_options = '--foo' AssertLinter 'foo', ale#Escape('foo') . ' --nowrap --foo' . ' %s' ================================================ FILE: test/linter/test_iverilog.vader ================================================ Before: call ale#assert#SetUpLinterTest('verilog', 'iverilog') After: call ale#assert#TearDownLinterTest() Execute(The default iverilog command should be correct): AssertLinter 'iverilog', 'iverilog -t null -Wall -y%s:h %t' Execute(iverilog options should be configurable): " Additional args for the linter let g:ale_verilog_iverilog_options = '-y.' AssertLinter 'iverilog', 'iverilog -t null -Wall -y%s:h -y. %t' ================================================ FILE: test/linter/test_j2lint.vader ================================================ Before: call ale#assert#SetUpLinterTest('jinja', 'j2lint') After: call ale#assert#TearDownLinterTest() Execute(The pycodestyle command callback should allow options): let g:ale_jinja_j2lint_options = '--exclude=test*.j2' AssertLinter 'j2lint', \ ale#Escape('j2lint') . ' --exclude=test*.j2 %t' Execute(The j2lint executable should be configurable): let g:ale_jinja_j2lint_executable = '~/.local/bin/j2lint' AssertLinter '~/.local/bin/j2lint', \ ale#Escape('~/.local/bin/j2lint'). ' %t' Execute(Setting executable to 'pipenv' appends 'run j2lint'): let g:ale_jinja_j2lint_executable = 'path/to/pipenv' AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run j2lint %t' Execute(Pipenv is detected when jinja_j2lint_auto_pipenv is set): let g:ale_jinja_j2lint_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run j2lint %t' Execute(Setting executable to 'poetry' appends 'run j2lint'): let g:ale_jinja_j2lint_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run j2lint %t' Execute(Poetry is detected when jinja_j2lint_auto_poetry is set): let g:ale_jinja_j2lint_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run j2lint %t' Execute(Setting executable to 'uv' appends 'run j2lint'): let g:ale_jinja_j2lint_executable = 'path/to/uv' AssertLinter 'path/to/uv', \ ale#Escape('path/to/uv') . ' run j2lint %t' Execute(uv is detected when jinja_j2lint_auto_uv is set): let g:ale_jinja_j2lint_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run j2lint %t' ================================================ FILE: test/linter/test_javac.vader ================================================ Before: call ale#assert#SetUpLinterTest('java', 'javac') call ale#test#SetFilename('dummy.java') let g:cp_sep = has('unix') ? ':' : ';' let g:prefix = ale#Escape('javac') . ' -Xlint' function! GetCommand(previous_output) abort let l:command = ale_linters#java#javac#GetCommand( \ bufnr(''), \ a:previous_output \) let l:split_command = split(l:command) let l:index = index(l:split_command, '-d') let l:split_command[l:index + 1] = 'TEMP' return join(l:split_command) endfunction After: unlet! g:cp_sep unlet! g:prefix delfunction GetCommand call ale#assert#TearDownLinterTest() Execute(The javac callback should return the correct default value): AssertLinterCwd '%s:h' AssertLinter 'javac', g:prefix . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should use string type g:ale_java_javac_classpath correctly): let g:ale_java_javac_classpath = 'foo.jar' AssertLinter 'javac', \ g:prefix \ . ' -cp ' . ale#Escape('foo.jar') \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should use list type g:ale_java_javac_classpath correctly): let g:ale_java_javac_classpath = ['foo.jar'] AssertLinter 'javac', \ g:prefix \ . ' -cp ' . ale#Escape('foo.jar') \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The executable should be configurable): let g:ale_java_javac_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' -Xlint' \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should include discovered classpaths): let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', \], {}) AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should combine discovered classpaths and manual ones): let g:ale_java_javac_classpath = 'configured.jar' let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', \], {}) AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join( \ [ \ '/foo/bar.jar', \ '/xyz/abc.jar', \ 'configured.jar', \ ], \ g:cp_sep \ )) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_classpath = 'configured.jar' . g:cp_sep . 'configured2.jar' let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', \], {}) AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join( \ [ \ '/foo/bar.jar', \ '/xyz/abc.jar', \ 'configured.jar', \ 'configured2.jar', \ ], \ g:cp_sep \ )) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_classpath = ['configured.jar'] let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', \], {}) AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join( \ [ \ '/foo/bar.jar', \ '/xyz/abc.jar', \ 'configured.jar', \ ], \ g:cp_sep \ )) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_classpath = ['configured.jar', 'configured2.jar'] let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', \], {}) AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join( \ [ \ '/foo/bar.jar', \ '/xyz/abc.jar', \ 'configured.jar', \ 'configured2.jar', \ ], \ g:cp_sep \ )) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should use string type g:ale_java_javac_sourcepath correctly): let g:ale_java_javac_sourcepath = '../test-files/java/with_main/build/gen/main' AssertLinter 'javac', \ g:prefix \ . ' -sourcepath ' . ale#Escape( \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen/main/') \ ) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should use list type g:ale_java_javac_sourcepath correctly): let g:ale_java_javac_sourcepath = ['../test-files/java/with_main/build/gen/main'] AssertLinter 'javac', \ g:prefix \ . ' -sourcepath ' . ale#Escape( \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen/main/') \ ) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback shouldn't add -sourcepath when g:ale_java_javac_sourcepath variable path doesn't exist): let g:ale_java_javac_sourcepath = '../test-files/java/with_main/build/gen3/main' AssertLinter 'javac', \ g:prefix \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should combine discovered sourcepath and manual ones): call ale#engine#Cleanup(bufnr('')) call ale#test#SetFilename('../test-files/java/with_main/src/main/java/com/something/dummy.java') call ale#engine#InitBufferInfo(bufnr('')) let g:ale_java_javac_sourcepath = '../test-files/java/with_main/build/gen/main' let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) AssertEqual \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/main/java/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen/main/'), \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_sourcepath = '../test-files/java/with_main/build/gen/main' \ . g:cp_sep . '../test-files/java/with_main/build/gen2/main' let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) AssertEqual \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/main/java/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen/main/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen2/main/') \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_sourcepath = ['../test-files/java/with_main/build/gen/main'] let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) AssertEqual \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/main/java/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen/main/') \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_sourcepath = [ \ '../test-files/java/with_main/build/gen/main', \ '../test-files/java/with_main/build/gen2/main' \ ] let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) AssertEqual \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/main/java/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen/main/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/build/gen2/main/') \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should detect source directories): call ale#engine#Cleanup(bufnr('')) noautocmd e! ../test-files/java/with_main/src/main/java/com/something/dummy call ale#engine#InitBufferInfo(bufnr('')) AssertLinter 'javac', \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape( \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/main/java/') \ ) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should combine detected source directories and classpaths): call ale#engine#Cleanup(bufnr('')) call ale#test#SetFilename('../test-files/java/with_main/src/main/java/com/something/dummy.java') call ale#engine#InitBufferInfo(bufnr('')) let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', \], {}) AssertEqual \ 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 . '/../test-files/java/with_main/src/main/java/') \ ) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should use g:ale_java_javac_options correctly): let g:ale_java_javac_options = '--anything --else' AssertLinter 'javac', \ g:prefix . ' -d ' . ale#Escape('TEMP_DIR') . ' --anything --else %t' Execute(The javac callback should include src/test/java for test paths): call ale#engine#Cleanup(bufnr('')) " The test path is only included for test files. " Regular Java files shouldn't import from tests. noautocmd e! ../test-files/java/with_main/src/test/java/com/something/dummy call ale#engine#InitBufferInfo(bufnr('')) AssertLinter 'javac', \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/main/java/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_main/src/test/java/'), \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should include src/main/jaxb when available): call ale#engine#Cleanup(bufnr('')) noautocmd e! ../test-files/java/with_jaxb/src/main/java/com/something/dummy call ale#engine#InitBufferInfo(bufnr('')) AssertLinter 'javac', \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/with_jaxb/src/main/java/'), \ ale#path#Simplify(g:dir . '/../test-files/java/with_jaxb/src/main/jaxb/'), \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should add -sourcepath even if src/java/main doesn't exist): call ale#engine#Cleanup(bufnr('')) call ale#test#SetFilename('../test-files/java/no_main/src/test/java/com/something/dummy.java') call ale#engine#InitBufferInfo(bufnr('')) AssertLinter 'javac', \ ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/../test-files/java/no_main/src/test/java/'), \ ], g:cp_sep)) \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' ================================================ FILE: test/linter/test_javalsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('java', 'javalsp') After: call ale#assert#TearDownLinterTest() Execute(The javalsp callback should return the correct default value): AssertLinter '', ale#Escape('') Execute(The javalsp java executable should be configurable): let b:ale_java_javalsp_executable = '/bin/foobar' AssertLinter '/bin/foobar', ale#Escape('/bin/foobar') Execute(The javalsp callback should return backward compatible value): let b:ale_java_javalsp_executable = '/bin/java' let cmd = [ \ ale#Escape('/bin/java'), \ '--add-exports jdk.compiler/com.sun.tools.javac.api=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.code=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.comp=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.main=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.tree=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.model=javacs', \ '--add-exports jdk.compiler/com.sun.tools.javac.util=javacs', \ '--add-opens jdk.compiler/com.sun.tools.javac.api=javacs', \ '-m javacs/org.javacs.Main', \] AssertLinter '/bin/java', join(cmd, ' ') Execute(The javalsp should have default config): AssertEqual \ { \ 'java': { \ 'classPath': [], \ 'externalDependencies': [] \ } \ }, \ ale_linters#java#javalsp#Config(bufnr('')) Execute(The javalsp should have add missing config): let b:ale_java_javalsp_config = { 'java': { 'classPath': ['aaa.jar'] } } AssertEqual \ { \ 'java': { \ 'classPath': ['aaa.jar'], \ 'externalDependencies': [] \ } \ }, \ ale_linters#java#javalsp#Config(bufnr('')) let b:ale_java_javalsp_config = \ { \ 'java': { \ 'externalDependencies': ['unit-test:2.0.0'] \ } \ } AssertEqual \ { \ 'java': { \ 'classPath': [], \ 'externalDependencies': ['unit-test:2.0.0'] \ } \ }, \ ale_linters#java#javalsp#Config(bufnr('')) ================================================ FILE: test/linter/test_javascript_deno_lsp.vader ================================================ Before: Save g:ale_deno_import_map Save g:ale_deno_unstable Save g:ale_deno_executable Save g:ale_deno_lsp_project_root let g:ale_deno_import_map = 'import_map.json' let g:ale_deno_unstable = 0 let g:ale_deno_executable = 'deno' let g:ale_deno_lsp_project_root = '' runtime autoload/ale/handlers/deno.vim call ale#assert#SetUpLinterTest('javascript', 'deno') After: call ale#assert#TearDownLinterTest() Execute(Should set deno lsp for JavaScript projects using stable Deno API): AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': '' \} Execute(Should set deno lsp using unstable Deno API if enabled by user): let g:ale_deno_unstable = 1 AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:true, \ 'importMap': '' \} Execute(Should set the default importMap filepath): call ale#test#SetFilename('../test-files/javascript_deno/main.js') AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': ale#path#Simplify(g:dir . '/../test-files/javascript_deno/import_map.json') \} Execute(Should set the importMap filepath from user defined importMap): let g:ale_deno_import_map = 'custom_import_map.json' call ale#test#SetFilename('../test-files/javascript_deno/main.js') AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': ale#path#Simplify(g:dir . '/../test-files/javascript_deno/custom_import_map.json') \} Execute(Should set the importMap filepath from user defined importMap with unstable API): let g:ale_deno_import_map = 'custom_import_map.json' let g:ale_deno_unstable = 1 call ale#test#SetFilename('../test-files/javascript_deno/main.js') AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:true, \ 'importMap': ale#path#Simplify(g:dir . '/../test-files/javascript_deno/custom_import_map.json') \} Execute(Should find project root containing tsconfig.json): call ale#test#SetFilename('../test-files/javascript_deno/main.js') AssertLSPLanguage 'javascript' AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/javascript_deno') Execute(Should use user-specified project root): let g:ale_deno_lsp_project_root = '/' call ale#test#SetFilename('../test-files/javascript_deno/main.js') AssertLSPLanguage 'javascript' AssertLSPProject '/' Execute(Check Deno LSP command): AssertLinter 'deno', ale#Escape('deno') . ' lsp' ================================================ FILE: test/linter/test_javascript_tsserver.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'tsserver') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'tsserver', ale#Escape('tsserver') Execute(should resolve correct path when nested 1): call ale#test#SetFilename('../test-files/tsserver/src/level-1/level-2/file3.ts') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/tsserver/src/level-1') Execute(should resolve correct path when nested 2): call ale#test#SetFilename('../test-files/tsserver/src/file1.ts') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/tsserver') ================================================ FILE: test/linter/test_jedils.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'jedils') Save b:ale_python_auto_virtualenv let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:venv_bin unlet! b:sep unlet! b:executable call ale#test#SetFilename('..') call ale#assert#TearDownLinterTest() Execute(The jedi-language-server command callback should return default string): call ale#test#SetFilename('./foo.py') AssertLinter 'jedi-language-server', ale#Escape('jedi-language-server') Execute(The jedi-language-server executable should be configurable): let g:ale_python_jedils_executable = '~/.local/bin/jedi-language-server' AssertLinter '~/.local/bin/jedi-language-server' , ale#Escape('~/.local/bin/jedi-language-server') Execute(virtualenv vars should be used when ale_python_auto_virtualenv = 1): let b:ale_python_auto_virtualenv = 1 call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:venv_bin = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir) let b:sep = has('win32') ? ';' : ':' let b:executable = ale#path#Simplify(b:venv_bin . '/jedi-language-server') AssertLinter b:executable, ale#python#AutoVirtualenvEnvString(bufnr('')) \ . ale#Escape(b:executable) Assert !empty(ale#python#AutoVirtualenvEnvString(bufnr(''))) Execute(You should be able to override the jedi-language-server virtualenv lookup): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_jedils_use_global = 1 AssertLinter 'jedi-language-server', ale#Escape('jedi-language-server') Execute(Setting executable to 'pipenv' appends 'run jedi-language-server'): let g:ale_python_jedils_executable = 'path/to/pipenv' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run jedi-language-server' Execute(poetry is detected when python_jedils_auto_poetry is set): let g:ale_python_jedils_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run jedi-language-server' Execute(uv is detected when python_jedils_auto_uv is set): let g:ale_python_jedils_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run jedi-language-server' ================================================ FILE: test/linter/test_jq.vader ================================================ Before: call ale#assert#SetUpLinterTest('json', 'jq') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'jq', ale#Escape('jq') ================================================ FILE: test/linter/test_jscs.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'jscs') After: call ale#assert#TearDownLinterTest() Execute(Should return the correct default values): AssertLinter 'jscs', \ ale#Escape('jscs') . ' --reporter inline --no-colors -' Execute(Should allow using a custom executable): let g:ale_javascript_jscs_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' --reporter inline --no-colors -' ================================================ FILE: test/linter/test_jshint.vader ================================================ 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 -' ================================================ FILE: test/linter/test_json_vscodejson.vader ================================================ Before: let g:executable_map = {} call ale#assert#SetUpLinterTest('json', 'vscodejson') runtime autoload/ale/engine.vim " Stub out IsExecutable so we can emulate it. function! ale#engine#IsExecutable(buffer, executable) abort return get(g:executable_map, a:executable) endfunction After: unlet! g:executable_map call ale#assert#TearDownLinterTest() runtime autoload/ale/engine.vim Execute(The default executable name should be correct): let g:executable_map = {'vscode-json-languageserver': 1} AssertLinter 'vscode-json-languageserver', [ale#Escape('vscode-json-languageserver') . ' --stdio'] Execute(We should fall back on the old executable name): let g:executable_map = {'vscode-json-languageserver': 0} AssertLinter 'vscode-json-language-server', [ale#Escape('vscode-json-language-server') . ' --stdio'] Execute(Executable name should be configurable): let b:ale_json_vscodejson_executable = 'foo' AssertLinter 'foo', [ale#Escape('foo') . ' --stdio'] ================================================ FILE: test/linter/test_jsonlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('json', 'jsonlint') After: call ale#assert#TearDownLinterTest() Execute(local executable should be detected correctly): call ale#test#SetFilename('../test-files/jsonlint/app/src/app.json') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/jsonlint/app/node_modules/.bin/jsonlint'), \ ale_linters#json#jsonlint#GetExecutable(bufnr('')) \ Execute(use_global should override project executable): let g:ale_json_jsonlint_use_global = 1 call ale#test#SetFilename('../test-files/jsonlint/app/src/app.json') AssertEqual \ 'jsonlint', \ ale_linters#json#jsonlint#GetExecutable(bufnr('')) \ Execute(manually defined should override default executable): let g:ale_json_jsonlint_use_global = 1 let g:ale_json_jsonlint_executable = 'custom_jsonlint' call ale#test#SetFilename('../test-files/jsonlint/app/src/app.json') AssertEqual \ 'custom_jsonlint', \ ale_linters#json#jsonlint#GetExecutable(bufnr('')) ================================================ FILE: test/linter/test_jsonnet_lint.vader ================================================ Before: call ale#assert#SetUpLinterTest('jsonnet', 'jsonnet_lint') call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') After: Restore call ale#assert#TearDownLinterTest() Execute(The default jsonnet-lint command should be correct): AssertLinter 'jsonnet-lint', \ ale#Escape('jsonnet-lint') . ' %t' Execute(jsonnet-lint command and options should be customizable): let g:ale_jsonnet_jsonnet_lint_executable = 'jsonnet' let g:ale_jsonnet_jsonnet_lint_options = 'fmt' AssertLinter 'jsonnet', \ ale#Escape('jsonnet') . ' fmt %t' ================================================ FILE: test/linter/test_jsonnetfmt.vader ================================================ Before: call ale#assert#SetUpLinterTest('jsonnet', 'jsonnetfmt') call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') After: Restore call ale#assert#TearDownLinterTest() Execute(The default jsonnetfmt command should be correct): AssertLinter 'jsonnetfmt', \ ale#Escape('jsonnetfmt') . ' %t' Execute(jsonnetfmt command and options should be customizable): let g:ale_jsonnet_jsonnetfmt_executable = 'jsonnet' let g:ale_jsonnet_jsonnetfmt_options = 'fmt' AssertLinter 'jsonnet', \ ale#Escape('jsonnet') . ' fmt %t' ================================================ FILE: test/linter/test_julia_languageserver.vader ================================================ 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') . \' --project=@. --startup-file=no --history-file=no -e ' . \ ale#Escape('using LanguageServer; using Pkg; import StaticLint; import SymbolServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, dirname(Pkg.Types.Context().env.project_file)); 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') . \' --project=@. --startup-file=no --history-file=no -e ' . \ ale#Escape('using LanguageServer; using Pkg; import StaticLint; import SymbolServer; server = LanguageServer.LanguageServerInstance(isdefined(Base, :stdin) ? stdin : STDIN, isdefined(Base, :stdout) ? stdout : STDOUT, dirname(Pkg.Types.Context().env.project_file)); server.runlinter = true; run(server);') Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/julia/test.jl') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/julia') ================================================ FILE: test/linter/test_kotlin_languageserver.vader ================================================ 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') Execute(Gradle project roots with build.gradle should be detected correctly): call ale#test#SetFilename('../test-files/gradle/build-gradle-project/src/main/kotlin/dummy.kt') AssertLSPProject ale#test#GetFilename('../test-files/gradle/build-gradle-project') Execute(Maven project roots with pom.xml should be detected correctly): call ale#test#SetFilename('../test-files/maven/maven-kotlin-project/src/main/kotlin/dummy.kt') AssertLSPProject ale#test#GetFilename('../test-files/maven/maven-kotlin-project') Execute(No root should be detected if configuration files can't be found): call ale#test#SetFilename('../test-files/gradle/non-gradle-project/src/main/kotlin/dummy.kt') AssertLSPProject '' ================================================ FILE: test/linter/test_kotlinc.vader ================================================ Before: call ale#assert#SetUpLinterTest('kotlin', 'kotlinc') call ale#test#SetFilename('test.kt') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'kotlinc', 'kotlinc ' . ale#Escape(expand('%:p')) ================================================ FILE: test/linter/test_languagetool.vader ================================================ Before: Save g:ale_languagetool_executable Save g:ale_languagetool_options let g:ale_languagetool_executable = 'languagetool' let g:ale_languagetool_options = '--autoDetect' call ale#assert#SetUpLinterTest('text', 'languagetool') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'languagetool', ale#Escape('languagetool') \ . ' --autoDetect %s' Execute(Should be able to set a custom executable): let g:ale_languagetool_executable = 'foobar' let g:ale_languagetool_options = '--language en' AssertLinter 'foobar' , ale#Escape('foobar') \ . ' --language en %s' ================================================ FILE: test/linter/test_lean_lake.vader ================================================ Before: call ale#assert#SetUpLinterTest('lean', 'lake') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'lake', ale#Escape('lake') . ' serve' Execute(The project root should be detected correctly without a lakefile): AssertLSPProject '.' Execute(The project root should be detected correctly from .toml): call ale#test#SetFilename('../test-files/lean/lakefile_toml/lakefile.toml') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/lean/lakefile_toml') Execute(The project root should be detected correctly from .lean): call ale#test#SetFilename('../test-files/lean/lakefile_lean/lakefile.lean') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/lean/lakefile_lean') Execute(The LSP values should be set correctly): call ale#test#SetFilename('../test-files/lean/lakefile_lean/Main.lean') AssertLSPLanguage 'lean' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/lean/lakefile_lean') ================================================ FILE: test/linter/test_less_stylelint.vader ================================================ Before: call ale#assert#SetUpLinterTest('less', 'stylelint') unlet! b:executable After: unlet! b:executable call ale#assert#TearDownLinterTest() Execute(node_modules directories should be discovered): call ale#test#SetFilename('../test-files/stylelint/nested/testfile.less') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/stylelint/node_modules/.bin/stylelint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --no-color --stdin-filename %s' Execute(The global override should work): let b:ale_less_stylelint_executable = 'foobar' let b:ale_less_stylelint_use_global = 1 call ale#test#SetFilename('../test-files/stylelint/nested/testfile.less') AssertLinter 'foobar', ale#Escape('foobar') . ' --no-color --stdin-filename %s' Execute(Extra options should be configurable): let b:ale_less_stylelint_options = '--whatever' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'stylelint', \ ale#Escape('stylelint') . ' --whatever --no-color --stdin-filename %s' ================================================ FILE: test/linter/test_lessc.vader ================================================ Before: call ale#assert#SetUpLinterTest('less', 'lessc') call ale#test#SetFilename('testfile.less') unlet! b:executable After: unlet! b:executable call ale#assert#TearDownLinterTest() Execute(node_modules directories should be discovered): call ale#test#SetFilename('../test-files/lessc/nested/testfile.less') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/lessc/node_modules/.bin/lessc' \) AssertLinter b:executable, ale#Escape(b:executable) \ . ' --no-color --lint' \ . ' --include-path=' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/lessc/nested')) \ . ' -' Execute(The global override should work): let b:ale_less_lessc_executable = 'foobar' let b:ale_less_lessc_use_global = 1 call ale#test#SetFilename('../test-files/lessc/nested/testfile.less') AssertLinter 'foobar', ale#Escape('foobar') \ . ' --no-color --lint' \ . ' --include-path=' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/lessc/nested')) \ . ' -' Execute(Extra options should be configurable): let b:ale_less_lessc_options = '--whatever' AssertLinter 'lessc', ale#Escape('lessc') \ . ' --no-color --lint' \ . ' --include-path=' \ . ale#Escape(ale#path#Simplify(g:dir)) \ . ' --whatever' \ . ' -' ================================================ FILE: test/linter/test_lexical.vader ================================================ Before: call ale#assert#SetUpLinterTest('elixir', 'lexical') After: call ale#assert#TearDownLinterTest() Execute(should set correct defaults): if has('win32') AssertLinter 'lexical\start_lexical.bat', 'lexical\start_lexical.bat' else AssertLinter 'lexical/start_lexical.sh', 'lexical/start_lexical.sh' endif Execute(should configure lexical release location): let b:ale_elixir_lexical_release = 'boo' if has('win32') AssertLinter 'boo\start_lexical.bat', 'boo\start_lexical.bat' else AssertLinter 'boo/start_lexical.sh', 'boo/start_lexical.sh' endif Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/elixir/umbrella_project/apps/app1/lib/app.ex') AssertLSPLanguage 'elixir' AssertLSPOptions {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/elixir/umbrella_project') ================================================ FILE: test/linter/test_lintr.vader ================================================ Before: call ale#assert#SetUpLinterTest('r', 'lintr') After: call ale#assert#TearDownLinterTest() Execute(The default lintr command should be correct): AssertLinterCwd '%s:h' AssertLinter 'Rscript', \ 'Rscript --no-save --no-restore --no-site-file --no-init-file -e ' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . 'lint(cache = FALSE, commandArgs(TRUE), ' \ . 'with_defaults())') \ . ' %t' Execute(The lintr options should be configurable): let b:ale_r_lintr_options = 'with_defaults(object_usage_linter = NULL)' AssertLinter 'Rscript', \ 'Rscript --no-save --no-restore --no-site-file --no-init-file -e ' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . 'lint(cache = FALSE, commandArgs(TRUE), ' \ . 'with_defaults(object_usage_linter = NULL))') \ . ' %t' Execute(If the lint_package flag is set, lintr::lint_package should be called): let b:ale_r_lintr_lint_package = 1 AssertLinter 'Rscript', \ 'Rscript --no-save --no-restore --no-site-file --no-init-file -e ' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . 'lint_package(cache = FALSE, ' \ . 'linters = with_defaults())') \ . ' %t' ================================================ FILE: test/linter/test_llc.vader ================================================ Before: call ale#assert#SetUpLinterTest('llvm', 'llc') function! AssertHasPrefix(str, prefix) abort let msg = printf("'%s' is expected to be prefixed with '%s'", a:str, a:prefix) AssertEqual stridx(a:str, a:prefix), 0, msg endfunction After: delfunction AssertHasPrefix call ale#assert#TearDownLinterTest() Execute(The llc command should be customizable): AssertLinter 'llc', \ ale#Escape('llc') . ' -filetype=null -o=' . g:ale#util#nul_file let g:ale_llvm_llc_executable = 'llc-5.0' AssertLinter 'llc-5.0', \ ale#Escape('llc-5.0') . ' -filetype=null -o=' . g:ale#util#nul_file ================================================ FILE: test/linter/test_llvm_mc.vader ================================================ Before: call ale#assert#SetUpLinterTest('asm', 'llvm_mc') call ale#test#SetFilename('test.cpp') let b:command_tail = ' --assemble' \ . ' --filetype=asm' \ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' ' After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The default llvm-mc command should be correct): AssertLinter 'llvm-mc', ale#Escape('llvm-mc') . b:command_tail Execute(The llvm-mc executable should be configurable): let b:ale_asm_llvm_mc_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail ================================================ FILE: test/linter/test_lua_language_server.vader ================================================ Before: call ale#assert#SetUpLinterTest('lua', 'lua_language_server') After: call ale#assert#TearDownLinterTest() Execute(The default lua-language-server settings should be correct): AssertLinter 'lua-language-server', ale#Escape('lua-language-server') AssertLSPConfig {} Execute(lua-language-server should be configurable): let b:ale_lua_language_server_executable = 'billy' let b:ale_lua_language_server_config = {'x': 'y'} AssertLinter 'billy', ale#Escape('billy') AssertLSPConfig {'x': 'y'} Execute(lua-language-server should detect the project root using .luarc.json): call ale#test#SetFilename('../lua/dummy.lua') AssertLSPProject ale#path#Simplify(g:dir . '/../lua') ================================================ FILE: test/linter/test_lua_selene.vader ================================================ Before: call ale#assert#SetUpLinterTest('lua', 'selene') After: call ale#assert#TearDownLinterTest() Execute(The lua selene command callback should return the correct default string): AssertLinter 'selene', ale#Escape('selene') . ' --display-style=json -' Execute(The lua selene command callback should let you set options): let g:ale_lua_selene_options = '--num-threads 2' AssertLinter 'selene', \ ale#Escape('selene') . ' --num-threads 2 --display-style=json -' Execute(The selene executable should be configurable): let g:ale_lua_selene_executable = 'selene.sh' AssertLinter 'selene.sh', ale#Escape('selene.sh') . ' --display-style=json -' ================================================ FILE: test/linter/test_luac.vader ================================================ Before: call ale#assert#SetUpLinterTest('lua', 'luac') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): 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 -' ================================================ FILE: test/linter/test_luacheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('lua', 'luacheck') " Default to testing linting Lua not in Vim directories. call ale#test#SetFilename('/test.lua') After: " Clear the variable for saving the result of the runtime check. " We don't want to cache the result between tests. unlet! b:ale_in_runtimepath call ale#assert#TearDownLinterTest() Execute(The luacheck default command should be correct): AssertLinter 'luacheck', \ ale#Escape('luacheck') . ' --formatter plain --codes --filename %s -' Execute(You should be able to set luacheck options): let g:ale_lua_luacheck_options = '--config filename' AssertLinter 'luacheck', \ ale#Escape('luacheck') \ . ' --config filename' \ . ' --formatter plain --codes --filename %s -' 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 -' Execute(The luacheck command should include vim as a global if in runtimepath): call ale#test#SetFilename('test.lua') AssertLinter 'luacheck', \ ale#Escape('luacheck') . ' --globals vim --formatter plain --codes --filename %s -' Execute(The default Vim globals should not be set if globals are already set): call ale#test#SetFilename('test.lua') let g:ale_lua_luacheck_options = '--globals foo' AssertLinter 'luacheck', \ ale#Escape('luacheck') . ' --globals foo --formatter plain --codes --filename %s -' ================================================ FILE: test/linter/test_markdown_markdownlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('markdown', 'markdownlint') After: call ale#assert#TearDownLinterTest() Execute(The default markdownlint command should be correct): AssertLinter 'markdownlint', ale#Escape('markdownlint') . ' %s' Execute(The executable should be configurable): let g:ale_markdown_markdownlint_executable = 'foo bar' let g:ale_markdown_markdownlint_options = '--option' AssertLinter 'foo bar', ale#Escape('foo bar') . ' --option %s' ================================================ FILE: test/linter/test_markdown_marksman.vader ================================================ Before: call ale#assert#SetUpLinterTest('markdown', 'marksman') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'marksman', ale#Escape('marksman') . ' server' ================================================ FILE: test/linter/test_markdown_mdl.vader ================================================ Before: call ale#assert#SetUpLinterTest('markdown', 'mdl') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'mdl', ale#Escape('mdl') . ' -j' Execute(The executable and options should be configurable): let g:ale_markdown_mdl_executable = 'foo bar' let g:ale_markdown_mdl_options = '--wat' AssertLinter 'foo bar', ale#Escape('foo bar') . ' -j --wat' Execute(Setting bundle appends 'exec mdl'): let g:ale_markdown_mdl_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') . ' exec mdl -j' ================================================ FILE: test/linter/test_markdown_vale.vader ================================================ Before: call ale#assert#SetUpLinterTest('markdown', 'vale') call ale#test#SetFilename('dummy.md') let g:ale_markdown_vale_executable = 'vale' let g:ale_markdown_vale_input_file = '%t' let g:ale_markdown_vale_options = '' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to vale): AssertLinter 'vale', ale#Escape('vale') \ . ' --output=JSON %t' Execute(Should be able to set a custom executable): let g:ale_markdown_vale_executable = 'bin/vale' AssertLinter 'bin/vale' , ale#Escape('bin/vale') \ . ' --output=JSON %t' Execute(Should be able to set custom options): let g:ale_markdown_vale_options = '--foo --bar' AssertLinter 'vale', ale#Escape('vale') \ . ' --output=JSON --foo --bar %t' Execute(Should be able to set a custom input file): let g:ale_markdown_vale_input_file = '%s' AssertLinter 'vale', ale#Escape('vale') \ . ' --output=JSON %s' ================================================ FILE: test/linter/test_mercury_mmc.vader ================================================ Before: call ale#assert#SetUpLinterTest('mercury', 'mmc') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinterCwd '%s:h' AssertLinter 'mmc', \ ale#Escape('mmc') . ' --errorcheck-only --make --output-compile-error-lines 100 %s:t:r' Execute(The executable should be configurable): let b:ale_mercury_mmc_executable = 'foo' AssertLinter 'foo', \ ale#Escape('foo') . ' --errorcheck-only --make --output-compile-error-lines 100 %s:t:r' Execute(The options should be configurable): let b:ale_mercury_mmc_options = '--bar' AssertLinter 'mmc', \ ale#Escape('mmc') . ' --errorcheck-only --bar %s:t:r' ================================================ FILE: test/linter/test_mypy.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'mypy') call ale#test#SetFilename('test.py') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The mypy callbacks should return the correct default values): AssertLinterCwd g:dir AssertLinter 'mypy', \ ale#Escape('mypy') \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(The mypy executable should be configurable, and escaped properly): let g:ale_python_mypy_executable = 'executable with spaces' AssertLinter 'executable with spaces', \ ale#Escape('executable with spaces') \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(The mypy command callback should let you set options): let g:ale_python_mypy_options = '--some-option' AssertLinter 'mypy', \ ale#Escape('mypy') \ . ' --some-option' \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(The mypy command should switch directories to the detected project root): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'mypy', \ ale#Escape('mypy') \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(The mypy callbacks should detect virtualenv directories and switch to the project root): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/mypy') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, \ ale#Escape(b:executable) \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(The mypy callbacks should cd to directory containing mypy.ini if found): call ale#test#SetFilename('../test-files/python/with_mypy_ini_and_pytest_ini/tests/testsubfolder/my_tests.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_mypy_ini_and_pytest_ini') AssertLinter 'mypy', \ ale#Escape('mypy') \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(You should able able to use the global mypy instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_mypy_use_global = 1 AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter 'mypy', \ ale#Escape('mypy') \ . ' --show-column-numbers' \ . ' --shadow-file %s %t %s' Execute(Setting executable to 'pipenv' appends 'run mypy'): let g:ale_python_mypy_executable = 'path/to/pipenv' AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'path/to/pipenv', \ 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): call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') let g:ale_python_mypy_auto_pipenv = 1 AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run mypy --show-column-numbers --shadow-file %s %t %s' Execute(Setting executable to 'poetry' appends 'run mypy'): let g:ale_python_mypy_executable = 'path/to/poetry' AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run mypy' \ . ' --show-column-numbers --shadow-file %s %t %s' Execute(Poetry is detected when python_mypy_auto_poetry is set): call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let g:ale_python_mypy_auto_poetry = 1 AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run mypy --show-column-numbers --shadow-file %s %t %s' Execute(uv is detected when python_mypy_auto_uv is set): call ale#test#SetFilename('../test-files/python/uv/whatever.py') let g:ale_python_mypy_auto_uv = 1 AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'uv', \ ale#Escape('uv') . ' run mypy --show-column-numbers --shadow-file %s %t %s' ================================================ FILE: test/linter/test_naga.vader ================================================ Before: call ale#assert#SetUpLinterTest('wgsl', 'naga') After: call ale#assert#TearDownLinterTest() Execute(The naga command should be customizable): let g:ale_wgsl_naga_executable = '/path/to/naga' AssertLinter '/path/to/naga', \ ale#Escape('/path/to/naga') . ' --stdin-file-path %s' ================================================ FILE: test/linter/test_nagelfar.vader ================================================ Before: call ale#assert#SetUpLinterTest('tcl', 'nagelfar') After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The default nagelfar command should be correct): AssertLinter 'nagelfar.tcl', ale#Escape('nagelfar.tcl') . ' %s' Execute(The negalfar executable and options should be configurable): let b:ale_tcl_nagelfar_executable = 'foobar' let b:ale_tcl_nagelfar_options = '--something' AssertLinter 'foobar', ale#Escape('foobar') . ' --something %s' ================================================ FILE: test/linter/test_nasm_nasm.vader ================================================ Before: call ale#assert#SetUpLinterTest('nasm', 'nasm') After: call ale#assert#TearDownLinterTest() Execute(The default nasm command should be correct): AssertLinter 'nasm', ale#Escape('nasm') \ . ' -X gnu -I %s:h' . (has('win32') ? '\' : '/') \ . ' %s -o ' . (has('win32') ? 'NUL' : '/dev/null') Execute(The nasm executable and options should be configurable): let b:ale_nasm_nasm_executable = '~/nasm' let b:ale_nasm_nasm_options = '-w-macro-params' AssertLinter '~/nasm', ale#Escape('~/nasm') \ . ' -X gnu -I %s:h' . (has('win32') ? '\' : '/') \ . ' -w-macro-params' \ . ' %s -o ' . (has('win32') ? 'NUL' : '/dev/null') ================================================ FILE: test/linter/test_nimlsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('nim', 'nimlsp') After: call ale#assert#TearDownLinterTest() Execute(It does not set nim sources by default): AssertLinter 'nimlsp', ale#Escape('nimlsp') Execute(Sets nimlsp and escapes sources from g:ale_nim_nimlsp_nim_sources): let g:ale_nim_nimlsp_nim_sources = '/path/to /Nim' AssertLinter 'nimlsp', ale#Escape('nimlsp') . ' ' . ale#Escape('/path/to /Nim') ================================================ FILE: test/linter/test_nix_deadnix.vader ================================================ Before: call ale#assert#SetUpLinterTest('nix', 'deadnix') After: call ale#assert#TearDownLinterTest() Execute(The deadnix command should be correct): AssertLinter 'deadnix', ale#Escape('deadnix') . ' -o json -- %t' Execute(Additional deadnix options should be configurable): let g:ale_nix_deadnix_options = '--foobar' AssertLinter 'deadnix', \ ale#Escape('deadnix') . ' -o json --foobar -- %t' Execute(The deadnix command should be configurable): let g:ale_nix_deadnix_executable = 'foo/bar' AssertLinter 'foo/bar', ale#Escape('foo/bar') . ' -o json -- %t' ================================================ FILE: test/linter/test_nix_statix.vader ================================================ Before: call ale#assert#SetUpLinterTest('nix', 'statix') After: call ale#assert#TearDownLinterTest() Execute(The default statix command should be correct): AssertLinter 'statix', ale#Escape('statix') . ' check -o errfmt --stdin' Execute(The statix executable and options should be configurable): let g:ale_nix_statix_check_executable = 'foo' let g:ale_nix_statix_check_options = '--foobar' AssertLinter 'foo', ale#Escape('foo') . ' check -o errfmt --stdin --foobar' ================================================ FILE: test/linter/test_npmgroovylint.vader ================================================ Before: Save b:ale_groovy_npmgroovylint_options call ale#assert#SetUpLinterTest('groovy', 'npmgroovylint') call ale#test#SetFilename('test.groovy') After: call ale#assert#TearDownLinterTest() Execute(The default npm-groovy-lint command should be correct): AssertLinter 'npm-groovy-lint', \ ale#Escape('npm-groovy-lint') . ' --failon none --output json --loglevel warning %t' Execute(Default options should be configurable): let b:ale_groovy_npmgroovylint_options = '--loglevel info' AssertLinter 'npm-groovy-lint', \ ale#Escape('npm-groovy-lint') . ' --failon none --output json --loglevel info %t' ================================================ FILE: test/linter/test_objc_ccls.vader ================================================ Before: call ale#assert#SetUpLinterTest('objc', 'ccls') Save b:ale_c_build_dir_names Save b:ale_objc_ccls_executable Save b:ale_objc_ccls_init_options After: call ale#assert#TearDownLinterTest() Execute(The project root should be detected correctly using compile_commands.json file): call ale#test#SetFilename(tempname() . '/dummy.m') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_compile_commands_json/dummy.m') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/with_compile_commands_json') Execute(The project root should be detected correctly using .ccls file): call ale#test#SetFilename(tempname() . '/dummy.m') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_ccls/dummy.m') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/with_ccls') Execute(The project root should be detected correctly using .ccls-root file): call ale#test#SetFilename(tempname() . '/dummy.m') AssertLSPProject '' call ale#test#SetFilename('../test-files/ccls/with_ccls-root/dummy.m') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ccls/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' } Execute(The compile command database should be detected correctly): call ale#test#SetFilename('../test-files/ccls/with_ccls/dummy.c') AssertLSPOptions {} call ale#test#SetFilename('../test-files/ccls/with_compile_commands_json/dummy.c') AssertLSPOptions { 'compilationDatabaseDirectory': \ ale#path#Simplify(g:dir . '/../test-files/ccls/with_compile_commands_json') } call ale#test#SetFilename('../test-files/ccls/with_build_dir/dummy.c') let b:ale_c_build_dir_names = ['unusual_build_dir_name'] AssertLSPOptions { 'compilationDatabaseDirectory': \ ale#path#Simplify(g:dir . '/../test-files/ccls/with_build_dir/unusual_build_dir_name') } ================================================ FILE: test/linter/test_ocaml_ocamllsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('ocaml', 'ocamllsp') Save &filetype let &filetype = 'ocaml' After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'ocaml' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/ocamllsp/file.ml') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ocamllsp') Execute(The executable should be run using opam exec by default): call ale#test#SetFilename('../test-files/ocamllsp/file.ml') AssertLinter 'ocamllsp', 'opam config exec -- ocamllsp' Execute(The executable should be run directly if use_opam flag is disabled): let g:ale_ocaml_ocamllsp_use_opam = 0 call ale#test#SetFilename('../test-files/ocamllsp/file.ml') AssertLinter 'ocamllsp', 'ocamllsp' ================================================ FILE: test/linter/test_ocaml_ols.vader ================================================ Before: call ale#assert#SetUpLinterTest('ocaml', 'ols') Save &filetype let &filetype = 'ocaml' After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'ocaml' Execute(The default executable should be correct): AssertLinter 'ocaml-language-server', \ ale#Escape('ocaml-language-server') . ' --stdio' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/ols/file.ml') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ols') Execute(The local executable should be used when available): call ale#test#SetFilename('../test-files/ols/file.ml') AssertLinter ale#path#Simplify(g:dir . '/../test-files/ols/node_modules/.bin/ocaml-language-server'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/ols/node_modules/.bin/ocaml-language-server')) . ' --stdio' Execute(The global executable should always be used when use_global is set): let g:ale_ocaml_ols_use_global = 1 call ale#test#SetFilename('../test-files/ols/file.ml') AssertLinter 'ocaml-language-server', \ ale#Escape('ocaml-language-server') . ' --stdio' Execute(The executable should be configurable): let g:ale_ocaml_ols_executable = 'foobar' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'foobar', ale#Escape('foobar') . ' --stdio' ================================================ FILE: test/linter/test_ocamlinterface_ocamllsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('ocamlinterface', 'ocamllsp') Save &filetype let &filetype = 'ocamlinterface' After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'ocaml.interface' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/ocamllsp/file.ml') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ocamllsp') Execute(The executable should be run using opam exec by default): call ale#test#SetFilename('../test-files/ocamllsp/file.ml') AssertLinter 'ocamllsp', 'opam config exec -- ocamllsp' Execute(The executable should be run directly if use_opam flag is disabled): let g:ale_ocaml_ocamllsp_use_opam = 0 call ale#test#SetFilename('../test-files/ocamllsp/file.ml') AssertLinter 'ocamllsp', 'ocamllsp' ================================================ FILE: test/linter/test_odin_ols.vader ================================================ Before: call ale#assert#SetUpLinterTest('odin', 'ols') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'ols', ale#Escape('ols') Execute(The LSP values should be set correctly): call ale#test#SetFilename('../test-files/odin/main.odin') AssertLSPLanguage 'odin' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject '.' ================================================ FILE: test/linter/test_openscad_sca2d.vader ================================================ Before: call ale#assert#SetUpLinterTest('openscad', 'sca2d') After: call ale#assert#TearDownLinterTest() Execute(The options should be used in the command): AssertLinter 'sca2d', ale#Escape('sca2d') . ' %s' let b:ale_openscad_sca2d_options = '--foobar' AssertLinter 'sca2d', ale#Escape('sca2d') . ' --foobar %s' ================================================ FILE: test/linter/test_packwerk.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'packwerk') call ale#test#SetFilename('../test-files/ruby/valid_rails_app/db/test.rb') let g:ale_ruby_packwerk_executable = 'packwerk' let g:ale_ruby_packwerk_options = '' let b:sep = has('win32') ? '\' : '/' After: unlet! b:sep call ale#assert#TearDownLinterTest() Execute(Executable should default to packwerk): AssertLinter 'packwerk', ale#Escape('packwerk') \ . ' check ' \ . ale#Escape('db' . b:sep . 'test.rb') Execute(Should be able to set a custom executable): let g:ale_ruby_packwerk_executable = 'bin/packwerk' AssertLinter 'bin/packwerk', ale#Escape('bin/packwerk') \ . ' check ' \ . ale#Escape('db' . b:sep . 'test.rb') Execute(Setting bundle appends 'exec packwerk'): let g:ale_ruby_packwerk_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec packwerk' \ . ' check ' \ . ale#Escape('db' . b:sep . 'test.rb') Execute(Command callback should be empty when not in a valid Rails app): call ale#test#SetFilename('../test-files/ruby/not_a_rails_app/test.rb') AssertLinter 'packwerk', '' ================================================ FILE: test/linter/test_perl.vader ================================================ Before: call ale#assert#SetUpLinterTest('perl', 'perl') After: call ale#assert#TearDownLinterTest() Execute(The default Perl command callback should be correct): AssertLinter 'perl', ale#Escape('perl') . ' -c -Mwarnings -Ilib %t' Execute(Overriding the executable and command should work): let b:ale_perl_perl_executable = 'foobar' let b:ale_perl_perl_options = '-w' AssertLinter 'foobar', ale#Escape('foobar') . ' -w %t' unlet b:ale_perl_perl_executable unlet b:ale_perl_perl_options ================================================ FILE: test/linter/test_perl6.vader ================================================ 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' ================================================ FILE: test/linter/test_perl_languageserver.vader ================================================ " Author: rymdbar Before: call ale#assert#SetUpLinterTest('perl', 'languageserver') After: call ale#assert#TearDownLinterTest() Execute(The default Perl command callback should be correct): AssertLinter 'perl', \ ale#Escape('perl') . ' -MPerl::LanguageServer -ePerl::LanguageServer::run' Execute(Overriding the executable should work): let b:ale_perl_perl_executable = 'plls' AssertLinter 'plls', ale#Escape('plls') . \ ' -MPerl::LanguageServer -ePerl::LanguageServer::run' unlet b:ale_perl_perl_executable Execute(The project root should be detected correctly in from build files): for mod in ['extutils-makemaker', 'module-build', 'dist-zilla'] call ale#test#SetFilename('../test-files/perl/' . mod . '/subdir/empty.pl') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/perl/' . mod) endfor Execute(The project root should be globally configurable): for mod in ['extutils-makemaker', 'module-build', 'dist-zilla'] call ale#test#SetFilename('../test-files/perl/'. mod . '/subdir/empty.pl') " Configuring g:ale_root using a Dictionary works. let g:ale_root.languageserver = \ ale#path#Simplify(g:dir . '/../test-files/perl') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/perl') unlet g:ale_root.languageserver " As tracked by , there " is a bug with g:ale_root. " While attempting to configure g:ale_root using a String might be a quite " limiting setup, it would be handy for debugging. However the test case is " missing here. It would unfortunately just fail. endfor Execute(The project root should be per buffer configurable): for mod in ['extutils-makemaker', 'module-build', 'dist-zilla'] call ale#test#SetFilename('../test-files/perl/'. mod . '/subdir/empty.pl') " Configuring b:ale_root using a String works. let b:ale_root = ale#path#Simplify(g:dir . '/../test-files/perl') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/perl') unlet b:ale_root " Configuring b:ale_root using a Dictionary works. let b:ale_root = { \ 'languageserver': ale#path#Simplify(g:dir . '/../test-files/perl') \ } AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/perl') unlet b:ale_root.languageserver endfor Execute(The LSP values should be set correctly): AssertLSPLanguage 'perl' AssertLSPOptions {} AssertLSPConfig {'perl': {'enable': 1}} Execute(Should accept configuration settings): let b:ale_perl_languageserver_config = { \ 'perl': { \ 'perlInc': ['/usr/share/perl5/', '/usr/local/share/perl5/' ], \ 'fileFilter': [''], \ }, \ } AssertLSPConfig { \ 'perl': { \ 'perlInc': ['/usr/share/perl5/', '/usr/local/share/perl5/' ], \ 'fileFilter': [''], \ }, \ } ================================================ FILE: test/linter/test_perlcritic.vader ================================================ Before: call ale#assert#SetUpLinterTest('perl', 'perlcritic') call ale#test#SetFilename('test.pl') let g:ale_perl_perlcritic_profile = '' After: unlet! b:readme_path call ale#assert#TearDownLinterTest() Execute(The command should be correct with g:ale_perl_perlcritic_showrules off): let b:ale_perl_perlcritic_showrules = 0 AssertLinter 'perlcritic', ale#Escape('perlcritic') \ . ' --verbose ' . ale#Escape('%l:%c %m\n') . ' --nocolor' Execute(The command should be correct with g:ale_perl_perlcritic_showrules on): let b:ale_perl_perlcritic_showrules = 1 AssertLinter 'perlcritic', ale#Escape('perlcritic') \ . ' --verbose ' . ale#Escape('%l:%c %m [%p]\n') . ' --nocolor' Execute(The command search for the profile file when set): let b:ale_perl_perlcritic_profile = 'README.md' let b:readme_path = ale#path#Simplify(expand('%:p:h:h:h') . '/README.md') AssertLinter 'perlcritic', ale#Escape('perlcritic') \ . ' --verbose ' . ale#Escape('%l:%c %m\n') . ' --nocolor' \ . ' --profile ' . ale#Escape(b:readme_path) Execute(Extra options should be set appropriately): let b:ale_perl_perlcritic_options = 'beep boop' AssertLinter 'perlcritic', ale#Escape('perlcritic') \ . ' --verbose ' . ale#Escape('%l:%c %m\n') . ' --nocolor' \ . ' beep boop' ================================================ FILE: test/linter/test_php.vader ================================================ 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 ================================================ FILE: test/linter/test_php_intelephense.vader ================================================ Before: call ale#assert#SetUpLinterTest('php', 'intelephense') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'intelephense', \ ale#Escape('intelephense') . ' --stdio' Execute(The project path should be correct for .git directories): call ale#test#SetFilename('../test-files/php/with-git/test.php') silent! call mkdir('../test-files/php/with-git/.git', 'p') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-git') Execute(The project path should be correct for composer.json file): call ale#test#SetFilename('../test-files/php/with-composer/test.php') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-composer') Execute(The project cache should be saved in a temp dir): call ale#test#SetFilename('../test-files/php/with-composer/test.php') let g:ale_php_intelephense_config = { 'storagePath': '/tmp/intelephense' } AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-composer') ================================================ FILE: test/linter/test_php_langserver.vader ================================================ Before: call ale#assert#SetUpLinterTest('php', 'langserver') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): call ale#test#SetFilename('../test-files/dummy') AssertLinter 'php-language-server.php', \ 'php ' . ale#Escape('php-language-server.php') Execute(Vendor executables should be detected): call ale#test#SetFilename('../test-files/php/test.php') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/php/vendor/bin/php-language-server.php'), \ 'php ' . ale#Escape(ale#path#Simplify( \ g:dir \ . '/../test-files/php/vendor/bin/php-language-server.php' \ )) Execute(The project path should be correct for .git directories): call ale#test#SetFilename('../test-files/php/with-git/test.php') silent! call mkdir('../test-files/php/with-git/.git') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-git') Execute(The project path should be correct for composer.json file): call ale#test#SetFilename('../test-files/php/with-composer/test.php') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-composer') ================================================ FILE: test/linter/test_phpactor.vader ================================================ Before: call ale#assert#SetUpLinterTest('php', 'phpactor') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'phpactor', \ ale#Escape('phpactor') . ' language-server' Execute(Overriding the executable should work): let b:ale_php_phpactor_executable = 'my_phpactor' AssertLinter 'my_phpactor', ale#Escape('my_phpactor') . ' language-server' unlet b:ale_php_phpactor_executable Execute(The project path should be correct for .git directories): call ale#test#SetFilename('../test-files/php/with-git/test.php') silent! call mkdir('../test-files/php/with-git/.git') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-git') Execute(The project path should be correct for composer.json file): call ale#test#SetFilename('../test-files/php/with-composer/test.php') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-composer') Execute(The LSP values should be set correctly): AssertLSPLanguage 'php' AssertLSPOptions {} AssertLSPConfig {} Execute(Should accept initialization options): let b:ale_php_phpactor_init_options = { \ 'language_server_phpstan.enabled': v:false, \ } AssertLSPOptions { \ 'language_server_phpstan.enabled': v:false, \ } ================================================ FILE: test/linter/test_phpcs.vader ================================================ 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('../test-files/phpcs/project-with-phpcs/foo/test.php') let g:executable = ale#path#Simplify(g:dir . '/../test-files/phpcs/project-with-phpcs/vendor/bin/phpcs') AssertLinterCwd '%s:h' 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('../test-files/phpcs/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('../test-files/phpcs/project-without-phpcs/foo/test.php') AssertLinter 'phpcs', ale#Escape('phpcs') \ . ' -s --report=emacs --stdin-path=%s' Execute(User provided options should be 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' Execute(The _standard option should be used): let g:ale_php_phpcs_standard = 'foobar' AssertLinter 'phpcs', ale#Escape('phpcs') \ . ' -s --report=emacs --stdin-path=%s --standard=' . ale#Escape('foobar') ================================================ FILE: test/linter/test_phpmd.vader ================================================ Before: call ale#assert#SetUpLinterTest('php', 'phpmd') After: call ale#assert#TearDownLinterTest() Execute(Custom executables should be used for the executable and command): let g:ale_php_phpmd_executable = 'phpmd_test' AssertLinter 'phpmd_test', \ ale#Escape('phpmd_test') \ . ' %t text cleancode,codesize,controversial,design,naming,unusedcode --ignore-violations-on-exit' ================================================ FILE: test/linter/test_phpstan.vader ================================================ Before: call ale#assert#SetUpLinterTest('php', 'phpstan') let g:old_dir = g:dir " Create a temporary directory and work within it, otherwise these tests " cannot be run in parallel. let g:parent_dir = tempname() let g:dir = ale#path#Simplify(g:parent_dir . '/src') call mkdir(g:parent_dir, '', 0750) call mkdir(g:dir, '', 0750) silent! execute 'cd ' . fnameescape(g:dir) silent! noautocmd execute 'file ' . fnameescape(ale#path#Simplify(g:dir . '/test.php')) call delete('./phpstan.neon') GivenCommandOutput ['0.10.2'] After: silent! execute 'cd ' . fnameescape(g:old_dir) call delete(g:dir, 'rf') let g:dir = g:old_dir unlet! g:old_dir call ale#assert#TearDownLinterTest() Execute(The local phpstan executable should be used): call mkdir('vendor/bin', 'p', 0750) call writefile([''], 'vendor/bin/phpstan') call ale#test#SetFilename('phpstan-test-files/foo/test.php') let g:executable = ale#path#Simplify(g:dir . '/vendor/bin/phpstan') AssertLinter g:executable, \ ale#Escape(g:executable) . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('4') . ' %s' AssertLinterCwd v:null Execute(use_global should override local executable detection): let g:ale_php_phpstan_use_global = 1 call mkdir('vendor/bin', 'p', 0750) call writefile([''], 'vendor/bin/phpstan') call ale#test#SetFilename('phpstan-test-files/foo/test.php') AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('4') . ' %s' Execute(Custom executables should be used for the executable and command): let g:ale_php_phpstan_executable = 'phpstan_test' AssertLinter 'phpstan_test', \ ale#Escape('phpstan_test') . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('4') . ' %s' Execute(project with level set to 3): call ale#test#SetFilename('phpstan-test-files/foo/test.php') let g:ale_php_phpstan_level = 3 AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('3') . ' %s' Execute(project with level set to 0): call ale#test#SetFilename('phpstan-test-files/foo/test.php') let g:ale_php_phpstan_level = 0 AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('0') . ' %s' Execute(Custom phpstan configuration file): let g:ale_php_phpstan_configuration = 'phpstan_config' AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -c ' . ale#Escape('phpstan_config') . ' -l ' . ale#Escape('4') . ' %s' Execute(Choose the right format for error format param): GivenCommandOutput ['0.10.3'] AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', \ ale#Escape('phpstan') . ' analyze --no-progress --error-format json -l ' . ale#Escape('4') . ' %s' \ ] Execute(Configuration file exists in current directory): call writefile(['parameters:', ' level: 7'], './phpstan.neon') let g:ale_php_phpstan_level = '' let g:ale_php_phpstan_configuration = '' AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json %s' \ ] AssertLinterCwd g:dir Execute(Configuration dist file exists in current directory): call writefile(['parameters:', ' level: 7'], './phpstan.neon.dist') let g:ale_php_phpstan_level = '' let g:ale_php_phpstan_configuration = '' AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json %s' \ ] AssertLinterCwd g:dir Execute(Configuration alternative dist file exists in current directory): call writefile(['parameters:', ' level: 7'], './phpstan.dist.neon') let g:ale_php_phpstan_level = '' let g:ale_php_phpstan_configuration = '' AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json %s' \ ] AssertLinterCwd g:dir Execute(Configuration file exists in current directory, but force phpstan level): call writefile(['parameters:', ' level: 7'], './phpstan.neon') let g:ale_php_phpstan_configuration = '' let g:ale_php_phpstan_level = '7' AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('7') . ' %s' \ ] Execute(Configuration file exists in current directory, but force phpstan configuration): call writefile(['parameters:', ' level: 7'], './phpstan.neon') let g:ale_php_phpstan_level = '' let g:ale_php_phpstan_configuration = 'phpstan.custom.neon' AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -c ' . ale#Escape('phpstan.custom.neon') . ' %s' \ ] Execute(Autoload parameter is added to the command): let g:ale_php_phpstan_autoload = 'autoload.php' AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -a ' . ale#Escape('autoload.php') . ' -l ' . ale#Escape('4') . ' %s' Execute(Memory limit parameter is added to the command): let g:ale_php_phpstan_memory_limit = '500M' AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json -l ' . ale#Escape('4') . ' --memory-limit=' . ale#Escape('500M') . ' %s' Execute(Directory is changed to that of the configuration file): call writefile([], '../phpstan.neon') AssertLinterCwd g:parent_dir AssertLinter 'phpstan', \ ale#Escape('phpstan') . ' analyze --no-progress --errorFormat json %s' ================================================ FILE: test/linter/test_pony_ponyc.vader ================================================ Before: call ale#assert#SetUpLinterTest('pony', 'ponyc') After: call ale#assert#TearDownLinterTest() Execute(The default ponyc command should be correct): AssertLinter 'ponyc', ale#Escape('ponyc') . ' --pass paint' Execute(The pony executable and options should be configurable): let b:ale_pony_ponyc_executable = 'foobar' let b:ale_pony_ponyc_options = '--some-option' AssertLinter 'foobar', ale#Escape('foobar') . ' --some-option' ================================================ FILE: test/linter/test_prospector.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'prospector') After: call ale#assert#TearDownLinterTest() Execute(Setting executable to 'pipenv' appends 'run prospector'): let g:ale_python_prospector_executable = 'path/to/pipenv' 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('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run prospector' \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s' Execute(Setting executable to 'poetry' appends 'run prospector'): let g:ale_python_prospector_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run prospector' \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s' Execute(Poetry is detected when python_prospector_auto_poetry is set): let g:ale_python_prospector_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run prospector' \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s' Execute(uv is detected when python_prospector_auto_uv is set): let g:ale_python_prospector_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run prospector' \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s' ================================================ FILE: test/linter/test_proto.vader ================================================ Before: call ale#assert#SetUpLinterTest('proto', 'protoc_gen_lint') call ale#test#SetFilename('test.proto') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'protoc', \ 'protoc' . ' -I ' . ale#Escape(getcwd()) . ' --lint_out=. ' . '%s' Execute(The callback should include any additional options): let b:ale_proto_protoc_gen_lint_options = '--some-option' AssertLinter 'protoc', \ 'protoc' . ' -I ' . ale#Escape(getcwd()) . ' --some-option --lint_out=. ' . '%s' ================================================ FILE: test/linter/test_protolint.vader ================================================ Before: call ale#assert#SetUpLinterTest('proto', 'protolint') call ale#test#SetFilename('test.proto') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'protolint', \ ale#Escape('protolint') \ . ' lint' \ . ' -reporter=unix' \ . ' %s' Execute(The callback should include any additional options): let b:ale_proto_protolint_executable = '/tmp/protolint' let b:ale_proto_protolint_config = '/tmp/protolint.yaml' AssertLinter '/tmp/protolint', \ ale#Escape('/tmp/protolint') \ . ' lint' \ . ' -config_path=' . ale#Escape('/tmp/protolint.yaml') \ . ' -reporter=unix' \ . ' %s' ================================================ FILE: test/linter/test_psalm.vader ================================================ Before: call ale#assert#SetUpLinterTest('php', 'psalm') After: unlet! g:i unlet! g:matched 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', \ ale#Escape('psalm') . ' --language-server' Execute(Vendor executables should be detected): call ale#test#SetFilename('../test-files/psalm/test.php') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/psalm/vendor/bin/psalm'), \ ale#Escape(ale#path#Simplify( \ g:dir \ . '/../test-files/psalm/vendor/bin/psalm' \ )) . ' --language-server' let g:ale_php_psalm_use_global = 1 AssertLinter 'psalm', \ ale#Escape('psalm') . ' --language-server' Execute(User provided options should be used): let g:ale_php_psalm_options = '--my-user-provided-option my-value' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'psalm', \ ale#Escape('psalm') \ . ' --language-server --my-user-provided-option my-value' Execute(The project path should be correct for composer.json file): call ale#test#SetFilename('../test-files/php/with-composer/test.php') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/php/with-composer') ================================================ FILE: test/linter/test_puglint.vader ================================================ Before: call ale#assert#SetUpLinterTest('pug', 'puglint') After: call ale#assert#TearDownLinterTest() Execute(puglint should detect local executables and package.json): call ale#test#SetFilename('../test-files/puglint/test.pug') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/package.json')) \ . ' -r inline %t' Execute(puglint should use global executables if configured): let g:ale_pug_puglint_use_global = 1 call ale#test#SetFilename('../test-files/puglint/test.pug') AssertLinter 'pug-lint', \ ale#Escape('pug-lint') \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/package.json')) \ . ' -r inline %t' Execute(puglint should detect .pug-lintrc): call ale#test#SetFilename('../test-files/puglint/puglint_rc_dir/subdir/test.pug') AssertLinter ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/puglint_rc_dir/.pug-lintrc')) \ . ' -r inline %t' Execute(puglint should detect .pug-lintrc.js): call ale#test#SetFilename('../test-files/puglint/puglint_rc_js_dir/subdir/test.pug') AssertLinter ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/puglint_rc_js_dir/.pug-lintrc.js')) \ . ' -r inline %t' Execute(puglint should detect .pug-lintrc.json): call ale#test#SetFilename('../test-files/puglint/puglint_rc_json_dir/subdir/test.pug') AssertLinter ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/node_modules/.bin/pug-lint')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/puglint/puglint_rc_json_dir/.pug-lintrc.json')) \ . ' -r inline %t' ================================================ FILE: test/linter/test_puppet_languageserver.vader ================================================ Before: call ale#assert#SetUpLinterTest('puppet', 'languageserver') After: call ale#assert#TearDownLinterTest() Execute(old-style module should find its root correctly): call ale#test#SetFilename('../test-files/puppet/old-style-module/manifests/init.pp') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/puppet/old-style-module'), \ ale_linters#puppet#languageserver#GetProjectRoot(bufnr('')) \ Execute(new-style module should find its root correctly): call ale#test#SetFilename('../test-files/puppet/new-style-module/lib/puppet/types/exampletype.rb') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/puppet/new-style-module'), \ ale_linters#puppet#languageserver#GetProjectRoot(bufnr('')) ================================================ FILE: test/linter/test_purescript_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('purescript', 'ls') After: call ale#assert#TearDownLinterTest() Execute(should set correct defaults): AssertLinter 'purescript-language-server', ale#Escape('purescript-language-server') . ' --stdio' Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/purescript/spago/Foo.purs') AssertLSPLanguage 'purescript' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/purescript/spago') Execute(should set correct project for bower): call ale#test#SetFilename('../test-files/purescript/bower/Foo.purs') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/purescript/bower') Execute(should set correct project for psc-package): call ale#test#SetFilename('../test-files/purescript/psc-package/Foo.purs') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/purescript/psc-package') Execute(should accept configuration settings): AssertLSPConfig {} let b:ale_purescript_ls_config = {'purescript': {'addSpagoSources': v:true}} AssertLSPConfig {'purescript': {'addSpagoSources': v:true}} ================================================ FILE: test/linter/test_pycln.vader ================================================ Before: Save g:ale_python_auto_pipenv let g:ale_python_auto_pipenv = 0 call ale#assert#SetUpLinterTest('python', 'pycln') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:cmd_tail = ' --check -' GivenCommandOutput ['pycln, version 1.3.0'] After: unlet! b:bin_dir unlet! b:executable unlet! b:cmd_tail call ale#assert#TearDownLinterTest() Execute(The pycln callbacks should return the correct default values): AssertLinterCwd expand('%:p:h') AssertLinter 'pycln', ale#Escape('pycln') . b:cmd_tail Execute(pycln should run with the file path of buffer in old versions): " version `1.3.0` supports liniting input from stdin GivenCommandOutput ['pycln, version 1.2.99'] AssertLinterCwd expand('%:p:h') AssertLinter 'pycln', ale#Escape('pycln') . b:cmd_tail[:-3] . ' %s' Execute(pycln should run with the stdin in new enough versions): GivenCommandOutput ['pycln, version 1.3.0'] AssertLinterCwd expand('%:p:h') AssertLinter 'pycln', ale#Escape('pycln') . b:cmd_tail[:-3] . ' -' Execute(The option for disabling changing directories should work): let g:ale_python_pycln_change_directory = 0 AssertLinterCwd '' AssertLinter 'pycln', ale#Escape('pycln') . b:cmd_tail Execute(The pycln executable and options should be configurable): let g:ale_python_pycln_executable = 'foo' let g:ale_python_pycln_options = '--some-flag' AssertLinter 'foo', ale#Escape('foo') . ' --some-flag' . b:cmd_tail Execute(The pycln callbacks shouldn't detect virtualenv directories where they don't exist): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'pycln', ale#Escape('pycln') . b:cmd_tail Execute(The pycln callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pycln' \) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, ale#Escape(b:executable) . b:cmd_tail Execute(You should able able to use the global pycln instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pycln_use_global = 1 AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter 'pycln', ale#Escape('pycln') . b:cmd_tail Execute(Setting executable to 'pipenv' appends 'run pycln'): let g:ale_python_pycln_executable = 'path/to/pipenv' let g:ale_python_pycln_use_global = 1 AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run pycln' \ . b:cmd_tail Execute(Pipenv is detected when python_pycln_auto_pipenv is set): let g:ale_python_pycln_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run pycln' \ . b:cmd_tail Execute(Setting executable to 'poetry' appends 'run pycln'): let g:ale_python_pycln_executable = 'path/to/poetry' let g:ale_python_pycln_use_global = 1 AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run pycln' \ . b:cmd_tail Execute(poetry is detected when python_pycln_auto_poetry is set): let g:ale_python_pycln_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'poetry', ale#Escape('poetry') . ' run pycln' \ . b:cmd_tail Execute(uv is detected when python_pycln_auto_uv is set): let g:ale_python_pycln_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'uv', ale#Escape('uv') . ' run pycln' \ . b:cmd_tail Execute(configuration files set in _config should be supported): let g:ale_python_pycln_config_file = ale#path#Simplify(g:dir . '/../test-files/pycln/other_config.xml') AssertLinter 'pycln', \ ale#Escape('pycln') \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/pycln/other_config.xml')) \ . b:cmd_tail Execute(configuration file set in _options overrides _config): let g:ale_python_pycln_config_file = '/foo.xml' let g:ale_python_pycln_options = '--config /bar.xml' AssertLinter 'pycln', ale#Escape('pycln') . ' --config /bar.xml' . b:cmd_tail let b:ale_python_pycln_options = '-x --config /bar.xml' AssertLinter 'pycln', ale#Escape('pycln') . ' -x --config /bar.xml' . b:cmd_tail ================================================ FILE: test/linter/test_pycodestyle.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pycodestyle') After: call ale#assert#TearDownLinterTest() Execute(The pycodestyle command callback should return default string): AssertLinter 'pycodestyle', ale#Escape('pycodestyle') . ' -' Execute(The pycodestyle command callback should allow options): let g:ale_python_pycodestyle_options = '--exclude=test*.py' AssertLinter 'pycodestyle', \ ale#Escape('pycodestyle') . ' --exclude=test*.py -' Execute(The pycodestyle executable should be configurable): let g:ale_python_pycodestyle_executable = '~/.local/bin/pycodestyle' AssertLinter '~/.local/bin/pycodestyle', \ ale#Escape('~/.local/bin/pycodestyle') . ' -' Execute(Setting executable to 'pipenv' appends 'run pycodestyle'): let g:ale_python_pycodestyle_executable = 'path/to/pipenv' 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('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pycodestyle -' Execute(Setting executable to 'poetry' appends 'run pycodestyle'): let g:ale_python_pycodestyle_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pycodestyle -' Execute(Poetry is detected when python_pycodestyle_auto_poetry is set): let g:ale_python_pycodestyle_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pycodestyle -' Execute(uv is detected when python_pycodestyle_auto_uv is set): let g:ale_python_pycodestyle_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pycodestyle -' ================================================ FILE: test/linter/test_pydocstyle.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pydocstyle') call ale#test#SetFilename('example/test.py') After: call ale#assert#TearDownLinterTest() Execute(The pydocstyle command callback should return default string): AssertLinterCwd '%s:h' AssertLinter 'pydocstyle', ale#Escape('pydocstyle') . ' %s' Execute(The pydocstyle command callback should allow options): let g:ale_python_pydocstyle_options = '--verbose' AssertLinter 'pydocstyle', ale#Escape('pydocstyle') . ' --verbose %s' Execute(The pydocstyle executable should be configurable): let g:ale_python_pydocstyle_executable = '~/.local/bin/pydocstyle' AssertLinter '~/.local/bin/pydocstyle', \ ale#Escape('~/.local/bin/pydocstyle') . ' %s' Execute(Setting executable to 'pipenv' appends 'run pydocstyle'): let g:ale_python_pydocstyle_executable = 'path/to/pipenv' AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run pydocstyle %s' Execute(Pipenv is detected when python_pydocstyle_auto_pipenv is set): let g:ale_python_pydocstyle_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run pydocstyle %s' Execute(Setting executable to 'poetry' appends 'run pydocstyle'): let g:ale_python_pydocstyle_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pydocstyle %s' Execute(Poetry is detected when python_pydocstyle_auto_poetry is set): let g:ale_python_pydocstyle_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', ale#Escape('poetry') . ' run pydocstyle %s' Execute(uv is detected when python_pydocstyle_auto_uv is set): let g:ale_python_pydocstyle_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', ale#Escape('uv') . ' run pydocstyle %s' ================================================ FILE: test/linter/test_pyflakes.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pyflakes') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The pyflakes command callback should return default string): AssertLinter 'pyflakes', ale#Escape('pyflakes') . ' %t' Execute(The pyflakes executable should be configurable): let g:ale_python_pyflakes_executable = '~/.local/bin/pyflakes' AssertLinter '~/.local/bin/pyflakes', \ ale#Escape('~/.local/bin/pyflakes') . ' %t' Execute(The pyflakes executable should be run from the virtualenv path): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pyflakes' \) AssertLinter b:executable, ale#Escape(b:executable) . ' %t' Execute(You should be able to override the pyflakes virtualenv lookup): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pyflakes_use_global = 1 AssertLinter 'pyflakes', ale#Escape('pyflakes') . ' %t' Execute(Setting executable to 'pipenv' appends 'run pyflakes'): let g:ale_python_pyflakes_executable = 'path/to/pipenv' call ale#test#SetFilename('../test-files/dummy') 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('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pyflakes %t' Execute(Setting executable to 'poetry' appends 'run pyflakes'): let g:ale_python_pyflakes_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pyflakes %t', Execute(Poetry is detected when python_pyflakes_auto_poetry is set): let g:ale_python_pyflakes_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pyflakes %t' Execute(uv is detected when python_pyflakes_auto_uv is set): let g:ale_python_pyflakes_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pyflakes %t' ================================================ FILE: test/linter/test_pylama.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pylama') call ale#test#SetFilename('test.py') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:command_tail = ' %s' After: unlet! b:bin_dir unlet! b:executable unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The default pylama command should be correct): AssertLinterCwd ale#path#Simplify(g:dir) AssertLinter 'pylama', ale#Escape('pylama') . b:command_tail Execute(The option for disabling changing directories should work): let g:ale_python_pylama_change_directory = 0 AssertLinterCwd '' AssertLinter 'pylama', ale#Escape('pylama') . b:command_tail Execute(The pylama executable should be configurable, and escaped properly): let g:ale_python_pylama_executable = 'executable with spaces' AssertLinterCwd ale#path#Simplify(g:dir) AssertLinter 'executable with spaces', \ ale#Escape('executable with spaces') . b:command_tail Execute(The pylama command callback should let you set options): let g:ale_python_pylama_options = '--some-option' AssertLinterCwd ale#path#Simplify(g:dir) AssertLinter 'pylama', ale#Escape('pylama') . ' --some-option' . b:command_tail Execute(The pylama command callback should switch directories to the detected project root): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'pylama', ale#Escape('pylama') . b:command_tail Execute(The pylama command callback shouldn't detect virtualenv directories where they don't exist): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'pylama', ale#Escape('pylama') . b:command_tail Execute(The pylama command callback should detect virtualenv directories and switch to the project root): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pylama' \) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, ale#Escape(b:executable) . b:command_tail Execute(You should able able to use the global pylama instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pylama_use_global = 1 AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter 'pylama', ale#Escape('pylama') . b:command_tail Execute(Setting executable to 'pipenv' appends 'run pylama'): let g:ale_python_pylama_executable = 'path/to/pipenv' AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run pylama' . b:command_tail Execute(Pipenv is detected when python_pylama_auto_pipenv is set): let g:ale_python_pylama_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run pylama' . b:command_tail Execute(Setting executable to 'poetry' appends 'run pylama'): let g:ale_python_pylama_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pylama' . b:command_tail Execute(poetry is detected when python_pylama_auto_poetry is set): let g:ale_python_pylama_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', ale#Escape('poetry') . ' run pylama' . b:command_tail Execute(uv is detected when python_pylama_auto_uv is set): let g:ale_python_pylama_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', ale#Escape('uv') . ' run pylama' . b:command_tail ================================================ FILE: test/linter/test_pylint.vader ================================================ Before: Save g:ale_python_auto_pipenv let g:ale_python_auto_pipenv = 0 call ale#assert#SetUpLinterTest('python', 'pylint') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:command_tail = ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' GivenCommandOutput ['pylint 2.3.0'] After: unlet! b:bin_dir unlet! b:executable unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The pylint callbacks should return the correct default values): AssertLinterCwd expand('%:p:h') AssertLinter 'pylint', ale#Escape('pylint') . b:command_tail Execute(Pylint should run with the --from-stdin in new enough versions): GivenCommandOutput ['pylint 2.4.0'] AssertLinterCwd expand('%:p:h') AssertLinter 'pylint', ale#Escape('pylint') . b:command_tail[:-3] . '--from-stdin %s' Execute(The option for disabling changing directories should work): let g:ale_python_pylint_change_directory = 0 AssertLinterCwd '' AssertLinter 'pylint', ale#Escape('pylint') . b:command_tail Execute(The pylint executable should be configurable, and escaped properly): let g:ale_python_pylint_executable = 'executable with spaces' AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . b:command_tail Execute(The pylint command callback should let you set options): let g:ale_python_pylint_options = '--some-option' AssertLinter 'pylint', ale#Escape('pylint') . ' --some-option' . b:command_tail Execute(The pylint callbacks shouldn't detect virtualenv directories where they don't exist): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'pylint', ale#Escape('pylint') . b:command_tail Execute(The pylint callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pylint' \) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, ale#Escape(b:executable) . b:command_tail Execute(You should able able to use the global pylint instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pylint_use_global = 1 AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter 'pylint', ale#Escape('pylint') . b:command_tail Execute(Setting executable to 'pipenv' appends 'run pylint'): let g:ale_python_pylint_executable = 'path/to/pipenv' let g:ale_python_pylint_use_global = 1 AssertLinter 'path/to/pipenv', 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('../test-files/python/pipenv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run pylint' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' Execute(Setting executable to 'poetry' appends 'run pylint'): let g:ale_python_pylint_executable = 'path/to/poetry' let g:ale_python_pylint_use_global = 1 AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run pylint' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' Execute(poetry is detected when python_pylint_auto_poetry is set): let g:ale_python_pylint_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'poetry', ale#Escape('poetry') . ' run pylint' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' Execute(uv is detected when python_pylint_auto_uv is set): let g:ale_python_pylint_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'uv', ale#Escape('uv') . ' run pylint' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' ================================================ FILE: test/linter/test_pylsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pylsp') Save b:ale_python_auto_virtualenv let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:venv_bin unlet! b:sep unlet! b:executable call ale#test#SetFilename('..') call ale#assert#TearDownLinterTest() Execute(The default pylsp command should be correct): call ale#test#SetFilename('./foo.py') AssertLinter 'pylsp', ale#Escape('pylsp') Execute(The pylsp command and executable should be configurable): let g:ale_python_pylsp_executable = '~/.local/bin/pylsp' let g:ale_python_pylsp_options = '--some-option' AssertLinter '~/.local/bin/pylsp' , ale#Escape('~/.local/bin/pylsp') \ . ' --some-option' Execute(The cwd and project root should be detected correctly): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#test#GetFilename('../test-files/python/with_virtualenv/subdir') AssertLSPProject ale#test#GetFilename('../test-files/python/with_virtualenv/subdir') Execute(The pylsp executable should be run from the virtualenv path): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pylsp' \) AssertEqual ale#Escape(b:executable), \ ale_linters#python#pylsp#GetCommand(bufnr('')) Execute(virtualenv vars should be used when ale_python_auto_virtualenv = 1): let b:ale_python_auto_virtualenv = 1 call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:venv_bin = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir) let b:sep = has('win32') ? ';' : ':' let b:executable = ale#path#Simplify(b:venv_bin . '/pylsp') AssertLinter b:executable, ale#python#AutoVirtualenvEnvString(bufnr('')) \ . ale#Escape(b:executable) Assert !empty(ale#python#AutoVirtualenvEnvString(bufnr(''))) Execute(You should be able to override the pylsp virtualenv lookup): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pylsp_use_global = 1 AssertLinter 'pylsp', ale#Escape('pylsp') Execute(Setting executable to 'pipenv' appends 'run pylsp'): let g:ale_python_pylsp_executable = 'path/to/pipenv' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run pylsp' Execute(Pipenv is detected when python_pylsp_auto_pipenv is set): let g:ale_python_pylsp_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pylsp' Execute(Setting executable to 'poetry' appends 'run pylsp'): let g:ale_python_pylsp_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run pylsp' Execute(poetry is detected when python_pylsp_auto_poetry is set): let g:ale_python_pylsp_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pylsp' Execute(uv is detected when python_pylsp_auto_uv is set): let g:ale_python_pylsp_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pylsp' Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_python_pylsp_config = {'pylsp': {'plugins': {'preload': {'enabled': v:false}}}} AssertLSPConfig {'pylsp': {'plugins': {'preload': {'enabled': v:false}}}} ================================================ FILE: test/linter/test_pymarkdown.vader ================================================ Before: call ale#assert#SetUpLinterTest('markdown', 'pymarkdown') After: call ale#assert#TearDownLinterTest() Execute(The pymarkdown command callback should return default string): AssertLinter 'pymarkdown', ale#Escape('pymarkdown') . ' scan-stdin' Execute(The pycodestyle command callback should allow options): let g:ale_markdown_pymarkdown_options = '--exclude=test*.py' AssertLinter 'pymarkdown', \ ale#Escape('pymarkdown') . ' --exclude=test*.py scan-stdin' Execute(The pymarkdown executable should be configurable): let g:ale_markdown_pymarkdown_executable = '~/.local/bin/pymarkdown' AssertLinter '~/.local/bin/pymarkdown', \ ale#Escape('~/.local/bin/pymarkdown') . ' scan-stdin' Execute(Setting executable to 'pipenv' appends 'run pymarkdown'): let g:ale_markdown_pymarkdown_executable = 'path/to/pipenv' AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run pymarkdown scan-stdin' Execute(Pipenv is detected when markdown_pymarkdown_auto_pipenv is set): let g:ale_markdown_pymarkdown_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pymarkdown scan-stdin' Execute(Setting executable to 'poetry' appends 'run pymarkdown'): let g:ale_markdown_pymarkdown_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pymarkdown scan-stdin' Execute(Poetry is detected when markdown_pymarkdown_auto_poetry is set): let g:ale_markdown_pymarkdown_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pymarkdown scan-stdin' Execute(Setting executable to 'uv' appends 'run pymarkdown'): let g:ale_markdown_pymarkdown_executable = 'path/to/uv' AssertLinter 'path/to/uv', \ ale#Escape('path/to/uv') . ' run pymarkdown scan-stdin' Execute(uv is detected when markdown_pymarkdown_auto_uv is set): let g:ale_markdown_pymarkdown_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pymarkdown scan-stdin' ================================================ FILE: test/linter/test_pymarkdown_handler.vader ================================================ Before: Save g:ale_warn_about_trailing_whitespace let g:ale_warn_about_trailing_whitespace = 1 runtime ale_linters/markdown/pymarkdown.vim After: Restore unlet! b:ale_warn_about_trailing_whitespace call ale#linter#Reset() Execute (Should parse error correctly): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'M', \ 'text': 'Headings should be surrounded by blank lines', \ 'code': 'MD022', \ } \ ], \ ale_linters#markdown#pymarkdown#Handle(bufnr(''), [ \ 'foo.md:1:1: MD022: Headings should be surrounded by blank lines', \ ]) Execute(Warnings about trailing whitespace should be reported by default): AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'M', \ 'text': 'who cares', \ 'code': 'MD009', \ }, \ ], \ ale_linters#markdown#pymarkdown#Handle(bufnr(''), [ \ 'foo.md:1:1: MD009: who cares', \ ]) Execute(Disabling trailing whitespace warnings should work): let b:ale_warn_about_trailing_whitespace = 0 AssertEqual \ [ \ ], \ ale_linters#markdown#pymarkdown#Handle(bufnr(''), [ \ 'foo.md:1:1: MD009: who cares', \ ]) ================================================ FILE: test/linter/test_pyre.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pyre') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The pyre command callback should return default string): call ale#test#SetFilename('./foo.py') AssertLinter 'pyre', ale#Escape('pyre') . ' persistent' Execute(The pyre executable should be configurable): let g:ale_python_pyre_executable = '~/.local/bin/pyre' AssertLinter '~/.local/bin/pyre', \ ale#Escape('~/.local/bin/pyre') . ' persistent' Execute(The pyre executable should be run from the virtualenv path): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pyre' \) AssertLinter b:executable, ale#Escape(b:executable) . ' persistent' Execute(You should be able to override the pyre virtualenv lookup): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pyre_use_global = 1 AssertLinter 'pyre', ale#Escape('pyre') . ' persistent' Execute(Setting executable to 'pipenv' appends 'run pyre'): let g:ale_python_pyre_executable = 'path/to/pipenv' call ale#test#SetFilename('../test-files/dummy') 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('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pyre persistent' Execute(Setting executable to 'poetry' appends 'run pyre'): let g:ale_python_pyre_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pyre persistent' Execute(Poetry is detected when python_pyre_auto_poetry is set): let g:ale_python_pyre_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pyre persistent' Execute(uv is detected when python_pyre_auto_uv is set): let g:ale_python_pyre_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pyre persistent' Execute(The FindProjectRoot should detect the project root directory for namespace package via .pyre_configuration.local): silent execute 'file ' . fnameescape(g:dir . '/../test-files/python/pyre_configuration_dir/foo/bar.py') AssertEqual \ ale#path#Simplify(g:dir . '/../test-files/python/pyre_configuration_dir'), \ ale#python#FindProjectRoot(bufnr('')) ================================================ FILE: test/linter/test_pyrefly.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pyrefly') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The pyrefly command callback should return default string): call ale#test#SetFilename('./foo.py') AssertLinter 'pyrefly', ale#Escape('pyrefly') . ' lsp' Execute(The pyrefly executable should be configurable): let g:ale_python_pyrefly_executable = '~/.local/bin/pyrefly' AssertLinter '~/.local/bin/pyrefly', \ ale#Escape('~/.local/bin/pyrefly') . ' lsp' Execute(The pyrefly executable should be run from the virtualenv path): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pyrefly' \) AssertLinter b:executable, ale#Escape(b:executable) . ' lsp' Execute(You should be able to override the pyrefly virtualenv lookup): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_pyrefly_use_global = 1 AssertLinter 'pyrefly', ale#Escape('pyrefly') . ' lsp' Execute(Setting executable to 'pipenv' appends 'run pyrefly'): let g:ale_python_pyrefly_executable = 'path/to/pipenv' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run pyrefly lsp' Execute(Pipenv is detected when python_pyrefly_auto_pipenv is set): let g:ale_python_pyrefly_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pyrefly lsp' Execute(Setting executable to 'poetry' appends 'run pyrefly lsp'): let g:ale_python_pyrefly_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pyrefly lsp' Execute(Poetry is detected when python_pyrefly_auto_poetry is set): let g:ale_python_pyrefly_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pyrefly lsp' Execute(uv is detected when python_pyrefly_auto_uv is set): let g:ale_python_pyrefly_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pyrefly lsp' ================================================ FILE: test/linter/test_pyrex_cython.vader ================================================ Before: call ale#assert#SetUpLinterTest('pyrex', 'cython') After: call ale#assert#TearDownLinterTest() Execute(The default cython command should be correct): AssertLinter 'cython', ale#Escape('cython') \ . ' --working %s:h' \ . ' --include-dir %s:h' \ . ' --warning-extra' \ . ' --output-file ' . g:ale#util#nul_file . ' %t' Execute(The cython executable should be configurable): let b:ale_pyrex_cython_executable = 'cython_foobar' AssertLinter 'cython_foobar', ale#Escape('cython_foobar') \ . ' --working %s:h' \ . ' --include-dir %s:h' \ . ' --warning-extra' \ . ' --output-file ' . g:ale#util#nul_file . ' %t' Execute(Additional cython options should be configurable): let b:ale_pyrex_cython_options = '--foobar' AssertLinter 'cython', ale#Escape('cython') \ . ' --working %s:h' \ . ' --include-dir %s:h' \ . ' --foobar' \ . ' --output-file ' . g:ale#util#nul_file . ' %t' ================================================ FILE: test/linter/test_pyright.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'pyright') Save b:ale_python_auto_virtualenv let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:venv_bin unlet! b:sep unlet! b:executable call ale#test#SetFilename('..') call ale#assert#TearDownLinterTest() Execute(The command callback should return the correct default string): call ale#test#SetFilename('./foo.py') AssertLinter \ 'pyright-langserver', \ ale#Escape('pyright-langserver') . ' --stdio' Execute(The executable should be configurable): let g:ale_python_pyright_executable = '/bin/foo-bar' AssertLinter \ '/bin/foo-bar', \ ale#Escape('/bin/foo-bar') . ' --stdio' Execute(The default configuration should be mostly empty): " The default configuration needs to have at least one key in it, " or the server won't start up properly. AssertLSPConfig {'python': {}} let b:ale_python_pyright_config = {} AssertLSPConfig {'python': {}} Execute(The cwd and project root should be detected correctly): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#test#GetFilename('../test-files/python/with_virtualenv/subdir') AssertLSPProject ale#test#GetFilename('../test-files/python/with_virtualenv/subdir') Execute(virtualenv paths should be set in configuration by default): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') AssertLSPConfig { \ 'python': { \ 'pythonPath': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/python'), \ 'venvPath': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env'), \ }, \} Execute(The pythonPath should be set based on whatever the override for the venvPath is set to): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') " This overrides the default detection of the path. let b:ale_python_pyright_config = { \ 'python': { \ 'venvPath': '/foo/bar', \ }, \} AssertLSPConfig { \ 'python': { \ 'pythonPath': ale#path#Simplify('/foo/bar/' . b:bin_dir . '/python'), \ 'venvPath': '/foo/bar', \ }, \} Execute(You should be able to override pythonPath when venvPath is detected): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') " This overrides the default detection of the path. let b:ale_python_pyright_config = { \ 'python': { \ 'pythonPath': '/bin/python', \ }, \} AssertLSPConfig { \ 'python': { \ 'pythonPath': '/bin/python', \ 'venvPath': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env'), \ }, \} Execute(You should be able to override both pythonPath and venvPath): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') " This overrides the default detection of the path. let b:ale_python_pyright_config = { \ 'python': { \ 'pythonPath': '/bin/python', \ 'venvPath': '/other/dir', \ }, \} AssertLSPConfig { \ 'python': { \ 'pythonPath': '/bin/python', \ 'venvPath': '/other/dir', \ }, \} Execute(You should be able to define other settings): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:ale_python_pyright_config = { \ 'python': { \ 'analysis': {'logLevel': 'warning'}, \ }, \ 'pyright': { \ 'disableLanguageServices': v:true, \ }, \} AssertLSPConfig { \ 'python': { \ 'analysis': {'logLevel': 'warning'}, \ 'pythonPath': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/python'), \ 'venvPath': ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env'), \ }, \ 'pyright': { \ 'disableLanguageServices': v:true, \ }, \} Execute(The pyright callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/pyright-langserver' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --stdio' Execute(virtualenv vars should be used when ale_python_auto_virtualenv = 1): let b:ale_python_auto_virtualenv = 1 call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:venv_bin = ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir) let b:sep = has('win32') ? ';' : ':' let b:executable = ale#path#Simplify(b:venv_bin . '/pyright-langserver') AssertLinter b:executable, ale#python#AutoVirtualenvEnvString(bufnr('')) \ . ale#Escape(b:executable) . ' --stdio' Assert !empty(ale#python#AutoVirtualenvEnvString(bufnr(''))) Execute(Setting executable to 'pipenv' should append 'run pyright-langserver'): call ale#test#SetFilename('../test-files') let g:ale_python_pyright_executable = 'path/to/pipenv' GivenCommandOutput [] AssertLinter 'path/to/pipenv', \ ale#Escape('path/to/pipenv') . ' run pyright-langserver --stdio' Execute(Pipenv is detected when python_pyright_auto_pipenv is set): let g:ale_python_pyright_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run pyright-langserver --stdio' Execute(Setting executable to 'poetry' should append 'run pyright-langserver'): let g:ale_python_pyright_executable = 'path/to/poetry' GivenCommandOutput [] AssertLinter 'path/to/poetry', \ ale#Escape('path/to/poetry') . ' run pyright-langserver --stdio' Execute(poetry is detected when python_pyright_auto_poetry is set): let g:ale_python_pyright_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd ale#python#FindProjectRootIni(bufnr('')) AssertLinter 'poetry', \ ale#Escape('poetry') . ' run pyright-langserver --stdio' Execute(uv is detected when python_pyright_auto_uv is set): let g:ale_python_pyright_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinter 'uv', \ ale#Escape('uv') . ' run pyright-langserver --stdio' ================================================ FILE: test/linter/test_qmlfmt.vader ================================================ Before: call ale#assert#SetUpLinterTest('qml', 'qmlfmt') After: call ale#assert#TearDownLinterTest() Execute(The qml qmlfmt command callback should return the correct default string): AssertLinter 'qmlfmt', ale#Escape('qmlfmt') . ' -e', Execute(The qmlfmt executable should be configurable): let g:ale_qml_qmlfmt_executable = '~/.local/bin/qmlfmt' AssertLinter '~/.local/bin/qmlfmt', ale#Escape('~/.local/bin/qmlfmt') . ' -e' ================================================ FILE: test/linter/test_r_languageserver.vader ================================================ Before: call ale#assert#SetUpLinterTest('r', 'languageserver') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'Rscript', 'Rscript --no-save --no-restore --no-site-file --no-init-file -e ' . ale#Escape('languageserver::run()') Execute(The project root should be detected correctly): AssertLSPProject '.' call ale#test#SetFilename('../test-files/r/dummy/test.R') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/r') Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_r_languageserver_config = {'r': {'lsp': {'debug': 'true', 'diagnostics': 'true'}}} AssertLSPConfig {'r': {'lsp': {'debug': 'true', 'diagnostics': 'true'}}} ================================================ FILE: test/linter/test_racket_langserver.vader ================================================ " Author: D. Ben Knoble " Description: Tests for racket-langserver lsp linter. Before: call ale#assert#SetUpLinterTest('racket', 'langserver') After: call ale#assert#TearDownLinterTest() Execute(command callback should return default string): AssertLinter 'racket', ale#Escape('racket').' -l racket-langserver' Execute(should set racket-langserver for deep module 3): call ale#test#SetFilename('../test-files/racket/many-inits/a/b/c/foo.rkt') AssertLSPLanguage 'racket' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/racket/many-inits') Execute(should set racket-langserver for deep module 2): call ale#test#SetFilename('../test-files/racket/many-inits/a/b/foo.rkt') AssertLSPLanguage 'racket' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/racket/many-inits') Execute(should set racket-langserver for deep module 1): call ale#test#SetFilename('../test-files/racket/many-inits/a/foo.rkt') AssertLSPLanguage 'racket' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/racket/many-inits') Execute(should set racket-langserver for top-level module): call ale#test#SetFilename('../test-files/racket/many-inits/foo.rkt') AssertLSPLanguage 'racket' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/racket/many-inits') Execute(should set racket-langserver for non-package module or script): call ale#test#SetFilename('../test-files/racket/simple-script/foo.rkt') AssertLSPLanguage 'racket' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/racket/simple-script') ================================================ FILE: test/linter/test_racket_raco.vader ================================================ Before: call ale#assert#SetUpLinterTest('racket', 'raco') After: call ale#assert#TearDownLinterTest() Execute(The default command and executable should be correct): AssertLinter 'raco', 'raco expand %s' ================================================ FILE: test/linter/test_rails_best_practices.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'rails_best_practices') call ale#test#SetFilename('../test-files/ruby/valid_rails_app/db/test.rb') let b:args = '--silent -f json' \ . ' --output-file ' . (has('win32') ? '%t' : '/dev/stdout') let b:app_path = ale#path#Simplify(g:dir . '/../test-files/ruby/valid_rails_app') let b:suffix = has('win32') ? '; type %t' : '' After: unlet! b:args unlet! b:app_path unlet! b:suffix call ale#assert#TearDownLinterTest() Execute(Executable should default to rails_best_practices): AssertLinter 'rails_best_practices', ale#Escape('rails_best_practices') \ . ' ' . b:args \ . ' ' . ale#Escape(b:app_path) \ . b:suffix Execute(Should be able to set a custom executable): let g:ale_ruby_rails_best_practices_executable = 'bin/rails_best_practices' AssertLinter 'bin/rails_best_practices', ale#Escape('bin/rails_best_practices') \ . ' ' . b:args \ . ' ' . ale#Escape(b:app_path) \ . b:suffix Execute(Setting bundle appends 'exec rails_best_practices'): let g:ale_ruby_rails_best_practices_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec rails_best_practices' \ . ' ' . b:args \ . ' ' . ale#Escape(b:app_path) \ . b:suffix Execute(Command callback should be empty when not in a valid Rails app): call ale#test#SetFilename('../test-files/ruby/not_a_rails_app/test.rb') AssertLinter 'rails_best_practices', '' ================================================ FILE: test/linter/test_reason_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('reason', 'ls') After: call ale#assert#TearDownLinterTest() Execute(The linter should not be run by default): AssertLinterNotExecuted Execute(The executable should be configurable): let b:ale_reason_ls_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') Execute(There should be no default project root): AssertLSPProject '' Execute(The project root should be detected using bsconfig.json): call ale#test#SetFilename('../test-files/reasonml/test.ml') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/reasonml') ================================================ FILE: test/linter/test_reason_ols.vader ================================================ Before: call ale#assert#SetUpLinterTest('reason', 'ols') Save &filetype let &filetype = 'reason' After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'reason' Execute(The default executable should be correct): AssertLinter 'ocaml-language-server', \ ale#Escape('ocaml-language-server') . ' --stdio' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/ols/file.re') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/ols') Execute(The local executable should be used when available): call ale#test#SetFilename('../test-files/ols/file.re') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/ols/node_modules/.bin/ocaml-language-server'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/ols/node_modules/.bin/ocaml-language-server')) . ' --stdio' Execute(The global executable should always be used when use_global is set): let g:ale_reason_ols_use_global = 1 call ale#test#SetFilename('../test-files/ols/file.re') AssertLinter 'ocaml-language-server', \ ale#Escape('ocaml-language-server') . ' --stdio' Execute(The executable should be configurable): let g:ale_reason_ols_executable = 'foobar' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'foobar', ale#Escape('foobar') . ' --stdio' ================================================ FILE: test/linter/test_redpen.vader ================================================ Before: " This is just one example of a language using the linter. call ale#assert#SetUpLinterTest('markdown', 'redpen') Save g:ale_redpen_options let g:ale_redpen_options = '' After: call ale#assert#TearDownLinterTest() Execute(The options should be omitted by default): AssertLinter \ 'redpen', \ 'redpen -f markdown -r json %t' Execute(The options should be used in the command): let g:ale_redpen_options = '--foo --bar' AssertLinter \ 'redpen', \ 'redpen -f markdown -r json --foo --bar %t' Execute(The command should work with different filetypes): " Test with a different filetype call ale#assert#SetUpLinterTest('text', 'redpen') AssertLinter \ 'redpen', \ 'redpen -f text -r json %t' ================================================ FILE: test/linter/test_reek.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'reek') After: call ale#assert#TearDownLinterTest() Execute(The reek callbacks should return the correct default values): GivenCommandOutput ['reek 5.0.0'] AssertLinter 'reek', [ \ ale#Escape('reek') . ' --version', \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', \] " Try with older versions. call ale#semver#ResetVersionCache() GivenCommandOutput ['reek 4.8.2'] AssertLinter 'reek', [ \ 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' GivenCommandOutput ['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() GivenCommandOutput ['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): GivenCommandOutput ['reek 5.0.0'] AssertLinter 'reek', [ \ ale#Escape('reek') . ' --version', \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', \] GivenCommandOutput [] AssertLinter 'reek', [ \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', \] ================================================ FILE: test/linter/test_refurb.vader ================================================ Before: Save g:ale_python_auto_pipenv Save g:ale_python_auto_poetry let g:ale_python_auto_pipenv = 0 let g:ale_python_auto_poetry = 0 call ale#assert#SetUpLinterTest('python', 'refurb') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The refurb callbacks should return the correct default values): AssertLinterCwd expand('%:p:h') AssertLinter 'refurb', ale#Escape('refurb') . ' %s' Execute(The option for disabling changing directories should work): let g:ale_python_refurb_change_directory = 0 AssertLinterCwd '' AssertLinter 'refurb', ale#Escape('refurb') . ' %s' Execute(The refurb executable should be configurable, and escaped properly): let g:ale_python_refurb_executable = 'executable with spaces' AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . ' %s' Execute(The refurb command callback should let you set options): let g:ale_python_refurb_options = '--some-flag' AssertLinter 'refurb', ale#Escape('refurb') . ' --some-flag %s' let g:ale_python_refurb_options = '--some-option value' AssertLinter 'refurb', ale#Escape('refurb') . ' --some-option value %s' Execute(The refurb callbacks shouldn't detect virtualenv directories where they don't exist): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'refurb', ale#Escape('refurb') . ' %s' Execute(The refurb callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/refurb' \) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, ale#Escape(b:executable) . ' %s' Execute(You should able able to use the global refurb instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_refurb_use_global = 1 AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter 'refurb', ale#Escape('refurb') . ' %s' Execute(Setting executable to 'pipenv' appends 'run refurb'): let g:ale_python_refurb_executable = 'path/to/pipenv' let g:ale_python_refurb_use_global = 1 AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run refurb %s' Execute(Pipenv is detected when python_refurb_auto_pipenv is set): let g:ale_python_refurb_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run refurb %s' Execute(Setting executable to 'poetry' appends 'run refurb'): let g:ale_python_refurb_executable = 'path/to/poetry' let g:ale_python_refurb_use_global = 1 AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run refurb %s' Execute(poetry is detected when python_refurb_auto_poetry is set): let g:ale_python_refurb_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'poetry', ale#Escape('poetry') . ' run refurb %s' Execute(uv is detected when python_refurb_auto_uv is set): let g:ale_python_refurb_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'uv', ale#Escape('uv') . ' run refurb %s' ================================================ FILE: test/linter/test_rego_opacheck.vader ================================================ " Based upon :help ale-development Before: call ale#assert#SetUpLinterTest('rego', 'opacheck') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'opa', \ ale#Escape('opa') . ' check %s:h --format json ' Execute(The default command should be overridden): let b:ale_rego_opacheck_executable = '/bin/other/opa' AssertLinter '/bin/other/opa', \ ale#Escape('/bin/other/opa') . ' check %s:h --format json ' ================================================ FILE: test/linter/test_remark_lint.vader ================================================ Before: " This is just one language for the linter. call ale#assert#SetUpLinterTest('markdown', 'remark_lint') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'remark', \ ale#Escape('remark') . ' --no-stdout --no-color' Execute(The executable should be configurable): let b:ale_markdown_remark_lint_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' --no-stdout --no-color' Execute(The options should be configurable): let b:ale_markdown_remark_lint_options = '--something' AssertLinter 'remark', \ ale#Escape('remark') . ' --something --no-stdout --no-color' Execute(The local executable from .bin should be used if available): call ale#test#SetFilename('../test-files/remark_lint/with_bin_path/foo.md') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/remark_lint/with_bin_path/node_modules/.bin/remark'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/remark_lint/with_bin_path/node_modules/.bin/remark')) \ . ' --no-stdout --no-color' Execute(The global executable should be used if the option is set): let b:ale_markdown_remark_lint_use_global = 1 call ale#test#SetFilename('../test-files/remark_lint/with_bin_path/foo.md') AssertLinter 'remark', ale#Escape('remark') \ . ' --no-stdout --no-color' ================================================ FILE: test/linter/test_rescript_language_server.vader ================================================ Before: call ale#assert#SetUpLinterTest('rescript', 'rescript_language_server') Save &filetype let &filetype = 'rescript' After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'rescript' Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/rescript/testfile.res') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/rescript') Execute(The command should be correct): call ale#test#SetFilename('../test-files/rescript/testfile.res') AssertLinter \ 'rescript-language-server', \ ale#Escape('rescript-language-server') . ' --stdio' ================================================ FILE: test/linter/test_revive.vader ================================================ Before: Save g:ale_go_go111module call ale#assert#SetUpLinterTest('go', 'revive') After: Restore unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The default revive command should be correct): AssertLinter 'revive', ale#Escape('revive') . ' %t' Execute(The revive executable should be configurable): let b:ale_go_revive_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' %t' Execute(The revive options should be configurable): let b:ale_go_revive_options = '--foo' AssertLinter 'revive', ale#Escape('revive') . ' --foo %t' Execute(The revive command should support Go environment variables): let b:ale_go_go111module = 'on' AssertLinter 'revive', \ ale#Env('GO111MODULE', 'on') . ale#Escape('revive') . ' %t' ================================================ FILE: test/linter/test_rflint.vader ================================================ Before: call ale#assert#SetUpLinterTest('robot', 'rflint') let b:rflint_format = ' --format' \ . ' "{filename}:{severity}:{linenumber}:{char}:{rulename}:{message}" %s' After: call ale#assert#TearDownLinterTest() unlet! b:rflint_format Execute(The rflint command callback should return default string): AssertLinter 'rflint', \ 'rflint' \ . b:rflint_format Execute(The rflint executable should be configurable): let g:ale_robot_rflint_executable = '~/.local/bin/rflint' AssertLinter '~/.local/bin/rflint', \ '~/.local/bin/rflint' \ . b:rflint_format ================================================ FILE: test/linter/test_rnix.vader ================================================ " Author: jD91mZM2 " Description: Tests for rnix-lsp language client Before: call ale#assert#SetUpLinterTest('nix', 'rnix_lsp') After: call ale#assert#TearDownLinterTest() Execute(should start rnix-lsp): AssertLSPLanguage 'nix' AssertLSPOptions {} AssertLSPProject ale#path#Simplify('.') ================================================ FILE: test/linter/test_roc_roc_language_server.vader ================================================ Before: call ale#assert#SetUpLinterTest('roc', 'roc_language_server') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'roc_language_server', ale#Escape('roc_language_server') Execute(The project root should be detected correctly in empty directory): AssertLSPProject '.' Execute(The project root should be detected correctly with main.roc): call ale#test#SetFilename('../test-files/roc/main.roc') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/roc') Execute(The LSP values should be set correctly): call ale#test#SetFilename('../test-files/roc/main.roc') AssertLSPLanguage 'roc' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/roc') ================================================ FILE: test/linter/test_rst_rstcheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('rst', 'rstcheck') After: call ale#assert#TearDownLinterTest() Execute(The default command should include --config for rstcheck >= 3.4.0): GivenCommandOutput ['rstcheck, version 3.4.0'] AssertLinter 'rstcheck', [ \ ale#Escape('rstcheck') . ' --version', \ ale#Escape('rstcheck') \ . ' --config ' \ . ale#Escape(expand('#' . bufnr('') . ':p:h')) \ . ' %t', \] Execute(The version check should be cached): GivenCommandOutput ['rstcheck, version 3.4.0'] AssertLinter 'rstcheck', [ \ ale#Escape('rstcheck') . ' --version', \ ale#Escape('rstcheck') \ . ' --config ' \ . ale#Escape(expand('#' . bufnr('') . ':p:h')) \ . ' %t', \] GivenCommandOutput [] AssertLinter 'rstcheck', [ \ ale#Escape('rstcheck') \ . ' --config ' \ . ale#Escape(expand('#' . bufnr('') . ':p:h')) \ . ' %t', \] Execute(The default command should not include --config for older versions): call ale#semver#ResetVersionCache() GivenCommandOutput ['rstcheck, version 3.3.0'] AssertLinter 'rstcheck', [ \ ale#Escape('rstcheck') . ' --version', \ ale#Escape('rstcheck') . ' %t', \] Execute(The command executable and options should be configurable): call ale#semver#ResetVersionCache() let b:ale_rst_rstcheck_executable = 'rstcheck2' let b:ale_rst_rstcheck_options = '--ignore-language=cpp' GivenCommandOutput ['rstcheck2, version 3.4.0'] AssertLinter 'rstcheck', [ \ ale#Escape('rstcheck2') . ' --version', \ ale#Escape('rstcheck2') \ . ' --ignore-language=cpp' \ . ' --config ' \ . ale#Escape(expand('#' . bufnr('') . ':p:h')) \ . ' %t', \] Execute(The linter should run with the current buffer directory as cwd): AssertLinterCwd '%s:h' ================================================ FILE: test/linter/test_rst_textlint.vader ================================================ " Author: januswel, w0rp Before: " This is just one language for the linter. call ale#assert#SetUpLinterTest('rst', 'textlint') " The configuration is shared between many languages. Save g:ale_textlint_executable Save g:ale_textlint_use_global Save g:ale_textlint_options let g:ale_textlint_executable = 'textlint' let g:ale_textlint_use_global = 0 let g:ale_textlint_options = '' unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options After: unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options call ale#assert#TearDownLinterTest() Execute(The default textlint command should be correct): AssertLinter 'textlint', \ ale#Escape('textlint') . ' -f json --stdin --stdin-filename %s' Execute(The text executable and command should be configurable): let b:ale_textlint_executable = 'foobar' let b:ale_textlint_options = '--something' AssertLinter 'foobar', \ ale#Escape('foobar') . ' --something -f json --stdin --stdin-filename %s' Execute(The local executable from .bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_bin_path/foo.txt') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint')) \ . ' -f json --stdin --stdin-filename %s' Execute(The local executable from textlint/bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_textlint_bin_path/foo.txt') if has('win32') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape('node.exe') . ' ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' else AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' endif ================================================ FILE: test/linter/test_rubocop.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'rubocop') call ale#test#SetFilename('dummy.rb') let g:ale_ruby_rubocop_executable = 'rubocop' let g:ale_ruby_rubocop_options = '' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to rubocop): AssertLinter 'rubocop', ale#Escape('rubocop') \ . ' --format json --force-exclusion --stdin %s' Execute(Should be able to set a custom executable): let g:ale_ruby_rubocop_executable = 'bin/rubocop' AssertLinter 'bin/rubocop' , ale#Escape('bin/rubocop') \ . ' --format json --force-exclusion --stdin %s' Execute(Setting bundle appends 'exec rubocop'): let g:ale_ruby_rubocop_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec rubocop' \ . ' --format json --force-exclusion --stdin %s' ================================================ FILE: test/linter/test_ruby.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'ruby') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'ruby', ale#Escape('ruby') . ' -w -c %t' Execute(The executable should be configurable): let g:ale_ruby_ruby_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' -w -c %t' ================================================ FILE: test/linter/test_ruby_debride.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'debride') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'debride', ale#Escape('debride') . ' %s' ================================================ FILE: test/linter/test_ruby_solargraph.vader ================================================ " Author: Horacio Sanson " 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(Setting bundle appends 'exec solargraph'): let g:ale_ruby_solargraph_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec solargraph' \ . ' stdio' Execute(should set solargraph for rails app): call ale#test#SetFilename('../test-files/ruby/valid_rails_app/app/models/thing.rb') AssertLSPLanguage 'ruby' AssertLSPOptions {} AssertLSPProject ale#test#GetFilename('../test-files/ruby/valid_rails_app') Execute(should set solargraph for ruby app1): call ale#test#SetFilename('../test-files/ruby/valid_ruby_app1/lib/file.rb') AssertLSPLanguage 'ruby' AssertLSPOptions {} AssertLSPProject ale#test#GetFilename('../test-files/ruby/valid_ruby_app1') Execute(should set solargraph for ruby app2): call ale#test#SetFilename('../test-files/ruby/valid_ruby_app2/lib/file.rb') AssertLSPLanguage 'ruby' AssertLSPOptions {} AssertLSPProject ale#test#GetFilename('../test-files/ruby/valid_ruby_app2') Execute(should set solargraph for ruby app3): call ale#test#SetFilename('../test-files/ruby/valid_ruby_app3/lib/file.rb') AssertLSPLanguage 'ruby' AssertLSPOptions {} AssertLSPProject ale#test#GetFilename('../test-files/ruby/valid_ruby_app3') Execute(should accept initialization options): AssertLSPOptions {} let b:ale_ruby_solargraph_options = { 'diagnostics': 'true' } AssertLSPOptions { 'diagnostics': 'true' } ================================================ FILE: test/linter/test_ruby_steep.vader ================================================ " Author: Loic Nageleisen " Description: Tests for steep linter. Before: call ale#assert#SetUpLinterTest('ruby', 'steep') let g:ale_ruby_steep_executable = 'steep' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to steep): call ale#test#SetFilename('../test-files/ruby/nested/foo/dummy.rb') AssertLinter 'steep', ale#Escape('steep') \ . ' check ' \ . ' dummy.rb' Execute(Should be able to set a custom executable): let g:ale_ruby_steep_executable = 'bin/steep' call ale#test#SetFilename('../test-files/ruby/nested/foo/dummy.rb') AssertLinter 'bin/steep' , ale#Escape('bin/steep') \ . ' check ' \ . ' dummy.rb' Execute(Setting bundle appends 'exec steep'): let g:ale_ruby_steep_executable = 'path to/bundle' call ale#test#SetFilename('../test-files/ruby/nested/foo/dummy.rb') AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec steep' \ . ' check ' \ . ' dummy.rb' Execute(should accept options): let g:ale_ruby_steep_options = '--severity-level=hint' call ale#test#SetFilename('../test-files/ruby/nested/foo/dummy.rb') AssertLinter 'steep', ale#Escape('steep') \ . ' check' \ . ' --severity-level=hint' \ . ' dummy.rb' Execute(Should not lint files out of steep root): call ale#test#SetFilename('../test-files/ruby/nested/dummy.rb') AssertLinter 'steep', '' Execute(Should lint files at top steep root): call ale#test#SetFilename('../test-files/ruby/nested/foo/dummy.rb') AssertLinter 'steep', ale#Escape('steep') \ . ' check ' \ . ' dummy.rb' Execute(Should lint files below top steep root): call ale#test#SetFilename('../test-files/ruby/nested/foo/one/dummy.rb') AssertLinter 'steep', ale#Escape('steep') \ . ' check ' \ . ' one' . (has('win32') ? '\' : '/') . 'dummy.rb' Execute(Should lint files at nested steep root): call ale#test#SetFilename('../test-files/ruby/nested/foo/two/dummy.rb') AssertLinter 'steep', ale#Escape('steep') \ . ' check ' \ . ' dummy.rb' Execute(Should lint files below nested steep root): call ale#test#SetFilename('../test-files/ruby/nested/foo/two/three/dummy.rb') AssertLinter 'steep', ale#Escape('steep') \ . ' check ' \ . ' three' . (has('win32') ? '\' : '/') . 'dummy.rb' ================================================ FILE: test/linter/test_ruff.vader ================================================ Before: Save g:ale_python_auto_pipenv let g:ale_python_auto_pipenv = 0 call ale#assert#SetUpLinterTest('python', 'ruff') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:command_head = ale#Escape('ruff') . ' -q --no-fix' let b:command_tail = ' --format json-lines --stdin-filename %s -' GivenCommandOutput ['ruff 0.0.83'] After: unlet! b:bin_dir unlet! b:executable unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The ruff callbacks should return the correct default values): AssertLinterCwd expand('%:p:h') AssertLinter 'ruff', b:command_head . b:command_tail Execute(ruff should run with the file path of buffer in old versions): " version `0.0.69` supports liniting input from stdin GivenCommandOutput ['ruff 0.0.68'] AssertLinterCwd expand('%:p:h') AssertLinter 'ruff', b:command_head . b:command_tail[:-23] . ' %s' Execute(ruff should run with the --output-format flag in new versions): GivenCommandOutput ['ruff 0.1.0'] AssertLinterCwd expand('%:p:h') AssertLinter 'ruff', b:command_head . ' --output-format json-lines --stdin-filename %s -' Execute(ruff should run with the stdin in new enough versions): GivenCommandOutput ['ruff 0.0.83'] AssertLinterCwd expand('%:p:h') AssertLinter 'ruff', b:command_head . b:command_tail[:-3] . ' -' " AssertLinter 'ruff', b:command_head . b:command_tail[:-3] . '--format json-lines -' Execute(ruff should run with the check subcmd in versions >= 0.3.0): GivenCommandOutput ['ruff 0.3.0'] AssertLinterCwd expand('%:p:h') let b:cmd_head = ale#Escape('ruff') . ' check -q --no-fix' AssertLinter 'ruff', b:cmd_head . ' --output-format json-lines --stdin-filename %s -' Execute(The option for disabling changing directories should work): let g:ale_python_ruff_change_directory = 0 AssertLinterCwd '' AssertLinter 'ruff', b:command_head . b:command_tail Execute(The ruff executable should be configurable, and escaped properly): let g:ale_python_ruff_executable = 'executable with spaces' AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . ' -q --no-fix' . b:command_tail Execute(The ruff command callback should let you set options): let g:ale_python_ruff_options = '--some-flag' AssertLinter 'ruff', b:command_head . ' --some-flag' . b:command_tail let g:ale_python_ruff_options = '--some-option value' AssertLinter 'ruff', b:command_head . ' --some-option value' . b:command_tail Execute(The ruff callbacks shouldn't detect virtualenv directories where they don't exist): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'ruff', b:command_head . b:command_tail Execute(The ruff callbacks should detect virtualenv directories): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/ruff' \) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, ale#Escape(b:executable) . ' -q --no-fix' . b:command_tail Execute(You should able able to use the global ruff instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_ruff_use_global = 1 AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter 'ruff', b:command_head . b:command_tail Execute(Setting executable to 'pipenv' appends 'run ruff'): let g:ale_python_ruff_executable = 'path/to/pipenv' let g:ale_python_ruff_use_global = 1 AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run ruff -q --no-fix' \ . b:command_tail Execute(Pipenv is detected when python_ruff_auto_pipenv is set): let g:ale_python_ruff_auto_pipenv = 1 call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run ruff -q --no-fix' \ . b:command_tail Execute(Setting executable to 'poetry' appends 'run ruff'): let g:ale_python_ruff_executable = 'path/to/poetry' let g:ale_python_ruff_use_global = 1 AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run ruff -q --no-fix' \ . b:command_tail Execute(poetry is detected when python_ruff_auto_poetry is set): let g:ale_python_ruff_auto_poetry = 1 call ale#test#SetFilename('../test-files/python/poetry/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'poetry', ale#Escape('poetry') . ' run ruff -q --no-fix' \ . b:command_tail Execute(uv is detected when python_ruff_auto_uv is set): let g:ale_python_ruff_auto_uv = 1 call ale#test#SetFilename('../test-files/python/uv/whatever.py') AssertLinterCwd expand('%:p:h') AssertLinter 'uv', ale#Escape('uv') . ' run ruff -q --no-fix' \ . b:command_tail ================================================ FILE: test/linter/test_rust_analyzer.vader ================================================ Before: call ale#assert#SetUpLinterTest('rust', 'analyzer') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'rust-analyzer', ale#Escape('rust-analyzer') Execute(The project root should be detected correctly in cargo projects): call ale#test#SetFilename('../test-files/rust/cargo/testfile.rs') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/rust/cargo') Execute(The project root should be detected correctly in non-cargo projects): call ale#test#SetFilename('../test-files/rust/rust-project/testfile.rs') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/rust/rust-project') Execute(The project root should be empty when no project files can be detected): call ale#test#SetFilename('../test-files/dummy') AssertLSPProject '' Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_rust_analyzer_config = {'diagnostics': {'disabled': ['unresolved-import']}} AssertLSPOptions {'diagnostics': {'disabled': ['unresolved-import']}} ================================================ FILE: test/linter/test_rust_rls.vader ================================================ Before: call ale#assert#SetUpLinterTest('rust', 'rls') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'rls', ale#Escape('rls') Execute(The toolchain should be configurable): let g:ale_rust_rls_toolchain = 'stable' AssertLinter 'rls', ale#Escape('rls') . ' +' . ale#Escape('stable') Execute(The toolchain should be omitted if not given): let g:ale_rust_rls_toolchain = '' AssertLinter 'rls', ale#Escape('rls') Execute(The project root should be detected correctly for cargo projects): call ale#test#SetFilename('../test-files/rust/cargo/testfile.rs') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/rust/cargo') Execute(The project root should be empty when no project files can be detected): call ale#test#SetFilename('../test-files/dummy') AssertLSPProject '' Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_rust_rls_config = {'rust': {'clippy_preference': 'on'}} AssertLSPConfig {'rust': {'clippy_preference': 'on'}} ================================================ FILE: test/linter/test_rustc.vader ================================================ Before: call ale#assert#SetUpLinterTest('rust', 'rustc') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): call ale#test#SetFilename('../test-files/dummy') AssertLinter 'rustc', 'rustc --error-format=json --emit=mir -o /dev/null -' Execute(The options should be configurable): call ale#test#SetFilename('../test-files/dummy') let b:ale_rust_rustc_options = '--foo' AssertLinter 'rustc', 'rustc --error-format=json --foo -' Execute(Some default paths should be included when the project is a Cargo project): call ale#test#SetFilename('../test-files/rust/cargo/testfile.rs') AssertLinter 'rustc', 'rustc --error-format=json --emit=mir -o /dev/null' \ . ' -L ' . ale#Escape(ale#path#GetAbsPath(g:dir, '../test-files/rust/cargo/target/debug/deps')) \ . ' -L ' . ale#Escape(ale#path#GetAbsPath(g:dir, '../test-files/rust/cargo/target/release/deps')) \ . ' -' ================================================ FILE: test/linter/test_ruumba.vader ================================================ 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 %s' 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 %s' 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 %s' ================================================ FILE: test/linter/test_sass_sasslint.vader ================================================ Before: call ale#assert#SetUpLinterTest('sass', 'sasslint') call ale#test#SetFilename('test.sass') unlet! b:executable After: call ale#assert#TearDownLinterTest() Execute(should default to source, bin/sass-lint.js): call ale#test#SetFilename('../test-files/sasslint/with-source/test.sass') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/sasslint/with-source/node_modules/sass-lint/bin/sass-lint.js' \) AssertLinter b:executable, \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(b:executable) \ . ' -v -q -f compact %t' Execute(should fallback to bin, .bin/sass-lint): call ale#test#SetFilename('../test-files/sasslint/with-bin/test.sass') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/sasslint/with-bin/node_modules/.bin/sass-lint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' -v -q -f compact %t' Execute(should fallback to global bin): AssertLinter 'sass-lint', ale#Escape('sass-lint') . ' -v -q -f compact %t' Execute(The global executable should be configurable): let b:ale_sass_sasslint_executable = 'foo' AssertLinter 'foo', ale#Escape('foo') . ' -v -q -f compact %t' Execute(The options should be configurable): let b:ale_sass_sasslint_options = '--bar' AssertLinter 'sass-lint', ale#Escape('sass-lint') . ' --bar -v -q -f compact %t' ================================================ FILE: test/linter/test_scala_metals.vader ================================================ " Author: Jeffrey Lau https://github.com/zoonfafer " Description: Tests for the Scala Metals linter Before: call ale#assert#SetUpLinterTest('scala', 'metals') After: call ale#assert#TearDownLinterTest() Execute(should set metals for sbt project with build.sbt): call ale#test#SetFilename('../test-files/scala/valid_sbt_project/Main.scala') AssertLSPLanguage 'scala' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/scala/valid_sbt_project') Execute(should not set metals for sbt project without build.sbt): call ale#test#SetFilename('../test-files/scala/invalid_sbt_project/Main.scala') AssertLSPLanguage 'scala' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject '' ================================================ FILE: test/linter/test_scala_sbtserver.vader ================================================ " Author: ophirr33 " 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('../test-files/scala/valid_sbt_project/Main.scala') AssertLSPLanguage 'scala' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#test#GetFilename('../test-files/scala/valid_sbt_project') AssertLSPAddress '127.0.0.1:4273' Execute(should not set sbtserver for sbt project without build.sbt): call ale#test#SetFilename('../test-files/scala/invalid_sbt_project/Main.scala') AssertLSPLanguage 'scala' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject '' AssertLSPAddress '127.0.0.1:4273' ================================================ FILE: test/linter/test_scalac.vader ================================================ Before: call ale#assert#SetUpLinterTest('scala', 'scalac') After: call ale#assert#TearDownLinterTest() Given scala(An empty Scala file): Execute(The default executable and command should be correct): AssertLinter 'scalac', ale#Escape('scalac') . ' -Ystop-after:parser %t' Given scala.sbt(An empty SBT file): Execute(scalac should not be run for sbt files): AssertLinterNotExecuted ================================================ FILE: test/linter/test_scalastyle.vader ================================================ Before: call ale#assert#SetUpLinterTest('scala', 'scalastyle') After: unlet! g:ale_scalastyle_config_loc call ale#linter#Reset() Execute(Should return the correct default command): AssertLinter 'scalastyle', 'scalastyle %t' Execute(Should allow using a custom config file): let b:ale_scala_scalastyle_config = '/dooper/config.xml' AssertLinter 'scalastyle', 'scalastyle' \ . ' --config ' . ale#Escape('/dooper/config.xml') \ . ' %t' Execute(Should support a legacy option for the scalastyle config): unlet! g:ale_scala_scalastyle_config let g:ale_scalastyle_config_loc = '/dooper/config.xml' call ale#linter#Reset() runtime ale_linters/scala/scalastyle.vim AssertLinter 'scalastyle', 'scalastyle' \ . ' --config ' . ale#Escape('/dooper/config.xml') \ . ' %t' Execute(Should allow using custom options): let b:ale_scala_scalastyle_options = '--warnings false --quiet true' AssertLinter 'scalastyle', 'scalastyle' \ . ' --warnings false --quiet true' \ . ' %t' ================================================ FILE: test/linter/test_scss_sasslint.vader ================================================ Before: call ale#assert#SetUpLinterTest('scss', 'sasslint') call ale#test#SetFilename('test.scss') unlet! b:executable After: call ale#assert#TearDownLinterTest() Execute(should default to source, bin/sass-lint.js): call ale#test#SetFilename('../test-files/sasslint/with-source/test.scss') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/sasslint/with-source/node_modules/sass-lint/bin/sass-lint.js' \) AssertLinter b:executable, \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(b:executable) \ . ' -v -q -f compact %t' Execute(should fallback to bin, .bin/sass-lint): call ale#test#SetFilename('../test-files/sasslint/with-bin/test.scss') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/sasslint/with-bin/node_modules/.bin/sass-lint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' -v -q -f compact %t' Execute(should fallback to global bin): AssertLinter 'sass-lint', ale#Escape('sass-lint') . ' -v -q -f compact %t' Execute(The global executable should be configurable): let b:ale_scss_sasslint_executable = 'foo' AssertLinter 'foo', ale#Escape('foo') . ' -v -q -f compact %t' Execute(The options should be configurable): let b:ale_scss_sasslint_options = '--bar' AssertLinter 'sass-lint', ale#Escape('sass-lint') . ' --bar -v -q -f compact %t' ================================================ FILE: test/linter/test_scss_stylelint.vader ================================================ 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('../test-files/stylelint/nested/testfile.scss') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/stylelint/node_modules/.bin/stylelint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --no-color --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('../test-files/stylelint/nested/testfile.scss') AssertLinter 'foobar', ale#Escape('foobar') . ' --no-color --stdin-filename %s' Execute(Extra options should be configurable): call ale#test#SetFilename('../test-files/dummy') let b:ale_scss_stylelint_options = '--configFile ''/absolute/path/to/file''' AssertLinter 'stylelint', \ ale#Escape('stylelint') . ' --configFile ''/absolute/path/to/file'' --no-color --stdin-filename %s' ================================================ FILE: test/linter/test_shellcheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('sh', 'shellcheck') call ale#test#SetFilename('test.sh') let b:suffix = ' -f gcc -' After: unlet! b:is_bash unlet! b:suffix call ale#assert#TearDownLinterTest() Execute(The default shellcheck command should be correct): AssertLinterCwd '%s:h' AssertLinter 'shellcheck', ale#Escape('shellcheck') . b:suffix Execute(The option disabling changing directories should work): let g:ale_sh_shellcheck_change_directory = 0 AssertLinterCwd '' AssertLinter 'shellcheck', ale#Escape('shellcheck') . b:suffix Execute(The shellcheck command should accept options): let b:ale_sh_shellcheck_options = '--foobar' AssertLinter 'shellcheck', ale#Escape('shellcheck') . ' --foobar' . b:suffix Execute(The shellcheck command should accept options and exclusions): let b:ale_sh_shellcheck_options = '--foobar' let b:ale_sh_shellcheck_exclusions = 'foo,bar' AssertLinter 'shellcheck', \ ale#Escape('shellcheck') . ' --foobar -e foo,bar' . b:suffix Execute(The shellcheck command should include the dialect): let b:is_bash = 1 AssertLinter 'shellcheck', ale#Escape('shellcheck') . ' -s bash' . b:suffix Execute(The shellcheck command should use ale_sh_shellcheck_dialect): let b:ale_sh_shellcheck_dialect = 'ksh93' AssertLinter 'shellcheck', ale#Escape('shellcheck') . ' -s ksh93' . b:suffix Execute(The shellcheck command should allow unspecified dialect): let b:ale_sh_shellcheck_dialect = '' AssertLinter 'shellcheck', ale#Escape('shellcheck') . b:suffix Execute(The shellcheck command should include the dialect before options and exclusions): let b:is_bash = 1 let b:ale_sh_shellcheck_options = '--foobar' let b:ale_sh_shellcheck_exclusions = 'foo,bar' AssertLinter 'shellcheck', ale#Escape('shellcheck') \ . ' -s bash --foobar -e foo,bar' \ . b:suffix Execute(The -x option should be added when the version is new enough): AssertLinter 'shellcheck', [ \ ale#Escape('shellcheck') . ' --version', \ ale#Escape('shellcheck') . b:suffix, \] GivenCommandOutput [ \ 'ShellCheck - shell script analysis tool', \ 'version: 0.4.4', \ 'license: GNU General Public License, version 3', \ 'website: http://www.shellcheck.net', \] AssertLinter 'shellcheck', [ \ ale#Escape('shellcheck') . ' --version', \ ale#Escape('shellcheck') . ' -x' . b:suffix, \] " We should cache the version check GivenCommandOutput [] AssertLinter 'shellcheck', [ \ ale#Escape('shellcheck') . ' -x' . b:suffix, \] Execute(The -x option should not be added when the version is too old): GivenCommandOutput [ \ 'ShellCheck - shell script analysis tool', \ 'version: 0.3.9', \ 'license: GNU General Public License, version 3', \ 'website: http://www.shellcheck.net', \] AssertLinter 'shellcheck', [ \ ale#Escape('shellcheck') . ' --version', \ ale#Escape('shellcheck') . b:suffix, \] Execute(The version check shouldn't be run again for old versions): GivenCommandOutput [ \ 'ShellCheck - shell script analysis tool', \ 'version: 0.3.9', \ 'license: GNU General Public License, version 3', \ 'website: http://www.shellcheck.net', \] AssertLinter 'shellcheck', [ \ ale#Escape('shellcheck') . ' --version', \ ale#Escape('shellcheck') . b:suffix, \] AssertLinter 'shellcheck', [ \ ale#Escape('shellcheck') . b:suffix, \] ================================================ FILE: test/linter/test_slang.vader ================================================ Before: call ale#assert#SetUpLinterTest('verilog', 'slang') After: call ale#assert#TearDownLinterTest() Execute(The default slang command should be correct): AssertLinter 'slang', 'slang -Weverything --diag-abs-paths -I%s:h -y%s:h %t' Execute(slang options should be configurable): " Additional args for the linter let g:ale_verilog_slang_options = '--define-macro DWIDTH=12' AssertLinter 'slang', 'slang -Weverything --diag-abs-paths -I%s:h -y%s:h --define-macro DWIDTH=12 %t' ================================================ FILE: test/linter/test_slimlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('slim', 'slimlint') let g:default_command = 'slim-lint %t' After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'slim-lint', 'slim-lint %t' Execute(The command should have the .rubocop.yml prepended as an env var if one exists): call ale#test#SetFilename('../test-files/slimlint/subdir/file.slim') AssertLinter 'slim-lint', \ ale#Env( \ 'SLIM_LINT_RUBOCOP_CONF', \ ale#path#Simplify(g:dir . '/../test-files/slimlint/.rubocop.yml') \ ) \ . 'slim-lint %t' ================================================ FILE: test/linter/test_solc.vader ================================================ Before: call ale#assert#SetUpLinterTest('solidity', 'solc') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'solc', 'solc %s' Execute(The options should be configurable): let g:ale_solidity_solc_options = '--foobar' AssertLinter 'solc', 'solc --foobar %s' ================================================ FILE: test/linter/test_solc_commit.vader ================================================ Before: call ale#assert#SetUpLinterTest('solidity', 'solc') let g:ale_solidity_solc_executable = 'solc-v0.8.4+commit.c7e474f2' After: call ale#assert#TearDownLinterTest() Execute(The executable command should be configurable): AssertLinter 'solc-v0.8.4+commit.c7e474f2', 'solc-v0.8.4+commit.c7e474f2 %s' Execute(The options should be configurable): let g:ale_solidity_solc_options = '--foobar' AssertLinter 'solc-v0.8.4+commit.c7e474f2', 'solc-v0.8.4+commit.c7e474f2 --foobar %s' ================================================ FILE: test/linter/test_solhint.vader ================================================ Before: call ale#assert#SetUpLinterTest('solidity', 'solhint') let b:args = ' --formatter unix %s' After: unlet! b:args unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinterCwd '' AssertLinter 'solhint', ale#Escape('solhint') . b:args Execute(The options should be configurable): let g:ale_solidity_solhint_options = '--foobar' AssertLinter 'solhint', ale#Escape('solhint') . ' --foobar' . b:args Execute(solhint should be run from a containing project with solhint executable): call ale#test#SetFilename('../test-files/solhint/Contract.sol') let b:executable = ale#path#Simplify(g:dir . '/../test-files/solhint/node_modules/.bin/solhint') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/solhint') AssertLinter b:executable, ale#Escape(b:executable) . b:args ================================================ FILE: test/linter/test_sorbet.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'sorbet') call ale#test#SetFilename('dummy.rb') let g:ale_ruby_sorbet_executable = 'srb' let g:ale_ruby_sorbet_options = '' let g:ale_ruby_sorbet_enable_watchman = 0 let g:ale_ruby_sorbet_initialization_options = { 'highlightUntyped': v:false } After: call ale#assert#TearDownLinterTest() Execute(Executable should default to srb): AssertLinter 'srb', ale#Escape('srb') \ . ' tc --lsp --disable-watchman' Execute(Able to enable watchman): let g:ale_ruby_sorbet_enable_watchman = 1 AssertLinter 'srb', ale#Escape('srb') \ . ' tc --lsp' Execute(Should be able to set a custom executable): let g:ale_ruby_sorbet_executable = 'bin/srb' AssertLinter 'bin/srb' , ale#Escape('bin/srb') \ . ' tc --lsp --disable-watchman' Execute(Setting bundle appends 'exec srb tc'): let g:ale_ruby_sorbet_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec srb' \ . ' tc --lsp --disable-watchman' Execute(Should use predetermined initialization_options by default): AssertLSPOptions { 'highlightUntyped': v:false } Execute(Should be able to set custom initialization_options): let g:ale_ruby_sorbet_initialization_options = {'enableTypedFalse': v:true} AssertLSPOptions {'enableTypedFalse': v:true} ================================================ FILE: test/linter/test_spectral.vader ================================================ Before: call ale#assert#SetUpLinterTest('yaml', 'spectral') After: call ale#assert#TearDownLinterTest() Execute(The yaml spectral command callback should return the correct default string): AssertLinter 'spectral', ale#Escape('spectral') . ' lint --ignore-unknown-format -q -f text %t' Execute(The yaml spectral command callback should be configurable): let g:ale_yaml_spectral_executable = '~/.local/bin/spectral' AssertLinter '~/.local/bin/spectral', \ ale#Escape('~/.local/bin/spectral') \ . ' lint --ignore-unknown-format -q -f text %t' Execute(The yaml spectral command callback should allow a global installation to be used): let g:ale_yaml_spectral_executable = '/usr/local/bin/spectral' let g:ale_yaml_spectral_use_global = 1 AssertLinter '/usr/local/bin/spectral', \ ale#Escape('/usr/local/bin/spectral') \ . ' lint --ignore-unknown-format -q -f text %t' Execute(The yaml spectral command callback should allow a local installation to be used): call ale#test#SetFilename('../test-files/spectral/openapi.yaml') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/spectral/node_modules/.bin/spectral'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/spectral/node_modules/.bin/spectral')) \ . ' lint --ignore-unknown-format -q -f text %t' ================================================ FILE: test/linter/test_sql_sqlfluff.vader ================================================ Before: call ale#assert#SetUpLinterTest('sql', 'sqlfluff') After: call ale#assert#TearDownLinterTest() Execute(The default sqlfluff command should be correct): AssertLinter 'sqlfluff', \ ale#Escape('sqlfluff') \ . ' lint --dialect ansi --format json %t' Execute(The sqlfluff executable and command should be configurable): let g:ale_sql_sqlfluff_executable = 'foobar' let g:ale_sql_sqlfluff_options = '--whatever' AssertLinter 'foobar', \ ale#Escape('foobar') \ . ' lint --dialect ansi --format json --whatever %t' ================================================ FILE: test/linter/test_sqllint.vader ================================================ Before: " Load the linter and set up a series of commands, reset linter variables, " clear caches, etc. " " Vader's 'Save' command will be called here for linter variables. call ale#assert#SetUpLinterTest('sql', 'sqllint') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'sql-lint', ['sql-lint'] ================================================ FILE: test/linter/test_standard.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'standard') call ale#test#SetFilename('testfile.js') unlet! b:executable After: call ale#assert#TearDownLinterTest() Execute(bin/cmd.js paths should be preferred): call ale#test#SetFilename('../test-files/standard/with-cmd/testfile.js') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/standard/with-cmd/node_modules/standard/bin/cmd.js' \) AssertLinter b:executable, \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(b:executable) \ . ' --stdin %s' Execute(.bin directories should be used too): call ale#test#SetFilename('../test-files/standard/with-bin/testfile.js') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/standard/with-bin/node_modules/.bin/standard' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --stdin %s' Execute(The global executable should be used otherwise): AssertLinter 'standard', ale#Escape('standard') . ' --stdin %s' Execute(The global executable should be configurable): let b:ale_javascript_standard_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --stdin %s' Execute(The options should be configurable): let b:ale_javascript_standard_options = '--wat' AssertLinter 'standard', ale#Escape('standard') . ' --wat --stdin %s' ================================================ FILE: test/linter/test_standardrb.vader ================================================ Before: call ale#assert#SetUpLinterTest('ruby', 'standardrb') call ale#test#SetFilename('dummy.rb') let g:ale_ruby_standardrb_executable = 'standardrb' let g:ale_ruby_standardrb_options = '' After: call ale#assert#TearDownLinterTest() Execute(Executable should default to standardrb): AssertLinter 'standardrb', ale#Escape('standardrb') \ . ' --format json --force-exclusion --stdin %s' Execute(Should be able to set a custom executable): let g:ale_ruby_standardrb_executable = 'bin/standardrb' AssertLinter 'bin/standardrb' , ale#Escape('bin/standardrb') \ . ' --format json --force-exclusion --stdin %s' Execute(Setting bundle appends 'exec standardrb'): let g:ale_ruby_standardrb_executable = 'path to/bundle' AssertLinter 'path to/bundle', ale#Escape('path to/bundle') \ . ' exec standardrb' \ . ' --format json --force-exclusion --stdin %s' ================================================ FILE: test/linter/test_standardts.vader ================================================ Before: call ale#assert#SetUpLinterTest('typescript', 'standard') call ale#test#SetFilename('testfile.js') unlet! b:executable After: call ale#assert#TearDownLinterTest() Execute(bin/cmd.js paths should be preferred): call ale#test#SetFilename('../test-files/standard/with-cmd/testfile.js') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/standard/with-cmd/node_modules/standard/bin/cmd.js' \) AssertLinter b:executable, \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(b:executable) \ . ' --stdin %s' Execute(.bin directories should be used too): call ale#test#SetFilename('../test-files/standard/with-bin/testfile.js') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/standard/with-bin/node_modules/.bin/standard' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --stdin %s' Execute(The global executable should be used otherwise): AssertLinter 'standard', ale#Escape('standard') . ' --stdin %s' Execute(The global executable should be configurable): let b:ale_typescript_standard_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --stdin %s' Execute(The options should be configurable): let b:ale_typescript_standard_options = '--wat' AssertLinter 'standard', ale#Escape('standard') . ' --wat --stdin %s' ================================================ FILE: test/linter/test_starknet.vader ================================================ Before: call ale#assert#SetUpLinterTest('cairo', 'starknet') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'starknet-compile', 'starknet-compile %s' Execute(Extra options should be supported): let g:ale_cairo_starknet_options = '--config' AssertLinter 'starknet-compile', 'starknet-compile --config %s' ================================================ FILE: test/linter/test_staticcheck.vader ================================================ Before: Save g:ale_go_go111module Save $GOPATH let $GOPATH = '/non/existent/directory' call ale#assert#SetUpLinterTest('go', 'staticcheck') call ale#test#SetFilename('test.go') After: unlet! b:ale_go_go111module call ale#assert#TearDownLinterTest() Execute(The staticcheck callback should return the right defaults): AssertLinterCwd '%s:h' AssertLinter 'staticcheck', ale#Escape('staticcheck') . ' .' Execute(staticcheck should be found in GOPATH): " This is a directory with a fake executable let $GOPATH = ale#test#GetFilename('../test-files/go/gopath') AssertLinter \ ale#test#GetFilename('../test-files/go/gopath/bin/staticcheck'), \ ale#Escape(ale#test#GetFilename('../test-files/go/gopath/bin/staticcheck')) \ . ' .' Execute(The staticcheck callback should use configured options): let b:ale_go_staticcheck_options = '-test' AssertLinter 'staticcheck', ale#Escape('staticcheck') . ' -test .' Execute(Unset the staticcheck `lint_package` option should use the correct command): let b:ale_go_staticcheck_lint_package = 0 AssertLinterCwd '%s:h' AssertLinter 'staticcheck', ale#Escape('staticcheck') . ' %s:t' Execute(The staticcheck callback should use the `GO111MODULE` option if set): let b:ale_go_go111module = 'off' AssertLinter 'staticcheck', \ ale#Env('GO111MODULE', 'off') . ale#Escape('staticcheck') . ' .' " Test with lint_package option set let b:ale_go_staticcheck_lint_package = 0 AssertLinter 'staticcheck', \ ale#Env('GO111MODULE', 'off') . ale#Escape('staticcheck') . ' %s:t' ================================================ FILE: test/linter/test_sugarss_stylelint.vader ================================================ Before: call ale#assert#SetUpLinterTest('sugarss', 'stylelint') unlet! b:executable After: unlet! b:executable call ale#assert#TearDownLinterTest() Execute(node_modules directories should be discovered): call ale#test#SetFilename('../test-files/stylelint/nested/testfile.sss') let b:executable = ale#path#Simplify( \ g:dir \ . '/../test-files/stylelint/node_modules/.bin/stylelint' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --syntax=sugarss --no-color --stdin-filename %s' Execute(The global override should work): let b:ale_sugarss_stylelint_executable = 'foobar' let b:ale_sugarss_stylelint_use_global = 1 call ale#test#SetFilename('../test-files/stylelint/nested/testfile.sss') AssertLinter 'foobar', ale#Escape('foobar') . ' --syntax=sugarss --no-color --stdin-filename %s' Execute(Extra options should be configurable): call ale#test#SetFilename('../test-files/dummy') let b:ale_sugarss_stylelint_options = '--configFile ''/absolute/path/to/file''' AssertLinter 'stylelint', \ ale#Escape('stylelint') . ' --configFile ''/absolute/path/to/file'' --syntax=sugarss --no-color --stdin-filename %s' ================================================ FILE: test/linter/test_superhtml.vader ================================================ Before: call ale#assert#SetUpLinterTest('html', 'superhtml') call ale#test#SetFilename('test.html') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'superhtml', \ ale#Escape('superhtml') . ' check --stdin' Execute(The executable should be configurable): let g:ale_html_superhtml_executable = '/usr/local/bin/superhtml' AssertLinter '/usr/local/bin/superhtml', \ ale#Escape('/usr/local/bin/superhtml') . ' check --stdin' Execute(The use_global option should be respected): let g:ale_html_superhtml_executable = 'custom_superhtml' let g:ale_html_superhtml_use_global = 1 AssertLinter 'custom_superhtml', \ ale#Escape('custom_superhtml') . ' check --stdin' ================================================ FILE: test/linter/test_svelteserver.vader ================================================ Before: call ale#assert#SetUpLinterTest('svelte', 'svelteserver') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'svelteserver', ale#Escape('svelteserver') . ' --stdio' ================================================ FILE: test/linter/test_swaglint.vader ================================================ Before: call ale#assert#SetUpLinterTest('yaml', 'swaglint') After: call ale#assert#TearDownLinterTest() Execute(The yaml swaglint command callback should return the correct default string): 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', \ 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', \ 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('../test-files/swaglint/docs/swagger.yaml') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/swaglint/node_modules/.bin/swaglint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/swaglint/node_modules/.bin/swaglint')) \ . ' -r compact --stdin' ================================================ FILE: test/linter/test_swift_appleswiftformat.vader ================================================ Before: call ale#assert#SetUpLinterTest('swift', 'appleswiftformat') After: call ale#assert#TearDownLinterTest() Execute(Should use default command when use_swiftpm is not set): call ale#test#SetFilename('../test-files/swift/non-swift-package-project/src/folder/dummy.swift') let g:ale_swift_appleswiftformat_executable = 'swift-format' let g:ale_swift_appleswiftformat_use_swiftpm = 0 AssertLinter 'swift-format', ale#Escape('swift-format') . ' lint %t' Execute(Should use default command and available configuration when use_swiftpm is not set): call ale#test#SetDirectory('/testplugin/test/test-files/swift/swift-package-project-with-config') call ale#test#SetFilename('src/folder/dummy.swift') let g:ale_swift_appleswiftformat_executable = 'swift-format' let g:ale_swift_appleswiftformat_use_swiftpm = 0 AssertLinter 'swift-format', \ ale#Escape('swift-format') . ' lint %t ' . '--configuration ' \ . glob(g:dir . '/.swift-format') call ale#test#RestoreDirectory() Execute(Should use swift run when use_swiftpm is set to 1): call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift') let g:ale_swift_appleswiftformat_use_swiftpm = 1 AssertLinter 'swift', ale#Escape('swift') . ' run swift-format lint %t' Execute(Should use the provided global executable): call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift') let g:ale_swift_appleswiftformat_executable = '/path/to/custom/swift-format' let g:ale_swift_appleswiftformat_use_swiftpm = 0 AssertLinter '/path/to/custom/swift-format', \ ale#Escape('/path/to/custom/swift-format') . ' lint %t' ================================================ FILE: test/linter/test_swift_sourcekitlsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('swift', 'sourcekitlsp') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift') AssertLinter 'sourcekit-lsp', ale#Escape('sourcekit-lsp') Execute(Should let users configure a global executable and override local paths): call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift') let g:ale_sourcekit_lsp_executable = '/path/to/custom/sourcekitlsp' AssertLinter '/path/to/custom/sourcekitlsp', \ ale#Escape('/path/to/custom/sourcekitlsp') Execute(The language should be correct): AssertLSPLanguage 'swift' ================================================ FILE: test/linter/test_swiftlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('swift', 'swiftlint') After: call ale#assert#TearDownLinterTest() Execute(Global installation should be the default executable): call ale#test#SetFilename('../test-files/swiftlint/global/testfile.swift') AssertEqual \ 'swiftlint', \ ale_linters#swift#swiftlint#GetExecutable(bufnr('')) Execute(React Native apps using CocoaPods should take precedence over the default executable): call ale#test#SetFilename('../test-files/swiftlint/react-native/testfile.swift') AssertEqual \ tolower(ale#test#GetFilename('../test-files/swiftlint/react-native/ios/Pods/SwiftLint/swiftlint')), \ tolower(ale_linters#swift#swiftlint#GetExecutable(bufnr(''))) Execute(CocoaPods installation should take precedence over the default executable): call ale#test#SetFilename('../test-files/swiftlint/cocoapods/testfile.swift') AssertEqual \ tolower(ale#test#GetFilename('../test-files/swiftlint/cocoapods/Pods/SwiftLint/swiftlint')), \ tolower(ale_linters#swift#swiftlint#GetExecutable(bufnr(''))) Execute(Top level CocoaPods installation should take precedence over React Native installation): call ale#test#SetFilename('../test-files/swiftlint/cocoapods-and-react-native/testfile.swift') AssertEqual \ tolower(ale#test#GetFilename('../test-files/swiftlint/cocoapods-and-react-native/Pods/SwiftLint/swiftlint')), \ tolower(ale_linters#swift#swiftlint#GetExecutable(bufnr(''))) Execute(use-global should override other versions): let g:ale_swift_swiftlint_use_global = 1 let g:ale_swift_swiftlint_executable = 'swiftlint_d' call ale#test#SetFilename('../test-files/swiftlint/cocoapods-and-react-native/testfile.swift') AssertEqual \ 'swiftlint_d', \ ale_linters#swift#swiftlint#GetExecutable(bufnr('')) ================================================ FILE: test/linter/test_systemd_analyze.vader ================================================ Before: call ale#assert#SetUpLinterTest('systemd', 'systemd_analyze') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'systemd-analyze', \ 'SYSTEMD_LOG_COLOR=0 ' . ale#Escape('systemd-analyze') . ' --user verify %s' ================================================ FILE: test/linter/test_terraform_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('terraform', 'terraform_ls') After: unlet! b:ale_terraform_terraform_executable unlet! b:ale_terraform_ls_executable unlet! b:ale_terraform_ls_options call ale#assert#TearDownLinterTest() Execute(The terraform-ls language should be correct): AssertLSPLanguage 'terraform' Execute(The default terraform-ls command should be correct): AssertLinter 'terraform-ls', ale#Escape('terraform-ls') . ' serve' Execute(The terrarform-ls executable and options should be configurable): let b:ale_terraform_ls_executable = 'foo' let b:ale_terraform_ls_options = '--bar' AssertLinter 'foo', ale#Escape('foo') . ' serve --bar' Execute(Should ignore non-absolute path custom terraform executables): let b:ale_terraform_terraform_executable = 'terraform' AssertLinter 'terraform-ls', ale#Escape('terraform-ls') . ' serve' Execute(Should set absolute custom terraform executable): let b:ale_terraform_terraform_executable = '/bin/terraform' AssertLinter 'terraform-ls', \ ale#Escape('terraform-ls') . ' serve -tf-exec /bin/terraform' Execute(Should return nearest directory with .terraform if found in parent directory): call ale#test#SetFilename('../test-files/terraform/main.tf') AssertLSPProject ale#test#GetFilename('../test-files/terraform') ================================================ FILE: test/linter/test_terraform_lsp.vader ================================================ Before: call ale#assert#SetUpLinterTest('terraform', 'terraform_lsp') After: unlet! b:ale_terraform_langserver_executable unlet! b:ale_terraform_langserver_options call ale#assert#TearDownLinterTest() Execute(Should send correct LSP language): AssertLSPLanguage 'terraform' Execute(Should load default executable): AssertLinter 'terraform-lsp', ale#Escape('terraform-lsp') Execute(Should configure custom executable): let b:ale_terraform_langserver_executable = 'foo' AssertLinter 'foo', ale#Escape('foo') Execute(Should set custom options): let b:ale_terraform_langserver_options = '--bar' AssertLinter 'terraform-lsp', \ ale#Escape('terraform-lsp') . ' --bar' Execute(Should return nearest directory with .terraform if found in parent directory): call ale#test#SetFilename('../test-files/terraform/main.tf') AssertLSPProject ale#test#GetFilename('../test-files/terraform') ================================================ FILE: test/linter/test_terraform_terraform.vader ================================================ " Based upon :help ale-development Before: call ale#assert#SetUpLinterTest('terraform', 'terraform') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'terraform', \ ale#Escape('terraform') . ' validate -no-color -json ' Execute(The default command should be overridden): let b:ale_terraform_terraform_executable = '/bin/other/terraform' AssertLinter '/bin/other/terraform', \ ale#Escape('/bin/other/terraform') . ' validate -no-color -json ' ================================================ FILE: test/linter/test_terraform_tflint.vader ================================================ Before: call ale#assert#SetUpLinterTest('terraform', 'tflint') After: call ale#assert#TearDownLinterTest() Execute(The default tflint command should be correct): AssertLinter 'tflint', ale#Escape('tflint') . ' -f json' Execute(Test tflint executable and command should be configurable): let g:ale_terraform_tflint_executable = 'fnord' let g:ale_terraform_tflint_options = '--whatever' AssertLinter 'fnord', ale#Escape('fnord') . ' --whatever -f json' Execute(Configuration files should be found): call ale#test#SetFilename('../test-files/tflint/foo/bar.tf') AssertLinter 'tflint', \ ale#Escape('tflint') \ . ' --config ' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/tflint/foo/.tflint.hcl')) \ . ' -f json' ================================================ FILE: test/linter/test_terraform_tfsec.vader ================================================ Before: call ale#assert#SetUpLinterTest('terraform', 'tfsec') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'tfsec', ale#Escape('tfsec') . ' --format json' Execute(The default executable should be configurable): let b:ale_terraform_tfsec_executable = '/usr/bin/tfsec' AssertLinter '/usr/bin/tfsec', ale#Escape('/usr/bin/tfsec') . ' --format json' Execute(Overriding options should work): let g:ale_terraform_tfsec_executable = '/usr/local/bin/tfsec' let g:ale_terraform_tfsec_options = '--minimum-severity MEDIUM' AssertLinter '/usr/local/bin/tfsec', \ ale#Escape('/usr/local/bin/tfsec') . ' --minimum-severity MEDIUM --format json' Execute(Configuration yml file should be found): call ale#test#SetFilename('../test-files/tfsec/yml/main.tf') AssertLinter 'tfsec', \ ale#Escape('tfsec') \ . ' --config-file ' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/tfsec/yml/.tfsec/config.yml')) \ . ' --format json' Execute(Configuration json file should be found): call ale#test#SetFilename('../test-files/tfsec/json/main.tf') AssertLinter 'tfsec', \ ale#Escape('tfsec') \ . ' --config-file ' \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/tfsec/json/.tfsec/config.json')) \ . ' --format json' ================================================ FILE: test/linter/test_tex_chktex.vader ================================================ Before: call ale#assert#SetUpLinterTest('tex', 'chktex') GivenCommandOutput ['ChkTeX v1.7.6 - Copyright 1995-96 Jens T. Berger Thielemann'] After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'chktex', [ \ ale#Escape('chktex') . ' --version', \ ale#Escape('chktex') \ . ' -v0 -p stdin -q' \ . ' -I', \] " The version check should be cached. GivenCommandOutput [] AssertLinter 'chktex', [ \ ale#Escape('chktex') \ . ' -v0 -p stdin -q' \ . ' -I', \] " Try newer version call ale#semver#ResetVersionCache() GivenCommandOutput ['ChkTeX v1.7.8 - Copyright 1995-96 Jens T. Berger Thielemann'] AssertLinter 'chktex', [ \ ale#Escape('chktex') . ' --version', \ ale#Escape('chktex') \ . ' -v0 -p stdin -q' \ . ' -S TabSize=1' \ . ' -I', \] Execute(The executable should be configurable): let g:ale_tex_chktex_executable = 'bin/foo' AssertLinter 'bin/foo', \ ale#Escape('bin/foo') \ . ' -v0 -p stdin -q' \ . ' -I' Execute(The options should be configurable): let b:ale_tex_chktex_options = '--something' AssertLinter 'chktex', \ ale#Escape('chktex') \ . ' -v0 -p stdin -q' \ . ' --something' ================================================ FILE: test/linter/test_tex_lacheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('tex', 'lacheck') After: call ale#assert#TearDownLinterTest() Execute(Executable should default to lacheck): AssertLinter 'lacheck', ale#Escape('lacheck') . ' %t' Execute(Should be able to set a custom executable): let g:ale_tex_lacheck_executable = 'bin/foo' AssertLinter 'bin/foo' , ale#Escape('bin/foo') . ' %t' ================================================ FILE: test/linter/test_tex_textlint.vader ================================================ " Author: januswel, w0rp Before: " This is just one language for the linter. call ale#assert#SetUpLinterTest('tex', 'textlint') " The configuration is shared between many languages. Save g:ale_textlint_executable Save g:ale_textlint_use_global Save g:ale_textlint_options let g:ale_textlint_executable = 'textlint' let g:ale_textlint_use_global = 0 let g:ale_textlint_options = '' unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options After: unlet! b:command_tail unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'textlint', \ ale#Escape('textlint') . ' -f json --stdin --stdin-filename %s' Execute(The executable should be configurable): let b:ale_textlint_executable = 'foobar' AssertLinter 'foobar', \ ale#Escape('foobar') . ' -f json --stdin --stdin-filename %s' Execute(The options should be configurable): let b:ale_textlint_options = '--something' AssertLinter 'textlint', \ ale#Escape('textlint') . ' --something -f json --stdin --stdin-filename %s' Execute(The local executable from .bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_bin_path/foo.txt') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint')) \ . ' -f json --stdin --stdin-filename %s' Execute(The local executable from textlint/bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_textlint_bin_path/foo.txt') if has('win32') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape('node.exe') . ' ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' else AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' endif ================================================ FILE: test/linter/test_texlab.vader ================================================ Before: call ale#assert#SetUpLinterTest('tex', 'texlab') Save &filetype let &filetype = 'tex' After: call ale#assert#TearDownLinterTest() Execute(The language string should be correct): AssertLSPLanguage 'tex' Execute(The default executable path should be correct): AssertLinter 'texlab', ale#Escape('texlab') Execute(The project root should be detected correctly): call ale#test#SetFilename('../test-files/tex/sample1.tex') silent! call mkdir('../test-files/tex/.git') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/tex') Execute(The executable should be configurable): let b:ale_tex_texlab_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') Execute(The options should be configurable): let b:ale_tex_texlab_options = '-v' AssertLinter 'texlab', ale#Escape('texlab') . ' ' . b:ale_tex_texlab_options Execute(Should accept configuration settings): AssertLSPConfig {} let b:ale_tex_texlab_config = {'build':{'onSave':v:true}} AssertLSPConfig {'build':{'onSave':v:true}} ================================================ FILE: test/linter/test_text_vale.vader ================================================ Before: call ale#assert#SetUpLinterTest('text', 'vale') After: call ale#assert#TearDownLinterTest() Execute(The Vale command should include extra options when configured): let g:ale_vale_executable = 'vale' let g:ale_vale_options = '--minAlertLevel=warning' AssertLinter 'vale', ale#Escape('vale') . ' --minAlertLevel=warning --output=JSON %t' Execute(The Vale command should not include extra options by default): let g:ale_vale_executable = 'vale' let g:ale_vale_options = '' AssertLinter 'vale', ale#Escape('vale') . ' --output=JSON %t' ================================================ FILE: test/linter/test_textlint.vader ================================================ " Author: januswel, w0rp Before: " This is just one language for the linter. call ale#assert#SetUpLinterTest('markdown', 'textlint') " The configuration is shared between many languages. Save g:ale_textlint_executable Save g:ale_textlint_use_global Save g:ale_textlint_options let g:ale_textlint_executable = 'textlint' let g:ale_textlint_use_global = 0 let g:ale_textlint_options = '' unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options After: unlet! b:command_tail unlet! b:ale_textlint_executable unlet! b:ale_textlint_use_global unlet! b:ale_textlint_options call ale#assert#TearDownLinterTest() Execute(The default textlint command should be correct): AssertLinter 'textlint', \ ale#Escape('textlint') . ' -f json --stdin --stdin-filename %s' Execute(The textlint executable and options should be configurable): let b:ale_textlint_executable = 'foobar' let b:ale_textlint_options = '--something' AssertLinter 'foobar', \ ale#Escape('foobar') . ' --something -f json --stdin --stdin-filename %s' Execute(The local executable from .bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_bin_path/foo.txt') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_bin_path/node_modules/.bin/textlint')) \ . ' -f json --stdin --stdin-filename %s' Execute(The local executable from textlint/bin should be used if available): call ale#test#SetFilename('../test-files/textlint/with_textlint_bin_path/foo.txt') if has('win32') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape('node.exe') . ' ' . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' else AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/textlint/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) \ . ' -f json --stdin --stdin-filename %s' endif ================================================ FILE: test/linter/test_thrift.vader ================================================ Before: call ale#assert#SetUpLinterTest('thrift', 'thrift') let b:suffix = ' -out ' . ale#Escape('TEMP_DIR') . ' %t' function! GetCommand(buffer) abort call ale#engine#InitBufferInfo(a:buffer) let l:command = ale_linters#thrift#thrift#GetCommand(a:buffer) call ale#engine#Cleanup(a:buffer) let l:split_command = split(l:command) let l:index = index(l:split_command, '-out') if l:index >= 0 let l:split_command[l:index + 1] = 'TEMP' endif return join(l:split_command) endfunction After: unlet! b:suffix delfunction GetCommand call ale#assert#TearDownLinterTest() Execute(The default command should be correct): 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 -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 -I . -strict' . b:suffix let b:ale_thrift_thrift_generators = [] 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'] AssertLinter 'thrift', ale#Escape('thrift') \ . ' --gen cpp -I included/path -strict' . b:suffix 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 -I . -strict --allow-64bit-consts' . b:suffix ================================================ FILE: test/linter/test_thriftcheck.vader ================================================ Before: call ale#assert#SetUpLinterTest('thrift', 'thriftcheck') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'thriftcheck', ale#Escape('thriftcheck') \ . ' --stdin-filename %s %t' Execute(The executable and options should be configurable): let b:ale_thrift_thriftcheck_executable = 'foobar' let b:ale_thrift_thriftcheck_options = '--errors-only' AssertLinter 'foobar', ale#Escape('foobar') \ . ' --errors-only --stdin-filename %s %t' ================================================ FILE: test/linter/test_toml_tombi.vader ================================================ Before: Save g:ale_toml_tombi_online call ale#assert#SetUpLinterTest('toml', 'tombi') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'tombi', ale#Escape('tombi') . ' lsp --offline' Execute(The default executable path should obey `toml_tombi_online`): let g:ale_toml_tombi_online = 1 AssertLinter 'tombi', ale#Escape('tombi') . ' lsp' Execute(The project root should be detected correctly with a configuration file): call ale#test#SetFilename('../test-files/toml/tombi/tombitoml/subdir/file.ext') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/toml/tombi/tombitoml') Execute(The project root should be detected correctly in Python projects): call ale#test#SetFilename('../test-files/toml/tombi/pyprojecttoml/subdir/file.ext') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/toml/tombi/pyprojecttoml') ================================================ FILE: test/linter/test_tslint.vader ================================================ Before: call ale#assert#SetUpLinterTest('typescript', 'tslint') call ale#test#SetFilename('test.ts') After: call ale#assert#TearDownLinterTest() Execute(The default tslint command should be correct): AssertLinterCwd '%s:h' AssertLinter 'tslint', 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', \ ale#Escape('tslint') . ' --format json' \ . ' -r ' . ale#Escape('/foo/bar') \ . ' %t' Execute(The executable should be configurable and escaped): let b:ale_typescript_tslint_executable = 'foo bar' AssertLinter 'foo bar', ale#Escape('foo bar') . ' --format json %t' ================================================ FILE: test/linter/test_typescript_deno_lsp.vader ================================================ Before: Save g:ale_deno_import_map Save g:ale_deno_importMap Save g:ale_deno_unstable Save g:ale_deno_executable Save g:ale_deno_lsp_project_root let g:ale_deno_import_map = 'import_map.json' let g:ale_deno_importMap = '' let g:ale_deno_unstable = 0 let g:ale_deno_executable = 'deno' let g:ale_deno_lsp_project_root = '' runtime autoload/ale/handlers/deno.vim call ale#assert#SetUpLinterTest('typescript', 'deno') After: call ale#assert#TearDownLinterTest() Execute(Should set deno lsp for TypeScript projects using stable Deno API): AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': '' \} Execute(Should set deno lsp using unstable Deno API if enabled by user): let g:ale_deno_unstable = 1 AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:true, \ 'importMap': '' \} Execute(Should set the default importMap filepath): call ale#test#SetFilename('../test-files/typescript/test.ts') AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': ale#path#Simplify(g:dir . '/../test-files/typescript/import_map.json') \} Execute(Should set the importMap filepath from user defined importMap): let g:ale_deno_importMap = 'custom_import_map.json' call ale#test#SetFilename('../test-files/typescript/test.ts') AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:false, \ 'importMap': ale#path#Simplify(g:dir . '/../test-files/typescript/custom_import_map.json') \} Execute(Should set the importMap filepath from user defined importMap with unstable API): let g:ale_deno_import_map = 'custom_import_map.json' let g:ale_deno_unstable = 1 call ale#test#SetFilename('../test-files/typescript/test.ts') AssertLSPOptions { \ 'enable': v:true, \ 'lint': v:true, \ 'unstable': v:true, \ 'importMap': ale#path#Simplify(g:dir . '/../test-files/typescript/custom_import_map.json') \} Execute(Should find project root containing tsconfig.json): call ale#test#SetFilename('../test-files/typescript/test.ts') AssertLSPLanguage 'typescript' AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/typescript') Execute(Should use user-specified project root): let g:ale_deno_lsp_project_root = '/' call ale#test#SetFilename('../test-files/typescript/test.ts') AssertLSPLanguage 'typescript' AssertLSPProject '/' Execute(Check Deno LSP command): AssertLinter 'deno', ale#Escape('deno') . ' lsp' ================================================ FILE: test/linter/test_typescript_tsserver.vader ================================================ Before: call ale#assert#SetUpLinterTest('typescript', 'tsserver') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'tsserver', ale#Escape('tsserver') ================================================ FILE: test/linter/test_unimport.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'unimport') call ale#test#SetFilename('test.py') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:executable unlet! b:bin_dir call ale#assert#TearDownLinterTest() Execute(The unimport callbacks should return the correct default values): AssertLinter 'unimport', ale#Escape('unimport') . ' --check %t' Execute(The unimport executable should be configurable, and escaped properly): let b:ale_python_unimport_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --check %t' Execute(The unimport command callback should let you set options): let b:ale_python_unimport_options = '--gitignore' AssertLinter 'unimport', ale#Escape('unimport') . ' --gitignore --check %t' Execute(The unimport command should switch directories to the detected project root): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'unimport', ale#Escape('unimport') . ' --check %t' Execute(The unimport callbacks should detect virtualenv directories and switch to the project root): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/unimport' \) AssertLinter b:executable, ale#Escape(b:executable) . ' --check %t' Execute(You should able able to use the global unimport instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_unimport_use_global = 1 AssertLinter 'unimport', ale#Escape('unimport') . ' --check %t' Execute(Setting executable to 'pipenv' appends 'run unimport'): let g:ale_python_unimport_executable = 'path/to/pipenv' AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run unimport --check %t' Execute(Pipenv is detected when python_unimport_auto_pipenv is set): call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') let g:ale_python_unimport_auto_pipenv = 1 AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'pipenv', ale#Escape('pipenv') . ' run unimport --check %t' Execute(Setting executable to 'poetry' appends 'run unimport'): let g:ale_python_unimport_executable = 'path/to/poetry' AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run unimport --check %t' Execute(Poetry is detected when python_unimport_auto_poetry is set): call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let g:ale_python_unimport_auto_poetry = 1 AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'poetry', ale#Escape('poetry') . ' run unimport --check %t' Execute(uv is detected when python_unimport_auto_uv is set): call ale#test#SetFilename('../test-files/python/uv/whatever.py') let g:ale_python_unimport_auto_uv = 1 AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'uv', ale#Escape('uv') . ' run unimport --check %t' ================================================ FILE: test/linter/test_v_command_callback.vader ================================================ Before: call ale#assert#SetUpLinterTest('v', 'v') After: call ale#assert#TearDownLinterTest() Execute(The default v command should be correct): AssertLinter 'v', ale#Escape('v') . ' . -o /tmp/vim-ale-v' Execute(The v executable and options should be configurable): let g:ale_v_v_executable = 'foobar' let g:ale_v_v_options = '--foo-bar' AssertLinter 'foobar', ale#Escape('foobar') . ' --foo-bar . -o /tmp/vim-ale-v' ================================================ FILE: test/linter/test_vcom.vader ================================================ Before: call ale#assert#SetUpLinterTest('vhdl', 'vcom') After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'vcom', ale#Escape('vcom') . ' -2008 -quiet -lint %t' let b:ale_vhdl_vcom_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' -2008 -quiet -lint %t' Execute(The options should be configurable): let b:ale_vhdl_vcom_options = '--something' AssertLinter 'vcom', ale#Escape('vcom') . ' --something %t' ================================================ FILE: test/linter/test_verilator.vader ================================================ Before: call ale#assert#SetUpLinterTest('verilog', 'verilator') After: call ale#assert#TearDownLinterTest() Execute(The default verilator command should be correct): AssertLinter 'verilator', 'verilator --lint-only -Wall -Wno-DECLFILENAME -I%s:h -y %s:h %t' Execute(verilator options should be configurable): " Additional args for the linter let g:ale_verilog_verilator_options = '-sv --default-language "1800-2012"' AssertLinter 'verilator', 'verilator --lint-only -Wall -Wno-DECLFILENAME -I%s:h -y %s:h -sv --default-language "1800-2012" %t' ================================================ FILE: test/linter/test_verilog_verible_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('verilog', 'verible_ls') After: call ale#assert#TearDownLinterTest() Execute(The default executable path and arguments should be correct): AssertLinter 'verible-verilog-ls', ale#Escape('verible-verilog-ls') . ' --rules_config_search' Execute(The project root should be detected correctly in empty directory): AssertLSPProject '.' Execute(The project root should be detected correctly with verible.filelist): call ale#test#SetFilename('../test-files/verilog/verible/module.sv') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/verilog/verible') Execute(The LSP values should be set correctly): call ale#test#SetFilename('../test-files/verilog/verible/module.sv') AssertLSPLanguage 'verilog' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/verilog/verible') Execute(The verible LSP callback should allow custom options): let g:ale_verilog_verible_ls_options = '--foo --bar' AssertLinter 'verible-verilog-ls', ale#Escape('verible-verilog-ls') . ' --foo --bar' Execute(The verible LSP callback should allow custom rules): let g:ale_verilog_verible_ls_rules = '+foo,-bar' AssertLinter 'verible-verilog-ls', ale#Escape('verible-verilog-ls') . ' --rules_config_search --rules=+foo,-bar' ================================================ FILE: test/linter/test_vim_vimls.vader ================================================ " Author: Jeffrey Lau https://github.com/zoonfafer " Description: Tests for the Vim vimls linter Before: call ale#assert#SetUpLinterTest('vim', 'vimls') After: if isdirectory(g:dir . '/.git') call delete(g:dir . '/.git', 'd') endif call ale#assert#TearDownLinterTest() Execute(should set correct defaults): AssertLinter 'vim-language-server', ale#Escape('vim-language-server') . ' --stdio' Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/vim/path_with_autoload/test.vim') AssertLSPLanguage 'vim' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/vim/path_with_autoload') Execute(should set correct project for .git/): let b:parent_dir = ale#path#Simplify(g:dir . '/..') let b:git_dir = b:parent_dir . '/.git' call ale#test#SetFilename('../test-files/vim/test.vim') if !isdirectory(b:git_dir) call mkdir(b:git_dir) endif AssertLSPProject ale#path#Simplify(b:parent_dir) call delete(b:git_dir, 'd') unlet! b:git_dir Execute(should set correct project for plugin/): call ale#test#SetFilename('../test-files/vim/path_with_plugin/test.vim') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/vim/path_with_plugin') Execute(should accept configuration settings): AssertLSPConfig {} let b:ale_vim_vimls_config = {'vim': {'foobar': v:true}} AssertLSPConfig {'vim': {'foobar': v:true}} Execute(should set correct project for .vimrc): call ale#test#SetFilename('../test-files/vim/path_with_vimrc/.vimrc') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/vim/path_with_vimrc') Execute(should set correct project for init.vim): call ale#test#SetFilename('../test-files/vim/path_with_initvim/init.vim') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/vim/path_with_initvim') Execute(should use the local executable when available): call ale#test#SetFilename('../test-files/vim/file.vim') AssertLinter ale#path#Simplify(g:dir . '/../test-files/vim/node_modules/.bin/vim-language-server'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/vim/node_modules/.bin/vim-language-server')) . ' --stdio' Execute(should let the global executable to be used): let g:ale_vim_vimls_use_global = 1 call ale#test#SetFilename('../test-files/vim/file.vim') AssertLinter 'vim-language-server', \ ale#Escape('vim-language-server') . ' --stdio' Execute(should allow the executable to be configured): let g:ale_vim_vimls_executable = 'foobar' call ale#test#SetFilename('../test-files/dummy') AssertLinter 'foobar', ale#Escape('foobar') . ' --stdio' ================================================ FILE: test/linter/test_vint.vader ================================================ Before: call ale#assert#SetUpLinterTest('vim', 'vint') let b:common_flags = (has('nvim') ? ' --enable-neovim' : '') \ . ' -f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"' After: unlet! b:common_flags call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'vint', [ \ ale#Escape('vint') .' --version', \ ale#Escape('vint') .' -s --no-color' . b:common_flags . ' %t', \] Execute(The executable should be configurable): let g:ale_vim_vint_executable = 'foobar' AssertLinter 'foobar', [ \ ale#Escape('foobar') .' --version', \ ale#Escape('foobar') .' -s --no-color' . b:common_flags . ' %t', \] Execute(The --no-color flag should not be used for older Vint versions): GivenCommandOutput ['v0.3.5'] AssertLinter 'vint', ale#Escape('vint') .' -s' . b:common_flags . ' %t' Execute(--stdin-display-name should be used in newer versions): GivenCommandOutput ['v0.4.0'] AssertLinter 'vint', ale#Escape('vint') .' -s --no-color' . b:common_flags \ . ' --stdin-display-name %s -' ================================================ FILE: test/linter/test_vlog.vader ================================================ Before: call ale#assert#SetUpLinterTest('verilog', 'vlog') After: unlet! b:command_tail call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'vlog', ale#Escape('vlog') . ' -quiet -lint %t' let b:ale_verilog_vlog_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' -quiet -lint %t' Execute(The options should be configurable): let b:ale_verilog_vlog_options = '--something' AssertLinter 'vlog', ale#Escape('vlog') . ' --something %t' ================================================ FILE: test/linter/test_volar.vader ================================================ Before: call ale#assert#SetUpLinterTest('vue', 'volar') let g:tsserver_path = '' let g:actual_path = '' let g:init_opts = {} After: call ale#assert#TearDownLinterTest() unlet g:tsserver_path unlet g:actual_path unlet g:init_opts Execute(Assert Volar LSP for Vue Project): call ale#test#SetFilename('../test-files/volar/src/App.vue') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/volar') Execute(Assert proper tsserverlibrary for Volar LSP): call ale#test#SetFilename('../test-files/volar/src/App.vue') let g:init_opts = ale_linters#vue#volar#GetInitializationOptions(bufnr('')) let g:tsserver_path = init_opts.typescript.tsdk let g:actual_path = ale#path#Simplify(g:dir . '/../test-files/volar/node_modules/typescript/lib/') AssertEqual g:tsserver_path, g:actual_path ================================================ FILE: test/linter/test_vulture.vader ================================================ Before: call ale#assert#SetUpLinterTest('python', 'vulture') call ale#test#SetFilename('test.py') let b:bin_dir = has('win32') ? 'Scripts' : 'bin' After: unlet! b:bin_dir unlet! b:executable call ale#assert#TearDownLinterTest() Execute(The vulture command callback should lint file directory by default): AssertLinterCwd expand('#' . bufnr('') . ':p:h') AssertLinter 'vulture', ale#Escape('vulture') . ' .' Execute(The vulture command callback should lint project root, when present): call ale#test#SetFilename('../test-files/python/no_virtualenv/subdir/foo/bar.py') AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/no_virtualenv/subdir') AssertLinter 'vulture', ale#Escape('vulture') . ' .' Execute(The option for disabling change directory works and only lints file): let g:ale_python_vulture_change_directory = 0 AssertLinterCwd '' AssertLinter 'vulture', ale#Escape('vulture') . ' %s' Execute(The vulture executable should be configurable, and escaped properly): let g:ale_python_vulture_executable = 'executable with spaces' AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . ' .' Execute(The vulture command callback should let you set options): let g:ale_python_vulture_options = '--some-option' AssertLinter 'vulture', ale#Escape('vulture') . ' --some-option .' Execute(The vulture command callback should detect virtualenv directories and switch to the project root): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let b:executable = ale#path#Simplify( \ g:dir . '/../test-files/python/with_virtualenv/env/' . b:bin_dir . '/vulture' \) AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/python/with_virtualenv/subdir') AssertLinter b:executable, ale#Escape(b:executable) . ' .' Execute(You should able able to use the global vulture instead): call ale#test#SetFilename('../test-files/python/with_virtualenv/subdir/foo/bar.py') let g:ale_python_vulture_use_global = 1 AssertLinter 'vulture', ale#Escape('vulture') . ' .' Execute(Setting executable to 'pipenv' appends 'run vulture'): let g:ale_python_vulture_executable = 'path/to/pipenv' AssertLinter 'path/to/pipenv', ale#Escape('path/to/pipenv') . ' run vulture' . ' .' Execute(Setting executable to 'poetry' appends 'run vulture'): let g:ale_python_vulture_executable = 'path/to/poetry' AssertLinter 'path/to/poetry', ale#Escape('path/to/poetry') . ' run vulture' . ' .' Execute(pipenv is detected when python_vulture_auto_pipenv is set): call ale#test#SetFilename('../test-files/python/pipenv/whatever.py') let g:ale_python_vulture_auto_pipenv = 1 AssertLinter 'pipenv', \ ale#Escape('pipenv') . ' run vulture' . ' .' Execute(poetry is detected when python_vulture_auto_poetry is set): call ale#test#SetFilename('../test-files/python/poetry/whatever.py') let g:ale_python_vulture_auto_poetry = 1 AssertLinter 'poetry', \ ale#Escape('poetry') . ' run vulture' . ' .' Execute(uv is detected when python_vulture_auto_uv is set): call ale#test#SetFilename('../test-files/python/uv/whatever.py') let g:ale_python_vulture_auto_uv = 1 AssertLinter 'uv', \ ale#Escape('uv') . ' run vulture' . ' .' ================================================ FILE: test/linter/test_write_good.vader ================================================ Before: " This is just one example of a language using the linter. call ale#assert#SetUpLinterTest('markdown', 'writegood') " The options are shared between many languages. Save g:ale_writegood_options Save g:ale_writegood_executable Save g:ale_writegood_use_global unlet! g:ale_writegood_options unlet! g:ale_writegood_executable unlet! g:ale_writegood_use_global call ale#test#SetFilename('testfile.txt') call ale#handlers#writegood#ResetOptions() After: call ale#assert#TearDownLinterTest() Execute(The global executable should be used when the local one cannot be found): AssertLinter \ 'write-good', \ ale#Escape('write-good') . ' %t', Execute(The options should be used in the command): let g:ale_writegood_options = '--foo --bar' AssertLinter \ 'write-good', \ ale#Escape('write-good') . ' --foo --bar %t', Execute(Should use the node_modules/.bin executable, if available): call ale#test#SetFilename('../test-files/write-good/node-modules/test.txt') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/write-good/node-modules/node_modules/.bin/write-good'), \ ale#Escape(ale#path#Simplify(g:dir . '/../test-files/write-good/node-modules/node_modules/.bin/write-good')) \ . ' %t', Execute(Should use the node_modules/write-good executable, if available): call ale#test#SetFilename('../test-files/write-good/node-modules-2/test.txt') AssertLinter \ ale#path#Simplify(g:dir . '/../test-files/write-good/node-modules-2/node_modules/write-good/bin/write-good.js'), \ (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../test-files/write-good/node-modules-2/node_modules/write-good/bin/write-good.js')) \ . ' %t', Execute(Should let users configure a global executable and override local paths): call ale#test#SetFilename('../test-files/write-good/node-modules-2/test.txt') let g:ale_writegood_executable = 'foo-bar' let g:ale_writegood_use_global = 1 AssertLinter 'foo-bar', ale#Escape('foo-bar') . ' %t' ================================================ FILE: test/linter/test_xmllint.vader ================================================ Before: call ale#assert#SetUpLinterTest('xml', 'xmllint') After: call ale#assert#TearDownLinterTest() Execute(The xml xmllint command callback should return the correct default string): AssertLinter 'xmllint', ale#Escape('xmllint') . ' --noout -' Execute(The xml xmllint command callback should let you set options): let g:ale_xml_xmllint_options = '--xinclude --postvalid' AssertLinter 'xmllint', \ ale#Escape('xmllint') . ' --xinclude --postvalid --noout -' Execute(The xmllint executable should be configurable): let g:ale_xml_xmllint_executable = '~/.local/bin/xmllint' AssertLinter '~/.local/bin/xmllint', \ ale#Escape('~/.local/bin/xmllint') . ' --noout -' ================================================ FILE: test/linter/test_xo.vader ================================================ Before: call ale#assert#SetUpLinterTest('javascript', 'xo') call ale#test#SetFilename('testfile.jsx') unlet! b:executable set filetype=javascriptreact runtime autoload/ale/handlers/xo.vim After: call ale#assert#TearDownLinterTest() Execute(The default xo command should be correct): AssertLinter 'xo', ale#Escape('xo') . ' --reporter json --stdin --stdin-filename %s' Execute(The xo executable and command should be configurable): let b:ale_javascript_xo_executable = 'foobar' let b:ale_javascript_xo_options = '--wat' AssertLinter 'foobar', ale#Escape('foobar') \ . ' --wat --reporter json --stdin --stdin-filename %s' ================================================ FILE: test/linter/test_xots.vader ================================================ Before: call ale#assert#SetUpLinterTest('typescript', 'xo') call ale#test#SetFilename('testfile.tsx') unlet! b:executable set filetype=typescriptreact runtime autoload/ale/handlers/xo.vim After: call ale#assert#TearDownLinterTest() Execute(The XO executable should be called): AssertLinter 'xo', ale#Escape('xo') . ' --reporter json --stdin --stdin-filename %s' Execute(The XO executable should be configurable): let b:ale_typescript_xo_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' --reporter json --stdin --stdin-filename %s' Execute(The XO options should be configurable): let b:ale_typescript_xo_options = '--wat' AssertLinter 'xo', ale#Escape('xo') . ' --wat --reporter json --stdin --stdin-filename %s' ================================================ FILE: test/linter/test_xvhdl.vader ================================================ Before: call ale#assert#SetUpLinterTest('vhdl', 'xvhdl') After: call ale#assert#TearDownLinterTest() Execute(The default xvhdl command should be correct): AssertLinter 'xvhdl', ale#Escape('xvhdl') . ' --2008 %t' Execute(The xvhdl executable and options should be configurable): let b:ale_vhdl_xvhdl_executable = 'foobar' let b:ale_vhdl_xvhdl_options = '--something' AssertLinter 'foobar', ale#Escape('foobar') . ' --something %t' ================================================ FILE: test/linter/test_xvlog.vader ================================================ Before: call ale#assert#SetUpLinterTest('verilog', 'xvlog') After: call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): AssertLinter 'xvlog', ale#Escape('xvlog') . ' %t' let b:ale_verilog_xvlog_executable = 'foobar' AssertLinter 'foobar', ale#Escape('foobar') . ' %t' Execute(The options should be configurable): let b:ale_verilog_xvlog_options = '--something' AssertLinter 'xvlog', ale#Escape('xvlog') . ' --something %t' ================================================ FILE: test/linter/test_yaml_actionlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('yaml', 'actionlint') call ale#test#SetFilename('/.github/file.yml') After: call ale#assert#TearDownLinterTest() Execute(Command should always have -no-color, -oneline and - options): let g:ale_yaml_actionlint_options = '' AssertLinter 'actionlint', ale#Escape('actionlint') . ' -no-color -oneline - ' Execute(Options should be added to command): let g:ale_yaml_actionlint_options = '-shellcheck= -pyflakes=' AssertLinter 'actionlint', \ ale#Escape('actionlint') . ' -shellcheck= -pyflakes= -no-color -oneline - ' Execute(actionlint not run on files outside of /.github/ paths): call ale#test#SetFilename('/something-else/file.yml') ================================================ FILE: test/linter/test_yaml_ls.vader ================================================ Before: call ale#assert#SetUpLinterTest('yaml', 'ls') After: call ale#assert#TearDownLinterTest() Execute(should set correct defaults): AssertLinter 'yaml-language-server', ale#Escape('yaml-language-server') . ' --stdio' Execute(should set correct LSP values): call ale#test#SetFilename('../test-files/yaml/test.yaml') AssertLSPLanguage 'yaml' AssertLSPOptions {} AssertLSPConfig {} AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/yaml') Execute(should accept configuration settings): AssertLSPConfig {} let b:ale_yaml_ls_config = {'yaml': {'hover': v:false, 'completion': v:true}} AssertLSPConfig {'yaml': {'hover': v:false, 'completion': v:true}} ================================================ FILE: test/linter/test_yang_lsp.vader ================================================ 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') ================================================ FILE: test/linter/test_yara_yls.vader ================================================ Before: call ale#assert#SetUpLinterTest('yara', 'yls') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'yls', ale#Escape('yls') . ' -v' ================================================ FILE: test/linter/test_yq.vader ================================================ Before: call ale#assert#SetUpLinterTest('yaml', 'yq') After: call ale#assert#TearDownLinterTest() Execute(The default command should be correct): AssertLinter 'yq', ale#Escape('yq') ================================================ FILE: test/linter/test_zeek.vader ================================================ Before: call ale#assert#SetUpLinterTest('zeek', 'zeek') let b:command_tail = ' --parse-only %s' After: call ale#assert#TearDownLinterTest() unlet! b:command_tail Execute(The default command should be correct): AssertLinter 'zeek', ale#Escape('zeek') . b:command_tail Execute(The zeek executable should be configurable, and escaped properly): let g:ale_zeek_zeek_executable = 'executable with spaces' AssertLinter 'executable with spaces', ale#Escape('executable with spaces') . b:command_tail ================================================ FILE: test/linter/test_zig_zlint.vader ================================================ Before: call ale#assert#SetUpLinterTest('zig', 'zlint') After: call ale#assert#TearDownLinterTest() Execute(The zlint executable and command should be configured correctly): AssertLinter 'zlint', ale#Escape('zlint') . ' %s -f gh' " Set a custom executable path let g:ale_zig_zlint_executable = '/custom/path/to/zlint' AssertLinter \ '/custom/path/to/zlint', \ ale#Escape('/custom/path/to/zlint') . ' %s -f gh' ================================================ FILE: test/linter/test_zig_zls.vader ================================================ Before: call ale#assert#SetUpLinterTest('zig', 'zls') After: call ale#assert#TearDownLinterTest() Execute(The default executable path should be correct): AssertLinter 'zls', ale#Escape('zls') Execute(The project root should be detected correctly): AssertLSPProject '' call ale#test#SetFilename('../test-files/zig/main.zig') AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/zig') ================================================ FILE: test/lsp/test_closing_documents.vader ================================================ Before: runtime autoload/ale/lsp.vim let g:message_list = [] function! MarkAllConnectionsInitialized() abort for l:conn in values(ale#lsp#GetConnections()) let l:conn.initialized = 1 endfor endfunction function! MarkDocumentOpened() abort for l:conn in values(ale#lsp#GetConnections()) let l:conn.open_documents[bufnr('')] = 1 endfor endfunction function! ale#lsp#Send(conn_id, message) abort let l:connections = ale#lsp#GetConnections() if !l:connections[a:conn_id].initialized throw 'LSP server not initialized yet!' endif call add(g:message_list, [a:conn_id] + a:message) endfunction call ale#lsp#ResetConnections() After: unlet! g:message_list delfunction MarkAllConnectionsInitialized delfunction MarkDocumentOpened call ale#lsp#ResetConnections() runtime autoload/ale/lsp.vim Execute(No errors should be thrown if the connection is not initialized): call ale#lsp#Register('command', '/foo', '', {}) call MarkDocumentOpened() call ale#engine#Cleanup(bufnr('')) AssertEqual [], g:message_list Execute(No messages should be sent if the document wasn't opened): call ale#lsp#Register('command', '/foo', '', {}) call MarkAllConnectionsInitialized() call ale#engine#Cleanup(bufnr('')) AssertEqual [], g:message_list Execute(A message should be sent if the document was opened): call ale#lsp#Register('command', '/foo', 'lang', {}) call MarkAllConnectionsInitialized() call ale#lsp#OpenDocument('command:/foo', bufnr('')) call ale#engine#Cleanup(bufnr('')) " We should only send the message once. call ale#engine#Cleanup(bufnr('')) AssertEqual \ [ \ ['command:/foo', 1, 'textDocument/didOpen', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ 'languageId': 'lang', \ 'text': "\n", \ }, \ }], \ ['command:/foo', 1, 'textDocument/didClose', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ }, \ }], \ ], \ g:message_list Execute(A message should be sent if the document was opened for tsserver): call ale#lsp#Register('command', '/foo', 'lang', {}) call ale#lsp#MarkConnectionAsTsserver('command:/foo') call ale#lsp#OpenDocument('command:/foo', bufnr('')) call ale#engine#Cleanup(bufnr('')) " We should only send the message once. call ale#engine#Cleanup(bufnr('')) AssertEqual \ [ \ ['command:/foo', 1, 'ts@open', {'file': expand('%:p')}], \ ['command:/foo', 1, 'ts@close', {'file': expand('%:p')}], \ ], \ g:message_list Execute(Re-opening and closing the documents should work): call ale#lsp#Register('command', '/foo', 'lang', {}) call MarkAllConnectionsInitialized() call ale#lsp#OpenDocument('command:/foo', bufnr('')) call ale#engine#Cleanup(bufnr('')) call ale#lsp#OpenDocument('command:/foo', bufnr('')) call ale#engine#Cleanup(bufnr('')) AssertEqual \ [ \ ['command:/foo', 1, 'textDocument/didOpen', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 2, \ 'languageId': 'lang', \ 'text': "\n", \ }, \ }], \ ['command:/foo', 1, 'textDocument/didClose', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ }, \ }], \ ['command:/foo', 1, 'textDocument/didOpen', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ 'languageId': 'lang', \ 'text': "\n", \ }, \ }], \ ['command:/foo', 1, 'textDocument/didClose', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ }, \ }], \ ], \ g:message_list Execute(Messages for closing documents should be sent to each server): call ale#lsp#Register('command', '/foo', 'lang', {}) call ale#lsp#Register('command', '/bar', 'lang', {}) call MarkAllConnectionsInitialized() call ale#lsp#OpenDocument('command:/foo', bufnr('')) call ale#lsp#OpenDocument('command:/bar', bufnr('')) call ale#engine#Cleanup(bufnr('')) " We should only send the message once. call ale#engine#Cleanup(bufnr('')) AssertEqual \ [ \ ['command:/foo', 1, 'textDocument/didOpen', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 2, \ 'languageId': 'lang', \ 'text': "\n", \ }, \ }], \ ['command:/bar', 1, 'textDocument/didOpen', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ 'languageId': 'lang', \ 'text': "\n", \ }, \ }], \ ['command:/bar', 1, 'textDocument/didClose', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ }, \ }], \ ['command:/foo', 1, 'textDocument/didClose', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ }, \ }], \ ], \ g:message_list ================================================ FILE: test/lsp/test_did_save_event.vader ================================================ Before: Save g:ale_lint_on_save Save g:ale_enabled Save g:ale_linters Save g:ale_run_synchronously Save g:ale_disable_lsp call ale#test#SetDirectory('/testplugin/test/completion') call ale#test#SetFilename('dummy.txt') runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim let g:ale_disable_lsp = 0 unlet! b:ale_disable_lsp let g:ale_lint_on_save = 1 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 return 'foobar' endfunction function! ProjectRootCallback() abort return expand('.') endfunction call ale#linter#Define('foobar', { \ 'name': 'dummy_linter', \ 'lsp': 'stdio', \ 'command': 'cat - > /dev/null', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'language': function('LanguageCallback'), \ 'project_root': function('ProjectRootCallback'), \ }) let g:ale_linters = {'foobar': ['dummy_linter']} function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', 'foobar', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} call a:Callback(a:linter, l:details) return 1 endfunction " Replace the Send function for LSP, so we can monitor calls to it. 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 unlet! b:ale_save_event_fired delfunction LanguageCallback delfunction ProjectRootCallback call ale#test#RestoreDirectory() call ale#linter#Reset() " Stop any timers we left behind. " This stops the tests from failing randomly. call ale#completion#StopTimer() runtime autoload/ale/completion.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim Given foobar (Some imaginary filetype): Execute(Server should be notified on save): call ale#events#SaveEvent(bufnr('')) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}], \ }], \ ], \ g:message_list Execute(Server should be notified on save with didSave is supported by server): " Replace has capability function to simulate didSave server capability function! ale#lsp#HasCapability(conn_id, capability) abort if a:capability == 'did_save' return 1 endif return 0 endfunction call ale#events#SaveEvent(bufnr('')) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}], \ }], \ [1, 'textDocument/didSave', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ }, \ }], \ ], \ g:message_list Execute(Server should be notified on change): call ale#events#FileChangedEvent(bufnr('')) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}], \ }], \ ], \ g:message_list ================================================ FILE: test/lsp/test_engine_lsp_response_handling.vader ================================================ Before: Save g:ale_set_lists_synchronously Save g:ale_buffer_info Save g:ale_lsp_error_messages Save g:ale_set_loclist Save g:ale_set_signs Save g:ale_set_quickfix Save g:ale_set_highlights Save g:ale_echo_cursor Save g:ale_disable_lsp Save g:ale_history_enabled Save g:ale_history_log_output let g:ale_disable_lsp = 0 let g:ale_set_lists_synchronously = 1 let g:ale_buffer_info = {} let g:ale_set_loclist = 1 " Disable features we don't need for these tests. let g:ale_set_signs = 0 let g:ale_set_quickfix = 0 let g:ale_set_highlights = 0 let g:ale_echo_cursor = 0 let g:ale_history_enabled = 1 let g:ale_history_log_output = 1 unlet! g:ale_lsp_error_messages unlet! b:ale_linters unlet! b:ale_disable_lsp call ale#linter#Reset() call ale#test#SetDirectory('/testplugin/test') call setloclist(0, []) After: Restore unlet! b:ale_linters call setloclist(0, []) call ale#test#RestoreDirectory() call ale#linter#Reset() call ale#lsp_linter#ClearLSPData() Given foobar(An empty file): Execute(tsserver syntax error responses should be handled correctly): runtime ale_linters/typescript/tsserver.vim if has('win32') call ale#test#SetFilename('filename,[]^$.ts') else call ale#test#SetFilename('filename*?,{}[]^$.ts') endif call ale#engine#InitBufferInfo(bufnr('')) if has('win32') AssertEqual 'filename,[]^$.ts', expand('%:p:t') else AssertEqual 'filename*?,{}[]^$.ts', expand('%:p:t') endif " When we get syntax errors and no semantic errors, we should keep the " syntax errors. call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': expand('%:p'), \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': ''','' expected.', \ "code":1005 \ }, \ ], \ }, \}) call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', \ 'body': { \ 'file': expand('%:p'), \ 'diagnostics':[ \ ], \ }, \}) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 14, \ 'vcol': 0, \ 'nr': 1005, \ 'type': 'E', \ 'text': '1005: '','' expected.', \ 'valid': 1, \ 'pattern': '', \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() " After we get empty syntax errors, we should clear them. call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': expand('%:p'), \ 'diagnostics':[ \ ], \ }, \}) AssertEqual \ [ \ ], \ ale#test#GetLoclistWithoutNewerKeys() " Syntax errors on the project root should not populate the LocList. call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': g:dir, \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': ''','' expected.', \ "code":1005 \ }, \ ], \ }, \}) AssertEqual \ [ \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(tsserver semantic error responses should be handled correctly): runtime ale_linters/typescript/tsserver.vim if has('win32') call ale#test#SetFilename('filename,[]^$.ts') else call ale#test#SetFilename('filename*?,{}[]^$.ts') endif call ale#engine#InitBufferInfo(bufnr('')) if has('win32') AssertEqual 'filename,[]^$.ts', expand('%:p:t') else AssertEqual 'filename*?,{}[]^$.ts', expand('%:p:t') endif " When we get syntax errors and no semantic errors, we should keep the " syntax errors. call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': expand('%:p'), \ 'diagnostics':[ \ ], \ }, \}) call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', \ 'body': { \ 'file': expand('%:p'), \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': 'Some semantic error', \ "code":1005 \ }, \ ], \ }, \}) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 14, \ 'vcol': 0, \ 'nr': 1005, \ 'type': 'E', \ 'text': '1005: Some semantic error', \ 'valid': 1, \ 'pattern': '', \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() " After we get empty syntax errors, we should clear them. call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', \ 'body': { \ 'file': expand('%:p'), \ 'diagnostics':[ \ ], \ }, \}) AssertEqual \ [ \ ], \ ale#test#GetLoclistWithoutNewerKeys() " Semantic errors on the project root should not populate the LocList. call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', \ 'body': { \ 'file': g:dir, \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': 'Some semantic error', \ "code":1005 \ }, \ ], \ }, \}) AssertEqual \ [ \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(tsserver errors should mark tsserver no longer active): let b:ale_linters = ['tsserver'] runtime ale_linters/typescript/tsserver.vim call ale#test#SetFilename('filename.ts') call ale#engine#InitBufferInfo(bufnr('')) let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('typescript') Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list) call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', \ 'body': { \ 'file': g:dir . '/filename.ts', \ 'diagnostics':[], \ }, \}) AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list Execute(LSP diagnostics responses should be handled correctly): let b:ale_linters = ['eclipselsp'] runtime ale_linters/java/eclipselsp.vim if has('win32') call ale#test#SetFilename('filename,[]^$.ts') else call ale#test#SetFilename('filename*?,{}[]^$.java') endif call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}}) if has('win32') AssertEqual 'filename,[]^$.ts', expand('%:p:t') else AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t') endif call ale#lsp_linter#HandleLSPResponse(1, { \ 'jsonrpc':'2.0', \ 'method':'textDocument/publishDiagnostics', \ 'params': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'diagnostics': [ \ { \ 'range': { \ 'start': { \ 'line': 0, \ 'character':0 \ }, \ 'end': { \ 'line': 0, \ 'character':0 \ } \ }, \ 'severity': 2, \ 'code': "", \ 'source': 'Java', \ 'message': 'Missing JRE 1-8' \ } \ ] \ } \}) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'pattern': '', \ 'valid': 1, \ 'vcol': 0, \ 'nr': -1, \ 'type': 'W', \ 'text': 'Missing JRE 1-8' \ } \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(LSP diagnostics responses on project root should not populate loclist): let b:ale_linters = ['eclipselsp'] runtime ale_linters/java/eclipselsp.vim call ale#test#SetFilename('filename.java') call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}}) call ale#lsp_linter#HandleLSPResponse(1, { \ 'jsonrpc':'2.0', \ 'method':'textDocument/publishDiagnostics', \ 'params': { \ 'uri':'file://' . g:dir, \ 'diagnostics': [ \ { \ 'range': { \ 'start': { \ 'line': 0, \ 'character':0 \ }, \ 'end': { \ 'line': 0, \ 'character':0 \ } \ }, \ 'severity': 2, \ 'code': "", \ 'source': 'Java', \ 'message': 'Missing JRE 1-8' \ } \ ] \ } \}) AssertEqual \ [ \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(LSP errors should mark linters no longer active): let b:ale_linters = ['pylsp'] runtime ale_linters/python/pylsp.vim call ale#test#SetFilename('filename.py') call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'pylsp', 'aliases': [], 'lsp': 'stdio'}}) let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('python') Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list) call ale#lsp_linter#HandleLSPResponse(1, { \ 'method': 'textDocument/publishDiagnostics', \ 'params': { \ 'uri': ale#path#ToFileURI(g:dir . '/filename.py'), \ 'diagnostics': [], \ }, \}) AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list Execute(LSP pull model diagnostic responses should be handled): let b:ale_linters = ['eclipselsp'] runtime ale_linters/java/eclipselsp.vim if has('win32') call ale#test#SetFilename('filename,[]^$.ts') else call ale#test#SetFilename('filename*?,{}[]^$.java') endif call ale#engine#InitBufferInfo(bufnr('')) let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('eclipselsp') call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}}) call ale#lsp_linter#SetDiagnosticURIMap({'347': ale#util#ToURI(expand('%:p'))}) if has('win32') AssertEqual 'filename,[]^$.ts', expand('%:p:t') else AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t') endif call ale#lsp_linter#HandleLSPResponse(1, { \ 'jsonrpc':'2.0', \ 'id': 347, \ 'result': { \ 'kind': 'full', \ 'items': [ \ { \ 'range': { \ 'start': { \ 'line': 0, \ 'character':0 \ }, \ 'end': { \ 'line': 0, \ 'character':0 \ } \ }, \ 'severity': 2, \ 'code': "", \ 'source': 'Java', \ 'message': 'Missing JRE 1-8' \ } \ ] \ }, \}) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'pattern': '', \ 'valid': 1, \ 'vcol': 0, \ 'nr': -1, \ 'type': 'W', \ 'text': 'Missing JRE 1-8' \ } \ ], \ ale#test#GetLoclistWithoutNewerKeys() AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list Execute(LSP pull model diagnostic responses that are 'unchanged' should be handled): let b:ale_linters = ['eclipselsp'] runtime ale_linters/java/eclipselsp.vim if has('win32') call ale#test#SetFilename('filename,[]^$.ts') else call ale#test#SetFilename('filename*?,{}[]^$.java') endif call ale#engine#InitBufferInfo(bufnr('')) let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('eclipselsp') let g:ale_buffer_info[bufnr('')].loclist = [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'pattern': '', \ 'valid': 1, \ 'vcol': 0, \ 'nr': -1, \ 'type': 'W', \ 'text': 'Missing JRE 1-8' \ }, \] call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}}) call ale#lsp_linter#SetDiagnosticURIMap({'347': ale#util#ToURI(expand('%:p'))}) if has('win32') AssertEqual 'filename,[]^$.ts', expand('%:p:t') else AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t') endif call ale#lsp_linter#HandleLSPResponse(1, { \ 'jsonrpc':'2.0', \ 'id': 347, \ 'result': { \ 'kind': 'unchanged', \ }, \}) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'pattern': '', \ 'valid': 1, \ 'vcol': 0, \ 'nr': -1, \ 'type': 'W', \ 'text': 'Missing JRE 1-8' \ } \ ], \ g:ale_buffer_info[bufnr('')].loclist AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list Execute(LSP errors should be logged in the history): call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'foobar', 'aliases': [], 'lsp': 'stdio'}}) call ale#lsp_linter#HandleLSPResponse(347, { \ 'jsonrpc': '2.0', \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ 'data': { \ 'traceback': ['123', '456'], \ }, \ }, \}) AssertEqual \ {'foobar': ["xyz\n123\n456"]}, \ get(g:, 'ale_lsp_error_messages', {}) ================================================ FILE: test/lsp/test_handling_window_requests.vader ================================================ Before: let g:expr_list = [] let g:linter_name = 'some_linter' let g:format = '%severity%:%linter%: %s' " Get the default value to restore it let g:default_severity = g:ale_lsp_show_message_severity let g:ale_lsp_show_message_severity = 'information' function! ale#util#ShowMessage(expr) abort call add(g:expr_list, a:expr) endfunction After: unlet! g:expr_list unlet! g:linter_name unlet! g:format let g:ale_lsp_show_message_severity = g:default_severity unlet! g:default_severity Execute(ale#lsp_window#HandleShowMessage() should only show errors when severity is set to "error"): let g:ale_lsp_show_message_severity = 'error' " We should escape the quotes from this message. call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an ''error'''}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual ['Error:some_linter: an ''error'''], g:expr_list Execute(ale#lsp_window#HandleShowMessage() should only show errors and warnings when severity is set to "warning"): let g:ale_lsp_show_message_severity = 'warning' call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an error'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual ['Error:some_linter: an error', 'Warning:some_linter: a warning'], g:expr_list Execute(ale#lsp_window#HandleShowMessage() should only show errors, warnings and infos when severity is set to "information"): let g:ale_lsp_show_message_severity = 'information' call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an error'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual [ \ 'Error:some_linter: an error', \ 'Warning:some_linter: a warning', \ 'Info:some_linter: an info'], \ g:expr_list Execute(ale#lsp_window#HandleShowMessage() should only show errors, warnings and infos when severity is set to "info"): let g:ale_lsp_show_message_severity = 'info' call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an error'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual [ \ 'Error:some_linter: an error', \ 'Warning:some_linter: a warning', \ 'Info:some_linter: an info'], \ g:expr_list Execute(ale#lsp_window#HandleShowMessage() should show all messages is severity is set to "log"): let g:ale_lsp_show_message_severity = 'log' call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an error'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual [ \ 'Error:some_linter: an error', \ 'Warning:some_linter: a warning', \ 'Info:some_linter: an info', \ 'Log:some_linter: a log'], \ g:expr_list Execute(ale#lsp_window#HandleShowMessage() should not show anything if severity is configured as disabled): let g:ale_lsp_show_message_severity = 'disabled' call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an error'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual [], g:expr_list Execute(ale#lsp_window#HandleShowMessage() should use "warning" when severity is set to an invalid value): let g:ale_lsp_show_message_severity = 'foo' call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':1,'message':'an error'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':2,'message':'a warning'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':3,'message':'an info'}) call ale#lsp_window#HandleShowMessage(g:linter_name, g:format, {'type':4,'message':'a log'}) AssertEqual [ \ 'Error:some_linter: an error', \ 'Warning:some_linter: a warning'], \ g:expr_list ================================================ FILE: test/lsp/test_lsp_address_split.vader ================================================ Execute(Address splitting should function as intended): AssertEqual ['foo', v:null], ale#lsp#SplitAddress('foo') AssertEqual ['foo:', v:null], ale#lsp#SplitAddress('foo:') AssertEqual ['foo', v:null], ale#lsp#SplitAddress('foo:0') AssertEqual ['foo', 123], ale#lsp#SplitAddress('foo:123') AssertEqual ['protocol:/foo:', v:null], ale#lsp#SplitAddress('protocol:/foo:') AssertEqual ['protocol:/foo', v:null], ale#lsp#SplitAddress('protocol:/foo:0') AssertEqual ['protocol:/foo', 123], ale#lsp#SplitAddress('protocol:/foo:123') AssertEqual ['protocol:foo', v:null], ale#lsp#SplitAddress('protocol:foo') ================================================ FILE: test/lsp/test_lsp_client_messages.vader ================================================ Before: let g:ale_lsp_next_version_id = 1 call ale#test#SetDirectory('/testplugin/test/lsp') call ale#test#SetFilename('foo/bar.ts') After: call ale#test#RestoreDirectory() Execute(ale#lsp#message#Initialize() should return correct messages): AssertEqual \ [ \ 0, \ 'initialize', \ { \ 'processId': getpid(), \ 'rootPath': '/foo/bar', \ 'capabilities': {}, \ 'initializationOptions': {'foo': 'bar'}, \ 'rootUri': 'file:///foo/bar', \ } \ ], \ ale#lsp#message#Initialize('/foo/bar', {'foo': 'bar'}, {}) Execute(ale#lsp#message#Initialized() should return correct messages): AssertEqual [1, 'initialized', {}], ale#lsp#message#Initialized() Execute(ale#lsp#message#Shutdown() should return correct messages): AssertEqual [0, 'shutdown'], ale#lsp#message#Shutdown() Execute(ale#lsp#message#Exit() should return correct messages): AssertEqual [1, 'exit'], ale#lsp#message#Exit(), Given typescript(A TypeScript file with 3 lines): Foo() Bar() Baz() Execute(ale#util#GetBufferContents() should return correctly formatted newlines): AssertEqual "Foo()\nBar()\nBaz()\n", ale#util#GetBufferContents(bufnr('')) Execute(ale#lsp#message#DidOpen() should return correct messages): let g:ale_lsp_next_version_id = 12 AssertEqual \ [ \ 1, \ 'textDocument/didOpen', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ 'languageId': 'typescript', \ 'version': 12, \ 'text': "Foo()\nBar()\nBaz()\n", \ }, \ } \ ], \ ale#lsp#message#DidOpen(bufnr(''), 'typescript') Execute(ale#lsp#message#DidChange() should return correct messages): let g:ale_lsp_next_version_id = 34 AssertEqual \ [ \ 1, \ 'textDocument/didChange', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ 'version': 34, \ }, \ 'contentChanges': [{'text': "Foo()\nBar()\nBaz()\n"}], \ } \ ], \ ale#lsp#message#DidChange(bufnr('')) " The version numbers should increment. AssertEqual \ 35, \ ale#lsp#message#DidChange(bufnr(''))[2].textDocument.version AssertEqual \ 36, \ ale#lsp#message#DidChange(bufnr(''))[2].textDocument.version Execute(ale#lsp#message#DidSave() should return correct messages): AssertEqual \ [ \ 1, \ 'textDocument/didSave', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ } \ ], \ ale#lsp#message#DidSave(bufnr(''), v:false) Execute(ale#lsp#message#DidSave() should return correct message with includeText capability): AssertEqual \ [ \ 1, \ 'textDocument/didSave', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ 'version': 1, \ }, \ 'text': ale#util#GetBufferContents(bufnr('')), \ } \ ], \ ale#lsp#message#DidSave(bufnr(''), v:true) Execute(ale#lsp#message#DidClose() should return correct messages): AssertEqual \ [ \ 1, \ 'textDocument/didClose', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ } \ ], \ ale#lsp#message#DidClose(bufnr('')) Execute(ale#lsp#message#Completion() should return correct messages): AssertEqual \ [ \ 0, \ 'textDocument/completion', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ } \ ], \ ale#lsp#message#Completion(bufnr(''), 12, 34, '') Execute(ale#lsp#message#Completion() should return correct messages with a trigger charaacter): AssertEqual \ [ \ 0, \ 'textDocument/completion', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ 'context': {'triggerKind': 2, 'triggerCharacter': '.'}, \ } \ ], \ ale#lsp#message#Completion(bufnr(''), 12, 34, '.') \ Execute(ale#lsp#message#Definition() should return correct messages): AssertEqual \ [ \ 0, \ 'textDocument/definition', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ } \ ], \ ale#lsp#message#Definition(bufnr(''), 12, 34) Execute(ale#lsp#message#TypeDefinition() should return correct messages): AssertEqual \ [ \ 0, \ 'textDocument/typeDefinition', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ } \ ], \ ale#lsp#message#TypeDefinition(bufnr(''), 12, 34) Execute(ale#lsp#message#Implementation() should return correct messages): AssertEqual \ [ \ 0, \ 'textDocument/implementation', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ } \ ], \ ale#lsp#message#Implementation(bufnr(''), 12, 34) Execute(ale#lsp#message#References() should return correct messages): AssertEqual \ [ \ 0, \ 'textDocument/references', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ 'context': {'includeDeclaration': v:false}, \ } \ ], \ 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 \ [ \ 0, \ 'textDocument/hover', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ 'position': {'line': 11, 'character': 33}, \ } \ ], \ ale#lsp#message#Hover(bufnr(''), 12, 34) Execute(ale#lsp#message#DidChangeConfiguration() should return correct messages): let g:ale_lsp_configuration = { \ 'foo': 'bar' \ } AssertEqual \ [ \ 1, \ 'workspace/didChangeConfiguration', \ { \ 'settings': { \ 'foo': 'bar', \ } \ } \ ], \ ale#lsp#message#DidChangeConfiguration(bufnr(''), g:ale_lsp_configuration) Execute(ale#lsp#message#Diagnostic() should return correct messages): AssertEqual \ [ \ 0, \ 'textDocument/diagnostic', \ { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(g:dir . '/foo/bar.ts'), \ }, \ } \ ], \ ale#lsp#message#Diagnostic(bufnr('')) Execute(ale#lsp#tsserver_message#Open() should return correct messages): AssertEqual \ [ \ 1, \ 'ts@open', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ } \ ], \ ale#lsp#tsserver_message#Open(bufnr('')) Execute(ale#lsp#tsserver_message#Close() should return correct messages): AssertEqual \ [ \ 1, \ 'ts@close', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ } \ ], \ ale#lsp#tsserver_message#Close(bufnr('')) Execute(ale#lsp#tsserver_message#Change() should return correct messages): AssertEqual \ [ \ 1, \ 'ts@change', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 1, \ 'offset': 1, \ 'endLine': 1073741824, \ 'endOffset': 1, \ 'insertString': "Foo()\nBar()\nBaz()\n", \ } \ ], \ ale#lsp#tsserver_message#Change(bufnr('')) Execute(ale#lsp#tsserver_message#Geterr() should return correct messages): AssertEqual \ [ \ 1, \ 'ts@geterr', \ { \ 'files': [ale#path#Simplify(g:dir . '/foo/bar.ts')], \ } \ ], \ ale#lsp#tsserver_message#Geterr(bufnr('')) Execute(ale#lsp#tsserver_message#Completions() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@completions', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ 'prefix': 'abc', \ 'includeExternalModuleExports': 1, \ } \ ], \ ale#lsp#tsserver_message#Completions(bufnr(''), 347, 12, 'abc', 1) Execute(ale#lsp#tsserver_message#CompletionEntryDetails() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@completionEntryDetails', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ 'entryNames': ['foo', 'bar'], \ } \ ], \ ale#lsp#tsserver_message#CompletionEntryDetails(bufnr(''), 347, 12, ['foo', 'bar']) Execute(ale#lsp#tsserver_message#Definition() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@definition', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ } \ ], \ ale#lsp#tsserver_message#Definition(bufnr(''), 347, 12) Execute(ale#lsp#tsserver_message#TypeDefinition() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@typeDefinition', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ } \ ], \ ale#lsp#tsserver_message#TypeDefinition(bufnr(''), 347, 12) Execute(ale#lsp#tsserver_message#Implementation() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@implementation', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ } \ ], \ ale#lsp#tsserver_message#Implementation(bufnr(''), 347, 12) Execute(ale#lsp#tsserver_message#References() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@references', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ } \ ], \ ale#lsp#tsserver_message#References(bufnr(''), 347, 12) Execute(ale#lsp#tsserver_message#Quickinfo() should return correct messages): AssertEqual \ [ \ 0, \ 'ts@quickinfo', \ { \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), \ 'line': 347, \ 'offset': 12, \ } \ ], \ ale#lsp#tsserver_message#Quickinfo(bufnr(''), 347, 12) ================================================ FILE: test/lsp/test_lsp_command_formatting.vader ================================================ Before: Save g:ale_command_wrapper runtime autoload/ale/lsp.vim let g:ale_command_wrapper = '' let g:args = [] " Mock the StartProgram function so we can just capture the arguments. function! ale#lsp#StartProgram(...) abort let g:args = a:000[1:] endfunction After: Restore unlet! g:args runtime autoload/ale/lsp.vim Execute(Command formatting should be applied correctly for LSP linters): call ale#lsp_linter#StartLSP( \ bufnr(''), \ { \ 'name': 'linter', \ 'language': {-> 'x'}, \ 'project_root': {-> '/foo/bar'}, \ 'lsp': 'stdio', \ 'executable': has('win32') ? 'cmd': 'true', \ 'command': '%e --foo', \ }, \ {-> 0} \) if has('win32') AssertEqual \ ['cmd', 'cmd /s/c "cmd --foo"'], \ g:args else AssertEqual \ ['true', [&shell, '-c', '''true'' --foo']], \ g:args endif ================================================ FILE: test/lsp/test_lsp_connections.vader ================================================ Before: let g:ale_lsp_next_message_id = 1 After: if exists('b:conn') && has_key(b:conn, 'id') call ale#lsp#RemoveConnectionWithID(b:conn.id) endif unlet! b:data unlet! b:conn Execute(GetNextMessageID() should increment appropriately): " We should get the initial ID, and increment a bit. AssertEqual 1, ale#lsp#GetNextMessageID() AssertEqual 2, ale#lsp#GetNextMessageID() AssertEqual 3, ale#lsp#GetNextMessageID() " Set the maximum ID. let g:ale_lsp_next_message_id = 9223372036854775807 " When we hit the maximum ID, the next ID afterwards should be 1. AssertEqual 9223372036854775807, ale#lsp#GetNextMessageID() AssertEqual 1, ale#lsp#GetNextMessageID() Execute(ale#lsp#CreateMessageData() should create an appropriate message): " NeoVim outputs JSON with spaces, so the output is a little different. if has('nvim') " 79 is the size in bytes for UTF-8, not the number of characters. AssertEqual \ [ \ 1, \ "Content-Length: 79\r\n\r\n" \ . '{"method": "someMethod", "jsonrpc": "2.0", "id": 1, "params": {"foo": "barÜ"}}', \ ], \ ale#lsp#CreateMessageData([0, 'someMethod', {'foo': 'barÜ'}]) " Check again to ensure that we use the next ID. AssertEqual \ [ \ 2, \ "Content-Length: 79\r\n\r\n" \ . '{"method": "someMethod", "jsonrpc": "2.0", "id": 2, "params": {"foo": "barÜ"}}', \ ], \ ale#lsp#CreateMessageData([0, 'someMethod', {'foo': 'barÜ'}]) else AssertEqual \ [ \ 1, \ "Content-Length: 71\r\n\r\n" \ . '{"method":"someMethod","jsonrpc":"2.0","id":1,"params":{"foo":"barÜ"}}', \ ], \ ale#lsp#CreateMessageData([0, 'someMethod', {'foo': 'barÜ'}]) AssertEqual \ [ \ 2, \ "Content-Length: 71\r\n\r\n" \ . '{"method":"someMethod","jsonrpc":"2.0","id":2,"params":{"foo":"barÜ"}}', \ ], \ ale#lsp#CreateMessageData([0, 'someMethod', {'foo': 'barÜ'}]) endif Execute(ale#lsp#CreateMessageData() should create messages without params): if has('nvim') AssertEqual \ [ \ 1, \ "Content-Length: 56\r\n\r\n" \ . '{"method": "someOtherMethod", "jsonrpc": "2.0", "id": 1}', \ ], \ ale#lsp#CreateMessageData([0, 'someOtherMethod']) else AssertEqual \ [ \ 1, \ "Content-Length: 51\r\n\r\n" \ . '{"method":"someOtherMethod","jsonrpc":"2.0","id":1}', \ ], \ ale#lsp#CreateMessageData([0, 'someOtherMethod']) endif Execute(ale#lsp#CreateMessageData() should create notifications): if has('nvim') AssertEqual \ [ \ 0, \ "Content-Length: 48\r\n\r\n" \ . '{"method": "someNotification", "jsonrpc": "2.0"}', \ ], \ ale#lsp#CreateMessageData([1, 'someNotification']) AssertEqual \ [ \ 0, \ "Content-Length: 74\r\n\r\n" \ . '{"method": "someNotification", "jsonrpc": "2.0", "params": {"foo": "bar"}}', \ ], \ ale#lsp#CreateMessageData([1, 'someNotification', {'foo': 'bar'}]) else AssertEqual \ [ \ 0, \ "Content-Length: 45\r\n\r\n" \ . '{"method":"someNotification","jsonrpc":"2.0"}', \ ], \ ale#lsp#CreateMessageData([1, 'someNotification']) AssertEqual \ [ \ 0, \ "Content-Length: 68\r\n\r\n" \ . '{"method":"someNotification","jsonrpc":"2.0","params":{"foo":"bar"}}', \ ], \ ale#lsp#CreateMessageData([1, 'someNotification', {'foo': 'bar'}]) endif Execute(ale#lsp#CreateMessageData() should create tsserver notification messages): if has('nvim') AssertEqual \ [ \ 0, \ '{"seq": null, "type": "request", "command": "someNotification"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([1, 'ts@someNotification']) AssertEqual \ [ \ 0, \ '{"seq": null, "arguments": {"foo": "bar"}, "type": "request", "command": "someNotification"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([1, 'ts@someNotification', {'foo': 'bar'}]) else AssertEqual \ [ \ 0, \ '{"seq":null,"type":"request","command":"someNotification"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([1, 'ts@someNotification']) AssertEqual \ [ \ 0, \ '{"seq":null,"arguments":{"foo":"bar"},"type":"request","command":"someNotification"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([1, 'ts@someNotification', {'foo': 'bar'}]) endif Execute(ale#lsp#CreateMessageData() should create tsserver messages expecting responses): if has('nvim') AssertEqual \ [ \ 1, \ '{"seq": 1, "type": "request", "command": "someMessage"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([0, 'ts@someMessage']) AssertEqual \ [ \ 2, \ '{"seq": 2, "arguments": {"foo": "bar"}, "type": "request", "command": "someMessage"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([0, 'ts@someMessage', {'foo': 'bar'}]) else AssertEqual \ [ \ 1, \ '{"seq":1,"type":"request","command":"someMessage"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([0, 'ts@someMessage']) AssertEqual \ [ \ 2, \ '{"seq":2,"arguments":{"foo":"bar"},"type":"request","command":"someMessage"}' \ . "\n", \ ], \ ale#lsp#CreateMessageData([0, 'ts@someMessage', {'foo': 'bar'}]) endif Execute(ale#lsp#ReadMessageData() should read single whole messages): AssertEqual \ ['', [{'id': 2, 'jsonrpc': '2.0', 'result': {'foo': 'barÜ'}}]], \ ale#lsp#ReadMessageData( \ "Content-Length: 49\r\n\r\n" \ . '{"id":2,"jsonrpc":"2.0","result":{"foo":"barÜ"}}' \ ) Execute(ale#lsp#ReadMessageData() should ignore other headers): AssertEqual \ ['', [{'id': 2, 'jsonrpc': '2.0', 'result': {'foo': 'barÜ'}}]], \ ale#lsp#ReadMessageData( \ "First-Header: 49\r\n" \ . "Content-Length: 49\r\n" \ . "Other-Header: 49\r\n" \ . "\r\n" \ . '{"id":2,"jsonrpc":"2.0","result":{"foo":"barÜ"}}' \ ) Execute(ale#lsp#ReadMessageData() should handle partial messages): let b:data = "Content-Length: 49\r\n\r\n" . '{"id":2,"jsonrpc":"2.0","result":' AssertEqual [b:data, []], ale#lsp#ReadMessageData(b:data) Execute(ale#lsp#ReadMessageData() should handle multiple messages): AssertEqual \ ['', [ \ {'id': 2, 'jsonrpc': '2.0', 'result': {'foo': 'barÜ'}}, \ {'id': 2, 'jsonrpc': '2.0', 'result': {'foo123': 'barÜ'}}, \ ]], \ ale#lsp#ReadMessageData( \ "Content-Length: 49\r\n\r\n" \ . '{"id":2,"jsonrpc":"2.0","result":{"foo":"barÜ"}}' \ . "Content-Length: 52\r\n\r\n" \ . '{"id":2,"jsonrpc":"2.0","result":{"foo123":"barÜ"}}' \ ) Execute(ale#lsp#ReadMessageData() should handle a message with part of a second message): let b:data = "Content-Length: 52\r\n\r\n" . '{"id":2,"jsonrpc":"2.' AssertEqual \ [b:data, [ \ {'id': 2, 'jsonrpc': '2.0', 'result': {'foo': 'barÜ'}}, \ ]], \ ale#lsp#ReadMessageData( \ "Content-Length: 49\r\n\r\n" \ . '{"id":2,"jsonrpc":"2.0","result":{"foo":"barÜ"}}' \ . b:data \ ) ================================================ FILE: test/lsp/test_lsp_custom_request.vader ================================================ Before: runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim let g:address = 'ccls_address' let g:conn_id = -1 let g:executable = 'ccls' let g:executable_or_address = '' let g:linter_name = 'ccls' let g:magic_number = 42 let g:no_result = 0 let g:message_list = [] let g:message_id = 1 let g:method = '$ccls/call' let g:parameters = {} let g:project_root = '/project/root' let g:response = '' let g:return_value = -1 let g:linter_list = [{ \ 'output_stream': 'stdout', \ 'lint_file': 0, \ 'language': 'cpp', \ 'name': g:linter_name, \ 'project_root': {b -> g:project_root}, \ 'aliases': [], \ 'read_buffer': 1, \ 'command': '%e' \ }] let g:callback_result = g:no_result " Encode dictionary to jsonrpc function! Encode(obj) abort let l:body = json_encode(a:obj) return 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body endfunction " Replace the StartLSP function to mock an LSP linter function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register(g:executable_or_address, g:project_root, '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) call ale#lsp#HandleMessage(g:conn_id, Encode({'method': 'initialize'})) let l:details = { \ 'command': g:executable, \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': g:project_root, \} call ale#lsp_linter#OnInit(a:linter, l:details, a:Callback) endfunction " Dummy callback function! Callback(response) abort let g:callback_result = a:response.result.value endfunction " Replace the GetAll function to mock an LSP linter function! ale#linter#GetAll(filetype) abort return g:linter_list endfunction " Replace the Send function to mock an LSP linter function! ale#lsp#Send(conn_id, message) abort call add(g:message_list, a:message) return g:message_id endfunction " Code for a test case function! TestCase(is_notification) abort " Test sending a custom request let g:return_value = ale#lsp_linter#SendRequest( \ bufnr('%'), \ g:linter_name, \ [a:is_notification, g:method, g:parameters], \ function('Callback')) Assert index(g:message_list, [a:is_notification, g:method, g:parameters]) >= 0 " Mock an incoming response to the request let g:response = Encode({ \ 'id': g:message_id, \ 'jsonrpc': '2.0', \ 'result': {'value': g:magic_number} \ }) call ale#lsp#HandleMessage(g:conn_id, g:response) AssertEqual \ a:is_notification ? g:no_result : g:magic_number, \ g:callback_result endfunction After: if g:conn_id isnot v:null call ale#lsp#RemoveConnectionWithID(g:conn_id) endif unlet! g:callback_result unlet! g:conn_id unlet! g:executable unlet! g:is_notification unlet! g:linter_name unlet! g:magic_number unlet! g:message_list unlet! g:message_id unlet! g:method unlet! g:no_result unlet! g:parameters unlet! g:project_root unlet! g:response unlet! g:return_value delfunction Encode delfunction Callback delfunction TestCase runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim Given cpp(Empty cpp file): Execute(Test custom request to server identified by executable): let g:executable_or_address = g:executable let g:linter_list[0].executable = {b -> g:executable} let g:linter_list[0].lsp = 'stdio' let g:is_notification = 0 call TestCase(g:is_notification) Given cpp(Empty cpp file): Execute(Test custom notification to server identified by executable): let g:executable_or_address = g:executable let g:linter_list[0].executable = {b -> g:executable} let g:linter_list[0].lsp = 'stdio' let g:is_notification = 1 call TestCase(g:is_notification) Given cpp(Empty cpp file): Execute(Test custom request to server identified by address): let g:executable_or_address = g:address let g:linter_list[0].address = {b -> g:address} let g:linter_list[0].lsp = 'socket' let g:is_notification = 0 call TestCase(g:is_notification) Given cpp(Empty cpp file): Execute(Test custom notification to server identified by address): let g:executable_or_address = g:address let g:linter_list[0].address = {b -> g:address} let g:linter_list[0].lsp = 'socket' let g:is_notification = 1 call TestCase(g:is_notification) ================================================ FILE: test/lsp/test_lsp_error_parsing.vader ================================================ Execute(Invalid responses should be handled): AssertEqual '', ale#lsp#response#GetErrorMessage({}) AssertEqual '', ale#lsp#response#GetErrorMessage({'error': 0}) AssertEqual '', ale#lsp#response#GetErrorMessage({'error': {}}) AssertEqual '', ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': 0, \ 'message': 'x', \ }, \}) AssertEqual '', ale#lsp#response#GetErrorMessage({'error': {'code': -32602}}) AssertEqual '', ale#lsp#response#GetErrorMessage({'error': {'code': -32603}}) Execute(Messages without tracebacks should be handled): AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ }, \}) AssertEqual 'abc', ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32603, \ 'message': 'abc', \ }, \}) Execute(Invalid traceback data should be tolerated): AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ 'data': { \ }, \ }, \}) AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ 'data': { \ 'traceback': 0, \ }, \ }, \}) AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ 'data': { \ 'traceback': [], \ }, \ }, \}) Execute(Messages with tracebacks should be handled): AssertEqual "xyz\n123\n456", ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ 'data': { \ 'traceback': ['123', '456'], \ }, \ }, \}) Execute(Messages with string data should be handled): AssertEqual "xyz\nUncaught Exception", ale#lsp#response#GetErrorMessage({ \ 'error': { \ 'code': -32602, \ 'message': 'xyz', \ 'data': 'Uncaught Exception', \ }, \}) ================================================ FILE: test/lsp/test_lsp_root_detection.vader ================================================ Before: Save g:ale_root Save b:ale_root let g:ale_root = {} call ale#assert#SetUpLinterTest('c', 'clangd') function! Hook1(buffer) return 'abc123' endfunction After: Restore delfunction Hook1 call ale#assert#TearDownLinterTest() Execute(The buffer-specific variable can be a string): let b:ale_root = '/some/path' call ale#test#SetFilename('other-file.c') AssertLSPProject '/some/path' Execute(The buffer-specific variable can be a dictionary): let b:ale_root = {'clangd': '/some/path', 'golangserver': '/other/path'} call ale#test#SetFilename('other-file.c') AssertLSPProject '/some/path' Execute(The buffer-specific variable can have funcrefs): let b:ale_root = {'clangd': function('Hook1'), 'golangserver': '/path'} call ale#test#SetFilename('other-file.c') AssertLSPProject 'abc123' Execute(The global variable can be a dictionary): let g:ale_root = {'clangd': '/some/path', 'golangserver': '/other/path'} call ale#test#SetFilename('other-file.c') AssertLSPProject '/some/path' Execute(The global variable can have funcrefs): let g:ale_root = {'clangd': function('Hook1'), 'golangserver': '/path'} call ale#test#SetFilename('other-file.c') AssertLSPProject 'abc123' Execute(The buffer-specific variable overrides the global variable): let b:ale_root = {'clangd': '/some/path', 'golangserver': '/other/path'} let g:ale_root = {'clangd': '/not/this/path', 'golangserver': '/elsewhere'} call ale#test#SetFilename('other-file.c') AssertLSPProject '/some/path' Execute(The global variable is queried if the buffer-specific has no value): let b:ale_root = {'golangserver': '/other/path'} let g:ale_root = {'clangd': '/some/path', 'golangserver': '/elsewhere'} call ale#test#SetFilename('other-file.c') AssertLSPProject '/some/path' Execute(No path should be returned by default): call ale#test#SetFilename(tempname() . '/other-file.c') AssertLSPProject '' ================================================ FILE: test/lsp/test_lsp_startup.vader ================================================ Before: Save g:ale_run_synchronously let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks unlet! g:ale_run_synchronously_emulate_commands runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim runtime autoload/ale/engine.vim runtime autoload/ale/job.vim runtime autoload/ale/socket.vim let g:job_map = {} let g:emulate_job_failure = 0 let g:next_job_id = 1 let g:lsp_started = 0 let g:socket_map = {} let g:emulate_socket_failure = 0 let g:next_channel_id = 0 let g:message_buffer = '' let g:calls = [] function! ale#engine#IsExecutable(buffer, executable) abort return !empty(a:executable) endfunction function! ale#job#HasOpenChannel(job_id) abort return has_key(g:job_map, a:job_id) endfunction function! ale#job#Stop(job_id) abort if has_key(g:job_map, a:job_id) call remove(g:job_map, a:job_id) endif endfunction function! ale#job#Start(command, options) abort if g:emulate_job_failure return 0 endif let l:job_id = g:next_job_id let g:next_job_id += 1 let g:job_map[l:job_id] = [a:command, a:options] return l:job_id endfunction function! ale#job#SendRaw(job_id, data) abort let g:message_buffer .= a:data endfunction function! ale#socket#IsOpen(channel_id) abort return has_key(g:socket_map, a:channel_id) endfunction function! ale#socket#Close(channel_id) abort if has_key(g:socket_map, a:channel_id) call remove(g:socket_map, a:channel_id) endif endfunction function! ale#socket#Open(address, options) abort if g:emulate_socket_failure return -1 endif let l:channel_id = g:next_channel_id let g:next_channel_id += 1 let g:socket_map[l:channel_id] = [a:address, a:options] return l:channel_id endfunction function! ale#socket#Send(channel_id, data) abort let g:message_buffer .= a:data endfunction function! PopMessages() abort let l:message_list = [] for l:line in split(g:message_buffer, '\(\r\|\n\|Content-Length\)\+') if l:line[:0] is '{' let l:data = json_decode(l:line) call add(l:message_list, l:data) endif endfor let g:message_buffer = '' return l:message_list endfunction function! SendMessage(message) abort let l:conn_id = keys(ale#lsp#GetConnections())[0] let l:body = json_encode(a:message) let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body call ale#lsp#HandleMessage(l:conn_id, l:data) endfunction function! Start(buffer) abort let l:linter = values(ale#linter#GetLintersLoaded())[0][0] return ale#lsp_linter#StartLSP( \ a:buffer, \ l:linter, \ {linter, details -> add(g:calls, [linter.name, details])}, \) endfunction function! AssertInitSuccess(linter_name, conn_prefix, language, root, command, buffer) abort let l:messages = PopMessages() if a:linter_name is# 'tsserver' AssertEqual \ [ \ { \ 'seq': v:null, \ 'arguments': { \ 'file': expand('#' . a:buffer . ':p'), \ }, \ 'type': 'request', \ 'command': 'open', \ }, \ ], \ l:messages else AssertEqual \ [ \ { \ 'method': 'initialize', \ 'jsonrpc': '2.0', \ 'id': 1, \ 'params': { \ 'initializationOptions': {}, \ 'rootUri': ale#path#ToFileURI(a:root), \ 'rootPath': a:root, \ 'processId': getpid(), \ 'capabilities': { \ 'workspace': { \ 'applyEdit': v:false, \ 'didChangeConfiguration': { \ 'dynamicRegistration': v:false, \ }, \ 'symbol': { \ 'dynamicRegistration': v:false, \ }, \ 'workspaceFolders': v:false, \ 'configuration': v:false, \ }, \ 'textDocument': { \ 'synchronization': { \ 'dynamicRegistration': v:false, \ 'willSave': v:false, \ 'willSaveWaitUntil': v:false, \ 'didSave': v:true, \ }, \ 'completion': { \ 'dynamicRegistration': v:false, \ 'completionItem': { \ 'snippetSupport': v:false, \ 'commitCharactersSupport': v:false, \ 'documentationFormat': ['plaintext', 'markdown'], \ 'deprecatedSupport': v:false, \ 'preselectSupport': v:false, \ }, \ 'contextSupport': v:false, \ }, \ 'hover': { \ 'dynamicRegistration': v:false, \ 'contentFormat': ['plaintext', 'markdown'], \ }, \ 'references': { \ 'dynamicRegistration': v:false, \ }, \ 'documentSymbol': { \ 'dynamicRegistration': v:false, \ 'hierarchicalDocumentSymbolSupport': v:false, \ }, \ 'definition': { \ 'dynamicRegistration': v:false, \ 'linkSupport': v:false, \ }, \ 'typeDefinition': { \ 'dynamicRegistration': v:false, \ }, \ 'implementation': { \ 'dynamicRegistration': v:false, \ 'linkSupport': v:false, \ }, \ 'diagnostic': { \ 'dynamicRegistration': v:true, \ 'relatedDocumentSupport': v:true, \ }, \ 'publishDiagnostics': { \ 'relatedInformation': v:true, \ }, \ 'codeAction': { \ 'dynamicRegistration': v:false, \ 'codeActionLiteralSupport': { \ 'codeActionKind': { \ 'valueSet': [] \ } \ } \ }, \ 'rename': { \ 'dynamicRegistration': v:false, \ }, \ }, \ }, \ }, \ }, \ ], \ l:messages call SendMessage({ \ 'jsonrpc': '2.0', \ 'id': 1, \ 'result': { \ 'capabilities': { \ 'renameProvider': v:true, \ 'executeCommandProvider': { \ 'commands': [], \ }, \ 'hoverProvider': v:true, \ 'documentSymbolProvider': v:true, \ 'documentRangeFormattingProvider': v:true, \ 'codeLensProvider': { \ 'resolveProvider': v:false \ }, \ 'referencesProvider': v:true, \ 'textDocumentSync': 2, \ 'documentFormattingProvider': v:true, \ 'codeActionProvider': v:true, \ 'signatureHelpProvider': { \ 'triggerCharacters': ['(', ','], \ }, \ 'completionProvider': { \ 'triggerCharacters': ['.'], \ 'resolveProvider': v:false \ }, \ 'definitionProvider': v:true, \ 'experimental': {}, \ 'documentHighlightProvider': v:true, \ 'workspaceSymbolProvider': v:true, \ }, \ }, \}) let l:messages = PopMessages() AssertEqual \ [ \ { \ 'method': 'initialized', \ 'jsonrpc': '2.0', \ 'params': {}, \ }, \ { \ 'method': 'textDocument/didOpen', \ 'jsonrpc': '2.0', \ 'params': { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('#' . a:buffer . ':p')), \ 'version': ale#lsp#message#GetNextVersionID() - 1, \ 'languageId': a:language, \ 'text': "\n", \ }, \ }, \ }, \ ], \ l:messages endif AssertEqual \ [ \ [ \ a:linter_name, \ { \ 'connection_id': a:conn_prefix . ':' . a:root, \ 'project_root': a:root, \ 'buffer': a:buffer, \ 'command': !empty(a:command) ? ale#job#PrepareCommand(a:buffer, a:command) : '', \ }, \ ], \ ], \ g:calls endfunction function! AssertInitFailure() abort let l:messages = PopMessages() AssertEqual [], l:messages AssertEqual [], g:calls endfunction call ale#linter#Reset() After: Restore call ale#linter#Reset() call ale#lsp#ResetConnections() unlet! g:ale_run_synchronously_callbacks unlet! g:job_map unlet! g:emulate_job_failure unlet! g:next_job_id unlet! g:lsp_started unlet! g:socket_map unlet! g:emulate_socket_failure unlet! g:next_channel_id unlet! g:message_buffer unlet! g:calls augroup VaderTest autocmd! augroup END augroup! VaderTest delfunction PopMessages delfunction Start delfunction AssertInitSuccess delfunction AssertInitFailure runtime autoload/ale/engine.vim runtime autoload/ale/job.vim runtime autoload/ale/socket.vim Execute(tsserver should be started correctly): runtime ale_linters/typescript/tsserver.vim Assert Start(bufnr('')) call AssertInitSuccess('tsserver', 'tsserver', '', '', ale#Escape('tsserver'), bufnr('')) Execute(tsserver failures should be handled appropriately): runtime ale_linters/typescript/tsserver.vim let g:emulate_job_failure = 1 Assert !Start(bufnr('')) call AssertInitFailure() Execute(LSP jobs should start correctly): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'stdio', \ 'executable': 'foo', \ 'command': 'foo', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) Assert Start(bufnr('')) call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', 'foo', bufnr('')) Execute(LSP job failures should be handled): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'stdio', \ 'executable': 'foo', \ 'command': 'foo', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) let g:emulate_job_failure = 1 Assert !Start(bufnr('')) call AssertInitFailure() Execute(LSP TCP connections should start correctly): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'foo', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) Assert Start(bufnr('')) call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', '', bufnr('')) Execute(LSP TCP connection failures should be handled): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'foo', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) let g:emulate_socket_failure = 1 Assert !Start(bufnr('')) call AssertInitFailure() Execute(Deferred executables should be handled correctly): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'stdio', \ 'executable': {b -> ale#command#Run(b, 'echo', {-> 'foo'})}, \ 'command': '%e -c', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) Assert Start(bufnr('')) call ale#test#FlushJobs() call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', ale#Escape('foo') . ' -c', bufnr('')) Execute(Deferred commands should be handled correctly): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'stdio', \ 'executable': 'foo', \ 'command': {b -> ale#command#Run(b, 'echo', {-> '%e -c'})}, \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) Assert Start(bufnr('')) call ale#test#FlushJobs() call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', ale#Escape('foo') . ' -c', bufnr('')) Execute(Deferred addresses should be handled correctly): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': {b -> ale#command#Run(b, 'echo', {-> 'localhost:1234'})}, \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) Assert Start(bufnr('')) call ale#test#FlushJobs() call AssertInitSuccess('foo', 'localhost:1234', 'foobar', '/foo/bar', '', bufnr('')) Execute(Servers that have crashed should be restarted): call ale#lsp#Register('foo', '/foo/bar', '', {}) call extend(ale#lsp#GetConnections()['foo:/foo/bar'], {'initialized': 1}) " Starting the program again should reset initialized to `0`. call ale#lsp#StartProgram('foo:/foo/bar', 'foobar', 'foobar --start') AssertEqual 0, ale#lsp#GetConnections()['foo:/foo/bar']['initialized'] AssertEqual ['initialize'], map(PopMessages(), 'v:val[''method'']') Execute(Current LSP buffer should receive ALELSPStarted): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'foo', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) augroup VaderTest autocmd! autocmd User ALELSPStarted let g:lsp_started = 1 augroup END Assert Start(bufnr('')) call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', '', bufnr('')) AssertEqual g:lsp_started, 1 Execute(Target LSP buffer should receive ALELSPStarted): call ale#linter#Define('foobar', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'foo', \ 'project_root': '/foo/bar', \ 'initialization_options': {}, \}) augroup VaderTest autocmd! autocmd User ALELSPStarted let g:lsp_started = 1 augroup END let buffer = bufnr('') enew! Assert Start(buffer) call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', '', buffer) execute 'buffer' . buffer AssertEqual g:lsp_started, 1 ================================================ FILE: test/lsp/test_other_initialize_message_handling.vader ================================================ Before: runtime autoload/ale/lsp.vim let g:message_list = [] " Register a fake connection and get it for tests. call ale#lsp#Register('ale-fake-lsp-server', '/code', '', {}) let b:conn = ale#lsp#GetConnections()['ale-fake-lsp-server:/code'] function! ale#lsp#Send(conn_id, message) abort call add(g:message_list, a:message) return 42 endfunction After: " Remove the connection with the ID. call ale#lsp#RemoveConnectionWithID(b:conn.id) unlet! b:conn unlet! g:message_list runtime autoload/ale/lsp.vim Execute(Messages with no method and capabilities should initialize projects): call ale#lsp#HandleInitResponse(b:conn, { \ 'result': {'capabilities': {}}, \}) AssertEqual 1, b:conn.initialized AssertEqual [[1, 'initialized', {}]], g:message_list Execute(Other messages should not initialize projects): call ale#lsp#HandleInitResponse(b:conn, {'method': 'lolwat'}) AssertEqual 0, b:conn.initialized AssertEqual [], g:message_list call ale#lsp#HandleInitResponse(b:conn, {'result': {'x': {}}}) AssertEqual 0, b:conn.initialized AssertEqual [], g:message_list Execute(Capabilities should be set up correctly): call ale#lsp#HandleInitResponse(b:conn, { \ 'jsonrpc': '2.0', \ 'id': 1, \ 'result': { \ 'capabilities': { \ 'renameProvider': v:true, \ 'executeCommandProvider': { \ 'commands': [], \ }, \ 'hoverProvider': v:true, \ 'documentSymbolProvider': v:true, \ 'documentRangeFormattingProvider': v:true, \ 'codeLensProvider': { \ 'resolveProvider': v:false \ }, \ 'referencesProvider': v:true, \ 'textDocumentSync': 2, \ 'documentFormattingProvider': v:true, \ 'codeActionProvider': v:true, \ 'signatureHelpProvider': { \ 'triggerCharacters': ['(', ','], \ }, \ 'completionProvider': { \ 'triggerCharacters': ['.'], \ 'resolveProvider': v:false \ }, \ 'definitionProvider': v:true, \ 'experimental': {}, \ 'documentHighlightProvider': v:true, \ 'workspaceSymbolProvider': v:true \ }, \ }, \}) AssertEqual 1, b:conn.initialized AssertEqual \ { \ 'code_actions': 1, \ 'completion': 1, \ 'completion_trigger_characters': ['.'], \ 'definition': 1, \ 'did_save': 0, \ 'filerename': 0, \ 'hover': 1, \ 'implementation': 0, \ 'includeText': 0, \ 'references': 1, \ 'rename': 1, \ 'pull_model': 0, \ 'symbol_search': 1, \ 'typeDefinition': 0, \ }, \ b:conn.capabilities AssertEqual [[1, 'initialized', {}]], g:message_list Execute(Disabled capabilities should be recognised correctly): call ale#lsp#HandleInitResponse(b:conn, { \ 'jsonrpc': '2.0', \ 'id': 1, \ 'result': { \ 'capabilities': { \ 'renameProvider': v:false, \ 'executeCommandProvider': { \ 'commands': [], \ }, \ 'hoverProvider': v:false, \ 'documentSymbolProvider': v:true, \ 'documentRangeFormattingProvider': v:true, \ 'codeLensProvider': { \ 'resolveProvider': v:false \ }, \ 'referencesProvider': v:false, \ 'textDocumentSync': 2, \ 'documentFormattingProvider': v:true, \ 'codeActionProvider': v:false, \ 'signatureHelpProvider': { \ 'triggerCharacters': ['(', ','], \ }, \ 'definitionProvider': v:false, \ 'experimental': {}, \ 'documentHighlightProvider': v:true, \ 'diagnosticProvider': {}, \ }, \ }, \}) AssertEqual 1, b:conn.initialized AssertEqual \ { \ 'code_actions': 0, \ 'completion': 0, \ 'completion_trigger_characters': [], \ 'definition': 0, \ 'did_save': 0, \ 'filerename': 0, \ 'hover': 0, \ 'implementation': 0, \ 'includeText': 0, \ 'references': 0, \ 'rename': 0, \ 'pull_model': 0, \ 'symbol_search': 0, \ 'typeDefinition': 0, \ }, \ b:conn.capabilities AssertEqual [[1, 'initialized', {}]], g:message_list Execute(Capabilities should be enabled when sent as Dictionaries): call ale#lsp#HandleInitResponse(b:conn, { \ 'jsonrpc': '2.0', \ 'id': 1, \ 'result': { \ 'capabilities': { \ 'renameProvider': {}, \ 'executeCommandProvider': { \ 'commands': [], \ }, \ 'hoverProvider': {}, \ 'documentSymbolProvider': v:true, \ 'documentRangeFormattingProvider': v:true, \ 'codeLensProvider': { \ 'resolveProvider': v:false \ }, \ 'completionProvider': { \ 'triggerCharacters': ['.'], \ 'resolveProvider': v:false \ }, \ 'referencesProvider': {}, \ 'textDocumentSync': { \ 'save': { \ 'includeText': v:true \ } \ }, \ 'documentFormattingProvider': v:true, \ 'codeActionProvider': v:true, \ 'signatureHelpProvider': { \ 'triggerCharacters': ['(', ','], \ }, \ 'definitionProvider': {}, \ 'typeDefinitionProvider': {}, \ 'implementationProvider': {}, \ 'experimental': {}, \ 'documentHighlightProvider': v:true, \ 'diagnosticProvider': { \ 'interFileDependencies': v:false, \ }, \ 'workspaceSymbolProvider': {} \ }, \ }, \}) AssertEqual 1, b:conn.initialized AssertEqual \ { \ 'code_actions': 1, \ 'completion': 1, \ 'completion_trigger_characters': ['.'], \ 'definition': 1, \ 'did_save': 1, \ 'filerename': 0, \ 'hover': 1, \ 'implementation': 1, \ 'includeText': 1, \ 'references': 1, \ 'rename': 1, \ 'pull_model': 1, \ 'symbol_search': 1, \ 'typeDefinition': 1, \ }, \ b:conn.capabilities AssertEqual [[1, 'initialized', {}]], g:message_list Execute(Results that are not dictionaries should be handled correctly): call ale#lsp#HandleInitResponse(b:conn, { \ 'jsonrpc': '2.0', \ 'id': 1, \ 'result': v:null, \}) AssertEqual [], g:message_list ================================================ FILE: test/lsp/test_read_lsp_diagnostics.vader ================================================ Before: function Range(start_line, start_char, end_line, end_char) abort return { \ 'start': {'line': a:start_line, 'character': a:start_char}, \ 'end': {'line': a:end_line, 'character': a:end_char}, \} endfunction After: delfunction Range Execute(ale#lsp#response#ReadDiagnostics() should handle errors): AssertEqual [ \ { \ 'type': 'E', \ 'text': 'Something went wrong!', \ 'lnum': 3, \ 'col': 11, \ 'end_lnum': 5, \ 'end_col': 15, \ 'code': 'some-error', \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'severity': 1, \ 'range': Range(2, 10, 4, 15), \ 'code': 'some-error', \ 'message': 'Something went wrong!', \ }, \ ]) Execute(ale#lsp#response#ReadDiagnostics() should handle warnings): AssertEqual [ \ { \ 'type': 'W', \ 'text': 'Something went wrong!', \ 'lnum': 2, \ 'col': 4, \ 'end_lnum': 2, \ 'end_col': 3, \ 'code': 'some-warning', \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'severity': 2, \ 'range': Range(1, 3, 1, 3), \ 'code': 'some-warning', \ 'message': 'Something went wrong!', \ }, \ ]) Execute(ale#lsp#response#ReadDiagnostics() should treat messages with missing severity as errors): AssertEqual [ \ { \ 'type': 'E', \ 'text': 'Something went wrong!', \ 'lnum': 3, \ 'col': 11, \ 'end_lnum': 5, \ 'end_col': 15, \ 'code': 'some-error', \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'range': Range(2, 10, 4, 15), \ 'code': 'some-error', \ 'message': 'Something went wrong!', \ }, \ ]) Execute(ale#lsp#response#ReadDiagnostics() should handle messages without codes): AssertEqual [ \ { \ 'type': 'E', \ 'text': 'Something went wrong!', \ 'lnum': 3, \ 'col': 11, \ 'end_lnum': 5, \ 'end_col': 15, \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'range': Range(2, 10, 4, 15), \ 'message': 'Something went wrong!', \ }, \ ]) Execute(ale#lsp#response#ReadDiagnostics() should include sources in detail): AssertEqual [ \ { \ 'type': 'E', \ 'text': 'Something went wrong!', \ 'detail': '[tslint] Something went wrong!', \ 'lnum': 10, \ 'col': 15, \ 'end_lnum': 12, \ 'end_col': 22, \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'range': Range(9, 14, 11, 22), \ 'message': 'Something went wrong!', \ 'source': 'tslint', \ } \ ]) Execute(ale#lsp#response#ReadDiagnostics() should keep line breaks in text): AssertEqual [ \ { \ 'type': 'E', \ 'text': "cannot borrow `cap` as mutable\r\nmore than once at a time\n\nmutable borrow starts here\rin previous iteration of loop", \ 'detail': "[rustc] cannot borrow `cap` as mutable\r\nmore than once at a time\n\nmutable borrow starts here\rin previous iteration of loop", \ 'lnum': 10, \ 'col': 15, \ 'end_lnum': 12, \ 'end_col': 22, \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'range': Range(9, 14, 11, 22), \ 'message': "cannot borrow `cap` as mutable\r\nmore than once at a time\n\nmutable borrow starts here\rin previous iteration of loop", \ 'source': 'rustc', \ } \ ]) 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': 15, \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'range': Range(2, 10, 4, 15), \ 'message': 'Something went wrong!', \ 'code': -1, \ }, \ ]) Execute(ale#lsp#response#ReadDiagnostics() should handle multiple messages): AssertEqual [ \ { \ 'type': 'E', \ 'text': 'Something went wrong!', \ 'lnum': 1, \ 'col': 3, \ 'end_lnum': 1, \ 'end_col': 2, \ }, \ { \ 'type': 'W', \ 'text': 'A warning', \ 'lnum': 2, \ 'col': 5, \ 'end_lnum': 2, \ 'end_col': 4, \ }, \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ 'range': Range(0, 2, 0, 2), \ 'message': 'Something went wrong!', \ }, \ { \ 'severity': 2, \ 'range': Range(1, 4, 1, 4), \ 'message': 'A warning', \ }, \ ]) 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': 2, \ 'detail': "Something went wrong!\n/tmp/someotherfile.txt:43:80:\n\tmight be this" \ } \ ], \ ale#lsp#response#ReadDiagnostics([ \ { \ '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, \ 'end_lnum': 1, \ 'end_col': 16, \ }, \ ], \ ale#lsp#response#ReadTSServerDiagnostics({"seq":0,"type":"event","event":"semanticDiag","body":{"file":"/bar/foo.ts","diagnostics":[{"start":{"line":1,"offset":11},"end":{"line":1,"offset":17},"text":"Operator ''+'' cannot be applied to types ''3'' and ''{}''.","code":2365}]}}) Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle warnings from tsserver): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 3, \ 'nr': 2515, \ 'code': '2515', \ 'end_lnum': 27, \ 'type': 'W', \ 'end_col': 13, \ 'text': 'Calls to ''console.log'' are not allowed. (no-console)', \ } \ ], \ ale#lsp#response#ReadTSServerDiagnostics({"seq":0,"type":"event","event":"semanticDiag","body":{"file":"","diagnostics":[{"start":{"line":27,"offset":3},"end":{"line":27,"offset":14},"text":"Calls to 'console.log' are not allowed. (no-console)","code":2515,"category":"warning","source":"tslint"}]}}) Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle suggestions from tsserver): AssertEqual \ [ \ { \ 'lnum': 27, \ 'col': 3, \ 'nr': 2515, \ 'code': '2515', \ 'end_lnum': 27, \ 'type': 'I', \ 'end_col': 13, \ 'text': 'Some info', \ } \ ], \ ale#lsp#response#ReadTSServerDiagnostics({"seq":0,"type":"event","event":"semanticDiag","body":{"file":"","diagnostics":[{"start":{"line":27,"offset":3},"end":{"line":27,"offset":14},"text":"Some info","code":2515,"category":"suggestion","source":"tslint"}]}}) ================================================ FILE: test/lsp/test_reset_lsp.vader ================================================ Before: Save g:ale_enabled 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 Save g:ale_buffer_info let g:ale_enabled = 0 let g:ale_set_signs = 0 let g:ale_set_quickfix = 0 let g:ale_set_loclist = 0 let g:ale_set_highlights = 0 let g:ale_echo_cursor = 0 let g:expr_list = [] function EmptyString() abort return '' endfunction runtime autoload/ale/util.vim function! ale#util#Execute(expr) abort call add(g:expr_list, a:expr) endfunction call ale#engine#InitBufferInfo(bufnr('')) " Call this function first, to clear LSP data. call ale#lsp_linter#ClearLSPData() call ale#linter#Define('testft', { \ 'name': 'lsplinter', \ 'lsp': 'tsserver', \ 'executable': function('EmptyString'), \ 'command': function('EmptyString'), \ 'project_root': function('EmptyString'), \ 'language': function('EmptyString'), \}) call ale#linter#Define('testft', { \ 'name': 'lsplinter2', \ 'lsp': 'tsserver', \ 'executable': function('EmptyString'), \ 'command': function('EmptyString'), \ 'project_root': function('EmptyString'), \ 'language': function('EmptyString'), \}) call ale#linter#Define('testft', { \ 'name': 'otherlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd': 'true', \ 'command': 'true', \ 'read_buffer': 0, \}) After: Restore delfunction EmptyString unlet! g:expr_list unlet! b:ale_save_event_fired " Clear LSP data after tests. call ale#lsp_linter#ClearLSPData() runtime autoload/ale/util.vim call ale#linter#Reset() Given testft(Some file with an imaginary filetype): Execute(ALEStopAllLSPs should clear the loclist): " For these tests we only need to set the keys we need. let g:ale_buffer_info[bufnr('')].loclist = [ \ {'linter_name': 'lsplinter'}, \ {'linter_name': 'otherlinter'}, \] let g:ale_buffer_info[bufnr('')].active_linter_list = [ \ {'name': 'lsplinter'}, \ {'name': 'otherlinter'}, \] ALEStopAllLSPs " The loclist should be updated. AssertEqual \ ['otherlinter'], \ map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.linter_name') " The LSP linter should be removed from the active linter list. AssertEqual \ ['otherlinter'], \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name') Execute(ALEStopLSP should stop a named LSP): let g:ale_buffer_info[bufnr('')].loclist = [ \ {'linter_name': 'lsplinter'}, \ {'linter_name': 'lsplinter2'}, \ {'linter_name': 'otherlinter'}, \] let g:ale_buffer_info[bufnr('')].active_linter_list = [ \ {'name': 'lsplinter'}, \ {'name': 'lsplinter2'}, \ {'name': 'otherlinter'}, \] call ale#lsp_linter#SetLSPLinterMap({ \ 'conn1': {'name': 'lsplinter'}, \ 'conn2': {'name': 'lsplinter2'}, \ 'conn3': {'name': 'lsplinter'}, \}) ALEStopLSP lsplinter " We should remove only the items for this linter. AssertEqual \ ['lsplinter2', 'otherlinter'], \ map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.linter_name') " The linter should be removed from the active linter list. AssertEqual \ ['lsplinter2', 'otherlinter'], \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name') " The connections linters with this name should be removed. AssertEqual \ {'conn2': {'name': 'lsplinter2'}}, \ ale#lsp_linter#GetLSPLinterMap() Execute(ALEStopLSP should not clear results for linters not running): let g:ale_buffer_info[bufnr('')].loclist = [ \ {'linter_name': 'lsplinter'}, \ {'linter_name': 'otherlinter'}, \] let g:ale_buffer_info[bufnr('')].active_linter_list = [ \ {'name': 'lsplinter'}, \ {'name': 'otherlinter'}, \] ALEStopLSP lsplinter " We should emit a message saying the server isn't running. AssertEqual \ ['echom ''No running language server with name: lsplinter'''], \ g:expr_list " We should keep the linter items. AssertEqual \ ['lsplinter', 'otherlinter'], \ map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.linter_name') AssertEqual \ ['lsplinter', 'otherlinter'], \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name') Execute(ALEStopLSP with a bang should not emit warnings): ALEStopLSP! lsplinter AssertEqual [], g:expr_list Execute(ALEStopLSP's completion function should suggest running linter names): call ale#lsp_linter#SetLSPLinterMap({ \ 'conn1': {'name': 'pyright'}, \ 'conn2': {'name': 'pylsp'}, \ 'conn3': {'name': 'imaginaryserver'}, \}) AssertEqual \ ['imaginaryserver', 'pylsp', 'pyright'], \ ale#lsp#reset#Complete('', '', 42) AssertEqual ['imaginaryserver'], ale#lsp#reset#Complete('inary', '', 42) AssertEqual ['pylsp'], ale#lsp#reset#Complete('LSP', '', 42) ================================================ FILE: test/lsp/test_update_config.vader ================================================ Before: runtime autoload/ale/lsp.vim let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) " Stub out this function, so we test updating configs. function! ale#lsp#Send(conn_id, message) abort endfunction 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(''), {}) ================================================ FILE: test/lua/ale_diagnostics_spec.lua ================================================ local eq = assert.are.same local diagnostics describe("ale.diagnostics.send", function() local buffer_map local signs_config local diagnostic_set_calls setup(function() _G.vim = { api = { nvim_buf_get_var = function(buffer, key) local buffer_table = buffer_map[buffer] or {} local value = buffer_table[key] if value == nil then error(key .. " is missing") end return value end, nvim_create_namespace = function() return 42 end, }, diagnostic = { severity = {ERROR = 1, WARN = 2, INFO = 3}, config = function() return {signs = signs_config} end, set = function(namespace, bufnr, _diagnostics, opts) table.insert(diagnostic_set_calls, { namespace = namespace, bufnr = bufnr, diagnostics = _diagnostics, opts = opts, }) end, }, tbl_extend = function(behavior, ...) assert(behavior == "force", "We should only use `force`") local merged = {} for _, arg in ipairs({...}) do for key, value in pairs(arg) do merged[key] = value end end return merged end, g = {}, } diagnostics = require("ale.diagnostics") end) teardown(function() _G.vim = nil end) before_each(function() buffer_map = {} diagnostic_set_calls = {} signs_config = false _G.vim.g = {} end) it("should set an empty list of diagnostics correctly", function() diagnostics.send(7, {}) eq( { { namespace = 42, bufnr = 7, diagnostics = {}, opts = {virtual_text = false} }, }, diagnostic_set_calls ) end) it("should handle basic case with all fields", function() diagnostics.send(1, { { bufnr = 1, lnum = 2, end_lnum = 3, col = 4, end_col = 5, type = "W", code = "123", text = "Warning message", linter_name = "eslint", }, }) eq({ { lnum = 1, end_lnum = 2, col = 3, end_col = 5, severity = vim.diagnostic.severity.WARN, code = "123", message = "Warning message", source = "eslint", }, }, diagnostic_set_calls[1].diagnostics) end) it("should default end_lnum to lnum when missing", function() diagnostics.send(1, { { bufnr = 1, lnum = 5, col = 2, end_col = 8, type = "E", text = "Error message", linter_name = "mylinter", }, }) eq({ { lnum = 4, end_lnum = 4, col = 1, end_col = 8, severity = vim.diagnostic.severity.ERROR, code = nil, message = "Error message", source = "mylinter", }, }, diagnostic_set_calls[1].diagnostics) end) it("should default col to 0 when missing", function() diagnostics.send(1, { { bufnr = 1, lnum = 10, end_lnum = 12, end_col = 6, type = "I", text = "Info message", }, }) eq({ { lnum = 9, end_lnum = 11, col = 0, end_col = 6, severity = vim.diagnostic.severity.INFO, code = nil, message = "Info message", source = nil, }, }, diagnostic_set_calls[1].diagnostics) end) it("should ignore non-matching buffers", function() diagnostics.send(1, { { bufnr = 2, lnum = 1, end_lnum = 2, col = 1, end_col = 4, type = "W", text = "Message", }, }) eq({}, diagnostic_set_calls[1].diagnostics) end) for _, set_signs_value in ipairs {1, true} do describe("signs with setting set_signs = " .. tostring(set_signs_value), function() before_each(function() _G.vim.g.ale_set_signs = set_signs_value _G.vim.g.ale_sign_priority = 10 end) it("and global config as `false` should enable signs with the given priority", function() diagnostics.send(7, {}) eq({priority = 10}, diagnostic_set_calls[1].opts.signs) end) it("and global config as a table should enable signs with the given priority", function() signs_config = {foo = "bar", priority = 5} diagnostics.send(7, {}) eq( {foo = "bar", priority = 10}, diagnostic_set_calls[1].opts.signs ) end) it("and global config as a function should enable signs with the given priority", function() signs_config = function() return {foo = "bar", priority = 5} end diagnostics.send(7, {}) local local_signs = diagnostic_set_calls[1].opts.signs eq("function", type(local_signs)) eq({foo = "bar", priority = 10}, local_signs()) end) end) end it("should toggle virtual_text correctly", function() for _, value in ipairs({"all", "2", 2, "current", "1", 1, true}) do diagnostic_set_calls = {} _G.vim.g.ale_virtualtext_cursor = value diagnostics.send(7, {}) eq({virtual_text = true}, diagnostic_set_calls[1].opts) end for _, value in ipairs({"disabled", "0", 0, false, nil}) do diagnostic_set_calls = {} _G.vim.g.ale_virtualtext_cursor = value diagnostics.send(7, {}) eq({virtual_text = false}, diagnostic_set_calls[1].opts) end end) end) ================================================ FILE: test/lua/ale_env_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.env", function() local is_win32 = false setup(function() _G.vim = { o = setmetatable({}, { __index = function(_, key) if key == "shell" then if is_win32 then return "cmd.exe" end return "bash" end return nil end }), fn = { has = function(feature) return feature == "win32" and is_win32 end, -- Mock a very poor version of shellescape() for Unix -- This shouldn't be called for Windows shellescape = function(str) return "'" .. str .. "'" end, fnamemodify = function(shell, _) return shell end } } end) teardown(function() _G.vim = nil end) before_each(function() is_win32 = false end) it("should escape values correctly on Unix", function() eq("name='xxx' ", ale.env('name', 'xxx')) eq("name='foo bar' ", ale.env('name', 'foo bar')) end) it("should escape values correctly on Windows", function() is_win32 = true eq('set name=xxx && ', ale.env('name', 'xxx')) eq('set "name=foo bar" && ', ale.env('name', 'foo bar')) end) end) ================================================ FILE: test/lua/ale_get_filename_mappings_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.get_filename_mappings", function() local buffer_map setup(function() _G.vim = { api = { nvim_buf_get_var = function(buffer, key) local buffer_table = buffer_map[buffer] or {} local value = buffer_table[key] if value == nil then error(key .. " is missing") end return value end, }, g = { }, } end) teardown(function() _G.vim = nil end) before_each(function() buffer_map = {[42] = {}} _G.vim.g = {} end) it("should return the correct mappings for given linters/fixers", function() vim.g.ale_filename_mappings = { a = {{"foo", "bar"}}, b = {{"baz", "foo"}}, } eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a")) eq({{"baz", "foo"}}, ale.get_filename_mappings(42, "b")) eq({}, ale.get_filename_mappings(42, "c")) buffer_map[42].ale_filename_mappings = {b = {{"abc", "xyz"}}} eq({}, ale.get_filename_mappings(42, "a")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "b")) eq({}, ale.get_filename_mappings(42, "c")) end) it("should return arrays set for use with all tools", function() vim.g.ale_filename_mappings = {{"foo", "bar"}} eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a")) eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "")) buffer_map[42].ale_filename_mappings = {{"abc", "xyz"}} eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "a")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "")) end) it("should let you use * as a fallback", function() vim.g.ale_filename_mappings = { a = {{"foo", "bar"}}, ["*"] = {{"abc", "xyz"}}, } eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "b")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "")) end) end) ================================================ FILE: test/lua/ale_has_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.has", function() setup(function() _G.vim = { fn = { ["ale#Has"] = function(feature) if feature == "ale-4.0.0" then return 1 end return 0 end, }, } end) teardown(function() _G.vim = nil end) it("should return valuse from ale#Has correctly", function() eq(true, ale.has("ale-4.0.0")) eq(false, ale.has("ale-20.0.0")) end) end) ================================================ FILE: test/lua/ale_lsp_send_message_spec.lua ================================================ local eq = assert.are.same local lsp = require("ale.lsp") describe("ale.lsp.send_message", function() local clients local version_minor local get_client_by_id_calls local vim_fn_calls setup(function() _G.vim = { version = function() return {minor = version_minor} end, lsp = { get_client_by_id = function(client_id) table.insert(get_client_by_id_calls, client_id) return clients[client_id] end, }, fn = setmetatable({}, { __index = function(_, key) return function(...) table.insert(vim_fn_calls, {key, ...}) if key ~= "ale#lsp#HandleResponse" then assert(false, "Invalid ALE function: " .. key) end return nil end end, }), } end) teardown(function() _G.vim = nil end) before_each(function() clients = {} version_minor = 11 get_client_by_id_calls = {} vim_fn_calls = {} end) it("should return 0 when a client cannot be found", function() eq(0, lsp.send_message({client_id = 999})) eq({999}, get_client_by_id_calls) eq({}, vim_fn_calls) end) it("should send notifications for Neovim 0.11+", function() local notify_calls = {} clients[1] = { notify = function(...) table.insert(notify_calls, {...}) return true end, } eq(-1, lsp.send_message({ client_id = 1, is_notification = true, method = "workspace/didChangeConfiguration", params = {settings = {python = {analysis = true}}}, })) eq({1}, get_client_by_id_calls) eq(1, #notify_calls) assert.is_true(notify_calls[1][1] == clients[1]) eq("workspace/didChangeConfiguration", notify_calls[1][2]) eq({settings = {python = {analysis = true}}}, notify_calls[1][3]) eq({}, vim_fn_calls) end) it("should return 0 if a notification fails for Neovim 0.11+", function() local notify_calls = {} clients[1] = { notify = function(...) table.insert(notify_calls, {...}) return false end, } eq(0, lsp.send_message({ client_id = 1, is_notification = true, method = "textDocument/didSave", params = {textDocument = {uri = "file://foo.py"}}, })) eq({1}, get_client_by_id_calls) eq(1, #notify_calls) assert.is_true(notify_calls[1][1] == clients[1]) eq("textDocument/didSave", notify_calls[1][2]) eq({textDocument = {uri = "file://foo.py"}}, notify_calls[1][3]) eq({}, vim_fn_calls) end) it("should send notifications for Neovim 0.10 and below", function() local notify_calls = {} version_minor = 10 clients[1] = { notify = function(...) table.insert(notify_calls, {...}) return true end, } eq(-1, lsp.send_message({ client_id = 1, is_notification = true, method = "textDocument/didSave", params = {textDocument = {uri = "file://foo.py"}}, })) eq({1}, get_client_by_id_calls) eq(1, #notify_calls) eq("textDocument/didSave", notify_calls[1][1]) eq({textDocument = {uri = "file://foo.py"}}, notify_calls[1][2]) eq({}, vim_fn_calls) end) it("should return 0 if a notification fails for Neovim 0.10 and below", function() local notify_calls = {} version_minor = 10 clients[1] = { notify = function(...) table.insert(notify_calls, {...}) return false end, } eq(0, lsp.send_message({ client_id = 1, is_notification = true, method = "textDocument/didSave", params = {textDocument = {uri = "file://foo.py"}}, })) eq({1}, get_client_by_id_calls) eq(1, #notify_calls) eq("textDocument/didSave", notify_calls[1][1]) eq({textDocument = {uri = "file://foo.py"}}, notify_calls[1][2]) eq({}, vim_fn_calls) end) it("should send requests and handle responses for Neovim 0.11+", function() local request_calls = {} clients[2] = { name = "server:/code", request = function(...) table.insert(request_calls, {...}) return true, 347 end, } eq(347, lsp.send_message({ client_id = 2, method = "textDocument/hover", params = {line = 10, character = 5}, })) eq({2}, get_client_by_id_calls) eq(1, #request_calls) assert.is_true(request_calls[1][1] == clients[2]) eq("textDocument/hover", request_calls[1][2]) eq({line = 10, character = 5}, request_calls[1][3]) eq(-1, request_calls[1][5]) eq("function", type(request_calls[1][4])) request_calls[1][4](nil, {contents = "hello"}, nil, nil) eq({ { "ale#lsp#HandleResponse", "server:/code", {id = 347, result = {contents = "hello"}}, }, }, vim_fn_calls) end) it("should return 0 if a request fails for Neovim 0.11+", function() local request_calls = {} clients[2] = { name = "server:/code", request = function(...) table.insert(request_calls, {...}) return false, 347 end, } eq(0, lsp.send_message({ client_id = 2, method = "textDocument/definition", params = {line = 10, character = 5}, })) eq({2}, get_client_by_id_calls) eq(1, #request_calls) assert.is_true(request_calls[1][1] == clients[2] ) eq("textDocument/definition", request_calls[1][2]) eq({line = 10, character = 5}, request_calls[1][3]) eq(-1, request_calls[1][5]) eq("function", type(request_calls[1][4])) eq({}, vim_fn_calls) end) it("should send requests and handle responses for Neovim 0.10 and below", function() local request_calls = {} version_minor = 10 clients[2] = { name = "server:/code", request = function(...) table.insert(request_calls, {...}) return true, 12 end, } eq(12, lsp.send_message({ client_id = 2, method = "textDocument/hover", params = {line = 10, character = 5}, })) eq({2}, get_client_by_id_calls) eq(1, #request_calls) eq("textDocument/hover", request_calls[1][1]) eq({line = 10, character = 5}, request_calls[1][2]) eq(-1, request_calls[1][4]) eq("function", type(request_calls[1][3])) request_calls[1][3](nil, {contents = "legacy"}, nil, nil) eq({ { "ale#lsp#HandleResponse", "server:/code", {id = 12, result = {contents = "legacy"}}, }, }, vim_fn_calls) end) it("should return 0 if a request fails for Neovim 0.10 and below", function() local request_calls = {} version_minor = 10 clients[2] = { name = "server:/code", request = function(...) table.insert(request_calls, {...}) return false, 12 end, } eq(0, lsp.send_message({ client_id = 2, method = "textDocument/hover", params = {line = 10, character = 5}, })) eq({2}, get_client_by_id_calls) eq(1, #request_calls) eq("textDocument/hover", request_calls[1][1]) eq({line = 10, character = 5}, request_calls[1][2]) eq(-1, request_calls[1][4]) eq("function", type(request_calls[1][3])) eq({}, vim_fn_calls) end) end) ================================================ FILE: test/lua/ale_lsp_start_spec.lua ================================================ local eq = assert.are.same local lsp = require("ale.lsp") describe("ale.lsp.start", function() local start_calls local rpc_connect_calls local vim_fn_calls local defer_calls local nvim_default_capabilities setup(function() _G.vim = { defer_fn = function(func, delay) table.insert(defer_calls, {func, delay}) end, empty_dict = function() -- Returns a table with a metatable to distinguish it from arrays return setmetatable({}, {__empty_dict = true}) end, fn = setmetatable({}, { __index = function(_, key) return function(...) table.insert(vim_fn_calls, {key, ...}) if key == "ale#lsp#GetLanguage" then return "python" end if key ~= "ale#lsp_linter#HandleLSPDiagnostics" and key ~= "ale#lsp#UpdateCapabilities" and key ~= "ale#lsp#CallInitCallbacks" then assert(false, "Invalid ALE function: " .. key) end return nil end end, }), lsp = { rpc = { connect = function(host, port) return function(dispatch) table.insert(rpc_connect_calls, { host = host, port = port, dispatch = dispatch, }) end end, }, start = function(...) table.insert(start_calls, {...}) return 42 end, protocol = { make_client_capabilities = function() return nvim_default_capabilities end, }, }, } end) teardown(function() _G.vim = nil end) before_each(function() start_calls = {} rpc_connect_calls = {} vim_fn_calls = {} defer_calls = {} nvim_default_capabilities = { textDocument = {}, } end) it("should start lsp programs with the correct arguments", function() lsp.start({ name = "server:/code", cmd = "server", root_dir = "/code", -- This Boolean value somehow ends up in Dictionaries from -- Vim for init_options, and we need to remove it. init_options = {[true] = 123}, }) -- Remove arguments with functions we can't apply equality checks -- for easily. for _, args in pairs(start_calls) do args[1].handlers = nil args[1].on_init = nil args[1].get_language_id = nil end eq({ { { cmd = "server", name = "server:/code", root_dir = "/code", init_options = {}, }, {attach = false, silent = true} } }, start_calls) eq({}, vim_fn_calls) end) it("should convert empty init_options to vim.empty_dict", function() -- Mock vim.empty_dict local empty_dict_called = false _G.vim.empty_dict = function() empty_dict_called = true return setmetatable({}, {__empty_dict = true}) end lsp.start({ name = "gopls:/code", cmd = "gopls", root_dir = "/code", -- Empty table without metatable (like from VimScript {}) init_options = {}, }) -- Verify that empty_dict was called eq(true, empty_dict_called) -- Verify init_options has metatable now eq(1, #start_calls) local init_opts = start_calls[1][1].init_options eq(true, getmetatable(init_opts) ~= nil) end) it("should preserve non-empty init_options", function() lsp.start({ name = "gopls:/code", cmd = "gopls", root_dir = "/code", init_options = {foo = "bar", nested = {baz = 123}}, }) -- Remove functions we can't compare for _, args in pairs(start_calls) do args[1].handlers = nil args[1].on_init = nil args[1].get_language_id = nil end eq(1, #start_calls) eq({foo = "bar", nested = {baz = 123}}, start_calls[1][1].init_options) end) it("should start lsp socket connections with the correct arguments", function() lsp.start({ name = "localhost:1234:/code", host = "localhost", port = 1234, root_dir = "/code", init_options = {foo = "bar"}, }) local cmd -- Remove arguments with functions we can't apply equality checks -- for easily. for _, args in pairs(start_calls) do cmd = args[1].cmd args[1].cmd = nil args[1].handlers = nil args[1].on_init = nil args[1].get_language_id = nil end eq({ { { name = "localhost:1234:/code", root_dir = "/code", init_options = {foo = "bar"}, }, {attach = false, silent = true} } }, start_calls) cmd("dispatch_value") eq({ {dispatch = "dispatch_value", host = "localhost", port = 1234}, }, rpc_connect_calls) eq({}, vim_fn_calls) end) it("should return the client_id value from vim.lsp.start", function() eq(42, lsp.start({})) end) it("should implement get_language_id correctly", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) eq("python", start_calls[1][1].get_language_id(347, "ftype")) eq({{"ale#lsp#GetLanguage", "server:/code", 347}}, vim_fn_calls) end) it("should enable dynamicRegistration for the pull model", function() nvim_default_capabilities = {textDocument = {diagnostic = {}}} lsp.start({name = "server:/code"}) eq(1, #start_calls) eq( { textDocument = { diagnostic = { dynamicRegistration = true, }, }, }, start_calls[1][1].capabilities ) end) it("should initialize clients with ALE correctly", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) start_calls[1][1].on_init({server_capabilities = {cap = 1}}) eq({ {"ale#lsp#UpdateCapabilities", "server:/code", {cap = 1}}, }, vim_fn_calls) eq(1, #defer_calls) eq(2, #defer_calls[1]) eq("function", type(defer_calls[1][1])) eq(0, defer_calls[1][2]) defer_calls[1][1]() eq({ {"ale#lsp#UpdateCapabilities", "server:/code", {cap = 1}}, {"ale#lsp#CallInitCallbacks", "server:/code"}, }, vim_fn_calls) end) it("should configure handlers correctly", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) local handlers = start_calls[1][1].handlers local handler_names = {} -- get keys from handlers for key, _ in pairs(handlers) do -- add key to handler_names mapping handler_names[key] = true end eq({ ["textDocument/publishDiagnostics"] = true, ["textDocument/diagnostic"] = true, ["workspace/diagnostic/refresh"] = true, }, handler_names) end) it("should handle push model published diagnostics", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) local handlers = start_calls[1][1].handlers eq("function", type(handlers["textDocument/publishDiagnostics"])) handlers["textDocument/publishDiagnostics"](nil, { uri = "file://code/foo.py", diagnostics = { { lnum = 1, end_lnum = 2, col = 3, end_col = 5, severity = 1, code = "123", message = "Warning message", } }, }) eq({ { "ale#lsp_linter#HandleLSPDiagnostics", "server:/code", "file://code/foo.py", { { lnum = 1, end_lnum = 2, col = 3, end_col = 5, severity = 1, code = "123", message = "Warning message", }, }, }, }, vim_fn_calls) end) it("should respond to workspace diagnostic refresh requests", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) local handlers = start_calls[1][1].handlers eq("function", type(handlers["workspace/diagnostic/refresh"])) eq({}, handlers["workspace/diagnostic/refresh"]()) end) it("should handle pull model diagnostics", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) local handlers = start_calls[1][1].handlers eq("function", type(handlers["textDocument/diagnostic"])) handlers["textDocument/diagnostic"]( nil, { kind = "full", items = { { lnum = 1, end_lnum = 2, col = 3, end_col = 5, severity = 1, code = "123", message = "Warning message", } }, }, { params = { textDocument = { uri = "file://code/foo.py", }, }, } ) eq({ { "ale#lsp_linter#HandleLSPDiagnostics", "server:/code", "file://code/foo.py", { { lnum = 1, end_lnum = 2, col = 3, end_col = 5, severity = 1, code = "123", message = "Warning message", }, }, }, }, vim_fn_calls) end) it("should handle unchanged pull model diagnostics", function() lsp.start({name = "server:/code"}) eq(1, #start_calls) local handlers = start_calls[1][1].handlers eq("function", type(handlers["textDocument/diagnostic"])) handlers["textDocument/diagnostic"]( nil, {kind = "unchanged"}, { params = { textDocument = { uri = "file://code/foo.py", }, }, } ) eq({ { "ale#lsp_linter#HandleLSPDiagnostics", "server:/code", "file://code/foo.py", "unchanged", }, }, vim_fn_calls) end) end) ================================================ FILE: test/lua/ale_pad_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.pad", function() it("should pad non-empty strings", function() eq(" foo", ale.pad("foo")) end) it("should return empty strings for nil or empty strings", function() eq("", ale.pad(nil)) eq("", ale.pad("")) end) end) ================================================ FILE: test/lua/ale_queue_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.queue", function() local queue_calls setup(function() _G.vim = { fn = { ["ale#Queue"] = function(...) table.insert(queue_calls, {...}) end, }, } end) teardown(function() _G.vim = nil end) before_each(function() queue_calls = {} end) it("should call ale#Queue with the right arguments", function() ale.queue(0) ale.queue(0, "") ale.queue(123, "lint_file") ale.queue(0, "", 42) ale.queue(123, "lint_file", 42) eq({ {0, nil, nil}, {0, "", nil}, {123, "lint_file", nil}, {0, "", 42}, {123, "lint_file", 42}, }, queue_calls) end) end) ================================================ FILE: test/lua/ale_var_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.var", function() local buffer_map setup(function() _G.vim = { api = { nvim_buf_get_var = function(buffer, key) local buffer_table = buffer_map[buffer] or {} local value = buffer_table[key] if value == nil then error(key .. " is missing") end return value end, }, g = { }, } end) teardown(function() _G.vim = nil end) before_each(function() buffer_map = {} _G.vim.g = {} end) it("should return nil for undefined variables", function() eq(nil, ale.var(1, "foo")) end) it("should return buffer-local values, if set", function() _G.vim.g.ale_foo = "global-value" buffer_map[1] = {ale_foo = "buffer-value"} eq("buffer-value", ale.var(1, "foo")) end) it("should return global values, if set", function() _G.vim.g.ale_foo = "global-value" eq("global-value", ale.var(1, "foo")) end) end) ================================================ FILE: test/lua/windows_escaping_spec.lua ================================================ local eq = assert.are.same local ale = require("ale") describe("ale.escape for cmd.exe", function() setup(function() _G.vim = { o = { shell = "cmd.exe" }, fn = { fnamemodify = function(shell, _) return shell end } } end) teardown(function() _G.vim = nil end) it("should allow not escape paths without special characters", function() eq("C:", ale.escape("C:")) eq("C:\\", ale.escape("C:\\")) eq("python", ale.escape("python")) eq("C:\\foo\\bar", ale.escape("C:\\foo\\bar")) eq("/bar/baz", ale.escape("/bar/baz")) eq("nul", ale.escape("nul")) eq("'foo'", ale.escape("'foo'")) end) it("should escape Windows paths with spaces appropriately", function() eq('"C:\\foo bar\\baz"', ale.escape('C:\\foo bar\\baz')) eq('"^foo bar^"', ale.escape('^foo bar^')) eq('"&foo bar&"', ale.escape('&foo bar&')) eq('"|foo bar|"', ale.escape('|foo bar|')) eq('"foo bar>"', ale.escape('>foo bar>')) eq('"^foo bar^"', ale.escape('^foo bar^')) eq('"\'foo\' \'bar\'"', ale.escape('\'foo\' \'bar\'')) end) it("should use caret escapes on special characters", function() eq('^^foo^^', ale.escape('^foo^')) eq('^&foo^&', ale.escape('&foo&')) eq('^|foo^|', ale.escape('|foo|')) eq('^foo^>', ale.escape('>foo>')) eq('^^foo^^', ale.escape('^foo^')) eq('\'foo\'^^\'bar\'', ale.escape('\'foo\'^\'bar\'')) end) it("should escape percent characters", function() eq('%%foo%%', ale.escape('%foo%')) eq('C:\foo%%\bar\baz%%', ale.escape('C:\foo%\bar\baz%')) eq('"C:\foo bar%%\baz%%"', ale.escape('C:\foo bar%\baz%')) eq('^^%%foo%%', ale.escape('^%foo%')) eq('"^%%foo%% %%bar%%"', ale.escape('^%foo% %bar%')) eq('"^%%foo%% %%bar%% """""', ale.escape('^%foo% %bar% ""')) end) end) ================================================ FILE: test/python/test_deoplete_source.py ================================================ import unittest import imp ale_module = imp.load_source( 'deoplete.sources.ale', '/testplugin/rplugin/python3/deoplete/sources/ale.py', ) class VimMock(object): def __init__(self, call_list, call_results, commands): self.__call_list = call_list self.__call_results = call_results self.__commands = commands def call(self, function, *args): self.__call_list.append((function, args)) return self.__call_results.get(function, 0) def command(self, command): self.__commands.append(command) class DeopleteSourceTest(unittest.TestCase): def setUp(self): super(DeopleteSourceTest, self).setUp() self.call_list = [] self.call_results = {'ale#completion#CanProvideCompletions': 1} self.commands = [] self.source = ale_module.Source('vim') self.source.vim = VimMock( self.call_list, self.call_results, self.commands) def test_attributes(self): """ Check all of the attributes we set. """ attributes = dict( (key, getattr(self.source, key)) for key in dir(self.source) if not key.startswith('__') and key != 'vim' and not hasattr(getattr(self.source, key), '__self__') ) self.assertEqual(attributes, { 'input_patterns': { '_': r'\.\w*$', 'rust': r'(\.|::)\w*$', 'typescript': r'(\.|\'|")\w*$', 'cpp': r'(\.|::|->)\w*$', 'c': r'(\.|->)\w*$', }, 'is_bytepos': True, 'is_volatile': True, 'mark': '[L]', 'min_pattern_length': 1, 'name': 'ale', 'rank': 1000, }) def test_complete_position(self): self.call_results['ale#completion#GetCompletionPositionForDeoplete'] = 2 context = {'input': 'foo'} self.assertEqual(self.source.get_complete_position(context), 2) self.assertEqual(self.call_list, [ ('ale#completion#GetCompletionPositionForDeoplete', ('foo',)), ]) def test_request_completion_results(self): context = {'event': 'TextChangedI', 'is_refresh': True} self.assertEqual(self.source.gather_candidates(context), []) self.assertEqual(self.call_list, [ ('ale#completion#CanProvideCompletions', ()), ]) self.assertEqual(self.commands, [ "call ale#completion#GetCompletions('ale-callback', " + \ "{'callback': {completions -> deoplete#auto_complete() }})" ]) def test_request_completion_results_from_buffer_without_providers(self): self.call_results['ale#completion#CanProvideCompletions'] = 0 context = {'event': 'TextChangedI', 'is_refresh': True} self.assertIsNone(self.source.gather_candidates(context), []) self.assertEqual(self.call_list, [ ('ale#completion#CanProvideCompletions', ()), ]) def test_async_event(self): context = {'event': 'Async', 'is_refresh': True} self.call_results['ale#completion#GetCompletionResult'] = [ { 'word': 'foobar', 'kind': 'v', 'icase': 1, 'menu': '', 'info': '', }, ] self.assertEqual(self.source.gather_candidates(context), [ { 'word': 'foobar', 'kind': 'v', 'icase': 1, 'menu': '', 'info': '', }, ]) self.assertEqual(self.call_list, [ ('ale#completion#CanProvideCompletions', ()), ('ale#completion#GetCompletionResult', ()), ]) ================================================ FILE: test/script/block-padding-checker ================================================ #!/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\\]+)') OPERATOR_END_RE = re.compile(r'(&&|\|\||\+|-|\*\| /)$') 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 SAME_INDENTATION_SET = set(['\\']) 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`' % (previous_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) if ( command in SAME_INDENTATION_SET and previous_indentation_level is not None and indentation_level != previous_indentation_level ): yield ( line_number, 'Line continuation should match previous indentation' ) if ( previous_indentation_level is not None and indentation_level != previous_indentation_level and abs(indentation_level - previous_indentation_level) != 4 # noqa ): yield ( line_number, 'Indentation should be 4 spaces' ) # 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 if OPERATOR_END_RE.search(line): yield ( line_number, 'Put operators at the start of lines instead' ) 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() ================================================ FILE: test/script/check-duplicate-tags ================================================ #!/usr/bin/env bash set -e grep --exclude=tags -roh '\*.*\*$' doc | sort | uniq -d ================================================ FILE: test/script/check-supported-tools-tables ================================================ #!/usr/bin/env bash set -e set -u # This script compares the table of supported tools in both supported-tools.md # (for GitHub) and doc/ale-supported-languages-and-tools.txt (for vim), so we # can complain if they don't match up. doc_file="$(mktemp -t doc.XXXXXXXX)" doc_sorted_file="$(mktemp -t doc-sorted.XXXXXXXX)" readme_file="$(mktemp -t readme.XXXXXXXX)" while read -r; do if [[ "$REPLY" =~ ^! ]]; then language="${REPLY/!/}" else echo "$language - $REPLY" fi done < <( grep '^\*\|^ *\*' doc/ale-supported-languages-and-tools.txt \ | sed -e '1,2d' \ | sed 's/^\* */!/' \ | sed -E 's/^ *\* *|!!|\^|\(.*\)|`//g' \ | sed 's/ *$//' ) > "$doc_file" while read -r; do if [[ "$REPLY" =~ ^! ]]; then language="${REPLY/!/}" else echo "$language - $REPLY" fi done < <( grep '^\*\|^ *\*' supported-tools.md \ | sed 's/^\* */!/' \ | sed -E 's/^ *\* *|:floppy_disk:|:warning:|\(.*\)|\[|\].*|-n flag//g' \ | sed 's/ *$//' ) > "$readme_file" exit_code=0 # Sort the tools ignoring case, and complain when things are out of order. LC_ALL=en_US.UTF-8 sort -f -k1,2 "$doc_file" -o "$doc_sorted_file" diff -U0 "$doc_sorted_file" "$doc_file" || exit_code=$? if ((exit_code)); then echo echo "The supported tools list isn't sorted properly" echo fi diff -U0 "$readme_file" "$doc_file" || exit_code=$? rm "$doc_file" rm "$doc_sorted_file" rm "$readme_file" exit "$exit_code" ================================================ FILE: test/script/check-tag-alignment ================================================ #!/usr/bin/env bash exit_code=0 # Documentation tags need to be aligned to the right margin, so look for # tags which aren't at the right margin. grep ' \*[^*]\+\*$' doc/ -r \ | awk '{ sep = index($0, ":"); if (length(substr($0, sep + 1 )) < 79) { print } }' \ | grep . && exit_code=1 exit $exit_code ================================================ FILE: test/script/check-tag-references ================================================ #!/usr/bin/env bash set -e exit_code=0 tag_regex='[gb]\?:\?\(ale\|ALE\)[a-zA-Z_\-]\+' tags="$(mktemp -t tags.XXXXXXXX)" refs="$(mktemp -t refs.XXXXXXXX)" result="$(mktemp -t refs.XXXXXXXX)" # Grep for tags and references, and complain if we find a reference without # a tag for the reference. Only our tags will be included. grep --exclude=tags -roh "\\*$tag_regex\\*" doc | sed 's/*//g' | sort -u > "$tags" grep --exclude=tags -roh "|$tag_regex|" doc | sed 's/|//g' | sort -u > "$refs" # Collect tags in a file we can display to the user if there are differences. comm -23 "$refs" "$tags" > "$result" exit_code=0 # If there are differences, show them and error out. if ! [[ $(wc -l < "$result") -eq 0 ]]; then cat "$result" exit_code=1 fi rm "$tags" rm "$refs" rm "$result" exit $exit_code ================================================ FILE: test/script/check-toc ================================================ #!/usr/bin/env bash set -e set -u # This script checks that the table of contents for the supported tools is # sorted, and that the table matches the files. toc_section_start_line="$( grep -m1 -n '^7\..*\*ale-other-integration-options\*' doc/ale.txt \ | sed 's/\([0-9]*\).*/\1/' \ )" toc_start_offset="$( \ tail -n +"$toc_section_start_line" doc/ale.txt \ | grep -m1 -n '^ .*\.\.\.' \ | sed 's/\([0-9]*\).*/\1/' \ )" # shellcheck disable=SC2003 toc_start_line="$(expr "$toc_section_start_line" + "$toc_start_offset" - 1)" toc_section_size="$( \ tail -n +"$toc_start_line" doc/ale.txt \ | grep -m1 -n '^===*$' \ | sed 's/\([0-9]*\).*/\1/' \ )" # shellcheck disable=SC2003 toc_end_line="$(expr "$toc_start_line" + "$toc_section_size" - 4)" toc_file="$(mktemp -t table-of-contents.XXXXXXXX)" heading_file="$(mktemp -t headings.XXXXXXXX)" tagged_toc_file="$(mktemp -t ale.txt.XXXXXXXX)" sorted_toc_file="$(mktemp -t sorted-ale.txt.XXXXXXXX)" sed -n "$toc_start_line,$toc_end_line"p doc/ale.txt \ | sed 's/^ \( *[^.][^.]*\)\.\.*|\(..*\)|/\1, \2/' \ > "$toc_file" # Get all of the doc files in a natural sorted order. doc_files="$(/usr/bin/env ls -1v doc | grep '^ale-' | sed 's/^/doc\//' | paste -sd ' ' -)" # shellcheck disable=SC2086 grep -h '\*ale-.*-options\|^[a-z].*\*ale-.*\*$' $doc_files \ | sed 's/^/ /' \ | sed 's/ALE Shell Integration/ALE sh Integration/' \ | sed 's/ALE BibTeX Integration/ALE bib Integration/' \ | sed 's/ ALE \(.*\) Integration/\1/' \ | sed 's/ *\*\(..*\)\*$/, \1/' \ | tr '[:upper:]' '[:lower:]' \ | sed 's/objective-c/objc/' \ | sed 's/c++/cpp/' \ > "$heading_file" exit_code=0 in_section=0 section_index=0 # Prefix numbers to table of contents entries so that sections aren't mixed up # with sub-sections when they are sorted. while read -r; do if [[ "$REPLY" =~ ^\ ]]; then if ! ((in_section)); then let section_index='section_index + 1' in_section=1 fi else if ((in_section)); then let section_index='section_index + 1' in_section=0 fi fi echo "$section_index $REPLY" >> "$tagged_toc_file" done < "$toc_file" # Sort the sections and sub-sections and remove the tags. sort -sn "$tagged_toc_file" | sed 's/[0-9][0-9]* //' > "$sorted_toc_file" echo 'Check for bad ToC sorting:' echo diff -U2 "$sorted_toc_file" "$toc_file" || exit_code=$? echo 'Check for mismatched ToC and headings:' echo diff -U3 "$toc_file" "$heading_file" || exit_code=$? rm "$toc_file" rm "$heading_file" rm "$tagged_toc_file" rm "$sorted_toc_file" exit "$exit_code" ================================================ FILE: test/script/custom-checks ================================================ #!/usr/bin/env bash set -e set -u exit_code=0 docker_flags=(--rm -v "$PWD:/testplugin" -v "$PWD/test:/home" -w /testplugin "$DOCKER_RUN_IMAGE") echo '========================================' echo 'Running custom linting rules' echo '========================================' echo 'Custom warnings/errors follow:' echo set -o pipefail "$DOCKER" run "${docker_flags[@]}" test/script/custom-linting-rules . || exit_code=$? set +o pipefail echo echo '========================================' echo 'Checking for duplicate tags' echo '========================================' echo 'Duplicate tags follow:' echo set -o pipefail "$DOCKER" run "${docker_flags[@]}" test/script/check-duplicate-tags . || exit_code=$? set +o pipefail echo echo '========================================' echo 'Checking for invalid tag references' echo '========================================' echo 'Invalid tag references tags follow:' echo set -o pipefail "$DOCKER" run "${docker_flags[@]}" test/script/check-tag-references || exit_code=$? set +o pipefail echo '========================================' echo 'diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables' echo '========================================' echo 'Differences follow:' echo set -o pipefail "$DOCKER" run "${docker_flags[@]}" test/script/check-supported-tools-tables || exit_code=$? set +o pipefail echo '========================================' echo 'Look for badly aligned doc tags' echo '========================================' echo 'Badly aligned tags follow:' echo set -o pipefail "$DOCKER" run "${docker_flags[@]}" test/script/check-tag-alignment || exit_code=$? set +o pipefail echo '========================================' echo 'Look for table of contents issues' echo '========================================' echo set -o pipefail "$DOCKER" run "${docker_flags[@]}" test/script/check-toc || exit_code=$? set +o pipefail echo '========================================' echo 'Check Python code' echo '========================================' echo "$DOCKER" run --rm -v "$PWD:/testplugin" "$DOCKER_RUN_IMAGE" \ python -W ignore -m unittest discover /testplugin/test/python \ || exit_code=$? echo exit $exit_code ================================================ FILE: test/script/custom-linting-rules ================================================ #!/usr/bin/env bash set -e set -u # This Bash script implements custom sanity checks for scripts beyond what # Vint covers, which are easy to check with regex. # A flag for automatically fixing some errors. FIX_ERRORS=0 RETURN_CODE=0 function print_help() { echo "Usage: test/script/custom-linting-rules [--fix] [DIRECTORY]" 1>&2 echo 1>&2 echo " -h, --help Print this help text" 1>&2 echo " --fix Automatically fix some errors" 1>&2 exit 1 } while [ $# -ne 0 ]; do case $1 in -h) ;& --help) print_help ;; --fix) FIX_ERRORS=1 shift ;; --) shift break ;; -?*) echo "Invalid argument: $1" 1>&2 exit 1 ;; *) break ;; esac done if [ $# -eq 0 ] || [ -z "$1" ]; then print_help fi shopt -s globstar directories=("$@") check_errors() { regex="$1" message="$2" include_arg='' exclude_arg='' if [ $# -gt 2 ]; then include_arg="--include $3" fi if [ $# -gt 3 ]; then shift shift shift while (( "$#" )); do exclude_arg="$exclude_arg --exclude $1" shift done fi for directory in "${directories[@]}"; do # shellcheck disable=SC2086 while read -r; do line=$(cut -d ":" -f2 <<< "$REPLY") if ((line > 1)); then line=$((line - 1)) file=$(cut -d ":" -f1 <<< "$REPLY") if sed -n "${line},${line}p" $file | grep -q '^ *" *no-custom-checks$'; then continue fi fi RETURN_CODE=1 echo "$REPLY $message" done < <(grep -H -n "$regex" $include_arg $exclude_arg "$directory"/**/*.vim \ | grep -v 'no-custom-checks' \ | grep -o '^[^:]\+:[0-9]\+' \ | sed 's:^\./::') done } if (( FIX_ERRORS )); then for directory in "${directories[@]}"; do sed -i "s/^\(function.*)\) *$/\1 abort/" "$directory"/**/*.vim sed -i "s/shellescape(/ale#Escape(/" "$directory"/**/*.vim sed -i 's/==#/is#/g' "$directory"/**/*.vim 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 # The arguments are: regex, explanation, [filename_filter], [list, of, exclusions] check_errors \ '^function.*) *$' \ 'Function without abort keyword (See :help except-compat)' check_errors '^function[^!]' 'function without !' check_errors ' \+$' 'Trailing whitespace' check_errors '^ * end\?i\? *$' 'Write endif, not en, end, or endi' check_errors '^ [^ ]' 'Use four spaces, not two spaces' check_errors $'\t' 'Use four spaces, not tabs' # This check should prevent people from using a particular inconsistent name. check_errors 'let g:ale_\w\+_\w\+_args =' 'Name your option g:ale___options instead' check_errors 'shellescape(' 'Use ale#Escape instead of shellescape' check_errors 'simplify(' 'Use ale#path#Simplify instead of simplify' check_errors 'tempname(' 'Use ale#util#Tempname instead of tempname' check_errors 'getcurpos(' "Use getpos('.') instead of getcurpos() if you don't need curswant, to avoid a bug that changes curswant" check_errors "expand(['\"]%" "Use expand('#' . a:buffer . '...') instead. You might get a filename for the wrong buffer." check_errors 'getcwd()' "Do not use getcwd(), as it could run from the wrong buffer. Use expand('#' . a:buffer . ':p:h') instead." check_errors '==#' "Use 'is#' instead of '==#'. 0 ==# 'foobar' is true" check_errors '==?' "Use 'is?' instead of '==?'. 0 ==? 'foobar' is true" 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. Ignore with \" no-custom-checks if needed" check_errors '^ *:\?redir' 'User execute() instead of redir' # Exclusions for grandfathered-in exceptions exclusions="clojure/clj_kondo.vim elixir/elixir_ls.vim go/golangci_lint.vim swift/swiftformat.vim" # shellcheck disable=SC2086 check_errors $'name.:.*\'[a-z_]*[^a-z_0-9][a-z_0-9]*\',$' 'Use snake_case names for linters' '*/ale_linters/*' $exclusions # 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. GitHub Actions 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 ================================================ FILE: test/script/dumb_named_pipe_server.py ================================================ """ This Python script creates a named pipe server that does nothing but send its input back to the client that connects to it. Only one argument must be given, the path of a named pipe to bind to. """ import os import socket import sys def main(): if len(sys.argv) < 2: sys.exit('You must specify a filepath') sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if os.path.exists(sys.argv[1]): os.remove(sys.argv[1]) sock.bind(sys.argv[1]) sock.listen(0) pid = os.fork() if pid: print(pid) sys.exit() while True: connection = sock.accept()[0] connection.settimeout(5) while True: try: connection.send(connection.recv(1024)) except socket.timeout: break connection.close() if __name__ == "__main__": main() ================================================ FILE: test/script/dumb_tcp_client.py ================================================ """ This is just a script for testing that the dumb TCP server actually works correctly, for verifying that problems with tests are in Vim. Pass the same port number given to the test server to check that it's working. """ import socket import sys def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) result = sock.connect_ex(('127.0.0.1', int(sys.argv[1]))) if result: sock.close() sys.exit("Couldn't connect to the socket!") data_sent = 'x' * 1024 sock.send(data_sent) data_received = sock.recv(1024) if data_sent != data_received: sock.close() sys.exit("Data sent didn't match data received.") sock.close() print("Everything was just fine.") if __name__ == "__main__": main() ================================================ FILE: test/script/dumb_tcp_server.py ================================================ """ This Python script creates a TCP server that does nothing but send its input back to the client that connects to it. Only one argument must be given, a port to bind to. """ import os import socket import sys def main(): if len(sys.argv) < 2 or not sys.argv[1].isdigit(): sys.exit('You must specify a port number') sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(('127.0.0.1', int(sys.argv[1]))) sock.listen(0) pid = os.fork() if pid: print(pid) sys.exit() while True: connection = sock.accept()[0] connection.settimeout(5) while True: try: connection.send(connection.recv(1024)) except socket.timeout: break connection.close() if __name__ == "__main__": main() ================================================ FILE: test/script/run-lua-tests ================================================ #!/usr/bin/env bash set -e set -u docker_flags=(--rm -v "$PWD:/testplugin" -v "$PWD/test:/home" -w /testplugin/test/lua "$DOCKER_RUN_IMAGE") quiet=0 while [ $# -ne 0 ]; do case $1 in -q) quiet=1 shift ;; --) shift break ;; -?*) echo "Invalid argument: $1" 1>&2 exit 1 ;; *) break ;; esac done function filter-busted-output() { local hit_failure_line=0 while read -r; do if ((quiet)); then # If we're using the quiet flag, the filter out lines until we hit # the first line with "Failure" and then print the rest. if ((hit_failure_line)); then echo "$REPLY" elif [[ "$REPLY" = *'Failure'* ]]; then hit_failure_line=1 echo "$REPLY" fi else echo "$REPLY" fi done } exit_code=0 set -o pipefail "$DOCKER" run -a stdout "${docker_flags[@]}" /usr/bin/busted-5.1 \ -m '../../lua/?.lua;../../lua/?/init.lua' . \ --output utfTerminal | filter-busted-output || exit_code=$? set +o pipefail exit "$exit_code" ================================================ FILE: test/script/run-vader-tests ================================================ #!/usr/bin/env bash set -e set -u docker_flags=(--rm -v "$PWD:/testplugin" -v "$PWD/test:/home" -w /testplugin "$DOCKER_RUN_IMAGE") red='\033[0;31m' green='\033[0;32m' nc='\033[0m' verbose=0 quiet=0 while [ $# -ne 0 ]; do case $1 in -v) verbose=1 shift ;; -q) quiet=1 shift ;; --) shift break ;; -?*) echo "Invalid argument: $1" 1>&2 exit 1 ;; *) break ;; esac done vim="$1" tests="$2" echo "$vim" case $vim in # Neovim 0.6+ requires headless argument to load Vader tests. neovim*) headless='--headless' ;; *) headless='' ;; esac # This file will be used to track if tests ran or not. # We can't use a variable, because we need to set a value in a sub-shell. run_file="$(mktemp -t tests_ran.XXXXXXXX)" function filter-vader-output() { local hit_first_vader_line=0 # When verbose mode is off, suppress output until Vader starts. local start_output="$verbose" local filtered_data='' while read -r; do # Search for the first Vader output line. # We can try starting tests again if they don't start. if ((!hit_first_vader_line)); then if [[ "$REPLY" = *'Starting Vader:'* ]]; then hit_first_vader_line=1 fi fi if ((!start_output)); then if ((hit_first_vader_line)); then start_output=1 else continue fi fi if ((quiet)); then if [[ "$REPLY" = *'Starting Vader:'* ]]; then filtered_data="$REPLY" elif [[ "$REPLY" = *'Success/Total'* ]]; then success="$(echo -n "$REPLY" | grep -o '[0-9]\+/' | head -n1 | cut -d/ -f1)" total="$(echo -n "$REPLY" | grep -o '/[0-9]\+' | head -n1 | cut -d/ -f2)" if [ "$success" -lt "$total" ]; then echo "$filtered_data" echo "$REPLY" fi filtered_data='' else filtered_data="$filtered_data"$'\n'"$REPLY" fi else echo "$REPLY" fi done # Note that we managed to get the Vader tests started if we did. if ((hit_first_vader_line)); then echo 1 > "$run_file" fi } function color-vader-output() { while read -r; do if [[ "$REPLY" = *'[EXECUTE] (X)'* ]]; then echo -en "$red" elif [[ "$REPLY" = *'[EXECUTE]'* ]] || [[ "$REPLY" = *'[ GIVEN]'* ]]; then echo -en "$nc" fi if [[ "$REPLY" = *'Success/Total'* ]]; then success="$(echo -n "$REPLY" | grep -o '[0-9]\+/' | head -n1 | cut -d/ -f1)" total="$(echo -n "$REPLY" | grep -o '/[0-9]\+' | head -n1 | cut -d/ -f2)" if [ "$success" -lt "$total" ]; then echo -en "$red" else echo -en "$green" fi echo "$REPLY" echo -en "$nc" else echo "$REPLY" fi done echo -en "$nc" } echo echo '========================================' echo "Running tests for $vim" echo '========================================' echo tries=0 while [ "$tries" -lt 5 ]; do tries=$((tries + 1)) exit_code=0 set -o pipefail # shellcheck disable=SC2086 "$DOCKER" run -a stderr -e VADER_OUTPUT_FILE=/dev/stderr "${docker_flags[@]}" \ "/vim-build/bin/$vim" -u test/vimrc ${headless} \ "+Vader! $tests" 2>&1 | filter-vader-output | color-vader-output || exit_code=$? set +o pipefail if [ -s "$run_file" ]; then break fi done if [ "$tries" -gt 1 ]; then echo echo "Tried to run tests $tries times" fi rm "$run_file" exit "$exit_code" ================================================ FILE: test/script/run-vint ================================================ #!/usr/bin/env bash set -e set -u exit_code=0 docker_flags=(--rm -v "$PWD:/testplugin" -v "$PWD/test:/home" -w /testplugin "$DOCKER_RUN_IMAGE") echo '========================================' echo 'Running Vint to lint our code' echo '========================================' echo 'Vint warnings/errors follow:' echo set -o pipefail "$DOCKER" run -a stdout "${docker_flags[@]}" vint -s . || exit_code=$? set +o pipefail echo exit $exit_code ================================================ FILE: test/sign/test_linting_sets_signs.vader ================================================ Given foobar (Some imaginary filetype): var y = 3+3; var y = 3 Before: Save g:ale_buffer_info Save g:ale_echo_cursor Save g:ale_run_synchronously Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs Save g:ale_command_wrapper Save g:ale_use_neovim_diagnostics_api let g:ale_command_wrapper = '' let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks let g:ale_set_signs = 1 " Disable features we don't need for these tests. let g:ale_set_quickfix = 0 let g:ale_set_loclist = 0 let g:ale_set_highlights = 0 let g:ale_echo_cursor = 0 let g:ale_use_neovim_diagnostics_api = 0 call ale#sign#Clear() function! TestCallback(buffer, output) return [ \ {'lnum': 1, 'text': 'foo', 'type': 'W'}, \ {'lnum': 2, 'text': 'foo', 'type': 'E'}, \] endfunction function! CollectSigns() redir => l:output if has('nvim-0.4.2') || has('patch-8.1.614') silent exec 'sign place group=ale_signs' else silent exec 'sign place' endif redir END let l:actual_sign_list = [] for l:line in split(l:output, "\n") let l:match = matchlist(l:line, ale#sign#ParsePattern()) if len(l:match) > 0 call add(l:actual_sign_list, [l:match[1], l:match[3]]) endif endfor return l:actual_sign_list 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: delfunction TestCallback delfunction CollectSigns unlet! g:ale_run_synchronously_callbacks call ale#sign#Clear() call ale#linter#Reset() Execute(The signs should be updated after linting is done): ALELint call ale#test#FlushJobs() AssertEqual [['1', 'ALEWarningSign'], ['2', 'ALEErrorSign']], CollectSigns() Execute(Signs should not be set when diagnostics API integration is enabled): let g:ale_use_neovim_diagnostics_api = 1 ALELint call ale#test#FlushJobs() AssertEqual [], CollectSigns() ================================================ FILE: test/sign/test_sign_column_highlighting.vader ================================================ Before: Save g:ale_change_sign_column_color Save &verbose function! ParseHighlight(name) abort redir => l:output silent execute 'highlight ' . a:name redir end return substitute(join(split(l:output)[2:]), ' Last set.*', '', '') endfunction function! SetHighlight(name, syntax) abort let l:match = matchlist(a:syntax, '\vlinks to (.+)$') if !empty(l:match) execute 'highlight link ' . a:name . ' ' . l:match[1] else execute 'highlight ' . a:name . ' ' a:syntax endif endfunction let g:sign_highlight = ParseHighlight('SignColumn') After: Restore delfunction ParseHighlight call SetHighlight('SignColumn', g:sign_highlight) delfunction SetHighlight unlet! g:sign_highlight call ale#sign#Clear() Execute(The SignColumn highlight shouldn't be changed if the option is off): let g:ale_change_sign_column_color = 0 let b:sign_highlight = ParseHighlight('SignColumn') call ale#sign#SetSigns(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'W', 'text': 'x'}, \]) AssertEqual b:sign_highlight, ParseHighlight('SignColumn') call ale#sign#SetSigns(bufnr(''), []) AssertEqual b:sign_highlight, ParseHighlight('SignColumn') Execute(The SignColumn highlight should be set and reset): let g:ale_change_sign_column_color = 1 call ale#sign#SetSigns(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'W', 'text': 'x'}, \]) AssertEqual 'links to ALESignColumnWithErrors', ParseHighlight('SignColumn') call ale#sign#SetSigns(bufnr(''), []) AssertEqual 'links to ALESignColumnWithoutErrors', ParseHighlight('SignColumn') Execute(The SignColumn should be correctly parsed when verbose=1): set verbose=1 highlight SignColumn ctermfg=246 ctermbg=7 guifg=#839496 guibg=Grey call ale#sign#SetUpDefaultColumnWithoutErrorsHighlight() AssertEqual \ has('nvim') \ ? 'ctermfg=246 ctermbg=7 guifg=#839496 guibg=Grey' \ : 'term=standout ctermfg=246 ctermbg=7 guifg=#839496 guibg=Grey', \ ParseHighlight('ALESignColumnWithoutErrors') ================================================ FILE: test/sign/test_sign_limits.vader ================================================ Before: Save g:ale_max_signs let g:ale_max_signs = -1 function! SetNProblems(sign_count) let l:loclist = [] let l:range = range(1, a:sign_count) call setline(1, l:range) for l:index in l:range call add(l:loclist, { \ 'bufnr': bufnr(''), \ 'lnum': l:index, \ 'col': 1, \ 'type': 'E', \ 'text': 'a', \}) endfor call ale#sign#SetSigns(bufnr(''), l:loclist) return sort(map(ale#sign#FindCurrentSigns(bufnr(''))[1], 'v:val[0]'), 'n') endfunction After: Restore unlet! b:ale_max_signs delfunction SetNProblems call ale#sign#Clear() Execute(There should be no limit on signs with negative numbers): AssertEqual range(1, 42), SetNProblems(42) Execute(0 signs should be set when the max is 0): let g:ale_max_signs = 0 AssertEqual [], SetNProblems(42) Execute(10 signs should be set when the max is 10): let g:ale_max_signs = 10 " We'll check that we set signs for the first 10 items, not other lines. AssertEqual range(1, 10), SetNProblems(42) Execute(5 signs should be set when the max is 5 for the buffer): let b:ale_max_signs = 5 AssertEqual range(1, 5), SetNProblems(42) ================================================ FILE: test/sign/test_sign_parsing.vader ================================================ Execute (Parsing English signs should work): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [0, [[9, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([ \ 'Signs for app.js:', \ ' line=9 id=1000001 group=ale_signs name=ALEWarningSign', \ ]) else AssertEqual \ [0, [[9, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([ \ 'Signs for app.js:', \ ' line=9 id=1000001 name=ALEWarningSign', \ ]) endif Execute (Parsing Russian signs should work): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [0, [[1, 1000001, 'ALEErrorSign']]], \ ale#sign#ParseSigns([' строка=1 id=1000001 группа=ale_signs имя=ALEErrorSign']) else AssertEqual \ [0, [[1, 1000001, 'ALEErrorSign']]], \ ale#sign#ParseSigns([' строка=1 id=1000001 имя=ALEErrorSign']) endif Execute (Parsing Japanese signs should work): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [0, [[1, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([' 行=1 識別子=1000001 グループ=ale_signs 名前=ALEWarningSign']) else AssertEqual \ [0, [[1, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([' 行=1 識別子=1000001 名前=ALEWarningSign']) endif Execute (Parsing Spanish signs should work): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [0, [[12, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([' línea=12 id=1000001 grupo=ale_signs nombre=ALEWarningSign']) else AssertEqual \ [0, [[12, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([' línea=12 id=1000001 nombre=ALEWarningSign']) endif Execute (Parsing Italian signs should work): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [0, [[1, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([' riga=1 id=1000001, gruppo=ale_signs nome=ALEWarningSign']) else AssertEqual \ [0, [[1, 1000001, 'ALEWarningSign']]], \ ale#sign#ParseSigns([' riga=1 id=1000001, nome=ALEWarningSign']) endif Execute (Parsing German signs should work): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [0, [[235, 1000001, 'ALEErrorSign']]], \ ale#sign#ParseSigns([' Zeile=235 id=1000001 Gruppe=ale_signs Name=ALEErrorSign']) else AssertEqual \ [0, [[235, 1000001, 'ALEErrorSign']]], \ ale#sign#ParseSigns([' Zeile=235 id=1000001 Name=ALEErrorSign']) endif Execute (The sign parser should indicate if the dummy sign is set): if has('nvim-0.4.2') || has('patch-8.1.614') AssertEqual \ [1, [[1, 1000001, 'ALEErrorSign']]], \ ale#sign#ParseSigns([ \ ' строка=1 id=1000001 group=ale_signs имя=ALEErrorSign', \ ' line=1 id=1000000 group=ale_signs name=ALEDummySign', \ ]) else AssertEqual \ [1, [[1, 1000001, 'ALEErrorSign']]], \ ale#sign#ParseSigns([ \ ' строка=1 id=1000001 имя=ALEErrorSign', \ ' line=1 id=1000000 name=ALEDummySign', \ ]) endif ================================================ FILE: test/sign/test_sign_placement.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_echo_cursor Save g:ale_run_synchronously Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs Save g:ale_command_wrapper let g:ale_command_wrapper = '' let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 let g:ale_set_signs = 1 " Disable features we don't need for these tests. let g:ale_set_quickfix = 0 let g:ale_set_loclist = 0 let g:ale_set_highlights = 0 let g:ale_echo_cursor = 0 call ale#linter#Reset() call ale#sign#Clear() function! GenerateResults(buffer, output) return [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': 'foo', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'W', \ 'text': 'bar', \ }, \ { \ 'lnum': 3, \ 'col': 1, \ 'type': 'E', \ 'text': 'baz', \ }, \ { \ 'lnum': 4, \ 'col': 1, \ 'type': 'E', \ 'text': 'use this one', \ }, \ { \ 'lnum': 4, \ 'col': 2, \ 'type': 'W', \ 'text': 'ignore this one', \ }, \ { \ 'lnum': 5, \ 'col': 1, \ 'type': 'W', \ 'text': 'ignore this one', \ }, \ { \ 'lnum': 5, \ 'col': 2, \ 'type': 'E', \ 'text': 'use this one', \ }, \] endfunction function! ParseSigns() redir => l:output if has('nvim-0.4.2') || has('patch-8.1.614') silent sign place group=ale_signs else silent sign place endif redir END return map( \ split(l:output, '\n')[2:], \ 'matchlist(v:val, ''' . ale#sign#ParsePattern() . ''')[1:3]', \) endfunction call ale#linter#Define('testft', { \ 'name': 'x', \ 'executable': has('win32') ? 'cmd' : 'true', \ 'command': 'true', \ 'callback': 'GenerateResults', \}) After: Restore unlet! g:ale_run_synchronously_callbacks unlet! g:loclist delfunction GenerateResults delfunction ParseSigns call ale#linter#Reset() call ale#sign#Clear() Execute(ale#sign#GetSignName should return the right sign names): AssertEqual 'ALEErrorSign', ale#sign#GetSignName([{'type': 'E'}]) AssertEqual 'ALEStyleErrorSign', ale#sign#GetSignName([{'type': 'E', 'sub_type': 'style'}]) AssertEqual 'ALEWarningSign', ale#sign#GetSignName([{'type': 'W'}]) AssertEqual 'ALEStyleWarningSign', ale#sign#GetSignName([{'type': 'W', 'sub_type': 'style'}]) AssertEqual 'ALEInfoSign', ale#sign#GetSignName([{'type': 'I'}]) AssertEqual 'ALEErrorSign', ale#sign#GetSignName([ \ {'type': 'E'}, \ {'type': 'W'}, \ {'type': 'I'}, \ {'type': 'E', 'sub_type': 'style'}, \ {'type': 'W', 'sub_type': 'style'}, \]) AssertEqual 'ALEWarningSign', ale#sign#GetSignName([ \ {'type': 'W'}, \ {'type': 'I'}, \ {'type': 'E', 'sub_type': 'style'}, \ {'type': 'W', 'sub_type': 'style'}, \]) AssertEqual 'ALEInfoSign', ale#sign#GetSignName([ \ {'type': 'I'}, \ {'type': 'E', 'sub_type': 'style'}, \ {'type': 'W', 'sub_type': 'style'}, \]) AssertEqual 'ALEStyleErrorSign', ale#sign#GetSignName([ \ {'type': 'E', 'sub_type': 'style'}, \ {'type': 'W', 'sub_type': 'style'}, \]) AssertEqual 'ALEStyleWarningSign', ale#sign#GetSignName([ \ {'type': 'W', 'sub_type': 'style'}, \]) Given testft(A file with warnings/errors): Foo Bar Baz Fourth line Fifth line Execute(The current signs should be set for running a job): ALELint call ale#test#FlushJobs() AssertEqual \ [ \ ['1', '1000001', 'ALEErrorSign'], \ ['2', '1000002', 'ALEWarningSign'], \ ['3', '1000003', 'ALEErrorSign'], \ ['4', '1000004', 'ALEErrorSign'], \ ['5', '1000005', 'ALEErrorSign'], \ ], \ ParseSigns() Execute(Loclist items with sign_id values should be kept): if has('nvim-0.4.2') || has('patch-8.1.614') exec 'sign place 1000347 group=ale_signs line=3 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000348 group=ale_signs line=15 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000349 group=ale_signs line=16 name=ALEWarningSign buffer=' . bufnr('') else exec 'sign place 1000347 line=3 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000348 line=15 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000349 line=16 name=ALEWarningSign buffer=' . bufnr('') endif let g:loclist = [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'E', 'text': 'a', 'sign_id': 1000348}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1, 'type': 'W', 'text': 'b', 'sign_id': 1000349}, \ {'bufnr': bufnr(''), 'lnum': 3, 'col': 1, 'type': 'E', 'text': 'c', 'sign_id': 1000347}, \ {'bufnr': bufnr(''), 'lnum': 4, 'col': 1, 'type': 'W', 'text': 'd'}, \ {'bufnr': bufnr(''), 'lnum': 15, 'col': 2, 'type': 'W', 'text': 'e'}, \ {'bufnr': bufnr(''), 'lnum': 16, 'col': 2, 'type': 'E', 'text': 'f'}, \] call ale#sign#SetSigns(bufnr(''), g:loclist) " Sign IDs from before should be kept, and new signs should use " IDs that haven't been used yet. AssertEqual \ [ \ {'bufnr': bufnr(''), 'lnum': 3, 'col': 1, 'type': 'E', 'text': 'c', 'sign_id': 1000347}, \ {'bufnr': bufnr(''), 'lnum': 4, 'col': 1, 'type': 'W', 'text': 'd', 'sign_id': 1000350}, \ {'bufnr': bufnr(''), 'lnum': 15, 'col': 1, 'type': 'E', 'text': 'a', 'sign_id': 1000348}, \ {'bufnr': bufnr(''), 'lnum': 15, 'col': 2, 'type': 'W', 'text': 'e', 'sign_id': 1000348}, \ {'bufnr': bufnr(''), 'lnum': 16, 'col': 1, 'type': 'W', 'text': 'b', 'sign_id': 1000351}, \ {'bufnr': bufnr(''), 'lnum': 16, 'col': 2, 'type': 'E', 'text': 'f', 'sign_id': 1000351}, \ ], \ g:loclist " Items should be grouped again. We should see error signs, where there " were warnings before, and errors where there were errors and where we " now have new warnings. AssertEqual \ [ \ ['15', '1000348', 'ALEErrorSign'], \ ['16', '1000351', 'ALEErrorSign'], \ ['3', '1000347', 'ALEErrorSign'], \ ['4', '1000350', 'ALEWarningSign'], \ ], \ sort(ParseSigns()) Execute(Items for other buffers should be ignored): let g:loclist = [ \ {'bufnr': bufnr('') - 1, 'lnum': 1, 'col': 1, 'type': 'E', 'text': 'a'}, \ {'bufnr': bufnr('') - 1, 'lnum': 2, 'col': 1, 'type': 'E', 'text': 'a', 'sign_id': 1000347}, \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'E', 'text': 'a'}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1, 'type': 'W', 'text': 'b'}, \ {'bufnr': bufnr(''), 'lnum': 3, 'col': 1, 'type': 'E', 'text': 'c'}, \ {'bufnr': bufnr(''), 'lnum': 4, 'col': 1, 'type': 'W', 'text': 'd'}, \ {'bufnr': bufnr(''), 'lnum': 15, 'col': 2, 'type': 'W', 'text': 'e'}, \ {'bufnr': bufnr(''), 'lnum': 16, 'col': 2, 'type': 'E', 'text': 'f'}, \ {'bufnr': bufnr('') + 1, 'lnum': 1, 'col': 1, 'type': 'E', 'text': 'a'}, \] call ale#sign#SetSigns(bufnr(''), g:loclist) AssertEqual \ [ \ ['1', '1000001', 'ALEErrorSign'], \ ['15', '1000005', 'ALEWarningSign'], \ ['16', '1000006', 'ALEErrorSign'], \ ['2', '1000002', 'ALEWarningSign'], \ ['3', '1000003', 'ALEErrorSign'], \ ['4', '1000004', 'ALEWarningSign'], \ ], \ sort(ParseSigns()) Execute(Signs should be downgraded correctly): call ale#sign#SetSigns(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'E', 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1, 'type': 'W', 'text': 'x'}, \]) AssertEqual \ [ \ ['1', '1000001', 'ALEErrorSign'], \ ['2', '1000002', 'ALEWarningSign'], \ ], \ sort(ParseSigns()) call ale#sign#SetSigns(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'W', 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1, 'type': 'I', 'text': 'x'}, \]) AssertEqual \ [ \ ['1', '1000003', 'ALEWarningSign'], \ ['2', '1000004', 'ALEInfoSign'], \ ], \ sort(ParseSigns()) Execute(Signs should be upgraded correctly): call ale#sign#SetSigns(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'W', 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1, 'type': 'I', 'text': 'x'}, \]) AssertEqual \ [ \ ['1', '1000001', 'ALEWarningSign'], \ ['2', '1000002', 'ALEInfoSign'], \ ], \ sort(ParseSigns()) call ale#sign#SetSigns(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 1, 'type': 'E', 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1, 'type': 'W', 'text': 'x'}, \]) AssertEqual \ [ \ ['1', '1000003', 'ALEErrorSign'], \ ['2', '1000004', 'ALEWarningSign'], \ ], \ sort(ParseSigns()) Execute(It should be possible to clear signs with empty lists): " We can fail to remove signs if there are multiple signs on one line, " say after deleting lines in Vim, etc. if has('nvim-0.4.2') || has('patch-8.1.614') exec 'sign place 1000347 group=ale_signs line=3 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000348 group=ale_signs line=3 name=ALEWarningSign buffer=' . bufnr('') exec 'sign place 1000349 group=ale_signs line=10 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000350 group=ale_signs line=10 name=ALEWarningSign buffer=' . bufnr('') else exec 'sign place 1000347 line=3 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000348 line=3 name=ALEWarningSign buffer=' . bufnr('') exec 'sign place 1000349 line=10 name=ALEErrorSign buffer=' . bufnr('') exec 'sign place 1000350 line=10 name=ALEWarningSign buffer=' . bufnr('') endif call ale#sign#SetSigns(bufnr(''), []) AssertEqual [], ParseSigns() Execute(No exceptions should be thrown when setting signs for invalid buffers): call ale#sign#SetSigns(123456789, [{'lnum': 15, 'col': 2, 'type': 'W', 'text': 'e'}]) ================================================ FILE: test/smoke_test.vader ================================================ Before: Save g:ale_enabled Save g:ale_set_lists_synchronously Save g:ale_buffer_info Save &shell let g:ale_enabled = 1 let g:ale_buffer_info = {} let g:ale_set_lists_synchronously = 1 function! TestCallback(buffer, output) " Windows adds extra spaces to the text from echo. return [{ \ 'lnum': 2, \ 'col': 3, \ 'text': substitute(a:output[0], ' *$', '', ''), \}] endfunction function! TestCallback2(buffer, output) return [{ \ 'lnum': 3, \ 'col': 4, \ 'text': substitute(a:output[0], ' *$', '', ''), \}] endfunction " Running the command in another subshell seems to help here. 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! g:i unlet! g:results unlet! g:expected_results delfunction TestCallback delfunction TestCallback2 call ale#engine#Cleanup(bufnr('')) call ale#linter#Reset() Given foobar (Some imaginary filetype): foo bar baz Execute(Linters should run with the default options): AssertEqual 'foobar', &filetype let g:expected_results = [{ \ 'bufnr': bufnr('%'), \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'foo bar', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }] " Try the test a few times over in NeoVim 0.3 or Windows or Vim 8.2, " where tests fail randomly. for g:i in range(has('nvim-0.3') || has('win32') || has('patch-8.2.2401') ? 5 : 1) call ale#Queue(0, '') call ale#test#WaitForJobs(2000) let g:results = ale#test#GetLoclistWithoutNewerKeys() if g:results == g:expected_results break endif endfor AssertEqual g:expected_results, g:results Execute(Linters should run in PowerShell too): if has('win32') set shell=powershell AssertEqual 'foobar', &filetype " Replace the callback to handle two lines. function! TestCallback(buffer, output) " Windows adds extra spaces to the text from echo. return [ \ { \ 'lnum': 1, \ 'col': 3, \ 'text': substitute(a:output[0], ' *$', '', ''), \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': substitute(a:output[1], ' *$', '', ''), \ }, \] endfunction " Recreate the command string to use &&, which PowerShell does not support. call ale#linter#Reset() call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': 'cmd', \ 'command': 'echo foo && echo bar', \}) call ale#Queue(0, '') call ale#test#WaitForJobs(4000) AssertEqual [ \ { \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 3, \ 'text': 'foo', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }, \ { \ 'bufnr': bufnr('%'), \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'bar', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }, \], ale#test#GetLoclistWithoutNewerKeys() endif ================================================ FILE: test/test-files/.circleci/config.yml ================================================ ================================================ FILE: test/test-files/.gitignore ================================================ # Don't ignore hidden files for this directory !.* ================================================ FILE: test/test-files/ada/testfile.adb ================================================ ================================================ FILE: test/test-files/ant/ant-project/build.xml ================================================ ================================================ FILE: test/test-files/ant/bin/ant ================================================ ================================================ FILE: test/test-files/bazel/BUILD ================================================ ================================================ FILE: test/test-files/bazel/WORKSPACE ================================================ ================================================ FILE: test/test-files/bazel/defs.bzl ================================================ ================================================ FILE: test/test-files/bib/dummy.bib ================================================ ================================================ FILE: test/test-files/biome/json/biome.json ================================================ ================================================ FILE: test/test-files/biome/json/src/test.ts ================================================ ================================================ FILE: test/test-files/biome/jsonc/biome.jsonc ================================================ ================================================ FILE: test/test-files/biome/jsonc/src/test.ts ================================================ ================================================ FILE: test/test-files/bzl/bazel-package/BUILD.bazel ================================================ ================================================ FILE: test/test-files/c/build_compile_commands_project/build/bad_folder_to_test_priority ================================================ ================================================ FILE: test/test-files/c/build_compile_commands_project/build/compile_commands.json ================================================ ================================================ FILE: test/test-files/c/configure_project/Makefile ================================================ ================================================ FILE: test/test-files/c/configure_project/configure ================================================ ================================================ FILE: test/test-files/c/configure_project/include/test.h ================================================ ================================================ FILE: test/test-files/c/configure_project/subdir/Makefile ================================================ ================================================ FILE: test/test-files/c/dummy.c ================================================ ================================================ FILE: test/test-files/c/git_and_nested_makefiles/include/test.h ================================================ ================================================ FILE: test/test-files/c/git_and_nested_makefiles/src/Makefile ================================================ ================================================ FILE: test/test-files/c/gnumakefile_project/GNUmakefile ================================================ ================================================ FILE: test/test-files/c/gnumakefile_project/file.c ================================================ ================================================ FILE: test/test-files/c/h_file_project/Makefile ================================================ ================================================ FILE: test/test-files/c/h_file_project/subdir/dummy ================================================ ================================================ FILE: test/test-files/c/h_file_project/test.h ================================================ ================================================ FILE: test/test-files/c/hpp_file_project/Makefile ================================================ ================================================ FILE: test/test-files/c/hpp_file_project/subdir/dummy ================================================ ================================================ FILE: test/test-files/c/hpp_file_project/test.hpp ================================================ ================================================ FILE: test/test-files/c/json_project/build/compile_commands.json ================================================ ================================================ FILE: test/test-files/c/json_project/include/test.h ================================================ ================================================ FILE: test/test-files/c/json_project/subdir/dummy ================================================ ================================================ FILE: test/test-files/c/makefile_project/Makefile ================================================ ================================================ FILE: test/test-files/c/makefile_project/_astylerc ================================================ ================================================ FILE: test/test-files/c/makefile_project/args ================================================ foolib.a -DARGS1 @subdir/args ================================================ FILE: test/test-files/c/makefile_project/include/test.h ================================================ ================================================ FILE: test/test-files/c/makefile_project/subdir/args ================================================ -DARGS2 ================================================ FILE: test/test-files/c/makefile_project/subdir/dummy ================================================ ================================================ FILE: test/test-files/c/makefile_project/subdir/file.c ================================================ ================================================ FILE: test/test-files/cargo/Cargo.toml ================================================ ================================================ FILE: test/test-files/cargo/workspace_paths/Cargo.toml ================================================ ================================================ FILE: test/test-files/cargo/workspace_paths/subpath/Cargo.toml ================================================ ================================================ FILE: test/test-files/ccls/with_build_dir/unusual_build_dir_name/compile_commands.json ================================================ ================================================ FILE: test/test-files/ccls/with_ccls/.ccls ================================================ ================================================ FILE: test/test-files/ccls/with_ccls-root/.ccls-root ================================================ ================================================ FILE: test/test-files/ccls/with_compile_commands_json/compile_commands.json ================================================ ================================================ FILE: test/test-files/checkstyle/other_config.xml ================================================ ================================================ FILE: test/test-files/clangd/with_build_dir/unusual_build_dir_name/compile_commands.json ================================================ ================================================ FILE: test/test-files/clangd/with_compile_commands/compile_commands.json ================================================ ================================================ FILE: test/test-files/clangformat/with_clangformat/.clang-format ================================================ ================================================ FILE: test/test-files/cpp/.astylerc ================================================ ================================================ FILE: test/test-files/cpp/dummy.cpp ================================================ ================================================ FILE: test/test-files/cppcheck/one/compile_commands.json ================================================ ================================================ FILE: test/test-files/cppcheck/one/two/three/file.c ================================================ ================================================ FILE: test/test-files/cppcheck/one/two/three/file.cpp ================================================ ================================================ FILE: test/test-files/cppcheck/with_build_dir/build/compile_commands.json ================================================ ================================================ FILE: test/test-files/cquery/build/compile_commands.json ================================================ ================================================ FILE: test/test-files/cquery/with_cquery/.cquery ================================================ ================================================ FILE: test/test-files/csslint/other-app/testfile.css ================================================ ================================================ FILE: test/test-files/csslint/some-app/.csslintrc ================================================ ================================================ FILE: test/test-files/csslint/some-app/subdir/testfile.css ================================================ ================================================ FILE: test/test-files/cucumber/features/cuke.feature ================================================ ================================================ FILE: test/test-files/cucumber/features/step_definitions/base_steps.rb ================================================ ================================================ FILE: test/test-files/d/test.d ================================================ ================================================ FILE: test/test-files/dart/.packages ================================================ ================================================ FILE: test/test-files/dart/testfile.dart ================================================ ================================================ FILE: test/test-files/dprint/blank.ts ================================================ ================================================ FILE: test/test-files/dprint/dprint.json ================================================ ================================================ FILE: test/test-files/elixir/mix_project/lib/app.ex ================================================ ================================================ FILE: test/test-files/elixir/mix_project/mix.exs ================================================ defmodule Test.MixProject do # fake mix project file end ================================================ FILE: test/test-files/elixir/testfile.ex ================================================ ================================================ FILE: test/test-files/elixir/umbrella_project/apps/app1/lib/app.ex ================================================ ================================================ FILE: test/test-files/elixir/umbrella_project/apps/app1/mix.exs ================================================ ================================================ FILE: test/test-files/elixir/umbrella_project/apps/app2/lib/app.ex ================================================ ================================================ FILE: test/test-files/elixir/umbrella_project/apps/app2/mix.exs ================================================ ================================================ FILE: test/test-files/elixir/umbrella_project/mix.exs ================================================ ================================================ FILE: test/test-files/elm/newapp/elm.json ================================================ ================================================ FILE: test/test-files/elm/newapp/src/Main.elm ================================================ ================================================ FILE: test/test-files/elm/newapp/tests/TestSuite.elm ================================================ ================================================ FILE: test/test-files/elm/newapp-notests/elm.json ================================================ ================================================ FILE: test/test-files/elm/newapp-notests/tests/TestMain.elm ================================================ ================================================ FILE: test/test-files/elm/oldapp/elm-package.json ================================================ ================================================ FILE: test/test-files/elm/oldapp/src/Main.elm ================================================ ================================================ FILE: test/test-files/elm/oldapp/tests/TestSuite.elm ================================================ ================================================ FILE: test/test-files/elm/src/subdir/testfile.elm ================================================ ================================================ FILE: test/test-files/erlang/app_with_elvis_config/elvis.config ================================================ ================================================ FILE: test/test-files/erlang/app_with_erlang_ls_config/_build/default/lib/dep/erlang_ls.config ================================================ ================================================ FILE: test/test-files/erlang/app_with_erlang_ls_config/deps/dep/erlang_ls.config ================================================ ================================================ FILE: test/test-files/erlang/app_with_erlang_ls_config/erlang_ls.config ================================================ ================================================ FILE: test/test-files/erlang/app_with_erlfmt/erlfmt ================================================ ================================================ FILE: test/test-files/erlang/erlang_mk_app/deps/dep/erlang.mk ================================================ ================================================ FILE: test/test-files/erlang/erlang_mk_app/erlang.mk ================================================ ================================================ FILE: test/test-files/erlang/kerl_otp_root/.kerl_config ================================================ ================================================ FILE: test/test-files/erlang/rebar3_app/_checkouts/dep/_build/.gitkeep ================================================ ================================================ FILE: test/test-files/eruby/dummy.html.erb ================================================ ================================================ FILE: test/test-files/eslint/astro-app/.eslintrc.js ================================================ ================================================ FILE: test/test-files/eslint/astro-app/package.json ================================================ ================================================ FILE: test/test-files/eslint/astro-app/src/pages/index.astro ================================================ --- --- Astro

Astro

================================================ FILE: test/test-files/eslint/astro-app/tsconfig.json ================================================ ================================================ FILE: test/test-files/eslint/other-app/subdir/testfile.js ================================================ ================================================ FILE: test/test-files/eslint/package.json ================================================ ================================================ FILE: test/test-files/eslint/react-app/.eslintrc.js ================================================ ================================================ FILE: test/test-files/eslint/react-app/subdir/testfile.css ================================================ ================================================ FILE: test/test-files/eslint/react-app/subdir/testfile.js ================================================ ================================================ FILE: test/test-files/eslint/react-app/subdir/testfile.ts ================================================ ================================================ FILE: test/test-files/eslint/react-app/subdir-with-config/.eslintrc ================================================ ================================================ FILE: test/test-files/eslint/react-app/subdir-with-package-json/package.json ================================================ ================================================ FILE: test/test-files/eslint/yarn2-app/.eslintrc.js ================================================ ================================================ FILE: test/test-files/eslint/yarn2-app/.yarn/sdks/eslint/bin/eslint.js ================================================ ================================================ FILE: test/test-files/eslint/yarn2-app/subdir/testfile.js ================================================ ================================================ FILE: test/test-files/fecs/fecs ================================================ ================================================ FILE: test/test-files/fish/testfile.fish ================================================ ================================================ FILE: test/test-files/flow/a/.flowconfig ================================================ ================================================ FILE: test/test-files/flow/a/sub/dummy ================================================ ================================================ FILE: test/test-files/flow/b/sub/dummy ================================================ ================================================ FILE: test/test-files/fortls-project/.fortls ================================================ { } ================================================ FILE: test/test-files/gleam/gleam.toml ================================================ ================================================ FILE: test/test-files/gleam/testfile.gleam ================================================ ================================================ FILE: test/test-files/go/go.mod ================================================ ================================================ FILE: test/test-files/go/go1/prj1/file.go ================================================ ================================================ FILE: test/test-files/go/go2/prj2/file.go ================================================ ================================================ FILE: test/test-files/go/gopath/bin/gopls ================================================ ================================================ FILE: test/test-files/go/gopath/bin/staticcheck ================================================ ================================================ FILE: test/test-files/go/testfile.go ================================================ ================================================ FILE: test/test-files/go/testfile2.go ================================================ ================================================ FILE: test/test-files/gradle/build-gradle-project/build.gradle ================================================ ================================================ FILE: test/test-files/gradle/build-gradle-project/src/main/kotlin/dummy.kt ================================================ ================================================ FILE: test/test-files/gradle/gradle ================================================ ================================================ FILE: test/test-files/gradle/non-gradle-project/src/main/kotlin/dummy.kt ================================================ ================================================ FILE: test/test-files/gradle/settings-gradle-project/settings.gradle ================================================ ================================================ FILE: test/test-files/gradle/settings-gradle-project/src/main/kotlin/dummy.kt ================================================ ================================================ FILE: test/test-files/gradle/unwrapped-project/build.gradle ================================================ ================================================ FILE: test/test-files/gradle/unwrapped-project/settings.gradle ================================================ ================================================ FILE: test/test-files/gradle/unwrapped-project/src/main/kotlin/dummy.kt ================================================ ================================================ FILE: test/test-files/gradle/wrapped-project/build.gradle ================================================ ================================================ FILE: test/test-files/gradle/wrapped-project/gradlew ================================================ ================================================ FILE: test/test-files/gradle/wrapped-project/settings.gradle ================================================ ================================================ FILE: test/test-files/gradle/wrapped-project/src/main/kotlin/dummy.kt ================================================ ================================================ FILE: test/test-files/hamllint/haml-lint-and-rubocop/.haml-lint.yml ================================================ ================================================ FILE: test/test-files/hamllint/haml-lint-and-rubocop/.rubocop.yml ================================================ ================================================ FILE: test/test-files/hamllint/haml-lint-and-rubocop/subdir/file.haml ================================================ ================================================ FILE: test/test-files/hamllint/haml-lint-yml/.haml-lint.yml ================================================ ================================================ FILE: test/test-files/hamllint/haml-lint-yml/subdir/file.haml ================================================ ================================================ FILE: test/test-files/hamllint/rubocop-yml/.rubocop.yml ================================================ ================================================ FILE: test/test-files/hamllint/rubocop-yml/subdir/file.haml ================================================ ================================================ FILE: test/test-files/haskell/haskell-packages-project/cabal.project ================================================ ================================================ FILE: test/test-files/haskell/haskell-packages-project/package-a/package-a.cabal ================================================ ================================================ FILE: test/test-files/haskell/haskell-packages-project/package-a/src/folder/dummy.hs ================================================ ================================================ FILE: test/test-files/haskell/haskell-simple-package/package-a/package-a.cabal ================================================ ================================================ FILE: test/test-files/haskell/haskell-simple-package/package-a/src/folder/dummy.hs ================================================ ================================================ FILE: test/test-files/hdl_server/foo.vhd ================================================ ================================================ FILE: test/test-files/hdl_server/with_config_file/.hdl_checker.config ================================================ ================================================ FILE: test/test-files/hdl_server/with_config_file/_hdl_checker.config ================================================ ================================================ FILE: test/test-files/hdl_server/with_config_file/foo.vhd ================================================ ================================================ FILE: test/test-files/hdl_server/with_git/files/foo.vhd ================================================ ================================================ FILE: test/test-files/hie_paths/file.hs ================================================ ================================================ FILE: test/test-files/html_beautify/html-beautify ================================================ ================================================ FILE: test/test-files/html_beautify/test.html ================================================ ================================================ FILE: test/test-files/htmlhint/with_config/.htmlhintrc ================================================ ================================================ FILE: test/test-files/ink/story/main.ink ================================================ ================================================ FILE: test/test-files/inko/test.inko ================================================ ================================================ FILE: test/test-files/inko/tests/test/test_foo.inko ================================================ ================================================ FILE: test/test-files/java/no_main/src/test/java/com/something/dummy ================================================ ================================================ FILE: test/test-files/java/with_jaxb/src/main/java/com/something/dummy ================================================ ================================================ FILE: test/test-files/java/with_jaxb/src/main/jaxb/com/something/dummy ================================================ ================================================ FILE: test/test-files/java/with_main/build/gen/main/java/com/something/dummy ================================================ ================================================ FILE: test/test-files/java/with_main/build/gen2/main/java/com/something/dummy ================================================ ================================================ FILE: test/test-files/java/with_main/src/main/java/com/something/dummy ================================================ ================================================ FILE: test/test-files/java/with_main/src/test/java/com/something/dummy ================================================ ================================================ FILE: test/test-files/javascript/test.js ================================================ ================================================ FILE: test/test-files/javascript_deno/custom_import_map.json ================================================ { "imports": {} } ================================================ FILE: test/test-files/javascript_deno/import_map.json ================================================ { "imports": {} } ================================================ FILE: test/test-files/javascript_deno/main.js ================================================ console.log("Hello World"); ================================================ FILE: test/test-files/javascript_deno/tsconfig.json ================================================ { "compilerOptions": { "allowJs": true, "esModuleInterop": true, "experimentalDecorators": true, "inlineSourceMap": true, "isolatedModules": true, "jsx": "react", "lib": ["deno.window"], "module": "esnext", "strict": true, "target": "esnext", "useDefineForClassFields": true }, "includes": ["main.js"] } ================================================ FILE: test/test-files/json/testfile.json ================================================ {"answer":42} ================================================ FILE: test/test-files/jsonlint/app/src/app.json ================================================ ================================================ FILE: test/test-files/jsonlint/app-without-jsonlint/src/app.json ================================================ ================================================ FILE: test/test-files/julia/REQUIRE ================================================ ================================================ FILE: test/test-files/julia/test.jl ================================================ ================================================ FILE: test/test-files/kotlin/testfile.kt ================================================ ================================================ FILE: test/test-files/lean/lakefile_lean/Main.lean ================================================ ================================================ FILE: test/test-files/lean/lakefile_lean/lakefile.lean ================================================ ================================================ FILE: test/test-files/lean/lakefile_toml/Main.lean ================================================ ================================================ FILE: test/test-files/lean/lakefile_toml/lakefile.toml ================================================ ================================================ FILE: test/test-files/long-line/setup.cfg ================================================ [flake8] max-line-length = 90 ================================================ FILE: test/test-files/lua/testfile.lua ================================================ ================================================ FILE: test/test-files/markdown/testfile.md ================================================ ================================================ FILE: test/test-files/maven/maven-java-project/module1/mvnw ================================================ ================================================ FILE: test/test-files/maven/maven-java-project/module1/mvnw.cmd ================================================ ================================================ FILE: test/test-files/maven/maven-java-project/module1/pom.xml ================================================ ================================================ FILE: test/test-files/maven/maven-java-project/module1/src/main/java/dummy1.java ================================================ ================================================ FILE: test/test-files/maven/maven-java-project/module2/pom.xml ================================================ ================================================ FILE: test/test-files/maven/maven-java-project/module2/src/main/java/dummy2.java ================================================ ================================================ FILE: test/test-files/maven/maven-kotlin-project/pom.xml ================================================ ================================================ FILE: test/test-files/maven/maven-kotlin-project/src/main/kotlin/dummy.kt ================================================ ================================================ FILE: test/test-files/maven/mvn ================================================ ================================================ FILE: test/test-files/maven/non-maven-project/src/main/java/dummy.java ================================================ ================================================ FILE: test/test-files/nim/with-git/src/source.nim ================================================ ================================================ FILE: test/test-files/ocaml/testfile.ml ================================================ ================================================ FILE: test/test-files/ocamllsp/dune-project ================================================ ================================================ FILE: test/test-files/odin/main.odin ================================================ ================================================ FILE: test/test-files/ols/.merlin ================================================ ================================================ FILE: test/test-files/openscad/dummy.scad ================================================ ================================================ FILE: test/test-files/pascal/test.pas ================================================ ================================================ FILE: test/test-files/perl/dist-zilla/dist.ini ================================================ # https://metacpan.org/pod/Dist::Zilla ================================================ FILE: test/test-files/perl/dist-zilla/subdir/empty.pl ================================================ ================================================ FILE: test/test-files/perl/extutils-makemaker/Makefile.PL ================================================ # https://perldoc.perl.org/ExtUtils::MakeMaker ================================================ FILE: test/test-files/perl/extutils-makemaker/subdir/empty.pl ================================================ ================================================ FILE: test/test-files/perl/module-build/Build.PL ================================================ # https://metacpan.org/pod/Module::Build ================================================ FILE: test/test-files/perl/module-build/subdir/empty.pl ================================================ ================================================ FILE: test/test-files/php/project-with-php-cs-fixer/test.php ================================================ ================================================ FILE: test/test-files/php/project-with-php-cs-fixer/vendor/bin/php-cs-fixer ================================================ ================================================ FILE: test/test-files/php/project-with-phpcbf/foo/test.php ================================================ ================================================ FILE: test/test-files/php/project-with-phpcbf/vendor/bin/phpcbf ================================================ ================================================ FILE: test/test-files/php/project-with-pint/test.php ================================================ ================================================ FILE: test/test-files/php/project-with-pint/vendor/bin/pint ================================================ ================================================ FILE: test/test-files/php/project-without-php-cs-fixer/test.php ================================================ ================================================ FILE: test/test-files/php/project-without-phpcbf/foo/test.php ================================================ ================================================ FILE: test/test-files/php/project-without-pint/test.php ================================================ ================================================ FILE: test/test-files/php/vendor/bin/php-language-server.php ================================================ ================================================ FILE: test/test-files/php/with-composer/composer.json ================================================ ================================================ FILE: test/test-files/php/with-composer/vendor/bin/php-language-server.php ================================================ ================================================ FILE: test/test-files/php/with-git/vendor/bin/php-language-server.php ================================================ ================================================ FILE: test/test-files/phpcs/project-with-phpcs/foo/test.php ================================================ ================================================ FILE: test/test-files/phpcs/project-with-phpcs/vendor/bin/phpcs ================================================ ================================================ FILE: test/test-files/phpcs/project-without-phpcs/foo/test.php ================================================ ================================================ FILE: test/test-files/prettier/testfile ================================================ ================================================ FILE: test/test-files/prettier/testfile.css ================================================ ================================================ FILE: test/test-files/prettier/testfile.js ================================================ ================================================ FILE: test/test-files/prettier/testfile.json ================================================ ================================================ FILE: test/test-files/prettier/testfile.scss ================================================ ================================================ FILE: test/test-files/prettier/testfile.ts ================================================ ================================================ FILE: test/test-files/prettier/with_config/.prettierrc ================================================ ================================================ FILE: test/test-files/prettier/with_config/testfile.js ================================================ ================================================ FILE: test/test-files/prettier/with_prettierignore/.prettierignore ================================================ ================================================ FILE: test/test-files/prettier/with_prettierignore/src/testfile.js ================================================ ================================================ FILE: test/test-files/proto/testfile.proto ================================================ ================================================ FILE: test/test-files/psalm/vendor/bin/psalm ================================================ ================================================ FILE: test/test-files/puglint/package.json ================================================ ================================================ FILE: test/test-files/puglint/puglint_rc_dir/.pug-lintrc ================================================ ================================================ FILE: test/test-files/puglint/puglint_rc_js_dir/.pug-lintrc.js ================================================ ================================================ FILE: test/test-files/puglint/puglint_rc_json_dir/.pug-lintrc.json ================================================ ================================================ FILE: test/test-files/puppet/dummy.pp ================================================ ================================================ FILE: test/test-files/puppet/new-style-module/lib/puppet/types/exampletype.rb ================================================ ================================================ FILE: test/test-files/puppet/new-style-module/metadata.json ================================================ ================================================ FILE: test/test-files/puppet/new-style-module/template/template.epp ================================================ ================================================ FILE: test/test-files/puppet/old-style-module/manifests/init.pp ================================================ ================================================ FILE: test/test-files/puppet/old-style-module/templates/template.epp ================================================ ================================================ FILE: test/test-files/purescript/bower/Foo.purs ================================================ ================================================ FILE: test/test-files/purescript/bower/bower.json ================================================ ================================================ FILE: test/test-files/purescript/psc-package/Foo.purs ================================================ ================================================ FILE: test/test-files/purescript/psc-package/psc-package.json ================================================ ================================================ FILE: test/test-files/purescript/spago/Foo.purs ================================================ ================================================ FILE: test/test-files/purescript/spago/spago.dhall ================================================ ================================================ FILE: test/test-files/python/namespace_package_manifest/MANIFEST.in ================================================ include README.md include *.ini *.cfg *.txt include requirements/*.txt ================================================ FILE: test/test-files/python/namespace_package_manifest/namespace/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_manifest/namespace/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_pytest/namespace/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_pytest/namespace/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_pytest/pytest.ini ================================================ [pytest] DJANGO_SETTINGS_MODULE=foo.settings ================================================ FILE: test/test-files/python/namespace_package_setup/namespace/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_setup/namespace/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_setup/setup.cfg ================================================ [flake8] max-line-length = 119 ================================================ FILE: test/test-files/python/namespace_package_tox/namespace/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_tox/namespace/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/namespace_package_tox/tox.ini ================================================ [tox] envlist = py352 ================================================ FILE: test/test-files/python/no_virtualenv/subdir/foo/COMMIT_EDITMSG ================================================ ================================================ FILE: test/test-files/python/no_virtualenv/subdir/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/no_virtualenv/subdir/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/pyre_configuration_dir/.pyre_configuration.local ================================================ ================================================ FILE: test/test-files/python/pyre_configuration_dir/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/pyre_configuration_dir/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/python-package-project/.flake8 ================================================ ================================================ FILE: test/test-files/python/python-package-project/package-name/module.py ================================================ ================================================ FILE: test/test-files/python/with_bandit/.bandit ================================================ ================================================ FILE: test/test-files/python/with_bandit/namespace/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/with_bandit/namespace/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/with_mypy_ini_and_pytest_ini/mypy.ini ================================================ ================================================ FILE: test/test-files/python/with_mypy_ini_and_pytest_ini/tests/pytest.ini ================================================ ================================================ FILE: test/test-files/python/with_mypy_ini_and_pytest_ini/tests/testsubfolder/my_tests.py ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/dir_with_yapf_config/.style.yapf ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/Scripts/activate ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/activate ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/autoflake ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/autoimport ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/autopep8 ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/black ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/flake8 ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/flakehell ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/gitlint ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/isort ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/jedi-language-server ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/mypy ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pycln ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pyflakes ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pylama ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pylint ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pylsp ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pyre ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pyrefly ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/pyright-langserver ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/refurb ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/reorder-python-imports ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/ruff ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/tidy-imports ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/unimport ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/vulture ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/yamlfix ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/env/bin/yapf ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/subdir/foo/COMMIT_EDITMSG ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/subdir/foo/__init__.py ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/subdir/foo/bar.py ================================================ ================================================ FILE: test/test-files/python/with_virtualenv/subdir/foo/bar.pyi ================================================ ================================================ FILE: test/test-files/r/.Rprofile ================================================ ================================================ FILE: test/test-files/racket/many-inits/a/b/c/foo.rkt ================================================ #lang racket/base (displayln "foo") ================================================ FILE: test/test-files/racket/many-inits/a/b/c/init.rkt ================================================ #lang info ================================================ FILE: test/test-files/racket/many-inits/a/b/foo.rkt ================================================ #lang racket/base (displayln "foo") ================================================ FILE: test/test-files/racket/many-inits/a/b/init.rkt ================================================ #lang info ================================================ FILE: test/test-files/racket/many-inits/a/foo.rkt ================================================ #lang racket/base (displayln "foo") ================================================ FILE: test/test-files/racket/many-inits/a/init.rkt ================================================ #lang info ================================================ FILE: test/test-files/racket/many-inits/foo.rkt ================================================ #lang racket/base (displayln "foo") ================================================ FILE: test/test-files/racket/many-inits/init.rkt ================================================ #lang info ================================================ FILE: test/test-files/racket/simple-script/foo.rkt ================================================ #lang racket/base (displayln "foo") ================================================ FILE: test/test-files/reasonml/bsconfig.json ================================================ ================================================ FILE: test/test-files/reasonml/testfile.re ================================================ ================================================ FILE: test/test-files/rescript/rescript.json ================================================ ================================================ FILE: test/test-files/rescript/testfile-noextension ================================================ ================================================ FILE: test/test-files/rescript/testfile.res ================================================ ================================================ FILE: test/test-files/rescript/testfile.resi ================================================ ================================================ FILE: test/test-files/roc/main.roc ================================================ ================================================ FILE: test/test-files/ruby/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/nested/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/nested/foo/Steepfile ================================================ ================================================ FILE: test/test-files/ruby/nested/foo/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/nested/foo/one/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/nested/foo/two/Steepfile ================================================ ================================================ FILE: test/test-files/ruby/nested/foo/two/dummmy.rb ================================================ ================================================ FILE: test/test-files/ruby/nested/foo/two/three/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/not_a_rails_app/file.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_rails_app/app/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_rails_app/app/models/thing.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_rails_app/app/views/my_great_view.html.erb ================================================ ================================================ FILE: test/test-files/ruby/valid_rails_app/config/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_rails_app/db/dummy.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_ruby_app1/Rakefile ================================================ ================================================ FILE: test/test-files/ruby/valid_ruby_app1/lib/file.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_ruby_app2/Gemfile ================================================ ================================================ FILE: test/test-files/ruby/valid_ruby_app2/lib/file.rb ================================================ ================================================ FILE: test/test-files/ruby/valid_ruby_app3/.solargraph.yml ================================================ ================================================ FILE: test/test-files/ruby/valid_ruby_app3/lib/file.rb ================================================ ================================================ FILE: test/test-files/ruby/with_config/.rubocop.yml ================================================ ================================================ FILE: test/test-files/ruby/with_config/.standard.yml ================================================ ================================================ FILE: test/test-files/rust/cargo/Cargo.toml ================================================ ================================================ FILE: test/test-files/rust/cargo/testfile.rs ================================================ ================================================ FILE: test/test-files/rust/rust-project/rust-project.json ================================================ ================================================ FILE: test/test-files/rust/rust-project/testfile.rs ================================================ ================================================ FILE: test/test-files/rustywind/test.html ================================================ ================================================ FILE: test/test-files/scala/dummy.scala ================================================ ================================================ FILE: test/test-files/scala/invalid_sbt_project/Main.scala ================================================ ================================================ FILE: test/test-files/scala/valid_sbt_project/Main.scala ================================================ ================================================ FILE: test/test-files/scala/valid_sbt_project/build.sbt ================================================ ================================================ FILE: test/test-files/slimlint/.rubocop.yml ================================================ ================================================ FILE: test/test-files/slimlint/subdir/file.slim ================================================ ================================================ FILE: test/test-files/smlnj/cm/foo.sml ================================================ ================================================ FILE: test/test-files/smlnj/cm/path/to/bar.sml ================================================ ================================================ FILE: test/test-files/smlnj/cm/sources.cm ================================================ ================================================ FILE: test/test-files/smlnj/file/qux.sml ================================================ ================================================ FILE: test/test-files/solhint/Contract.sol ================================================ ================================================ FILE: test/test-files/solhint/package.json ================================================ ================================================ FILE: test/test-files/spectral/openapi.yaml ================================================ ================================================ FILE: test/test-files/stack/stack.yaml ================================================ ================================================ FILE: test/test-files/stylua/stylua_config_dir/stylua.toml ================================================ ================================================ FILE: test/test-files/stylua/stylua_dot_config_dir/.stylua.toml ================================================ ================================================ FILE: test/test-files/swaglint/docs/swagger.yaml ================================================ ================================================ FILE: test/test-files/swift/dummy.swift ================================================ ================================================ FILE: test/test-files/swift/non-swift-package-project/src/folder/dummy.swift ================================================ ================================================ FILE: test/test-files/swift/swift-package-project/Package.swift ================================================ ================================================ FILE: test/test-files/swift/swift-package-project/src/folder/dummy.swift ================================================ ================================================ FILE: test/test-files/swift/swift-package-project-with-config/.swift-format ================================================ { "version": 1, "lineLength": 100, "indentation": { "spaces": 4 }, "respectsExistingLineBreaks": true, "lineBreakBeforeControlFlowKeywords": true, "lineBreakBeforeEachArgument": true } ================================================ FILE: test/test-files/swift/swift-package-project-with-config/Package.swift ================================================ ================================================ FILE: test/test-files/swift/swift-package-project-with-config/src/folder/dummy.swift ================================================ ================================================ FILE: test/test-files/swiftlint/cocoapods/Pods/SwiftLint/swiftlint ================================================ ================================================ FILE: test/test-files/swiftlint/cocoapods-and-react-native/Pods/SwiftLint/swiftlint ================================================ ================================================ FILE: test/test-files/swiftlint/cocoapods-and-react-native/ios/Pods/SwiftLint/swiftlint ================================================ ================================================ FILE: test/test-files/swiftlint/react-native/ios/Pods/SwiftLint/swiftlint ================================================ ================================================ FILE: test/test-files/terraform/.terraform/dummy ================================================ ================================================ FILE: test/test-files/terraform/main.tf ================================================ ================================================ FILE: test/test-files/tex/sample1.tex ================================================ ================================================ FILE: test/test-files/tex/sample2.tex ================================================ ================================================ FILE: test/test-files/tex/testfile.tex ================================================ ================================================ FILE: test/test-files/tflint/foo/.tflint.hcl ================================================ ================================================ FILE: test/test-files/tflint/foo/bar.tf ================================================ ================================================ FILE: test/test-files/tfsec/json/.tfsec/config.json ================================================ ================================================ FILE: test/test-files/tfsec/json/main.tf ================================================ ================================================ FILE: test/test-files/tfsec/yml/.tfsec/config.yml ================================================ ================================================ FILE: test/test-files/tfsec/yml/main.tf ================================================ ================================================ FILE: test/test-files/tidy/.tidyrc ================================================ ================================================ FILE: test/test-files/tidy/test.html ================================================ ================================================ FILE: test/test-files/tidy/tidy ================================================ ================================================ FILE: test/test-files/toml/tombi/pyprojecttoml/pyproject.toml ================================================ ================================================ FILE: test/test-files/toml/tombi/pyprojecttoml/subdir/file.toml ================================================ ================================================ FILE: test/test-files/toml/tombi/tombitoml/subdir/file.toml ================================================ ================================================ FILE: test/test-files/toml/tombi/tombitoml/tombi.toml ================================================ ================================================ FILE: test/test-files/top/ale-special-directory-name-dont-use-this-please/empty-file ================================================ ================================================ FILE: test/test-files/top/example.ini ================================================ ================================================ FILE: test/test-files/top/middle/bottom/dummy.txt ================================================ ================================================ FILE: test/test-files/top/needle_dir/needle ================================================ ================================================ FILE: test/test-files/top/needle_dir/target/needle/.gitkeep ================================================ ================================================ FILE: test/test-files/top/needle_dir/target/query/buffer.txt ================================================ ================================================ FILE: test/test-files/top/needle_file/needle/.gitkeep ================================================ ================================================ FILE: test/test-files/top/needle_file/target/needle ================================================ ================================================ FILE: test/test-files/top/needle_file/target/query/buffer.txt ================================================ ================================================ FILE: test/test-files/tsserver/src/file1.ts ================================================ ================================================ FILE: test/test-files/tsserver/src/level-1/file2.ts ================================================ ================================================ FILE: test/test-files/tsserver/src/level-1/level-2/file3.ts ================================================ ================================================ FILE: test/test-files/tsserver/src/level-1/tsconfig.json ================================================ ================================================ FILE: test/test-files/tsserver/tsconfig.json ================================================ ================================================ FILE: test/test-files/typescript/custom_import_map.json ================================================ ================================================ FILE: test/test-files/typescript/import_map.json ================================================ ================================================ FILE: test/test-files/typescript/test.ts ================================================ ================================================ FILE: test/test-files/typescript/tsconfig.json ================================================ ================================================ FILE: test/test-files/verilog/verible/module.sv ================================================ ================================================ FILE: test/test-files/verilog/verible/verible.filelist ================================================ ./module.sv ================================================ FILE: test/test-files/vim/invalid_vim_project/test.vim ================================================ ================================================ FILE: test/test-files/vim/path_with_autoload/autoload/test.vim ================================================ ================================================ FILE: test/test-files/vim/path_with_autoload/test.vim ================================================ ================================================ FILE: test/test-files/vim/path_with_initvim/init.vim ================================================ ================================================ FILE: test/test-files/vim/path_with_plugin/plugin/test.vim ================================================ ================================================ FILE: test/test-files/vim/path_with_plugin/test.vim ================================================ ================================================ FILE: test/test-files/vim/path_with_vimrc/.vimrc ================================================ ================================================ FILE: test/test-files/volar/package.json ================================================ ================================================ FILE: test/test-files/volar/src/App.vue ================================================ ================================================ FILE: test/test-files/xml/dummy.xml ================================================ ================================================ FILE: test/test-files/xo/monorepo/package.json ================================================ ================================================ FILE: test/test-files/xo/monorepo/packages/a/index.js ================================================ ================================================ FILE: test/test-files/xo/monorepo/packages/a/index.ts ================================================ ================================================ FILE: test/test-files/xo/monorepo/packages/a/package.json ================================================ ================================================ FILE: test/test-files/yaml/test.yaml ================================================ ================================================ FILE: test/test-files/yara/dummy.yar ================================================ rule dummy { condition: false } ================================================ FILE: test/test-files/zig/build.zig ================================================ ================================================ FILE: test/test_ale_has.vader ================================================ Execute(Checks for versions below the current version should succeed): AssertEqual 1, ale#Has('ale-4.0.0') AssertEqual 1, ale#Has('ALE-2.2.1') AssertEqual 1, ale#Has('ALE-1.0.0') Execute(Checks for newer versions should fail): AssertEqual 0, ale#Has('ALE-20.0.0') ================================================ FILE: test/test_ale_info.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_cache_executable_check_failures Save g:ale_change_sign_column_color Save g:ale_command_wrapper Save g:ale_completion_delay Save g:ale_completion_enabled Save g:ale_completion_max_suggestions Save g:ale_disable_lsp Save g:ale_echo_cursor Save g:ale_echo_msg_error_str Save g:ale_echo_msg_format Save g:ale_echo_msg_info_str Save g:ale_echo_msg_warning_str Save g:ale_fix_on_save Save g:ale_fixers Save g:ale_history_enabled Save g:ale_history_log_output Save g:ale_info_default_mode Save g:ale_keep_list_window_open Save g:ale_lint_delay Save g:ale_lint_on_enter Save g:ale_lint_on_filetype_changed Save g:ale_lint_on_insert_leave Save g:ale_lint_on_save Save g:ale_lint_on_text_changed Save g:ale_linters Save g:ale_linters_explicit Save g:ale_linters_ignore Save g:ale_list_vertical Save g:ale_list_window_size Save g:ale_loclist_msg_format Save g:ale_lsp_error_messages Save g:ale_max_buffer_history_size Save g:ale_max_signs Save g:ale_maximum_file_size Save g:ale_open_list Save g:ale_pattern_options Save g:ale_pattern_options_enabled Save g:ale_root Save g:ale_set_balloons Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs Save g:ale_sign_column_always Save g:ale_sign_error Save g:ale_sign_info Save g:ale_sign_offset Save g:ale_sign_style_error Save g:ale_sign_style_warning Save g:ale_sign_warning Save g:ale_sign_highlight_linenrs Save g:ale_type_map Save g:ale_use_neovim_diagnostics_api Save g:ale_use_global_executables Save g:ale_virtualtext_cursor Save g:ale_warn_about_trailing_blank_lines Save g:ale_warn_about_trailing_whitespace unlet! b:ale_history let g:ale_buffer_info = {} let g:ale_cache_executable_check_failures = 0 let g:ale_change_sign_column_color = 0 let g:ale_command_wrapper = '' let g:ale_completion_delay = 100 let g:ale_completion_enabled = 0 let g:ale_completion_max_suggestions = 50 let g:ale_disable_lsp = 0 let g:ale_echo_cursor = 1 let g:ale_echo_msg_error_str = 'Error' let g:ale_echo_msg_format = '%code: %%s' let g:ale_echo_msg_info_str = 'Info' let g:ale_echo_msg_warning_str = 'Warning' let g:ale_fix_on_save = 0 let g:ale_history_enabled = 1 let g:ale_history_log_output = 1 " This needs to be set to echo for this series of tests. let g:ale_info_default_mode = 'echo' let g:ale_keep_list_window_open = 0 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 = 1 let g:ale_lint_on_save = 1 let g:ale_lint_on_text_changed = 'normal' let g:ale_linters_explicit = 0 let g:ale_linters_ignore = {'python': ['pyright']} let g:ale_list_vertical = 0 let g:ale_list_window_size = 10 let g:ale_loclist_msg_format = '%code: %%s' let g:ale_lsp_error_messages = {} let g:ale_max_buffer_history_size = 20 let g:ale_max_signs = -1 let g:ale_maximum_file_size = 0 let g:ale_open_list = 0 let g:ale_pattern_options = {} let g:ale_pattern_options_enabled = 0 let g:ale_root = {} let g:ale_set_balloons = 0 let g:ale_set_highlights = 1 let g:ale_set_loclist = 1 let g:ale_set_quickfix = 0 let g:ale_set_signs = 1 let g:ale_sign_column_always = 0 let g:ale_sign_error = '>>' let g:ale_sign_info = '--' let g:ale_sign_offset = 1000000 let g:ale_sign_style_error = '>>' let g:ale_sign_style_warning = '--' let g:ale_sign_warning = '--' let g:ale_sign_highlight_linenrs = 0 let g:ale_type_map = {} let g:ale_use_neovim_diagnostics_api = 0 let g:ale_use_global_executables = v:null let g:ale_virtualtext_cursor = 'disabled' let g:ale_warn_about_trailing_blank_lines = 1 let g:ale_warn_about_trailing_whitespace = 1 let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout'} let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout'} call ale#engine#ResetExecutableCache() call ale#linter#Reset() call ale#linter#PreventLoading('testft') let g:ale_linters = {} let g:ale_fixers = {} let g:ale_linter_aliases = {} let g:ale_buffer_info = {} let g:fixer_lines = [ \ ' Suggested Fixers:', \ ' ''foo'' - Fix things the foo way', \ ' ', \] let g:globals_lines = [ \ ' Global Variables:', \ 'let g:ale_cache_executable_check_failures = 0', \ 'let g:ale_change_sign_column_color = 0', \ 'let g:ale_command_wrapper = ''''', \ 'let g:ale_completion_delay = 100', \ 'let g:ale_completion_enabled = 0', \ 'let g:ale_completion_max_suggestions = 50', \ 'let g:ale_disable_lsp = 0', \ 'let g:ale_echo_cursor = 1', \ 'let g:ale_echo_msg_error_str = ''Error''', \ 'let g:ale_echo_msg_format = ''%code: %%s''', \ 'let g:ale_echo_msg_info_str = ''Info''', \ 'let g:ale_echo_msg_warning_str = ''Warning''', \ 'let g:ale_enabled = 1', \ 'let g:ale_fix_on_save = 0', \ 'let g:ale_fixers = {}', \ 'let g:ale_history_enabled = 1', \ 'let g:ale_info_default_mode = ''echo''', \ 'let g:ale_history_log_output = 1', \ 'let g:ale_keep_list_window_open = 0', \ '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 = 1', \ 'let g:ale_lint_on_save = 1', \ 'let g:ale_lint_on_text_changed = ''normal''', \ 'let g:ale_linter_aliases = {}', \ 'let g:ale_linters = {}', \ 'let g:ale_linters_explicit = 0', \ 'let g:ale_linters_ignore = {''python'': [''pyright'']}', \ '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', \ 'let g:ale_maximum_file_size = 0', \ 'let g:ale_open_list = 0', \ 'let g:ale_pattern_options = {}', \ 'let g:ale_pattern_options_enabled = 0', \ 'let g:ale_root = {}', \ 'let g:ale_set_balloons = 0', \ 'let g:ale_set_highlights = 1', \ 'let g:ale_set_loclist = 1', \ 'let g:ale_set_quickfix = 0', \ 'let g:ale_set_signs = 1', \ 'let g:ale_sign_column_always = 0', \ 'let g:ale_sign_error = ''>>''', \ 'let g:ale_sign_info = ''--''', \ 'let g:ale_sign_offset = 1000000', \ 'let g:ale_sign_style_error = ''>>''', \ 'let g:ale_sign_style_warning = ''--''', \ 'let g:ale_sign_warning = ''--''', \ 'let g:ale_sign_highlight_linenrs = 0', \ 'let g:ale_type_map = {}', \ 'let g:ale_use_neovim_diagnostics_api = 0', \ 'let g:ale_use_global_executables = v:null', \ 'let g:ale_virtualtext_cursor = ''disabled''', \ 'let g:ale_warn_about_trailing_blank_lines = 1', \ 'let g:ale_warn_about_trailing_whitespace = 1', \ ' ', \] let g:command_header = [ \ ' Command History:', \] function CheckInfo(expected_list) abort let l:output = '' redir => l:output noautocmd silent ALEInfo redir END AssertEqual a:expected_list, split(l:output, "\n") endfunction call ale#test#SetDirectory('/testplugin/test') call ale#fix#registry#Clear() call ale#fix#registry#Add('foo', 'x', [], 'Fix things the foo way') After: Restore if exists('g:info_test_file') && filereadable(g:info_test_file) call delete(g:info_test_file) endif unlet! g:testlinter1 unlet! g:testlinter2 unlet! b:ale_history unlet! b:ale_linters unlet! g:output unlet! g:fixer_lines unlet! g:variables_lines unlet! g:globals_string unlet! g:command_header unlet! g:ale_testft_testlinter1_foo unlet! g:ale_testft_testlinter1_bar unlet! g:ale_testft2_testlinter2_foo unlet! b:ale_testft2_testlinter2_foo unlet! g:ale_testft2_testlinter2_bar unlet! g:info_test_file unlet! g:ale_testft_build_dir_names unlet! g:ale_testft_testlinter2_option delfunction CheckInfo call ale#test#RestoreDirectory() call ale#fix#registry#ResetToDefaults() Given nolintersft (Empty buffer with no linters): Execute (ALEInfo with no linters should return the right output): call CheckInfo( \ [ \ ' Current Filetype: nolintersft', \ 'Available Linters: []', \ ' Enabled Linters: []', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given (Empty buffer with no filetype): Execute (ALEInfo should return buffer-local global ALE settings): let b:ale_linters = {'x': ['y']} call insert( \ g:globals_lines, \ 'let b:ale_linters = {''x'': [''y'']}', \ index(g:globals_lines, 'let g:ale_linters = {}') + 1 \) call CheckInfo( \ [ \ ' Current Filetype: ', \ 'Available Linters: []', \ ' Enabled Linters: []', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given (Empty buffer with no filetype): Execute (ALEInfo with no filetype should return the right output): call CheckInfo( \ [ \ ' Current Filetype: ', \ 'Available Linters: []', \ ' Enabled Linters: []', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft (Empty buffer): Execute (ALEInfo with a single linter should return the right output): call ale#linter#Define('testft', g:testlinter1) call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft (Empty buffer): Execute (ALEInfo with two linters should return the right output): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft (Empty buffer): Execute (ALEInfo should calculate enabled linters correctly): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter2']} let g:globals_lines[index(g:globals_lines, 'let g:ale_linters = {}')] \ = 'let g:ale_linters = {''testft'': [''testlinter2'']}' call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft (Empty buffer): Execute (ALEInfo should only return linters for current filetype): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo with compound filetypes should return linters for both of them): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should return appropriately named global variables): let g:ale_testft_testlinter1_foo = 'abc' let g:ale_testft_testlinter1_bar = ['abc'] let g:ale_testft2_testlinter2_foo = 123 let g:ale_testft2_testlinter2_bar = {'x': 'y'} call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + [ \ ' Linter Variables:', \ 'let g:ale_testft2_testlinter2_bar = {''x'': ''y''}', \ 'let g:ale_testft2_testlinter2_foo = 123', \ 'let g:ale_testft_testlinter1_bar = [''abc'']', \ 'let g:ale_testft_testlinter1_foo = ''abc''', \ ' ', \ ] \ + g:globals_lines \ + g:command_header \) Execute (ALEInfoToFile should write to a file correctly): let g:ale_testft_testlinter1_foo = 'abc' let g:ale_testft_testlinter1_bar = ['abc'] let g:ale_testft2_testlinter2_foo = 123 let g:ale_testft2_testlinter2_bar = {'x': 'y'} call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) let g:info_test_file = tempname() execute 'ALEInfoToFile ' . fnameescape(g:info_test_file) AssertEqual \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + [ \ ' Linter Variables:', \ 'let g:ale_testft2_testlinter2_bar = {''x'': ''y''}', \ 'let g:ale_testft2_testlinter2_foo = 123', \ 'let g:ale_testft_testlinter1_bar = [''abc'']', \ 'let g:ale_testft_testlinter1_foo = ''abc''', \ ' ', \ ] \ + g:globals_lines \ + g:command_header, \ readfile(g:info_test_file) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should buffer-local linter variables): let g:ale_testft2_testlinter2_foo = 123 let b:ale_testft2_testlinter2_foo = 456 call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + [ \ ' Linter Variables:', \ 'let g:ale_testft2_testlinter2_foo = 123', \ 'let b:ale_testft2_testlinter2_foo = 456', \ ' ', \ ] \ + g:globals_lines \ + g:command_header \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should output linter aliases): let g:testlinter1.aliases = ['testftalias1', 'testftalias2'] let g:testlinter2.aliases = ['testftalias3', 'testftalias4'] let g:ale_testft2_testlinter2_foo = 123 let b:ale_testft2_testlinter2_foo = 456 call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Linter Aliases:', \ '''testlinter1'' -> [''testftalias1'', ''testftalias2'']', \ '''testlinter2'' -> [''testftalias3'', ''testftalias4'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + [ \ ' Linter Variables:', \ 'let g:ale_testft2_testlinter2_foo = 123', \ 'let b:ale_testft2_testlinter2_foo = 456', \ ' ', \ ] \ + g:globals_lines \ + g:command_header \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should return command history): let b:ale_history = [ \ {'status': 'started', 'job_id': 347, 'command': 'first command'}, \ {'status': 'started', 'job_id': 347, 'command': ['/bin/bash', '\c', 'last command']}, \] call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \ + [ \ '', \ '(started) ''first command''', \ '(started) [''/bin/bash'', ''\c'', ''last command'']', \ ] \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo command history should print exit codes correctly): let b:ale_history = [ \ {'status': 'finished', 'exit_code': 0, 'job_id': 347, 'command': 'first command'}, \ {'status': 'finished', 'exit_code': 1, 'job_id': 347, 'command': ['/bin/bash', '\c', 'last command']}, \] call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \ + [ \ '', \ '(finished - exit code 0) ''first command''', \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', \ ] \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo command history should print command output if logging is on): let g:ale_history_log_output = 1 let b:ale_history = [ \ { \ 'status': 'finished', \ 'exit_code': 0, \ 'job_id': 347, \ 'command': 'first command', \ 'output': ['some', 'first command output'], \ }, \ { \ 'status': 'finished', \ 'exit_code': 1, \ 'job_id': 347, \ 'command': ['/bin/bash', '\c', 'last command'], \ 'output': ['different second command output'], \ }, \ { \ 'status': 'finished', \ 'exit_code': 0, \ 'job_id': 347, \ 'command': 'command with no output', \ 'output': [], \ }, \] call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \ + [ \ '', \ '(finished - exit code 0) ''first command''', \ '', \ '<<>>', \ 'some', \ 'first command output', \ '<<>>', \ '', \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', \ '', \ '<<>>', \ 'different second command output', \ '<<>>', \ '', \ '(finished - exit code 0) ''command with no output''', \ '', \ '<<>>', \ ] \) Execute (ALEInfo should include executable checks in the history): call ale#linter#Define('testft', g:testlinter1) call ale#engine#IsExecutable(bufnr(''), has('win32') ? 'cmd' : 'echo') call ale#engine#IsExecutable(bufnr(''), has('win32') ? 'cmd' : 'echo') call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \ + [ \ '', \ '(executable check - success) ' . (has('win32') ? 'cmd' : 'echo'), \ '(executable check - failure) TheresNoWayThisIsExecutable', \ '(executable check - failure) TheresNoWayThisIsExecutable', \ ] \) Execute (The option for caching failing executable checks should work): let g:ale_cache_executable_check_failures = 1 " Replace output for the variable we have to modify above. call map(g:globals_lines, { \ _, val -> val =~ 'ale_cache_executable_check_failures' ? 'let g:ale_cache_executable_check_failures = 1' : val \}) call ale#linter#Define('testft', g:testlinter1) call ale#engine#IsExecutable(bufnr(''), has('win32') ? 'cmd' : 'echo') call ale#engine#IsExecutable(bufnr(''), has('win32') ? 'cmd' : 'echo') call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \ + [ \ '', \ '(executable check - success) ' . (has('win32') ? 'cmd' : 'echo'), \ '(executable check - failure) TheresNoWayThisIsExecutable', \ ] \) Given testft (Empty buffer): Execute (LSP errors for a linter should be outputted): let g:ale_lsp_error_messages = {'testlinter1': ['foo', 'bar']} call ale#linter#Define('testft', g:testlinter1) call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + [ \ ' LSP Error Messages:', \ '', \ '(Errors for testlinter1)', \ 'foo', \ 'bar', \ ] \ + g:command_header \) Given testft (Empty buffer): Execute (LSP errors for other linters shouldn't appear): let g:ale_lsp_error_messages = {'testlinter2': ['foo']} call ale#linter#Define('testft', g:testlinter1) call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should include linter global options): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) " eg: like g:c_build_dir_names let g:ale_testft_build_dir_names = ['build', 'bin'] let g:variables_lines = [ \ ' Linter Variables:', \ 'let g:ale_testft_build_dir_names = [''build'', ''bin'']', \ ' ', \] call CheckInfo( \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:variables_lines \ + g:globals_lines \ + g:command_header \) Given testft (Empty buffer with two filetypes): Execute (ALEInfo should include linter global options for enabled linters): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1']} " should not appear, since not enabled let g:ale_testft_testlinter2_option = 'test' let g:globals_lines[index(g:globals_lines, 'let g:ale_linters = {}')] \ = 'let g:ale_linters = {''testft'': [''testlinter1'']}' call CheckInfo( \ [ \ ' Current Filetype: testft', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'']', \ ' Ignored Linters: []', \ ] \ + g:fixer_lines \ + g:globals_lines \ + g:command_header \) Given ale-info (An ALEInfo buffer): Execute(ALEInfo should not report information about its own window): call CheckInfo([]) ================================================ FILE: test/test_ale_info_to_clipboard.vader ================================================ After: unlet! g:output Execute(ALEInfo -clipboard should tell the user that clipboard support is required): " When run in the Docker image, there's no clipboard support, so this test " will actually run. if !has('clipboard') let g:output = '' redir => g:output :ALEInfo -clipboard redir END AssertEqual 'clipboard not available. Try :ALEInfoToFile instead.', join(split(g:output)) endif ================================================ FILE: test/test_ale_lint_command.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_enabled let g:ale_buffer_info = {} let g:ale_enabled = 1 let g:expected_loclist = [{ \ 'bufnr': bufnr('%'), \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'foo bar', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}] function! ToggleTestCallback(buffer, output) return [{ \ 'bufnr': a:buffer, \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': join(split(a:output[0])), \ 'type': 'E', \ 'nr': -1, \}] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'ToggleTestCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': 'echo foo bar', \}) After: Restore unlet! g:expected_loclist unlet! b:i call ale#engine#Cleanup(bufnr('')) call ale#linter#Reset() let g:ale_buffer_info = {} delfunction ToggleTestCallback Given foobar (Some imaginary filetype): foo bar baz Execute(ALELint should run the linters): AssertEqual 'foobar', &filetype " Try to run the linter a few times, as it fails randomly in NeoVim. for b:i in range(5) ALELint call ale#test#WaitForJobs(2000) if !has('nvim') " Sleep so the delayed list function can run. " This breaks the tests in NeoVim for some reason. sleep 1ms endif if ale#test#GetLoclistWithoutNewerKeys() == g:expected_loclist break endif endfor " Check the loclist AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() ================================================ FILE: test/test_ale_lint_stop_command.vader ================================================ Before: Save g:ale_buffer_info let g:ale_buffer_info = {} call ale#linter#PreventLoading('testft') call ale#linter#Define('testft', { \ 'name': 'testlinter', \ 'callback': {-> []}, \ 'executable': has('win32') ? 'cmd' : 'true', \ 'command': 'sleep 9001', \}) After: Restore call ale#linter#Reset() Given testft (An empty file): Execute(ALELintStop should stop ALE from linting): ALELint Assert ale#engine#IsCheckingBuffer(bufnr('')), 'ALE did not start checking the buffer' ALELintStop Assert !ale#engine#IsCheckingBuffer(bufnr('')), 'ALELintStop didn''t work' ================================================ FILE: test/test_ale_populate_command.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_enabled Save g:ale_set_quickfix Save g:ale_set_loclist Save g:ale_open_list let g:ale_buffer_info = {} let g:ale_enabled = 1 let g:ale_set_quickfix = 0 let g:ale_set_loclist = 0 let g:ale_open_list = 1 let g:expected_loclist = [{ \ 'bufnr': bufnr('%'), \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'foo bar', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}] function! ToggleTestCallback(buffer, output) return [{ \ 'bufnr': a:buffer, \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': join(split(a:output[0])), \ 'type': 'E', \ 'nr': -1, \}] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'ToggleTestCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': 'echo foo bar', \}) After: Restore unlet! g:expected_loclist unlet! b:i call ale#engine#Cleanup(bufnr('')) call ale#linter#Reset() " Not sure this is necessary since it was Save/Restore-d let g:ale_buffer_info = {} delfunction ToggleTestCallback Given foobar (Some imaginary filetype): foo bar baz Execute(ALEPopulateQuickfix should have results): AssertEqual 'foobar', &filetype " Clear so we can check that they're unmodified. call setqflist([]) call setloclist(winnr(), []) " Try to run the linter a few times, as it fails randomly in NeoVim. for b:i in range(5) ALELint call ale#test#WaitForJobs(2000) if !has('nvim') " Sleep so the delayed list function can run. " This breaks the tests in NeoVim for some reason. sleep 1ms endif if ale#test#GetLoclistWithoutNewerKeys() == g:expected_loclist break endif endfor AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() AssertEqual [], ale#test#GetQflistWithoutNewerKeys() ALEPopulateLocList AssertNotEqual 0, get(getloclist(0, {'winid':0}), 'winid', 0) AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() ALEPopulateQuickfix AssertEqual g:expected_loclist, ale#test#GetQflistWithoutNewerKeys() ================================================ FILE: test/test_ale_toggle.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_set_signs Save g:ale_set_lists_synchronously Save g:ale_run_synchronously Save g:ale_pattern_options Save g:ale_pattern_options_enabled Save g:ale_set_balloons let g:ale_set_signs = 1 let g:ale_set_lists_synchronously = 1 let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks let g:ale_pattern_options = {} let g:ale_pattern_options_enabled = 1 let g:ale_set_balloons = \ has('balloon_eval') && has('gui_running') || \ has('balloon_eval_term') && !has('gui_running') unlet! b:ale_enabled let g:ale_buffer_info = {} let g:expected_loclist = [{ \ 'bufnr': bufnr('%'), \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'foo bar', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \}] let g:expected_groups = [ \ 'ALECleanupGroup', \ 'ALEEvents', \ 'ALEHighlightBufferGroup', \] let g:has_nvim_highlight = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace') function! ToggleTestCallback(buffer, output) return [{ \ 'bufnr': a:buffer, \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'foo bar', \ 'type': 'E', \ 'nr': -1, \}] endfunction function! ParseAuGroups() redir => l:output silent exec 'autocmd' redir end let l:results = [] for l:line in split(l:output, "\n") let l:match = matchlist(l:line, '^ALE[a-zA-Z]\+') " We don't care about some groups here. if !empty(l:match) \&& l:match[0] !=# 'ALECompletionGroup' \&& l:match[0] !=# 'ALEBufferFixGroup' \&& l:match[0] !=# 'ALEPatternOptionsGroup' call add(l:results, l:match[0]) endif endfor call uniq(sort(l:results)) return l:results endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'ToggleTestCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': 'echo', \ 'read_buffer': 0, \}) call ale#sign#Clear() After: Restore unlet! g:ale_run_synchronously_callbacks unlet! g:expected_loclist unlet! g:expected_groups unlet! b:ale_enabled unlet! g:output unlet! g:has_nvim_highlight call ale#linter#Reset() " Toggle ALE back on if we fail when it's disabled. if !g:ale_enabled ALEToggle endif delfunction ToggleTestCallback delfunction ParseAuGroups call setloclist(0, []) call ale#sign#Clear() call clearmatches() Given foobar (Some imaginary filetype): foo bar baz Execute(ALEToggle should reset everything and then run again): AssertEqual 'foobar', &filetype ALELint call ale#test#FlushJobs() " First check that everything is there... AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%')) " Only check the legacy matches if not using the new NeoVIM API. if !g:has_nvim_highlight AssertEqual \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') endif AssertEqual g:expected_groups, ParseAuGroups() AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist " Now Toggle ALE off. ALEToggle " Everything should be cleared. Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed' AssertEqual [], ale#test#GetLoclistWithoutNewerKeys(), 'The loclist was not cleared' AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared' if !g:has_nvim_highlight AssertEqual [], getmatches(), 'The highlights were not cleared' endif AssertEqual g:expected_groups, ParseAuGroups() " Toggle ALE on, everything should be set up and run again. ALEToggle call ale#test#FlushJobs() AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%')) if !g:has_nvim_highlight AssertEqual \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') endif AssertEqual g:expected_groups, ParseAuGroups() AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist Execute(ALEToggle should skip filename keys and preserve them): AssertEqual 'foobar', &filetype let g:ale_buffer_info['/foo/bar/baz.txt'] = { \ 'job_list': [], \ 'active_linter_list': [], \ 'loclist': [], \ 'temporary_file_list': [], \ 'temporary_directory_list': [], \ 'history': [], \} ALELint call ale#test#FlushJobs() " Now Toggle ALE off. ALEToggle AssertEqual \ { \ 'job_list': [], \ 'active_linter_list': [], \ 'loclist': [], \ 'temporary_file_list': [], \ 'temporary_directory_list': [], \ 'history': [], \ }, \ get(g:ale_buffer_info, '/foo/bar/baz.txt', {}) " Toggle ALE on again. ALEToggle call ale#test#FlushJobs() AssertEqual \ { \ 'job_list': [], \ 'active_linter_list': [], \ 'loclist': [], \ 'temporary_file_list': [], \ 'temporary_directory_list': [], \ 'history': [], \ }, \ get(g:ale_buffer_info, '/foo/bar/baz.txt', {}) Execute(ALEDisable should reset everything and stay disabled): ALELint call ale#test#FlushJobs() AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() ALEDisable call ale#test#FlushJobs() AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() AssertEqual 0, g:ale_enabled ALEDisable call ale#test#FlushJobs() AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() AssertEqual 0, g:ale_enabled Execute(ALEEnable should enable ALE and lint again): let g:ale_enabled = 0 ALEEnable call ale#test#FlushJobs() AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual 1, g:ale_enabled Execute(ALEReset should reset everything for a buffer): AssertEqual 'foobar', &filetype ALELint call ale#test#FlushJobs() " First check that everything is there... AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%')) if !g:has_nvim_highlight AssertEqual \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') endif AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist " Now Toggle ALE off. ALEReset call ale#test#FlushJobs() " Everything should be cleared. Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed' AssertEqual [], ale#test#GetLoclistWithoutNewerKeys(), 'The loclist was not cleared' AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared' if !g:has_nvim_highlight AssertEqual [], getmatches(), 'The highlights were not cleared' endif AssertEqual 1, g:ale_enabled Execute(ALEToggleBuffer should reset everything and then run again): AssertEqual 'foobar', &filetype ALELint call ale#test#FlushJobs() " First check that everything is there... AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%')) if !g:has_nvim_highlight AssertEqual \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') endif AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist " Now Toggle ALE off. ALEToggleBuffer " Everything should be cleared. Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed' AssertEqual [], ale#test#GetLoclistWithoutNewerKeys(), 'The loclist was not cleared' AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared' if !g:has_nvim_highlight AssertEqual [], getmatches(), 'The highlights were not cleared' endif " Toggle ALE on, everything should be set up and run again. ALEToggleBuffer call ale#test#FlushJobs() AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%')) if !g:has_nvim_highlight AssertEqual \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') endif AssertEqual g:expected_groups, ParseAuGroups() AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist Execute(ALEDisableBuffer should reset everything and stay disabled): ALELint call ale#test#FlushJobs() AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() ALEDisableBuffer call ale#test#FlushJobs() AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() AssertEqual 0, b:ale_enabled Execute(ALEEnableBuffer should enable ALE and lint again): let b:ale_enabled = 0 ALEEnableBuffer call ale#test#FlushJobs() AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual 1, b:ale_enabled Execute(ALEEnableBuffer should complain when ALE is disabled globally): let g:ale_enabled = 0 let b:ale_enabled = 0 redir => g:output ALEEnableBuffer redir END AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() AssertEqual 0, b:ale_enabled AssertEqual 0, g:ale_enabled AssertEqual \ 'ALE cannot be enabled locally when disabled globally', \ join(split(g:output)) Execute(ALEResetBuffer should reset everything for a buffer): AssertEqual 'foobar', &filetype ALELint call ale#test#FlushJobs() " First check that everything is there... AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutNewerKeys() AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%')) if !g:has_nvim_highlight AssertEqual \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}], \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}') endif AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist " Now Toggle ALE off. ALEResetBuffer call ale#test#FlushJobs() " Everything should be cleared. Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed' AssertEqual [], ale#test#GetLoclistWithoutNewerKeys(), 'The loclist was not cleared' AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared' if !g:has_nvim_highlight AssertEqual [], getmatches(), 'The highlights were not cleared' endif AssertEqual 1, g:ale_enabled AssertEqual 1, get(b:, 'ale_enabled', 1) Execute(Disabling ALE should disable balloons): " These tests won't run in the console, but we can run them manually in GVim. if has('balloon_eval') && has('gui_running') \|| (has('balloon_eval_term') && !has('gui_running')) call ale#linter#Reset() " Enable balloons, so we can check the expr value. call ale#balloon#Enable() if has('balloon_eval') && has('gui_running') AssertEqual 1, &ballooneval else AssertEqual 1, &balloonevalterm endif AssertEqual 'ale#balloon#Expr()', &balloonexpr " Toggle ALE off. ALEToggle " The balloon settings should be reset. if has('balloon_eval') && has('gui_running') AssertEqual 0, &ballooneval else AssertEqual 0, &balloonevalterm endif AssertEqual '', &balloonexpr endif Execute(Enabling ALE should enable balloons if the setting is on): if has('balloon_eval') && has('gui_running') \|| (has('balloon_eval_term') && !has('gui_running')) call ale#linter#Reset() call ale#balloon#Disable() ALEDisable let g:ale_set_balloons = 0 ALEEnable if has('balloon_eval') && has('gui_running') AssertEqual 0, &ballooneval else AssertEqual 0, &balloonevalterm endif AssertEqual '', &balloonexpr ALEDisable let g:ale_set_balloons = 1 ALEEnable if has('balloon_eval') && has('gui_running') AssertEqual 1, &ballooneval else AssertEqual 1, &balloonevalterm endif AssertEqual 'ale#balloon#Expr()', &balloonexpr endif ================================================ FILE: test/test_ale_var.vader ================================================ Before: let g:ale_some_variable = 'abc' After: unlet! g:ale_some_variable unlet! b:undefined_variable_name Execute(ale#Var should return global variables): AssertEqual 'abc', ale#Var(bufnr(''), 'some_variable') Execute(ale#Var should return buffer overrides): let b:ale_some_variable = 'def' AssertEqual 'def', ale#Var(bufnr(''), 'some_variable') Execute(ale#Var should return buffer overrides for buffer numbers as strings): let b:ale_some_variable = 'def' AssertEqual 'def', ale#Var(string(bufnr('')), 'some_variable') Execute(ale#Var should throw exceptions for undefined variables): let b:undefined_variable_name = 'def' AssertThrows call ale#Var(bufnr(''), 'undefined_variable_name') ================================================ FILE: test/test_alejobstarted_autocmd.vader ================================================ Before: Save g:ale_buffer_info let g:job_started_success = 0 let g:ale_run_synchronously = 1 unlet! b:ale_linted function! TestCallback(buffer, output) return [] endfunction call ale#linter#PreventLoading('testft') call ale#linter#Define('testft', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd' : 'true', \ 'command': 'true', \}) After: Restore let g:ale_run_synchronously = 0 augroup VaderTest autocmd! augroup END augroup! VaderTest unlet! g:job_started_success delfunction TestCallback call ale#linter#Reset() Given testft (An empty file): 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 ALELint AssertEqual g:job_started_success, 1 ================================================ FILE: test/test_alelint_autocmd.vader ================================================ Before: let g:pre_success = 0 let g:post_success = 0 let g:ale_run_synchronously = 1 unlet! b:ale_linted After: let g:ale_run_synchronously = 0 let g:ale_buffer_info = {} augroup VaderTest autocmd! augroup END augroup! VaderTest 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 call ale#Queue(0) AssertEqual g:pre_success, 1 AssertEqual g:post_success, 1 Execute(b:ale_linted should be increased after each lint cycle): AssertEqual get(b:, 'ale_linted'), 0 call ale#Queue(0) AssertEqual get(b:, 'ale_linted'), 1 call ale#Queue(0) AssertEqual get(b:, 'ale_linted'), 2 ================================================ FILE: test/test_ant_build_classpath_command.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/java/javac.vim Save $PATH let $PATH = ale#path#Simplify(g:dir . '/test-files/ant/bin') After: Restore call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return `cd '[dir]' && 'ant' classpath -S -q`): call ale#test#SetFilename('test-files/ant/ant-project/Main.java') AssertEqual \ [ \ ale#path#Simplify(g:dir . '/test-files/ant/ant-project'), \ ale#Escape('ant') . ' classpath' . ' -S' . ' -q', \ ], \ ale#ant#BuildClasspathCommand(bufnr('')) Execute(Should return empty string if ant cannot be executed): call ale#test#SetFilename('test-files/ant/not-an-ant-project/Main.java') AssertEqual ['', ''], ale#ant#BuildClasspathCommand(bufnr('')) ================================================ FILE: test/test_ant_find_project_root.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/java/javac.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return current directory if called on the project root): call ale#test#SetFilename('test-files/ant/ant-project/Main.java') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/ant/ant-project'), \ ale#ant#FindProjectRoot(bufnr('')) Execute(Should return root directory if called on a deeply nested source file): call ale#test#SetFilename('test-files/ant/ant-project/src/several/namespace/layers/A.java') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/ant/ant-project'), \ ale#ant#FindProjectRoot(bufnr('')) Execute(Should return empty string if called on a non-ant project): call ale#test#SetFilename('test-files/ant/non-ant-project/Main.java') AssertEqual \ '', \ ale#ant#FindProjectRoot(bufnr('')) Execute(Should return empty string if called on a file in a non-ant project): call ale#test#SetFilename('test-files/ant/non-ant-project/several/namespace/layers/A.java') AssertEqual \ '', \ ale#ant#FindProjectRoot(bufnr('')) ================================================ FILE: test/test_autocmd_commands.vader ================================================ Before: function! CheckAutocmd(group) call ale#events#Init() redir => l:output execute 'silent! autocmd ' . a:group redir END let l:matches = [] let l:header = '' " Some event names have aliases, and NeoVim and Vim produce " different output. The names are remapped to fix this. let l:event_name_corrections = { \ 'BufWrite': 'BufWritePre', \ 'BufRead': 'BufReadPost', \} " autocmd commands are split across two lines in output, so we " must merge the lines back into one simple line. for l:line in split(l:output, "\n") if l:line =~# '^ALE' && split(l:line)[0] ==# a:group let l:header = split(l:line)[1] let l:header = get(l:event_name_corrections, l:header, l:header) elseif !empty(l:header) " There's an extra line for buffer events, and we should only look " for the one matching the current buffer. if l:line =~# '' let l:header .= ' ' elseif l:line[:0] is# ' ' call add(l:matches, join(split(l:header . l:line))) else let l:header = '' endif endif endfor call sort(l:matches) return l:matches endfunction Save g:ale_completion_enabled Save g:ale_echo_cursor Save g:ale_enabled Save g:ale_fix_on_save Save g:ale_lint_on_enter Save g:ale_lint_on_filetype_changed Save g:ale_lint_on_insert_leave Save g:ale_lint_on_save Save g:ale_lint_on_text_changed Save g:ale_pattern_options_enabled Save g:ale_hover_cursor Save g:ale_close_preview_on_insert " Turn everything on by default for these tests. let g:ale_completion_enabled = 1 let g:ale_echo_cursor = 1 let g:ale_enabled = 1 let g:ale_fix_on_save = 1 let g:ale_lint_on_enter = 1 let g:ale_lint_on_filetype_changed = 1 let g:ale_lint_on_insert_leave = 1 let g:ale_lint_on_save = 1 let g:ale_lint_on_text_changed = 1 let g:ale_pattern_options_enabled = 1 let g:ale_hover_cursor = 1 let g:ale_close_preview_on_insert = 0 After: delfunction CheckAutocmd Restore if g:ale_completion_enabled call ale#completion#Enable() else call ale#completion#Disable() endif call ale#events#Init() Execute (All events should be set up when everything is on): let g:ale_echo_cursor = 1 " The InsertEnter event is only added when a mapping is not set. AssertEqual \ [ \ 'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', \ 'BufReadPost * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', \ 'BufWinEnter * call ale#events#LintOnEnter(str2nr(expand('''')))', \ 'BufWritePost * call ale#events#SaveEvent(str2nr(expand('''')))', \ 'CursorHold * if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarningWithDelay() | endif', \ 'CursorHold if exists(''*ale#lsp#Send'') | call ale#hover#ShowTruncatedMessageAtCursor() | endif', \ 'CursorMoved * if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarningWithDelay() | endif', \ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('''')))', \ 'FileType * call ale#events#FileTypeEvent( str2nr(expand('''')), expand(''''))', \ ] + ( \ maparg("\", 'i') isnot# '' && !exists('##ModeChanged') \ ? [ \ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('''')))', \ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('''')))', \ ] \ : [] \ ) + ( \ exists('##ModeChanged') \ ? ['ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand('''')))'] \ : [] \ ) + [ \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ ], \ CheckAutocmd('ALEEvents') Execute (Only the required events should be bound even if various settings are off): let g:ale_enabled = 1 let g:ale_completion_enabled = 0 let g:ale_echo_cursor = 0 let g:ale_fix_on_save = 0 let g:ale_lint_on_enter = 0 let g:ale_lint_on_filetype_changed = 0 let g:ale_lint_on_insert_leave = 0 let g:ale_lint_on_save = 0 let g:ale_lint_on_text_changed = 0 let g:ale_pattern_options_enabled = 0 let g:ale_hover_cursor = 0 AssertEqual \ [ \ 'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', \ 'BufReadPost * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', \ 'BufWritePost * call ale#events#SaveEvent(str2nr(expand('''')))', \ ], \ CheckAutocmd('ALEEvents') Execute (The cursor hover event should be enabled with g:ale_hover_cursor = 1): let g:ale_enabled = 1 let g:ale_completion_enabled = 0 let g:ale_echo_cursor = 0 let g:ale_fix_on_save = 0 let g:ale_lint_on_enter = 0 let g:ale_lint_on_filetype_changed = 0 let g:ale_lint_on_insert_leave = 0 let g:ale_lint_on_save = 0 let g:ale_lint_on_text_changed = 0 let g:ale_pattern_options_enabled = 0 let g:ale_hover_cursor = 1 AssertEqual \ [ \ 'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', \ 'BufReadPost * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', \ 'BufWritePost * call ale#events#SaveEvent(str2nr(expand('''')))', \ 'CursorHold * if exists(''*ale#lsp#Send'') | call ale#hover#ShowTruncatedMessageAtCursor() | endif', \ ], \ CheckAutocmd('ALEEvents') Execute (g:ale_lint_on_text_changed = 1 bind both events): let g:ale_lint_on_text_changed = 1 AssertEqual \ [ \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_text_changed = 'always' should bind both events): let g:ale_lint_on_text_changed = 'always' AssertEqual \ [ \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_text_changed = 'normal' should bind only TextChanged): let g:ale_lint_on_text_changed = 'normal' AssertEqual \ [ \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_text_changed = 'insert' should bind only TextChangedI): let g:ale_lint_on_text_changed = 'insert' AssertEqual \ [ \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_insert_leave = 1 should bind InsertLeave or ModeChanged if available): let g:ale_lint_on_insert_leave = 1 let g:ale_echo_cursor = 0 " CI at least should run this check. " There isn't an easy way to save an restore a mapping during running the test. if maparg("\", 'i') isnot# '' && !exists('##ModeChanged') AssertEqual \ [ \ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('''')))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''') else " If the ModeChanged event is available, starting the timer in InsertEnter is not necessary. AssertEqual \ [ \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''') endif if !exists('##ModeChanged') " If the ModeChanged event is not available, bind InsertLeave. AssertEqual \ [ \ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('''')))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''') else AssertEqual \ [ \ 'ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand('''')))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^ModeChanged''') endif Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event): let g:ale_lint_on_filetype_changed = 1 AssertEqual \ [ \ 'FileType * call ale#events#FileTypeEvent( ' \ . 'str2nr(expand('''')), ' \ . 'expand('''')' \ . ')', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''\v^FileType''') Execute (ALECleanupGroup should include the right commands): if exists('##VimSuspend') AssertEqual [ \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''''))) | endif', \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand('''')))', \ '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(''''))) | endif', \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand('''')))', \], CheckAutocmd('ALECleanupGroup') endif Execute(ALECompletionActions should always be set up): AssertEqual [ \ 'CompleteDone * call ale#completion#HandleUserData(v:completed_item)', \], CheckAutocmd('ALECompletionActions') Execute(Enabling completion should set up autocmd events correctly): let g:ale_completion_enabled = 0 call ale#completion#Enable() AssertEqual [ \ 'CompleteDone * call ale#completion#Done()', \ 'TextChangedI * call ale#completion#Queue()', \], CheckAutocmd('ALECompletionGroup') AssertEqual 1, g:ale_completion_enabled Execute(Disabling completion should remove autocmd events correctly): let g:ale_completion_enabled = 1 call ale#completion#Enable() call ale#completion#Disable() AssertEqual [], CheckAutocmd('ALECompletionGroup') AssertEqual 0, g:ale_completion_enabled Execute(ALE should try to close the preview window on InsertEnter): let g:ale_lint_on_insert_leave = 0 let g:ale_close_preview_on_insert = 1 AssertEqual \ [ \ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('''')))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''') ================================================ FILE: test/test_balloon_messages.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_enabled Save g:ale_set_balloons let g:ale_set_balloons = 1 let g:ale_buffer_info[bufnr('')] = {'loclist': [ \ { \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'col': 10, \ 'linter_name': 'eslint', \ 'type': 'W', \ 'text': 'Ignore me.', \ }, \ { \ 'bufnr': bufnr(''), \ 'lnum': 1, \ 'col': 10, \ 'text': 'Missing semicolon. (semi)', \ 'type': 'E', \ }, \ { \ 'bufnr': bufnr(''), \ 'lnum': 2, \ 'col': 10, \ 'text': 'Infix operators must be spaced. (space-infix-ops)' \ }, \ { \ 'bufnr': bufnr(''), \ 'lnum': 2, \ 'col': 15, \ 'text': 'Missing radix parameter (radix)' \ }, \]} After: Restore unlet! b:ale_enabled unlet! b:ale_set_balloons Execute(Balloon messages should be shown for the correct lines): AssertEqual \ 'Missing semicolon. (semi)', \ ale#balloon#MessageForPos(bufnr(''), 1, 1) Execute(Balloon messages should be shown for earlier columns): AssertEqual \ 'Infix operators must be spaced. (space-infix-ops)', \ ale#balloon#MessageForPos(bufnr(''), 2, 1) Execute(Balloon messages should be shown for later columns): AssertEqual \ 'Missing radix parameter (radix)', \ ale#balloon#MessageForPos(bufnr(''), 2, 16) Execute(Balloon messages should be disabled if ALE is disabled globally): let g:ale_enabled = 0 " Enabling the buffer should not make a difference. let b:ale_enabled = 1 AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) Execute(Balloon messages should be disabled if ALE is disabled for a buffer): let b:ale_enabled = 0 AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) Execute(Balloon messages should be disabled if the global setting is off): let g:ale_set_balloons = 0 AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) Execute(Balloon messages should be disabled if the buffer setting is off): let b:ale_set_balloons = 0 AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) Execute(The balloon buffer setting should override the global one): let g:ale_set_balloons = 0 let b:ale_set_balloons = 1 AssertEqual \ 'Missing semicolon. (semi)', \ ale#balloon#MessageForPos(bufnr(''), 1, 1) ================================================ FILE: test/test_c_flag_parsing.vader ================================================ Before: Save g:ale_c_parse_makefile Save g:ale_c_always_make Save b:ale_c_always_make call ale#test#SetDirectory('/testplugin/test') let g:ale_c_parse_makefile = 1 let g:ale_c_always_make = 1 let b:ale_c_always_make = 1 function SplitAndParse(path_prefix, command) abort let l:args = ale#c#ShellSplit(a:command) return ale#c#ParseCFlags(a:path_prefix, 0, l:args) endfunction After: delfunction SplitAndParse Restore call ale#test#RestoreDirectory() Execute(The make command should be correct): call ale#test#SetFilename('test-files/c/makefile_project/subdir/file.c') AssertEqual \ [ \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 'make -n --always-make', \ ], \ ale#c#GetMakeCommand(bufnr('')) " You should be able to disable --always-make for a buffer. let b:ale_c_always_make = 0 AssertEqual \ [ \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 'make -n', \ ], \ ale#c#GetMakeCommand(bufnr('')) Execute(Should recognize GNUmakefile as a makefile): call ale#test#SetFilename('test-files/c/gnumakefile_project/file.c') AssertEqual \ [ \ ale#path#Simplify(g:dir. '/test-files/c/gnumakefile_project'), \ 'make -n --always-make', \ ], \ ale#c#GetMakeCommand(bufnr('')) Execute(The CFlags parser should be able to parse include directives): call ale#test#SetFilename('test-files/c/makefile_project/subdir/file.c') AssertEqual \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')), \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c']) AssertEqual \ '-isystem ' . ale#Escape('/usr/include/dir'), \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -isystem /usr/include/dir -c file.c']) Execute(ParseCFlags should ignore -c and -o): call ale#test#SetFilename('test-files/c/makefile_project/subdir/file.c') AssertEqual \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')), \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c -o a.out']) Execute(The CFlags parser should be able to parse macro directives): call ale#test#SetFilename('test-files/c/makefile_project/subdir/file.c') AssertEqual \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/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-files/c/makefile_project/subdir/file.c') AssertEqual \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/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-files/c/makefile_project/subdir/file.c') AssertEqual \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/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 \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/kernel/include')) \ . ' -DTEST=`date +%s`', \ SplitAndParse( \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 'gcc -Isubdir ' \ . '-I'. ale#path#Simplify('kernel/include') \ . ' -DTEST=`date +%s` -c file.c' \ ) Execute(We should handle paths with spaces in double quotes): AssertEqual \ '-Dgoal=9' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/kernel/include')) \ . ' -DTEST=`date +%s`', \ SplitAndParse( \ ale#path#Simplify(g:dir. '/test-files/c/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' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/kernel/include')) \ . ' -DTEST=`date +%s`', \ SplitAndParse( \ ale#path#Simplify(g:dir. '/test-files/c/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' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir-with-dash')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/kernel/include')) \ . ' -DTEST=`date +%s`', \ SplitAndParse( \ ale#path#Simplify(g:dir. '/test-files/c/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(We should handle -D with minuses): AssertEqual \ '-Dgoal=9' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')) \ . ' -Dmacro-with-dash' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir-with-dash')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/kernel/include')) \ . ' -DTEST=`date +%s`', \ SplitAndParse( \ ale#path#Simplify(g:dir. '/test-files/c/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(We should handle flags at the end of the line): AssertEqual \ '-Dgoal=9' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/subdir')) \ . ' -Dmacro-with-dash' \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/dir-with-dash')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/kernel/include')), \ SplitAndParse( \ ale#path#Simplify(g:dir. '/test-files/c/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): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) " We should read the absolute path filename entry, not the other ones. AssertEqual \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'): [ \ { \ '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'), \ }, \ ], \ "xmms2-mpris.c": [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme') \ . ' -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'), \ }, \ ], \ }, \ { \ ale#path#Simplify('/foo/bar/xmms2-mpris/src'): [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris/src'), \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme') \ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o' \ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'), \ 'file': 'other.c', \ }, \ ], \ "src": [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme') \ . ' -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((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'), \ }, \ ], \ }, \ ) Execute(ParseCompileCommandsFlags should fall back to files with the same name): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) " We should prefer the basename file flags, not the base dirname flags. AssertEqual \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ "xmms2-mpris.c": [ \ { \ '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'), \ }, \ ], \ }, \ { \ "src": [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme') \ . ' -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((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'), \ }, \ ], \ }, \ ) Execute(ParseCompileCommandsFlags should parse flags for exact directory matches): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) " We should ues the exact directory flags, not the file basename flags. AssertEqual \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ "xmms2-mpris.c": [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme') \ . ' -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'), \ }, \ ], \ }, \ { \ ale#path#Simplify('/foo/bar/xmms2-mpris/src'): [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris/src'), \ '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': 'other.c', \ }, \ ], \ "src": [ \ { \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme') \ . ' -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((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'), \ }, \ ], \ }, \ ) Execute(ParseCompileCommandsFlags should fall back to files in the same directory): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) AssertEqual \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ {}, \ { \ "src": [ \ { \ '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((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'), \ }, \ ], \ }, \ ) Execute(ParseCompileCommandsFlags should tolerate items without commands): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) AssertEqual \ '', \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ "xmms2-mpris.c": [ \ { \ 'directory': '/foo/bar/xmms2-mpris', \ 'file': '/foo/bar/xmms2-mpris/src/xmms2-mpris.c', \ }, \ ], \ }, \ {}, \ ) Execute(ParseCompileCommandsFlags should take commands from matching .c files for .h files): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h')) AssertEqual \ '-I ' . ale#Escape('/usr/include/xmms2'), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ 'xmms2-mpris.c': [ \ { \ 'directory': '/foo/bar/xmms2-mpris', \ 'file': (has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-mpris.c', \ 'command': '/usr/bin/cc -I' . '/usr/include/xmms2' \ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o' \ . ' -c ' . '/foo/bar/xmms2-mpris/src/xmms2-mpris.c', \ }, \ ], \ }, \ {}, \ ) Execute(ParseCompileCommandsFlags should take commands from matching .cpp files for .hpp files): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.hpp')) AssertEqual \ '-I ' . ale#Escape('/usr/include/xmms2'), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ 'xmms2-mpris.cpp': [ \ { \ 'directory': '/foo/bar/xmms2-mpris', \ 'file': (has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-mpris.cpp', \ 'command': '/usr/bin/cc -I' . '/usr/include/xmms2' \ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o' \ . ' -c ' . '/foo/bar/xmms2-mpris/src/xmms2-mpris.cpp', \ }, \ ], \ }, \ { \ }, \ ) Execute(ParseCompileCommandsFlags should take commands from matching .cpp files for .h files): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h')) AssertEqual \ '-I ' . ale#Escape('/usr/include/xmms2'), \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ 'xmms2-mpris.cpp': [ \ { \ 'directory': '/foo/bar/xmms2-mpris', \ 'file': (has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-mpris.cpp', \ 'command': '/usr/bin/cc -I' . '/usr/include/xmms2' \ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o' \ . ' -c ' . '/foo/bar/xmms2-mpris/src/xmms2-mpris.cpp', \ }, \ ], \ }, \ { \ }, \ ) Execute(ParseCompileCommandsFlags should not take commands from .c files for .h files with different names): silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/other.h')) AssertEqual \ '', \ ale#c#ParseCompileCommandsFlags( \ bufnr(''), \ { \ 'xmms2-mpris.c': [ \ { \ 'directory': '/foo/bar/xmms2-mpris', \ 'file': (has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-mpris.c', \ 'command': '/usr/bin/cc -I' . '/usr/include/xmms2' \ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o' \ . ' -c ' . '/foo/bar/xmms2-mpris/src/xmms2-mpris.c', \ }, \ ], \ }, \ { \ }, \ ) Execute(ShellSplit should not merge flags): AssertEqual \ [ \ 'gcc', \ '-Dgoal=9', \ '-Tlinkerfile.ld', \ 'blabla', \ '-Isubdir', \ 'subdir/somedep1.o', \ 'subdir/somedep2.o', \ '-I''dir with spaces''', \ '-Idir-with-dash', \ 'subdir/somedep3.o', \ 'subdir/somedep4.o', \ '-I' . ale#path#Simplify('kernel/include'), \ 'subdir/somedep5.o', \ 'subdir/somedep6.o', \ ], \ ale#c#ShellSplit( \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ . 'subdir/somedep1.o ' . 'subdir/somedep2.o ' \ . '-I''dir with spaces''' . ' -Idir-with-dash ' \ . 'subdir/somedep3.o ' . 'subdir/somedep4.o ' \ . ' -I'. ale#path#Simplify('kernel/include') . ' ' \ . 'subdir/somedep5.o ' . 'subdir/somedep6.o' \ ) Execute(ShellSplit should handle parenthesis and quotes): AssertEqual \ [ \ 'gcc', \ '-Dgoal=9', \ '-Tlinkerfile.ld', \ 'blabla', \ '-Dtest1="('' '')"', \ 'file1.o', \ '-Dtest2=''(` `)''', \ 'file2.o', \ '-Dtest3=`(" ")`', \ 'file3.o', \ ] , \ ale#c#ShellSplit( \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla ' \ . '-Dtest1="('' '')" file1.o ' \ . '-Dtest2=''(` `)'' file2.o ' \ . '-Dtest3=`(" ")` file3.o' \ ) Execute(We should include several important flags): AssertEqual \ '-I ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/inc')) \ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/include')) \ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/incquote')) \ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/incsystem')) \ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/incafter')) \ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/incframework')) \ . ' -include file.h' \ . ' -imacros macros.h' \ . ' -Dmacro="value"' \ . ' -DGoal=9' \ . ' -D macro2' \ . ' -D macro3="value"' \ . ' -Bbdir' \ . ' -B bdir2' \ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3' \ . ' -isysroot sysroot --sysroot=test --no-sysroot-suffix -imultilib multidir' \ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi' \ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++' \ . ' -iplugindir=dir -march=native -w', \ ale#c#ParseCFlags( \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 0, \ [ \ 'gcc', \ '-Iinc', \ '-I', \ 'include', \ '-iquote', \ 'incquote', \ '-isystem', \ 'incsystem', \ '-idirafter', \ 'incafter', \ '-iframework', \ 'incframework', \ '-include', \ 'file.h', \ '-imacros', \ 'macros.h', \ '-Dmacro="value"', \ '-DGoal=9', \ '-D', \ 'macro2', \ '-D', \ 'macro3="value"', \ '-Bbdir', \ '-B', \ 'bdir2', \ '-iprefix', \ 'prefix', \ '-iwithprefix', \ 'prefix2', \ '-iwithprefixbefore', \ 'prefix3', \ '-isysroot', \ 'sysroot', \ '--sysroot=test', \ '--no-sysroot-suffix', \ '-imultilib', \ 'multidir', \ '-Wsome-warning', \ '-std=c89', \ '-pedantic', \ '-pedantic-errors', \ '-ansi', \ '-foption', \ '-O2', \ '-C', \ '-CC', \ '-trigraphs', \ '-nostdinc', \ '-nostdinc++', \ '-iplugindir=dir', \ '-march=native', \ '-w', \ ], \ ) Execute(We should quote the flags we need to quote): AssertEqual \ '-I ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/inc')) \ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/include')) \ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/incquote')) \ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/incsystem')) \ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test-files/c/makefile_project/incafter')) \ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test-files/c/makefile_project/incframework')) \ . ' -include file.h' \ . ' -imacros macros.h' \ . ' ' . ale#Escape('-Dmacro="value"') \ . ' -DGoal=9' \ . ' -D macro2' \ . ' -D ' . ale#Escape('macro3="value"') \ . ' -Bbdir' \ . ' -B bdir2' \ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3' \ . ' -isysroot sysroot --sysroot=test' \ . ' ' . ale#Escape('--sysroot="quoted"') \ . ' ' . ale#Escape('--sysroot=foo bar') \ . ' --no-sysroot-suffix -imultilib multidir' \ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi' \ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++' \ . ' -iplugindir=dir -march=native -w', \ ale#c#ParseCFlags( \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 1, \ [ \ 'gcc', \ '-Iinc', \ '-I', \ 'include', \ '-iquote', \ 'incquote', \ '-isystem', \ 'incsystem', \ '-idirafter', \ 'incafter', \ '-iframework', \ 'incframework', \ '-include', \ 'file.h', \ '-imacros', \ 'macros.h', \ '-Dmacro="value"', \ '-DGoal=9', \ '-D', \ 'macro2', \ '-D', \ 'macro3="value"', \ '-Bbdir', \ '-B', \ 'bdir2', \ '-iprefix', \ 'prefix', \ '-iwithprefix', \ 'prefix2', \ '-iwithprefixbefore', \ 'prefix3', \ '-isysroot', \ 'sysroot', \ '--sysroot=test', \ '--sysroot="quoted"', \ '--sysroot=foo bar', \ '--no-sysroot-suffix', \ '-imultilib', \ 'multidir', \ '-Wsome-warning', \ '-std=c89', \ '-pedantic', \ '-pedantic-errors', \ '-ansi', \ '-foption', \ '-O2', \ '-C', \ '-CC', \ '-trigraphs', \ '-nostdinc', \ '-nostdinc++', \ '-iplugindir=dir', \ '-march=native', \ '-w', \ ], \ ) Execute(We should exclude other flags that cause problems): AssertEqual \ '', \ ale#c#ParseCFlags( \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 0, \ [ \ 'gcc', \ '-Wl,option', \ '-Wa,option', \ '-Wp,option', \ '-c', \ 'filename.c', \ 'somelib.a', \ '-fdump-file=name', \ '-fdiagnostics-arg', \ '-fno-show-column', \ '-fstack-usage', \ '-Tlinkerfile.ld', \ ], \ ) Execute(We should expand @file in CFlags): AssertEqual \ '-DARGS1 -DARGS2 -O2', \ ale#c#ParseCFlags( \ ale#path#Simplify(g:dir. '/test-files/c/makefile_project'), \ 0, \ [ \ 'gcc', \ '-g', \ '@./args', \ '-O2', \ ], \ ) ================================================ FILE: test/test_cleanup.vader ================================================ After: unlet! g:buffer let g:ale_buffer_info = {} Execute('ALE globals should be cleared when the buffer is deleted): new let g:ale_buffer_info = { \ bufnr(''): {'temporary_file_list': [], 'temporary_directory_list': []}, \ 10347: {'temporary_file_list': [], 'temporary_directory_list': []}, \} bdelete AssertEqual {10347: {'temporary_file_list': [], 'temporary_directory_list': []}}, g:ale_buffer_info ================================================ FILE: test/test_code_action.vader ================================================ Before: let g:notified_changes = [] runtime autoload/ale/lsp.vim function! ale#lsp#NotifyForChanges(conn_id, buffer) abort call add(g:notified_changes, { \ 'conn_id': a:conn_id, \ 'buffer': a:buffer \}) endfunction Save g:ale_enabled let g:ale_enabled = 0 let g:file1 = tempname() let g:file2 = tempname() let g:test = {} let g:test.create_change = {line, offset, end_line, end_offset, value -> \{ \ 'changes': [{ \ 'fileName': g:file1, \ 'textChanges': [{ \ 'start': { \ 'line': line, \ 'offset': offset, \ }, \ 'end': { \ 'line': end_line, \ 'offset': end_offset, \ }, \ 'newText': value, \ }], \ }] \}} function! WriteFileAndEdit() abort let g:test.text = [ \ 'class Name {', \ ' value: string', \ '}', \] call writefile(g:test.text, g:file1, 'S') execute 'edit ' . g:file1 endfunction! After: " Close the extra buffers if we opened it. if bufnr(g:file1) != -1 && buflisted(bufnr(g:file1)) execute ':bp! | :bd! ' . bufnr(g:file1) endif if bufnr(g:file2) != -1 && buflisted(bufnr(g:file2)) execute ':bp! | :bd! ' . bufnr(g:file2) endif if filereadable(g:file1) call delete(g:file1) endif if filereadable(g:file2) call delete(g:file2) endif unlet! g:notified_changes " unlet! g:expected_notified_changes unlet! g:file1 unlet! g:file2 unlet! g:test unlet! g:changes delfunction WriteFileAndEdit runtime autoload/ale/lsp.vim Restore Execute(It should modify and save multiple files): call writefile([ \ 'class Name {', \ ' value: string', \ '}', \ '', \ 'class B {', \ ' constructor(readonly a: Name) {}', \ '}' \], g:file1, 'S') call writefile([ \ 'import A from "A"', \ 'import {', \ ' B,', \ ' C,', \ '} from "module"', \ 'import D from "D"', \], g:file2, 'S') call ale#code_action#HandleCodeAction( \ { \ 'changes': [{ \ 'fileName': g:file1, \ 'textChanges': [{ \ 'start': { \ 'line': 1, \ 'offset': 7, \ }, \ 'end': { \ 'line': 1, \ 'offset': 11, \ }, \ 'newText': 'Value', \ }, { \ 'start': { \ 'line': 6, \ 'offset': 27, \ }, \ 'end': { \ 'line': 6, \ 'offset': 31, \ }, \ 'newText': 'Value', \ }], \ }, { \ 'fileName': g:file2, \ 'textChanges': [{ \ 'start': { \ 'line': 2, \ 'offset': 1, \ }, \ 'end': { \ 'line': 6, \ 'offset': 1, \ }, \ 'newText': "import {A, B} from 'module'\n\n", \ }] \ }], \ }, \ {'should_save': 1, 'conn_id': 'test_conn'}, \) AssertEqual [ \ 'class Value {', \ ' value: string', \ '}', \ '', \ 'class B {', \ ' constructor(readonly a: Value) {}', \ '}', \ '', \], readfile(g:file1, 'b') AssertEqual [ \ 'import A from "A"', \ 'import {A, B} from ''module''', \ '', \ 'import D from "D"', \ '', \], readfile(g:file2, 'b') AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(g:file1), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(g:file2), \}], g:notified_changes Execute(Beginning of file can be modified): let g:test.text = [ \ 'class Name {', \ ' value: string', \ '}', \] call writefile(g:test.text, g:file1, 'S') call ale#code_action#HandleCodeAction( \ { \ 'changes': [{ \ 'fileName': g:file1, \ 'textChanges': [{ \ 'start': { \ 'line': 1, \ 'offset': 1, \ }, \ 'end': { \ 'line': 1, \ 'offset': 1, \ }, \ 'newText': "type A: string\ntype B: number\n", \ }], \ }] \ }, \ {'should_save': 1, 'conn_id': 'test_conn'}, \) AssertEqual [ \ 'type A: string', \ 'type B: number', \] + g:test.text + [''], readfile(g:file1, 'b') AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(g:file1), \}], g:notified_changes Execute(End of file can be modified): let g:test.text = [ \ 'class Name {', \ ' value: string', \ '}', \] call writefile(g:test.text, g:file1, 'S') call ale#code_action#HandleCodeAction( \ { \ 'changes': [{ \ 'fileName': g:file1, \ 'textChanges': [{ \ 'start': { \ 'line': 4, \ 'offset': 1, \ }, \ 'end': { \ 'line': 4, \ 'offset': 1, \ }, \ 'newText': "type A: string\ntype B: number\n", \ }], \ }] \ }, \ {'should_save': 1, 'conn_id': 'test_conn'}, \) AssertEqual g:test.text + [ \ 'type A: string', \ 'type B: number', \ '', \], readfile(g:file1, 'b') AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(g:file1), \}], g:notified_changes Execute(Current buffer contents will be reloaded): let g:test.text = [ \ 'class Name {', \ ' value: string', \ '}', \] call writefile(g:test.text, g:file1, 'S') execute 'edit ' . g:file1 let g:test.buffer = bufnr(g:file1) call ale#code_action#HandleCodeAction( \ { \ 'changes': [{ \ 'fileName': g:file1, \ 'textChanges': [{ \ 'start': { \ 'line': 1, \ 'offset': 1, \ }, \ 'end': { \ 'line': 1, \ 'offset': 1, \ }, \ 'newText': "type A: string\ntype B: number\n", \ }], \ }] \ }, \ {'should_save': 1, 'conn_id': 'test_conn'}, \) AssertEqual [ \ 'type A: string', \ 'type B: number', \] + g:test.text + [''], readfile(g:file1, 'b') AssertEqual [ \ 'type A: string', \ 'type B: number', \] + g:test.text, getbufline(g:test.buffer, 1, '$') AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(g:file1), \}], g:notified_changes Execute(Unlisted buffer contents will be modified correctly): let g:test.text = [ \ 'class Name {', \ ' value: string', \ '}', \] call writefile(g:test.text, g:file1, 'S') execute 'edit ' . g:file1 let g:test.buffer = bufnr(g:file1) execute 'bd' AssertEqual bufnr(g:file1), g:test.buffer call ale#code_action#HandleCodeAction( \ { \ 'changes': [{ \ 'fileName': g:file1, \ 'textChanges': [{ \ 'start': { \ 'line': 1, \ 'offset': 1, \ }, \ 'end': { \ 'line': 1, \ 'offset': 1, \ }, \ 'newText': "type A: string\ntype B: number\n", \ }], \ }] \ }, \ {'should_save': 1, 'conn_id': 'test_conn'}, \) AssertEqual [ \ 'type A: string', \ 'type B: number', \] + g:test.text + [''], readfile(g:file1, 'b') AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(g:file1), \}], g:notified_changes # Tests for cursor repositioning. In comments `=` designates change range, and # `C` cursor position # C === Execute(Cursor will not move when it is before text change): call WriteFileAndEdit() let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2') call setpos('.', [0, 1, 1, 0]) call ale#code_action#HandleCodeAction(g:test.changes, { \ 'should_save': 1, \ 'conn_id': 'test_conn', \}) AssertEqual [1, 1], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes call setpos('.', [0, 2, 2, 0]) call ale#code_action#HandleCodeAction(g:test.changes, { \ 'should_save': 1, \ 'conn_id': 'test_conn', \}) AssertEqual [2, 2], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # ====C==== Execute(Cursor column will move to the change end when cursor between start/end): let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2') for r in range(3, 8) call WriteFileAndEdit() call setpos('.', [0, 2, r, 0]) AssertEqual ' value: string', getline('.') call ale#code_action#HandleCodeAction(g:test.changes, { \ 'should_save': 1, \ 'conn_id': 'test_conn', \}) AssertEqual ' value2: string', getline('.') AssertEqual [2, 9], getpos('.')[1:2] endfor AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}, { \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # ====C Execute(Cursor column will move back when new text is shorter): call WriteFileAndEdit() call setpos('.', [0, 2, 8, 0]) AssertEqual ' value: string', getline('.') call ale#code_action#HandleCodeAction( \ g:test.create_change(2, 3, 2, 8, 'val'), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual ' val: string', getline('.') AssertEqual [2, 6], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # ==== C Execute(Cursor column will move forward when new text is longer): call WriteFileAndEdit() call setpos('.', [0, 2, 8, 0]) AssertEqual ' value: string', getline('.') call ale#code_action#HandleCodeAction( \ g:test.create_change(2, 3, 2, 8, 'longValue'), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual ' longValue: string', getline('.') AssertEqual [2, 12], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # ========= # = # C Execute(Cursor line will move when updates are happening on lines above): call WriteFileAndEdit() call setpos('.', [0, 3, 1, 0]) AssertEqual '}', getline('.') call ale#code_action#HandleCodeAction( \ g:test.create_change(1, 1, 2, 1, "test\ntest\n"), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual '}', getline('.') AssertEqual [4, 1], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # ========= # =C Execute(Cursor line and column will move when change on lines above and just before cursor column): call WriteFileAndEdit() call setpos('.', [0, 2, 2, 0]) AssertEqual ' value: string', getline('.') call ale#code_action#HandleCodeAction( \ g:test.create_change(1, 1, 2, 1, "test\ntest\n123"), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual '123 value: string', getline('.') AssertEqual [3, 5], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # ========= # ======C== # = Execute(Cursor line and column will move at the end of changes): call WriteFileAndEdit() call setpos('.', [0, 2, 10, 0]) AssertEqual ' value: string', getline('.') call ale#code_action#HandleCodeAction( \ g:test.create_change(1, 1, 3, 1, "test\n"), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual '}', getline('.') AssertEqual [2, 1], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes # C == # === Execute(Cursor will not move when changes happening on lines >= cursor, but after cursor): call WriteFileAndEdit() call setpos('.', [0, 2, 3, 0]) AssertEqual ' value: string', getline('.') call ale#code_action#HandleCodeAction( \ g:test.create_change(2, 10, 3, 1, "number\n"), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual ' value: number', getline('.') AssertEqual [2, 3], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes Execute(Cursor will not move when change covers entire file): call WriteFileAndEdit() call setpos('.', [0, 2, 3, 0]) call ale#code_action#HandleCodeAction( \ g:test.create_change(1, 1, len(g:test.text) + 1, 1, \ join(g:test.text + ['x'], "\n")), \ { \ 'should_save': 1, \ 'conn_id': 'test_conn', \ }) AssertEqual [2, 3], getpos('.')[1:2] AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes Execute(It should just modify file when should_save is set to v:false): call WriteFileAndEdit() let g:test.change = g:test.create_change(1, 1, 1, 1, "import { writeFile } from 'fs';\n") call ale#code_action#HandleCodeAction(g:test.change, { \ 'conn_id': 'test_conn', \}) AssertEqual 1, getbufvar(bufnr(''), '&modified') AssertEqual [ \ 'import { writeFile } from ''fs'';', \ 'class Name {', \ ' value: string', \ '}', \], getline(1, '$') AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes Given typescript(An example TypeScript file): type Foo = {} export interface ISomething { fooLongName: Foo | null } export class SomethingElse implements ISomething { // Bindings fooLongName!: ISomething['fooLongName'] } Execute(): let g:changes = [ \ {'end': {'offset': 14, 'line': 4}, 'newText': 'foo', 'start': {'offset': 3, 'line': 4}}, \ {'end': {'offset': 40, 'line': 9}, 'newText': 'foo', 'start': {'offset': 29, 'line': 9}}, \ {'end': {'offset': 14, 'line': 9}, 'newText': 'foo', 'start': {'offset': 3, 'line': 9}}, \] call ale#code_action#ApplyChanges(expand('%:p'), g:changes, { \ 'conn_id': 'test_conn', \}) AssertEqual [{ \ 'conn_id': 'test_conn', \ 'buffer': bufnr(''), \}], g:notified_changes Expect(The changes should be applied correctly): type Foo = {} export interface ISomething { foo: Foo | null } export class SomethingElse implements ISomething { // Bindings foo!: ISomething['foo'] } ================================================ FILE: test/test_code_action_corner_cases.vader ================================================ " Tests for various corner cases of applying code changes from LSP. " " These can be verified against the reference vscode implementation using the " following javascript program: " " const { TextDocument } = require('vscode-languageserver-textdocument'); " const { TextEdit, Position, Range } = require('vscode-languageserver-types'); " function MkPos(line, offset) { return Position.create(line - 1, offset - 1); } " function MkInsert(pos, newText) { return TextEdit.insert(pos, newText); } " function MkDelete(start, end) { return TextEdit.del(Range.create(start, end)); } " function TestChanges(s, es) { " return TextDocument.applyEdits(TextDocument.create(null, null, null, s), es); " } " " const fs = require("fs"); " const assert = require('assert').strict; " const testRegex = /(? ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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#code_action#HandleCodeAction(code_action, options) abort let g:handle_code_action_called = 1 Assert !get(a:options, 'should_save') call add(g:code_actions, a:code_action) endfunction function! ale#util#Input(message, value) abort return '2' endfunction After: Restore if g:conn_id isnot v:null call ale#lsp#RemoveConnectionWithID(g:conn_id) endif call ale#test#RestoreDirectory() call ale#linter#Reset() unlet! g:capability_checked unlet! g:InitCallback unlet! g:old_filename unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters unlet! g:options unlet! g:code_actions unlet! g:handle_code_action_called runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/codefix.vim runtime autoload/ale/code_action.vim Execute(Failed codefix responses should be handled correctly): call ale#codefix#HandleTSServerResponse( \ 1, \ {'command': 'getCodeFixes', 'request_seq': 3} \) AssertEqual g:handle_code_action_called, 0 Given typescript(Some typescript file): foo somelongerline () bazxyzxyzxyz Execute(getCodeFixes from tsserver should be handled): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleTSServerResponse(1, { \ 'command': 'getCodeFixes', \ 'request_seq': 3, \ 'success': v:true, \ 'type': 'response', \ 'body': [ \ { \ 'description': 'Import default "x" from module "./z"', \ 'fixName': 'import', \ 'changes': [ \ { \ 'fileName': "/foo/bar/file1.ts", \ 'textChanges': [ \ { \ 'end': { \ 'line': 2, \ 'offset': 1, \ }, \ 'newText': 'import x from "./z";^@', \ 'start': { \ 'line': 2, \ 'offset': 1, \ } \ } \ ] \ } \ ] \ } \ ] \}) AssertEqual g:handle_code_action_called, 1 AssertEqual \ [ \ { \ 'description': 'codefix', \ 'changes': [ \ { \ 'fileName': "/foo/bar/file1.ts", \ 'textChanges': [ \ { \ 'end': { \ 'line': 2, \ 'offset': 1 \ }, \ 'newText': 'import x from "./z";^@', \ 'start': { \ 'line': 2, \ 'offset': 1 \ } \ } \ ] \ } \ ] \ } \ ], \ g:code_actions Execute(getCodeFixes from tsserver should be handled with user input if there are more than one action): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleTSServerResponse(1, { \ 'command': 'getCodeFixes', \ 'request_seq': 3, \ 'success': v:true, \ 'type': 'response', \ 'body': [ \ { \ 'description': 'Import default "x" from module "./z"', \ 'fixName': 'import', \ 'changes': [ \ { \ 'fileName': "/foo/bar/file1.ts", \ 'textChanges': [ \ { \ 'end': { \ 'line': 2, \ 'offset': 1, \ }, \ 'newText': 'import x from "./z";^@', \ 'start': { \ 'line': 2, \ 'offset': 1, \ } \ } \ ] \ } \ ] \ }, \ { \ 'description': 'Import default "x" from module "./y"', \ 'fixName': 'import', \ 'changes': [ \ { \ 'fileName': "/foo/bar/file1.ts", \ 'textChanges': [ \ { \ 'end': { \ 'line': 2, \ 'offset': 1, \ }, \ 'newText': 'import x from "./y";^@', \ 'start': { \ 'line': 2, \ 'offset': 1, \ } \ } \ ] \ } \ ] \ } \ ] \}) AssertEqual g:handle_code_action_called, 1 AssertEqual \ [ \ { \ 'description': 'codefix', \ 'changes': [ \ { \ 'fileName': "/foo/bar/file1.ts", \ 'textChanges': [ \ { \ 'end': { \ 'line': 2, \ 'offset': 1 \ }, \ 'newText': 'import x from "./y";^@', \ 'start': { \ 'line': 2, \ 'offset': 1 \ } \ } \ ] \ } \ ] \ } \ ], \ g:code_actions Execute(Prints a tsserver error message when getCodeFixes unsuccessful): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleTSServerResponse(1, { \ 'command': 'getCodeFixes', \ 'request_seq': 3, \ 'success': v:false, \ 'message': 'something is wrong', \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''Error while getting code fixes. Reason: something is wrong'''], g:expr_list Execute(Does nothing when where are no code fixes): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleTSServerResponse(1, { \ 'command': 'getCodeFixes', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [] \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''No code fixes available.'''], g:expr_list Execute(tsserver codefix requests should be sent): call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'code': 2304, 'linter_name': 'tsserver'}]}} call setpos('.', [bufnr(''), 2, 16, 0]) " ALECodeAction call ale#codefix#Execute(0) " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'code_actions', g:capability_checked AssertEqual \ 'function(''ale#codefix#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@getCodeFixes', { \ 'startLine': 2, \ 'startOffset': 16, \ 'endLine': 2, \ 'endOffset': 17, \ 'file': expand('%:p'), \ 'errorCodes': [2304], \ }] \ ], \ g:message_list Execute(tsserver codefix requests should be sent only for error with code): call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 16, 'linter_name': 'tsserver'}, {'lnum': 2, 'col': 16, 'code': 2304, 'linter_name': 'tsserver'}]}} call setpos('.', [bufnr(''), 2, 16, 0]) " ALECodeAction call ale#codefix#Execute(0) " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'code_actions', g:capability_checked AssertEqual \ 'function(''ale#codefix#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@getCodeFixes', { \ 'startLine': 2, \ 'startOffset': 16, \ 'endLine': 2, \ 'endOffset': 17, \ 'file': expand('%:p'), \ 'errorCodes': [2304], \ }] \ ], \ g:message_list Execute(getApplicableRefactors from tsserver should be handled): call ale#codefix#SetMap({3: { \ 'buffer': expand('%:p'), \ 'line': 1, \ 'column': 2, \ 'end_line': 3, \ 'end_column': 4, \ 'connection_id': 0, \}}) call ale#codefix#HandleTSServerResponse(1, \ {'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:true, 'body': [{'actions': [{'description': 'Extract to constant in enclosing scope', 'name': 'constant_scope_0'}], 'description': 'Extract constant', 'name': 'Extract Symbol'}, {'actions': [{'description': 'Extract to function in module scope', 'name': 'function_scope_1'}], 'description': 'Extract function', 'name': 'Extract Symbol'}], 'command': 'getApplicableRefactors'}) AssertEqual \ [ \ [0, 'ts@getEditsForRefactor', { \ 'startLine': 1, \ 'startOffset': 2, \ 'endLine': 3, \ 'endOffset': 5, \ 'file': expand('%:p'), \ 'refactor': 'Extract Symbol', \ 'action': 'function_scope_1', \ }] \ ], \ g:message_list Execute(getApplicableRefactors should print error on failure): call ale#codefix#SetMap({3: { \ 'buffer': expand('%:p'), \ 'line': 1, \ 'column': 2, \ 'end_line': 3, \ 'end_column': 4, \ 'connection_id': 0, \}}) call ale#codefix#HandleTSServerResponse(1, \ {'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:false, 'message': 'oops', 'command': 'getApplicableRefactors'}) AssertEqual ['echom ''Error while getting applicable refactors. Reason: oops'''], g:expr_list Execute(getApplicableRefactors should do nothing if there are no refactors): call ale#codefix#SetMap({3: { \ 'buffer': expand('%:p'), \ 'line': 1, \ 'column': 2, \ 'end_line': 3, \ 'end_column': 4, \ 'connection_id': 0, \}}) call ale#codefix#HandleTSServerResponse(1, \ {'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:true, 'body': [], 'command': 'getApplicableRefactors'}) AssertEqual ['echom ''No applicable refactors available.'''], g:expr_list Execute(getEditsForRefactor from tsserver should be handled): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleTSServerResponse(1, \{'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:true, 'body': {'edits': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 35, 'line': 9}, 'newText': 'newFunction(app);', 'start': {'offset': 3, 'line': 8}}, {'end': {'offset': 4, 'line': 19}, 'newText': '^@function newFunction(app: Router) {^@ app.use(booExpressCsrf());^@ app.use(booExpressRequireHttps);^@}^@', 'start': {'offset': 4, 'line': 19}}]}], 'renameLocation': {'offset': 3, 'line': 8}, 'renameFilename': '/foo/bar/file.ts'}, 'command': 'getEditsForRefactor' } \) AssertEqual g:handle_code_action_called, 1 AssertEqual \ [ \ { \ 'description': 'editsForRefactor', \ 'changes': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 35, 'line': 9}, 'newText': 'newFunction(app);', 'start': {'offset': 3, 'line': 8}}, {'end': {'offset': 4, 'line': 19}, 'newText': '^@function newFunction(app: Router) {^@ app.use(booExpressCsrf());^@ app.use(booExpressRequireHttps);^@}^@', 'start': {'offset': 4, 'line': 19}}]}], \ } \ ], \ g:code_actions Execute(getEditsForRefactor should print error on failure): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleTSServerResponse(1, \{'seq': 0, 'request_seq': 3, 'type': 'response', 'success': v:false, 'message': 'oops', 'command': 'getEditsForRefactor' } \) AssertEqual ['echom ''Error while getting edits for refactor. Reason: oops'''], g:expr_list Execute(Failed LSP responses should be handled correctly): call ale#codefix#HandleLSPResponse( \ 1, \ {'method': 'workspace/applyEdit', 'request_seq': 3} \) AssertEqual g:handle_code_action_called, 0 Given python(Some python file): def main(): a = 1 b = a + 2 Execute("workspace/applyEdit" from LSP should be handled): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleLSPResponse(1, \ {'id': 0, 'jsonrpc': '2.0', 'method': 'workspace/applyEdit', 'params': {'edit': {'changes': {'file:///foo/bar/file.ts': [{'range': {'end': {'character': 27, 'line': 7}, 'start': {'character': 27, 'line': 7}}, 'newText': ', Config'}, {'range': {'end': {'character': 12, 'line': 96}, 'start': {'character': 2, 'line': 94}}, 'newText': 'await newFunction(redis, imageKey, cover, config);'}, {'range': {'end': {'character': 2, 'line': 99}, 'start': {'character': 2, 'line': 99}}, 'newText': '^@async function newFunction(redis: IRedis, imageKey: string, cover: Buffer, config: Config) {^@ try {^@ await redis.set(imageKey, cover, ''ex'', parseInt(config.coverKeyTTL, 10));^@ }^@ catch { }^@}^@'}]}}}}) AssertEqual g:handle_code_action_called, 1 AssertEqual \ [{'description': 'applyEdit', 'changes': [{'fileName': '/foo/bar/file.ts', 'textChanges': [{'end': {'offset': 28, 'line': 8}, 'newText': ', Config', 'start': {'offset': 28, 'line': 8}}, {'end': {'offset': 13, 'line': 97}, 'newText': 'await newFunction(redis, imageKey, cover, config);', 'start': {'offset': 3, 'line': 95}}, {'end': {'offset': 3, 'line': 100}, 'newText': '^@async function newFunction(redis: IRedis, imageKey: string, cover: Buffer, config: Config) {^@ try {^@ await redis.set(imageKey, cover, ''ex'', parseInt(config.coverKeyTTL, 10));^@ }^@ catch { }^@}^@', 'start': {'offset': 3, 'line': 100}}]}]}], \ g:code_actions Execute(Code Actions from LSP should be handled when returned with documentChanges): call ale#codefix#SetMap({2: {}}) call ale#codefix#HandleLSPResponse(1, \ {'id': 2, 'jsonrpc': '2.0', 'result': [{'diagnostics': v:null, 'edit': {'changes': v:null, 'documentChanges': [{'edits': [{'range': {'end': {'character': 4, 'line': 2}, 'start': {'character': 4, 'line': 1}}, 'newText': ''}, {'range': {'end': {'character': 9, 'line': 2}, 'start': {'character': 8, 'line': 2}}, 'newText': '(1)'}], 'textDocument': {'uri': 'file:///foo/bar/test.py', 'version': v:null}}]}, 'kind': 'refactor.inline', 'title': 'Inline variable', 'command': v:null}, {'diagnostics': v:null, 'edit': {'changes': v:null, 'documentChanges': [{'edits': [{'range': {'end': {'character': 0, 'line': 0}, 'start': {'character': 0, 'line': 0}}, 'newText': 'def func_bomdjnxh():^@ a = 1return a^@^@^@'}, {'range': {'end': {'character': 9, 'line': 1}, 'start': {'character': 8, 'line': 1}}, 'newText': 'func_bomdjnxh()^@'}], 'textDocument': {'uri': 'file:///foo/bar/test.py', 'version': v:null}}]}, 'kind': 'refactor.extract', 'title': 'Extract expression into function ''func_bomdjnxh''', 'command': v:null}]}) AssertEqual g:handle_code_action_called, 1 AssertEqual \ [{'description': 'codeaction', 'changes': [{'fileName': '/foo/bar/test.py', 'textChanges': [{'end': {'offset': 1, 'line': 1}, 'newText': 'def func_bomdjnxh():^@ a = 1return a^@^@^@', 'start': {'offset': 1, 'line': 1}}, {'end': {'offset': 10, 'line': 2}, 'newText': 'func_bomdjnxh()^@', 'start': {'offset': 9, 'line': 2}}]}]}], \ g:code_actions Execute(LSP Code Actions handles CodeAction responses): call ale#codefix#SetMap({3: { \ 'connection_id': 0, \}}) call ale#codefix#HandleLSPResponse(1, \ {'id': 3, 'jsonrpc': '2.0', 'result': [{'kind': 'refactor', 'title': 'Extract to inner function in function ''getVideo''', 'command': {'arguments': [{'file': '/foo/bar/file.ts', 'endOffset': 0, 'action': 'function_scope_0', 'startOffset': 1, 'startLine': 65, 'refactor': 'Extract Symbol', 'endLine': 68}], 'title': 'Extract to inner function in function ''getVideo''', 'command': '_typescript.applyRefactoring'}}, {'kind': 'refactor', 'title': 'Extract to function in module scope', 'command': {'arguments': [{'file': '/foo/bar/file.ts', 'endOffset': 0, 'action': 'function_scope_1', 'startOffset': 1, 'startLine': 65, 'refactor': 'Extract Symbol', 'endLine': 68}], 'title': 'Extract to function in module scope', 'command': '_typescript.applyRefactoring'}}]}) AssertEqual \ [[0, 'workspace/executeCommand', {'arguments': [{'file': '/foo/bar/file.ts', 'action': 'function_scope_1', 'endOffset': 0, 'refactor': 'Extract Symbol', 'endLine': 68, 'startLine': 65, 'startOffset': 1}], 'command': '_typescript.applyRefactoring'}]], \ g:message_list Execute(LSP Code Actions handles Command responses): call ale#codefix#SetMap({2: { \ 'connection_id': 2, \}}) call ale#codefix#HandleLSPResponse(1, \ {'id': 2, 'jsonrpc': '2.0', 'result': [{'title': 'fake for testing'}, {'arguments': [{'documentChanges': [{'edits': [{'range': {'end': {'character': 31, 'line': 2}, 'start': {'character': 31, 'line': 2}}, 'newText': ', createVideo'}], 'textDocument': {'uri': 'file:///foo/bar/file.ts', 'version': 1}}]}], 'title': 'Add ''createVideo'' to existing import declaration from "./video"', 'command': '_typescript.applyWorkspaceEdit'}]}) AssertEqual \ [[0, 'workspace/executeCommand', {'arguments': [{'documentChanges': [{'edits': [{'range': {'end': {'character': 31, 'line': 2}, 'start': {'character': 31, 'line': 2}}, 'newText': ', createVideo'}], 'textDocument': {'uri': 'file:///foo/bar/file.ts', 'version': 1}}]}], 'command': '_typescript.applyWorkspaceEdit'}]], \ g:message_list Execute(Prints message when LSP code action returns no results): call ale#codefix#SetMap({3: {}}) call ale#codefix#HandleLSPResponse(1, \ {'id': 3, 'jsonrpc': '2.0', 'result': []}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''No code actions received from server'''], g:expr_list Execute(LSP code action requests should be sent): call ale#linter#Reset() runtime ale_linters/python/jedils.vim let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'end_lnum': 2, 'end_col': 6, 'code': 2304, 'text': 'oops'}]}} call setpos('.', [bufnr(''), 2, 5, 0]) " ALECodeAction call ale#codefix#Execute(0) " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'code_actions', g:capability_checked AssertEqual \ 'function(''ale#codefix#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [0, 'textDocument/codeAction', { \ 'context': { \ 'diagnostics': [{'range': {'end': {'character': 6, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}] \ }, \ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}}, \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))} \ }] \ ], \ g:message_list[-1:] Execute(LSP code action requests should be sent only for error with code): call ale#linter#Reset() runtime ale_linters/python/jedils.vim let g:ale_buffer_info = {bufnr(''): {'loclist': [{'lnum': 2, 'col': 5, 'end_lnum': 2, 'end_col': 6, 'code': 2304, 'text': 'oops'}]}} call setpos('.', [bufnr(''), 2, 5, 0]) " ALECodeAction call ale#codefix#Execute(0) " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'code_actions', g:capability_checked AssertEqual \ 'function(''ale#codefix#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [0, 'textDocument/codeAction', { \ 'context': { \ 'diagnostics': [{'range': {'end': {'character': 6, 'line': 1}, 'start': {'character': 4, 'line': 1}}, 'code': 2304, 'message': 'oops'}] \ }, \ 'range': {'end': {'character': 5, 'line': 1}, 'start': {'character': 4, 'line': 1}}, \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))} \ }] \ ], \ g:message_list[-1:] ================================================ FILE: test/test_computed_lint_file_values.vader ================================================ Before: Save g:ale_enabled Save g:ale_run_synchronously Save g:ale_set_lists_synchronously Save g:ale_buffer_info let g:ale_enabled = 1 let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 let g:ale_set_lists_synchronously = 1 function! TestCallback(buffer, output) " Windows adds extra spaces to the text from echo. return [{ \ 'lnum': 2, \ 'col': 3, \ 'text': 'testlinter1', \}] endfunction function! TestCallback2(buffer, output) " Windows adds extra spaces to the text from echo. return [{ \ 'lnum': 1, \ 'col': 3, \ 'text': 'testlinter2', \}] endfunction function! TestCallback3(buffer, output) " Windows adds extra spaces to the text from echo. return [{ \ 'lnum': 3, \ 'col': 3, \ 'text': 'testlinter3', \}] endfunction " These two linters computer their lint_file values after running commands. call ale#linter#Define('foobar', { \ 'name': 'testlinter1', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''', \ 'lint_file': {b -> ale#command#Run(b, 'echo', {-> 1})}, \}) call ale#linter#Define('foobar', { \ 'name': 'testlinter2', \ 'callback': 'TestCallback2', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''', \ 'lint_file': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 1})})}, \}) " This one directly computes the result. call ale#linter#Define('foobar', { \ 'name': 'testlinter3', \ 'callback': 'TestCallback3', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''', \ 'lint_file': {b -> 1}, \}) let g:filename = tempname() call writefile([], g:filename) call ale#test#SetFilename(g:filename) After: delfunction TestCallback call ale#engine#Cleanup(bufnr('')) Restore call ale#linter#Reset() " Items and markers, etc. call setloclist(0, []) call clearmatches() call ale#sign#Clear() if filereadable(g:filename) call delete(g:filename) endif unlet g:filename Given foobar(A file with some lines): foo bar baz Execute(lint_file results where the result is eventually computed should be run): call ale#Queue(0, 'lint_file') call ale#test#FlushJobs() AssertEqual \ [ \ { \ 'bufnr': bufnr('%'), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 3, \ 'text': 'testlinter2', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }, \ { \ 'bufnr': bufnr('%'), \ 'lnum': 2, \ 'vcol': 0, \ 'col': 3, \ 'text': 'testlinter1', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }, \ { \ 'bufnr': bufnr('%'), \ 'lnum': 3, \ 'vcol': 0, \ 'col': 3, \ 'text': 'testlinter3', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(Linters where lint_file eventually evaluates to 1 shouldn't be run if we don't want to run them): call ale#Queue(0, '') call ale#test#FlushJobs() AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() Execute(Keeping computed lint_file jobs running should work): AssertEqual 'testlinter2', ale#linter#Get('foobar')[1].name call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#MarkLinterActive( \ g:ale_buffer_info[bufnr('')], \ ale#linter#Get('foobar')[1] \) call ale#engine#RunLinters(bufnr(''), ale#linter#Get('foobar'), 0) Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list), \ 'The active linter list was empty' Assert ale#engine#IsCheckingBuffer(bufnr('')), \ 'The IsCheckingBuffer function returned 0' ================================================ FILE: test/test_cursor_warnings.vader ================================================ Before: Save g:ale_echo_msg_format Save g:ale_echo_cursor Save b:ale_lint_on_insert_leave let g:ale_echo_msg_format = '%code: %%s' let b:ale_lint_on_insert_leave = 0 " We should prefer the error message at column 10 instead of the warning. let g:ale_buffer_info = { \ bufnr('%'): { \ 'loclist': [ \ { \ 'lnum': 1, \ 'col': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'W', \ 'code': 'semi', \ 'text': 'Ignore me.', \ }, \ { \ 'lnum': 1, \ 'col': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'E', \ 'code': 'semi', \ 'text': "Missing\nsemicolon.\r", \ 'detail': "Every statement should end with a semicolon\nsecond line", \ }, \ { \ 'lnum': 1, \ 'col': 14, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'I', \ 'text': 'Some information', \ }, \ { \ 'lnum': 2, \ 'col': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'W', \ 'code': 'space-infix-ops', \ 'text': 'Infix operators must be spaced.', \ }, \ { \ 'lnum': 2, \ 'col': 15, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'E', \ 'code': 'radix', \ 'text': 'Missing radix parameter', \ }, \ { \ 'lnum': 3, \ 'col': 1, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'E', \ 'text': 'lowercase error', \ }, \ ], \ }, \} " Turn off other features, we only care about this one feature in this test. let g:ale_set_loclist = 0 let g:ale_set_signs = 0 let g:ale_set_highlights = 0 let g:ale_echo_cursor = 1 runtime autoload/ale/cursor.vim let g:last_message = '' function! ale#cursor#Echom(message) abort let g:last_message = a:message endfunction call ale#linter#Reset() call ale#linter#PreventLoading('javascript') After: Restore unlet! g:last_message runtime autoload/ale/cursor.vim call cursor(1, 1) let g:ale_set_loclist = 1 let g:ale_set_signs = 1 let g:ale_set_highlights = 1 let g:ale_buffer_info = {} unlet! g:output unlet! b:ale_loclist_msg_format " Clearing the messages breaks tests on NeoVim for some reason, but all " we need to do for these tests is just make it so the last message isn't " carried over between test cases. echomsg '' " Close the preview window if it's open. if &filetype is# 'ale-preview' noautocmd :q! endif call ale#linter#Reset() Given javascript(A Javscript file with warnings/errors): var x = 3 + 12345678 var x = 5*2 + parseInt("10"); //" comment Execute(Messages should be shown for the correct lines): call cursor(1, 1) call ale#cursor#EchoCursorWarning() AssertEqual 'semi: Missing semicolon.', g:last_message Execute(Messages should be shown for earlier columns): call cursor(2, 1) call ale#cursor#EchoCursorWarning() AssertEqual 'space-infix-ops: Infix operators must be spaced.', g:last_message Execute(Messages should be shown for later columns): call cursor(2, 16) call ale#cursor#EchoCursorWarning() AssertEqual 'radix: Missing radix parameter', g:last_message Execute(The message at the cursor should be shown when linting ends): call cursor(1, 1) call ale#engine#SetResults( \ bufnr('%'), \ g:ale_buffer_info[bufnr('%')].loclist, \) AssertEqual 'semi: Missing semicolon.', g:last_message Execute(The message at the cursor should be shown when leaving insert mode): call cursor(2, 9) call feedkeys("i\", 'tnix') AssertEqual 'space-infix-ops: Infix operators must be spaced.', g:last_message Execute(ALEDetail should print 'detail' attributes): call cursor(1, 1) ALEDetail AssertEqual \ ['Every statement should end with a semicolon', 'second line'], \ getline(1, '$') Execute(ALEDetail should print regular 'text' attributes): call cursor(2, 10) ALEDetail " ALEDetail opens a window, so check the text in it. AssertEqual \ ['Infix operators must be spaced.'], \ getline(1, '$') Execute(ALEDetail should not capitlise cursor messages): call cursor(3, 1) call ale#cursor#EchoCursorWarning() AssertEqual 'lowercase error', g:last_message Execute(The linter name should be formatted into the message correctly): let g:ale_echo_msg_format = '%linter%: %s' call cursor(2, 9) call ale#cursor#EchoCursorWarning() AssertEqual \ 'bettercode: Infix operators must be spaced.', \ g:last_message Execute(The severity should be formatted into the message correctly): let g:ale_echo_msg_format = '%severity%: %s' call cursor(2, 9) call ale#cursor#EchoCursorWarning() AssertEqual \ 'Warning: Infix operators must be spaced.', \ g:last_message call cursor(1, 10) call ale#cursor#EchoCursorWarning() AssertEqual 'Error: Missing semicolon.', g:last_message call cursor(1, 14) call ale#cursor#EchoCursorWarning() AssertEqual 'Info: Some information', g:last_message Execute(The type should be formatted into the message correctly): let g:ale_echo_msg_format = '%type%: %s' call cursor(2, 9) call ale#cursor#EchoCursorWarning() AssertEqual \ 'W: Infix operators must be spaced.', \ g:last_message call cursor(1, 10) call ale#cursor#EchoCursorWarning() AssertEqual 'E: Missing semicolon.', g:last_message call cursor(1, 14) call ale#cursor#EchoCursorWarning() AssertEqual 'I: Some information', g:last_message Execute(The %code% and %ifcode% should show the code and some text): let g:ale_echo_msg_format = '%(code) %%s' call cursor(2, 9) call ale#cursor#EchoCursorWarning() AssertEqual \ '(space-infix-ops) Infix operators must be spaced.', \ g:last_message Execute(The %code% and %ifcode% should be removed when there's no code): let g:ale_echo_msg_format = '%(code) %%s' call cursor(1, 14) call ale#cursor#EchoCursorWarning() AssertEqual 'Some information', g:last_message Execute(The buffer message format option should take precedence): let g:ale_echo_msg_format = '%(code) %%s' let b:ale_echo_msg_format = 'FOO %s' call cursor(1, 14) call ale#cursor#EchoCursorWarning() AssertEqual 'FOO Some information', g:last_message Execute(The cursor message shouldn't be echoed if the option is off): let g:ale_echo_cursor = 0 let g:last_message = 'foo' call cursor(1, 1) call ale#cursor#EchoCursorWarning() AssertEqual 'foo', g:last_message ================================================ FILE: test/test_deferred_command_string.vader ================================================ Before: Save g:ale_run_synchronously Save g:ale_emulate_job_failure Save g:ale_buffer_info let g:ale_run_synchronously = 1 let g:ale_buffer_info = {} let b:ale_history = [] call ale#linter#Reset() call ale#assert#SetUpLinterTestCommands() call ale#linter#Define('foobar', { \ 'name': 'lint_file_linter', \ 'callback': 'LintFileCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 'foo'})})}, \ 'read_buffer': 0, \}) " Run the test commands in the shell. let g:ale_run_synchronously_emulate_commands = 0 After: Restore call ale#assert#TearDownLinterTest() unlet! g:ale_run_synchronously_callbacks Given foobar (Some imaginary filetype): Execute(It should be possible to compute a command based on the result of other commands): AssertLinter has('win32') ? 'cmd' : 'echo', 'foo' ALELint call ale#test#FlushJobs() AssertEqual \ 1, \ len(filter(copy(b:ale_history), 'string(v:val.command) =~# ''foo''')) Execute(We should handle the deferered command failing): let g:ale_emulate_job_failure = 1 AssertLinter has('win32') ? 'cmd' : 'echo', 0 ALELint call ale#test#FlushJobs() AssertEqual \ 0, \ len(filter(copy(b:ale_history), 'string(v:val.command) =~# ''foo''')) ================================================ FILE: test/test_deferred_executable_string.vader ================================================ Before: Save g:ale_run_synchronously Save g:ale_emulate_job_failure Save g:ale_buffer_info let g:ale_run_synchronously = 1 let g:ale_buffer_info = {} let b:ale_history = [] call ale#linter#Reset() call ale#assert#SetUpLinterTestCommands() call ale#linter#Define('foobar', { \ 'name': 'lint_file_linter', \ 'callback': 'LintFileCallback', \ 'executable': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 'foo'})})}, \ 'command': 'echo', \ 'read_buffer': 0, \}) After: Restore call ale#assert#TearDownLinterTest() Given foobar (Some imaginary filetype): Execute(It should be possible to compute an executable to check based on the result of commands): AssertLinter 'foo', 'echo' ALELint call ale#test#FlushJobs() AssertEqual \ [{'status': 0, 'job_id': 'executable', 'command': 'foo'}], \ filter(copy(b:ale_history), 'v:val.job_id is# ''executable''') Execute(We should handle the deferered executable command failing): let g:ale_emulate_job_failure = 1 AssertLinter 0, 'echo' ALELint call ale#test#FlushJobs() AssertEqual \ [], \ filter(copy(b:ale_history), 'v:val.job_id is# ''executable''') ================================================ FILE: test/test_deno_executable_detection.vader ================================================ Before: Save g:ale_deno_executable runtime autoload/ale/handlers/deno.vim After: unlet! b:ale_deno_executable call ale#linter#Reset() Execute(Default executable should be detected correctly): AssertEqual \ 'deno', \ ale#handlers#deno#GetExecutable(bufnr('')) Execute(User specified executable should override default): let g:ale_deno_executable = '/path/to/deno-bin' AssertEqual \ '/path/to/deno-bin', \ ale#handlers#deno#GetExecutable(bufnr('')) ================================================ FILE: test/test_disabling_ale.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_enabled Save b:ale_enabled Save g:ale_maximum_file_size Save b:ale_maximum_file_size function! SetUpCursorData() let g:ale_buffer_info = { \ bufnr('%'): { \ 'loclist': [ \ { \ 'lnum': 2, \ 'col': 10, \ 'linter_name': 'testlinter', \ 'type': 'W', \ 'text': 'X' \ }, \ ], \ }, \} call cursor(2, 16) endfunction function! TestCallback(buffer, output) return [] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': 'echo', \ 'command': 'true', \}) function GetLastMessage() redir => l:output silent mess redir END " Filter out messages that could come from saving this test file. let l:lines = filter(split(l:output, "\n"), 'v:val !~ ''written\|No line''') return empty(l:lines) ? '' : l:lines[-1] endfunction echomsg '' After: Restore call ale#linter#Reset() delfunction TestCallback delfunction GetLastMessage delfunction SetUpCursorData Given foobar (Some imaginary filetype): foo bar baz Execute(Linting shouldn't happen when ALE is disabled globally): let g:ale_enabled = 0 let g:ale_buffer_info = {} call ale#Queue(0) AssertEqual {}, g:ale_buffer_info call SetUpCursorData() call ale#cursor#EchoCursorWarning() AssertEqual '', GetLastMessage() Execute(Linting shouldn't happen when ALE is disabled locally): let b:ale_enabled = 0 let g:ale_buffer_info = {} call ale#Queue(0) AssertEqual {}, g:ale_buffer_info call SetUpCursorData() call ale#cursor#EchoCursorWarning() AssertEqual '', GetLastMessage() Execute(Linting shouldn't happen when the file is too large with global options): let g:ale_maximum_file_size = 12 let g:ale_buffer_info = {} call ale#Queue(0) AssertEqual {}, g:ale_buffer_info " We shouldn't show cursor warnings. call SetUpCursorData() call ale#cursor#EchoCursorWarning() AssertEqual '', GetLastMessage() Execute(Linting shouldn't happen when the file is too large with local options): let b:ale_maximum_file_size = 12 let g:ale_buffer_info = {} call ale#Queue(0) AssertEqual {}, g:ale_buffer_info call SetUpCursorData() call ale#cursor#EchoCursorWarning() AssertEqual '', GetLastMessage() ================================================ FILE: test/test_env_function.vader ================================================ Execute(ale#Env should produce the correct syntax): if has('win32') AssertEqual 'set name=xxx && ', ale#Env('name', 'xxx') AssertEqual 'set "name=foo bar" && ', ale#Env('name', 'foo bar') else AssertEqual 'name=''xxx'' ', ale#Env('name', 'xxx') AssertEqual 'name=''foo bar'' ', ale#Env('name', 'foo bar') endif ================================================ FILE: test/test_errors_removed_after_filetype_changed.vader ================================================ Before: Save &filetype Save g:ale_buffer_info Save g:ale_echo_cursor Save g:ale_run_synchronously Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs let g:ale_buffer_info = {} " Enable only the one feature we need. 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 let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks call setloclist(0, []) noautocmd let &filetype = 'foobar' function! TestCallback(buffer, output) return [{'text': 'x', 'lnum': 1}] endfunction call ale#linter#PreventLoading('foobar') call ale#linter#Define('foobar', { \ 'name': 'buffer_linter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd': 'true', \ 'command': 'true', \ 'read_buffer': 0, \}) call ale#linter#PreventLoading('foobar2') call ale#linter#Define('foobar2', { \ 'name': 'buffer_linter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd': 'true', \ 'command': 'true', \ 'read_buffer': 0, \}) After: Restore unlet! g:ale_run_synchronously_callbacks delfunction TestCallback call ale#linter#Reset() call setloclist(0, []) Execute(Error should be removed when the filetype changes to something else we cannot check): call ale#Queue(0) call ale#test#FlushJobs() sleep 1ms AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()) noautocmd let &filetype = 'foobar2' call ale#Queue(0) call ale#test#FlushJobs() sleep 1ms " We should get some items from the second filetype. AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()) noautocmd let &filetype = 'xxx' call ale#Queue(0) call ale#test#FlushJobs() sleep 1ms AssertEqual 0, len(ale#test#GetLoclistWithoutNewerKeys()) ================================================ FILE: test/test_filename_mapping.vader ================================================ Before: Save g:ale_filename_mappings Save b:ale_filename_mappings let g:ale_filename_mappings = {} unlet! b:ale_filename_mappings After: Restore Execute(ale#GetFilenameMappings should return the correct mappings for given linters/fixers): let g:ale_filename_mappings = {'a': [['foo', 'bar']], 'b': [['baz', 'foo']]} AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), 'a') AssertEqual [['baz', 'foo']], ale#GetFilenameMappings(bufnr(''), 'b') AssertEqual [], ale#GetFilenameMappings(bufnr(''), 'c') let b:ale_filename_mappings = {'b': [['abc', 'xyz']]} AssertEqual [], ale#GetFilenameMappings(bufnr(''), 'a') AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), 'b') AssertEqual [], ale#GetFilenameMappings(bufnr(''), 'c') Execute(ale#GetFilenameMappings should return Lists set for use with all tools): let g:ale_filename_mappings = [['foo', 'bar']] AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), 'a') AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), '') AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), v:null) let b:ale_filename_mappings = [['abc', 'xyz']] AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), 'a') AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), '') AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), v:null) Execute(ale#GetFilenameMappings should let you use * as a fallback): let g:ale_filename_mappings = {'a': [['foo', 'bar']], '*': [['abc', 'xyz']]} AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), 'a') AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), 'b') AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), '') AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), v:null) Execute(ale#filename_mapping#Invert should invert filename mappings): AssertEqual \ [['b', 'a'], ['y', 'x']], \ ale#filename_mapping#Invert([['a', 'b'], ['x', 'y']]) \ Execute(ale#filename_mapping#Map return the filename as-is if there are no mappings): AssertEqual \ '/foo//bar', \ ale#filename_mapping#Map('/foo//bar', [['/bar', '/data/']]) Execute(ale#filename_mapping#Map should map filenames): AssertEqual \ '/data/bar', \ ale#filename_mapping#Map('/foo//bar', [ \ ['/data/', '/baz/'], \ ['/foo/', '/data/'], \ ['/foo/', '/xyz/'], \ ]) ================================================ FILE: test/test_filerename.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.txt') let g:old_filename = expand('%:p') let g:Callback = '' let g:expr_list = [] let g:message_list = [] let g:handle_code_action_called = 0 let g:code_actions = [] let g:options = {} let g:capability_checked = '' let g:conn_id = v:null let g:InitCallback = v:null runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/filerename.vim runtime autoload/ale/code_action.vim function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) if a:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(g:conn_id) endif let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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#code_action#HandleCodeAction(code_action, options) abort let g:handle_code_action_called = 1 Assert get(a:options, 'should_save') call add(g:code_actions, a:code_action) endfunction function! ale#util#Input(message, value, completion) abort return 'a-new-name' endfunction call ale#filerename#SetMap({ \ 3: { \ 'old_name': 'oldName', \ 'new_name': 'aNewName', \ }, \}) After: if g:conn_id isnot v:null call ale#lsp#RemoveConnectionWithID(g:conn_id) endif call ale#filerename#SetMap({}) call ale#test#RestoreDirectory() call ale#linter#Reset() unlet! g:capability_checked unlet! g:InitCallback unlet! g:old_filename unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters unlet! g:options unlet! g:code_actions unlet! g:handle_code_action_called runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/filerename.vim runtime autoload/ale/code_action.vim Execute(Other messages for the tsserver handler should be ignored): call ale#filerename#HandleTSServerResponse(1, {'command': 'foo'}) AssertEqual g:handle_code_action_called, 0 Execute(Failed file rename responses should be handled correctly): call ale#filerename#SetMap({3: {'old_name': 'oldName', 'new_name': 'a-test'}}) call ale#filerename#HandleTSServerResponse( \ 1, \ {'command': 'getEditsForFileRename', 'request_seq': 3} \) AssertEqual g:handle_code_action_called, 0 Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(Code actions from tsserver should be handled): call ale#filerename#HandleTSServerResponse(1, { \ 'command': 'getEditsForFileRename', \ 'seq': 0, \ 'request_seq': 3, \ 'type': 'response', \ 'success': v:true, \ 'body': [ \ { \ 'fileName': '/foo/bar/file1.tsx', \ 'textChanges': [ \ { \ 'end': {'offset': 55, 'line': 22}, \ 'newText': './file2', \ 'start': {'offset': 34, 'line': 22}, \ } \ ] \ } \ ], \}) AssertEqual \ [ \ { \ 'description': 'filerename', \ 'changes': [ \ { \ 'fileName': '/foo/bar/file1.tsx', \ 'textChanges': [ \ { \ 'end': {'offset': 55, 'line': 22}, \ 'newText': './file2', \ 'start': {'offset': 34, 'line': 22}, \ } \ ] \ } \ ], \ } \ ], \ g:code_actions Execute(HandleTSServerResponse does nothing when no data in filerename_map): call ale#filerename#HandleTSServerResponse(1, { \ 'command': 'getEditsForFileRename', \ 'request_seq': -9, \ 'success': v:true, \ 'body': {} \}) AssertEqual g:handle_code_action_called, 0 Execute(Prints a tsserver error message when unsuccessful): call ale#filerename#HandleTSServerResponse(1, { \ 'command': 'getEditsForFileRename', \ 'request_seq': 3, \ 'success': v:false, \ 'message': 'This file cannot be renamed', \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''Error renaming file "oldName" to "aNewName". ' . \ 'Reason: This file cannot be renamed'''], g:expr_list Execute(Does nothing when no changes): call ale#filerename#HandleTSServerResponse(1, { \ 'command': 'getEditsForFileRename', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [], \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''No changes while renaming "oldName" to "aNewName"'''], g:expr_list Execute(tsserver file rename requests should be sent): call ale#filerename#SetMap({}) call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFileRename " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'filerename', g:capability_checked AssertEqual \ 'function(''ale#filerename#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@getEditsForFileRename', { \ 'oldFilePath': expand('%:p'), \ 'newFilePath': 'a-new-name', \ }] \ ], \ g:message_list AssertEqual {'42': {'old_name': expand('%:p'), 'new_name': 'a-new-name'}}, \ ale#filerename#GetMap() ================================================ FILE: test/test_filetype_guessing.vader ================================================ Before: augroup TestFiletypeGroup autocmd! autocmd BufEnter,BufRead *.x setf xfiletype autocmd BufEnter,BufRead *.y set filetype=yfiletype autocmd BufEnter,BufRead *.z setlocal filetype=zfiletype autocmd BufEnter,BufRead *.jsx set filetype=javascript.jsx augroup END After: augroup TestFiletypeGroup autocmd! augroup END augroup! TestFiletypeGroup Execute(ALE should guess file extensions appropriately): " The whole string should be used, if there's a match. AssertEqual '.jsx', ale#filetypes#GuessExtension('javascript.jsx') " The first part should be used. AssertEqual '.x', ale#filetypes#GuessExtension('xfiletype.yfiletype') ================================================ FILE: test/test_filetype_linter_defaults.vader ================================================ Before: Save g:ale_linters Save g:ale_linters_explicit let g:ale_linters_explicit = 0 let g:ale_linters = {} function! GetLinterNames(filetype) abort return sort(map(ale#linter#Get(a:filetype), 'v:val.name')) endfunction After: Restore call ale#linter#Reset() Execute(The defaults for the apkbuild filetype should be correct): AssertEqual ['apkbuild_lint', 'secfixes_check'], GetLinterNames('apkbuild') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('apkbuild') Execute(The defaults for the csh filetype should be correct): AssertEqual ['shell'], GetLinterNames('csh') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('csh') Execute(The defaults for the elixir filetype should be correct): AssertEqual ['credo', 'dialyxir', 'dogma'], GetLinterNames('elixir') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('elixir') Execute(The defaults for the go filetype should be correct): AssertEqual ['gofmt', 'golangci-lint', 'gopls', 'govet'], GetLinterNames('go') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('go') Execute(The defaults for the hack filetype should be correct): AssertEqual ['hack'], GetLinterNames('hack') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('hack') Execute(The defaults for the help filetype should be correct): AssertEqual [], GetLinterNames('help') Execute(The defaults for the inko filetype should be correct): AssertEqual ['inko'], GetLinterNames('inko') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('inko') Execute(The defaults for the json filetype should be correct): AssertEqual ['biome', 'jsonlint', 'spectral', 'vscodejson'], GetLinterNames('json') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('json') Execute(The defaults for the json5 filetype should be correct): AssertEqual [], GetLinterNames('json5') Execute(The defaults for the jsonc filetype should be correct): AssertEqual ['biome'], GetLinterNames('jsonc') Execute(The defaults for the perl filetype should be correct): AssertEqual ['perlcritic'], GetLinterNames('perl') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('perl') Execute(The defaults for the perl6 filetype should be correct): AssertEqual [], GetLinterNames('perl6') Execute(The defaults for the python filetype should be correct): AssertEqual ['flake8', 'mypy', 'pylint', 'pyright', 'ruff'], GetLinterNames('python') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('python') Execute(The defaults for the rust filetype should be correct): AssertEqual ['analyzer', 'cargo'], GetLinterNames('rust') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('rust') Execute(The defaults for the spec filetype should be correct): AssertEqual [], GetLinterNames('spec') Execute(The defaults for the text filetype should be correct): AssertEqual [], GetLinterNames('text') Execute(The defaults for the vue filetype should be correct): AssertEqual ['eslint', 'vls'], GetLinterNames('vue') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('vue') Execute(The defaults for the zsh filetype should be correct): AssertEqual ['shell'], GetLinterNames('zsh') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('zsh') Execute(The defaults for the verilog filetype should be correct): " This filetype isn't configured with default, so we can test loading all " available linters with this. AssertEqual ['hdl_checker', 'iverilog', 'slang', 'verible_ls', 'verilator', 'vlog', 'xvlog', 'yosys'], GetLinterNames('verilog') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('verilog') Execute(The defaults for the vader filetype should be correct): AssertEqual ['vimls'], GetLinterNames('vader') let g:ale_linters_explicit = 1 AssertEqual [], GetLinterNames('vader') Execute(Default aliases for React should be defined): AssertEqual ['javascript', 'jsx'], ale#linter#ResolveFiletype('javascriptreact') AssertEqual ['typescript', 'tsx'], ale#linter#ResolveFiletype('typescriptreact') Execute(The defaults for the yaml filetype should be correct): AssertEqual ['actionlint', 'spectral', 'yaml-language-server', 'yamllint'], GetLinterNames('yaml') ================================================ FILE: test/test_find_nearest_directory.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(We should be able to find a directory some directory down): call ale#test#SetFilename('test-files/top/middle/bottom/dummy.txt') AssertEqual \ ale#path#Simplify(expand('%:p:h:h:h:h:h') . '/test-files/top/ale-special-directory-name-dont-use-this-please/'), \ ale#path#FindNearestDirectory(bufnr('%'), 'ale-special-directory-name-dont-use-this-please') Execute(We shouldn't find anything for files which don't match): AssertEqual \ '', \ ale#path#FindNearestDirectory(bufnr('%'), 'ale-this-should-never-match-anything') ================================================ FILE: test/test_find_nearest_file.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(We should be able to find a configuration file further up): call ale#test#SetFilename('test-files/top/middle/bottom/dummy.txt') AssertEqual \ ale#path#Simplify(expand('%:p:h:h:h:h:h') . '/test-files/top/example.ini'), \ ale#path#FindNearestFile(bufnr('%'), 'example.ini') Execute(We shouldn't find anything for files which don't match): AssertEqual '', ale#path#FindNearestFile(bufnr('%'), 'cantfindthis') ================================================ FILE: test/test_find_nearest_file_or_directory.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(We should find a directory when searching and it is closer): call ale#test#SetFilename('test-files/top/needle_dir/target/query/buffer.txt') AssertEqual \ ale#path#Simplify(expand('%:p:h:h:h:h:h:h') . '/test-files/top/needle_dir/target/needle/'), \ ale#path#FindNearestFileOrDirectory(bufnr('%'), 'needle') Execute(We should find a file when searching and it is closer): call ale#test#SetFilename('test-files/top/needle_file/target/query/buffer.txt') AssertEqual \ ale#path#Simplify(expand('%:p:h:h:h:h:h:h') . '/test-files/top/needle_file/target/needle'), \ ale#path#FindNearestFileOrDirectory(bufnr('%'), 'needle') Execute(We shouldn't find anything for files which don't match): AssertEqual '', ale#path#FindNearestFileOrDirectory(bufnr('%'), 'cantfindthis') ================================================ FILE: test/test_find_references.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.txt') Save g:ale_default_navigation Save g:ale_references_show_contents let g:old_filename = expand('%:p') let g:Callback = '' let g:expr_list = [] let g:message_list = [] let g:preview_called = 0 let g:item_list = [] let g:options = {} let g:capability_checked = '' let g:conn_id = v:null let g:InitCallback = v:null let g:ale_default_navigation = 'buffer' let g:ale_references_show_contents = 1 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, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) if a:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(g:conn_id) endif let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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, options) abort let g:preview_called = 1 let g:item_list = a:item_list let g:options = a:options call ale#preview#SetLastSelection(a:item_list, a:options) endfunction After: Restore 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() unlet! g:capability_checked unlet! g:InitCallback unlet! g:old_filename unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters unlet! g:options 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 tsserver handler should be ignored): call ale#references#HandleTSServerResponse(1, {'command': 'foo'}) Execute(Failed reference responses should be handled correctly): call ale#references#SetMap({3: {}}) call ale#references#HandleTSServerResponse( \ 1, \ {'command': 'references', 'request_seq': 3} \) AssertEqual {}, ale#references#GetMap() Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(Results should be shown for tsserver responses): " We should remember these options when we repeat the selection. call ale#references#SetMap( \ { \ 3: { \ 'ignorethis': 'x', \ 'open_in': 'tab', \ 'use_relative_paths': 1, \ 'use_fzf': 0, \ } \ } \) call ale#references#HandleTSServerResponse(1, { \ 'command': 'references', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'symbolStartOffset': 9, \ 'refs': [ \ { \ 'file': '/foo/bar/app.ts', \ 'isWriteAccess': v:true, \ 'lineText': 'import {doSomething} from ''./whatever''', \ 'end': {'offset': 24, 'line': 9}, \ 'start': {'offset': 9, 'line': 9}, \ 'isDefinition': v:true, \ }, \ { \ 'file': '/foo/bar/app.ts', \ 'isWriteAccess': v:false, \ 'lineText': ' doSomething()', \ 'end': {'offset': 18, 'line': 804}, \ 'start': {'offset': 3, 'line': 804}, \ 'isDefinition': v:false, \ }, \ { \ 'file': '/foo/bar/other/app.ts', \ 'isWriteAccess': v:false, \ 'lineText': ' doSomething()', \ 'end': {'offset': 18, 'line': 51}, \ 'start': {'offset': 3, 'line': 51}, \ 'isDefinition': v:false, \ }, \ ], \ 'symbolDisplayString': 'import doSomething', \ 'symbolName': 'doSomething()', \ }, \}) AssertEqual \ [ \ {'filename': '/foo/bar/app.ts', 'column': 9, 'line': 9, 'match': 'import {doSomething} from ''./whatever'''}, \ {'filename': '/foo/bar/app.ts', 'column': 3, 'line': 804, 'match': 'doSomething()'}, \ {'filename': '/foo/bar/other/app.ts', 'column': 3, 'line': 51, 'match': 'doSomething()'}, \ ], \ g:item_list AssertEqual {}, ale#references#GetMap() " We should be able to repeat selections with ALERepeatSelection let g:item_list = [] ALERepeatSelection AssertEqual \ [ \ {'filename': '/foo/bar/app.ts', 'column': 9, 'line': 9, 'match': 'import {doSomething} from ''./whatever'''}, \ {'filename': '/foo/bar/app.ts', 'column': 3, 'line': 804, 'match': 'doSomething()'}, \ {'filename': '/foo/bar/other/app.ts', 'column': 3, 'line': 51, 'match': 'doSomething()'}, \ ], \ g:item_list AssertEqual {}, ale#references#GetMap() AssertEqual \ { \ 'open_in': 'tab', \ 'use_relative_paths': 1, \ }, \ g:options Execute(Results should be put to quickfix for tsserver responses): call ale#references#SetMap( \ { \ 3: { \ 'ignorethis': 'x', \ 'open_in': 'quickfix', \ } \ } \) call ale#references#HandleTSServerResponse(1, { \ 'command': 'references', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'symbolStartOffset': 9, \ 'refs': [ \ { \ 'file': '/foo/bar/app.ts', \ 'isWriteAccess': v:true, \ 'lineText': 'import {doSomething} from ''./whatever''', \ 'end': {'offset': 24, 'line': 9}, \ 'start': {'offset': 9, 'line': 9}, \ 'isDefinition': v:true, \ }, \ { \ 'file': '/foo/bar/app.ts', \ 'isWriteAccess': v:false, \ 'lineText': ' doSomething()', \ 'end': {'offset': 18, 'line': 804}, \ 'start': {'offset': 3, 'line': 804}, \ 'isDefinition': v:false, \ }, \ { \ 'file': '/foo/bar/other/app.ts', \ 'isWriteAccess': v:false, \ 'lineText': ' doSomething()', \ 'end': {'offset': 18, 'line': 51}, \ 'start': {'offset': 3, 'line': 51}, \ 'isDefinition': v:false, \ }, \ ], \ 'symbolDisplayString': 'import doSomething', \ 'symbolName': 'doSomething()', \ }, \}) AssertEqual \ 3, \ len(getqflist()) AssertEqual {}, ale#references#GetMap() Execute(The preview window should not be opened for empty tsserver responses): call ale#references#SetMap({3: {}}) call ale#references#HandleTSServerResponse(1, { \ 'command': 'references', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'symbolStartOffset': 9, \ 'refs': [ \ ], \ 'symbolDisplayString': 'import doSomething', \ 'symbolName': 'doSomething()', \ }, \}) Assert !g:preview_called AssertEqual {}, ale#references#GetMap() AssertEqual ['echom ''No references found.'''], g:expr_list Execute(tsserver reference requests should be sent): call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFindReferences " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'references', g:capability_checked AssertEqual \ 'function(''ale#references#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@references', {'file': expand('%:p'), 'line': 2, 'offset': 5}] \ ], \ g:message_list AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 0, 'use_fzf': 0, }}, ale#references#GetMap() Execute('-relative' argument should enable 'use_relative_paths' in HandleTSServerResponse): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFindReferences -relative call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 1, 'use_fzf': 0}}, ale#references#GetMap() Execute(`-tab` should display results in tabs): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFindReferences -tab call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'tab', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap() Execute(The default navigation type should be used): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) let g:ale_default_navigation = 'tab' ALEFindReferences call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'tab', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap() Execute(`-split` should display results in splits): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFindReferences -split call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'split', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap() Execute(`-vsplit` should display results in vsplits): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFindReferences -vsplit call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'vsplit', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap() Execute(`-quickfix` should display results in quickfix): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEFindReferences -quickfix call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'quickfix', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap() Given python(Some Python file): foo somelongerline bazxyzxyzxyz Execute(LSP reference responses should be handled): call ale#references#SetMap({3: {}}) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI(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': '', \ }, \ { \ 'filename': ale#path#Simplify(g:dir . '/other_file'), \ 'line': 8, \ 'column': 16, \ 'match': '', \ }, \ ], \ g:item_list AssertEqual {}, ale#references#GetMap() Execute(LSP reference responses should be put to quickfix): call ale#references#SetMap({3: { 'open_in': 'quickfix' }}) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/other_file')), \ 'range': { \ 'start': {'line': 7, 'character': 15}, \ }, \ }, \ ], \ } \) AssertEqual \ 2, \ len(getqflist()) Execute(LSP reference responses should contain line contents): let tempfile = tempname() let contents = ['line1 sometext', 'line2 othertext', 'line3 moretext'] call writefile(contents, tempfile) call ale#references#SetMap({3: { 'show_contents': 1 }}) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI(tempfile), \ 'range': { \ 'start': {'line': 0, 'character': 6}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI(tempfile), \ 'range': { \ 'start': {'line': 2, 'character': 1}, \ }, \ }, \ ], \ } \) AssertEqual \ 2, \ len(g:item_list) AssertEqual contents[0], g:item_list[0]['match'] AssertEqual contents[2], g:item_list[1]['match'] call ale#references#SetMap({3: { 'show_contents': 1, 'open_in': 'quickfix' }}) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI(tempfile), \ 'range': { \ 'start': {'line': 0, 'character': 6}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI(tempfile), \ 'range': { \ 'start': {'line': 2, 'character': 1}, \ }, \ }, \ ], \ } \) AssertEqual \ 2, \ len(getqflist()) AssertEqual contents[0], getqflist()[0]['text'] AssertEqual contents[2], getqflist()[1]['text'] Execute(LSP reference responses should not contain line contents when disabled): call ale#references#SetMap({3: { 'show_contents': 0 }}) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI('dummy'), \ 'range': { \ 'start': {'line': 0, 'character': 6}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI('dummy'), \ 'range': { \ 'start': {'line': 2, 'character': 1}, \ }, \ }, \ ], \ } \) AssertEqual \ 2, \ len(g:item_list) AssertEqual '', g:item_list[0]['match'] AssertEqual '', g:item_list[1]['match'] call ale#references#SetMap({3: { 'show_contents': 0, 'open_in': 'quickfix' }} ) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI('dummy'), \ 'range': { \ 'start': {'line': 0, 'character': 6}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI('dummy'), \ 'range': { \ 'start': {'line': 2, 'character': 1}, \ }, \ }, \ ], \ } \) AssertEqual \ 2, \ len(getqflist()) AssertEqual '', getqflist()[0]['text'] AssertEqual '', getqflist()[1]['text'] Execute(LSP reference responses should respect the global configuration): let g:ale_references_show_contents = 0 call ale#references#SetMap({3: {}}) let tempfile = tempname() let contents = ['line1 sometext', 'line2 othertext', 'line3 moretext'] call writefile(contents, tempfile) call ale#references#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI(tempfile), \ 'range': { \ 'start': {'line': 0, 'character': 6}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI(tempfile), \ 'range': { \ 'start': {'line': 2, 'character': 1}, \ }, \ }, \ ], \ } \) AssertEqual \ 2, \ len(g:item_list) AssertEqual '', g:item_list[0]['match'] AssertEqual '', g:item_list[1]['match'] Execute(Preview windows should not be opened for empty LSP reference responses): call ale#references#SetMap({3: {}}) call ale#references#HandleLSPResponse(1, {'id': 3, 'result': []}) Assert !g:preview_called AssertEqual {}, ale#references#GetMap() AssertEqual ['echom ''No references found.'''], g:expr_list Execute(LSP reference responses with a null result should be handled): call ale#references#SetMap({3: {}}) call ale#references#HandleLSPResponse(1, {'id': 3, 'result': v:null}) Assert !g:preview_called AssertEqual {}, ale#references#GetMap() AssertEqual ['echom ''No references found.'''], g:expr_list Execute(LSP reference requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEFindReferences " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'references', g:capability_checked AssertEqual \ 'function(''ale#references#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/references', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ 'context': {'includeDeclaration': v:false}, \ }], \ ], \ g:message_list AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap() Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResponse): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEFindReferences -relative call g:InitCallback() AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 1, 'use_fzf': 0}}, ale#references#GetMap() ================================================ FILE: test/test_floating_preview.vader ================================================ Before: let g:ale_floating_preview = 0 let g:ale_hover_to_floating_preview = 0 let g:ale_detail_to_floating_preview = 0 runtime autoload/ale/floating_preview.vim let g:floated_lines = [] let g:floating_preview_show_called = 0 " Stub out so we can track the call function! ale#floating_preview#Show(lines, ...) abort let g:floating_preview_show_called = 1 let g:floated_lines = a:lines return win_getid() endfunction let g:ale_buffer_info = { \ bufnr('%'): { \ 'loclist': [ \ { \ 'lnum': 1, \ 'col': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'notalinter', \ 'nr': -1, \ 'type': 'E', \ 'code': 'semi', \ 'text': "Missing semicolon.\r", \ 'detail': "Every statement should end with a semicolon\nsecond line", \ }, \ ], \ } \} call ale#linter#Reset() call ale#linter#PreventLoading('javascript') After: Restore let g:ale_floating_preview = 0 let g:ale_hover_to_floating_preview = 0 let g:ale_detail_to_floating_preview = 0 call cursor(1, 1) let g:ale_buffer_info = {} " Close the preview window if it's open. if &filetype is# 'ale-preview' noautocmd :q! endif call ale#linter#Reset() Given javascript(A file with warnings/errors): var x = 3 + 12345678 var x = 5*2 + parseInt("10"); // comment Execute(Floating preview is used with ALEDetail when g:ale_floating_preview set): let g:ale_floating_preview = 1 call cursor(1, 10) ALEDetail let expected = ["Every statement should end with a semicolon", "second line"] AssertEqual 1, g:floating_preview_show_called AssertEqual expected, g:floated_lines Execute(Floating preview is used with ALEDetail when g:ale_detail_to_floating_preview set): let g:ale_detail_to_floating_preview = 1 call cursor(1, 10) ALEDetail let expected = ["Every statement should end with a semicolon", "second line"] AssertEqual 1, g:floating_preview_show_called AssertEqual expected, g:floated_lines Execute(Floating preview is not used with ALEDetail by default): call cursor(1, 10) ALEDetail AssertEqual 0, g:floating_preview_show_called ================================================ FILE: test/test_format_command.vader ================================================ Before: silent! cd /testplugin/test silent file top/middle/bottom/dummy.txt function! CheckTempFile(filename) abort " Check every part of the temporary filename, except the random part. AssertEqual fnamemodify(tempname(), ':h'), fnamemodify(a:filename, ':h:h') AssertEqual 'dummy.txt', fnamemodify(a:filename, ':t') endfunction runtime autoload/ale/command.vim function! ale#command#CreateTempFile(buffer, temporary_file, input) abort return !empty(a:temporary_file) endfunction After: unlet! g:result unlet! g:match delfunction CheckTempFile runtime autoload/ale/command.vim Execute(FormatCommand should do nothing to basic command strings): AssertEqual \ ['', 'awesome-linter do something', 0], \ ale#command#FormatCommand(bufnr('%'), '', 'awesome-linter do something', 0, v:null, v:null, []) Execute(FormatCommand should handle %%, and ignore other percents): AssertEqual \ ['', '% %%d %%f %x %', 0], \ ale#command#FormatCommand(bufnr('%'), '', '%% %%%d %%%f %x %', 0, v:null, v:null, []) Execute(FormatCommand should convert %s to the current filename): AssertEqual \ [ \ '', \ 'foo ' . ale#Escape(expand('%:p')) . ' bar ' . ale#Escape(expand('%:p')), \ 0, \ ], \ ale#command#FormatCommand(bufnr('%'), '', 'foo %s bar %s', 0, v:null, v:null, []) Execute(FormatCommand should convert %t to a new temporary filename): let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0, v:null, v:null, []) call CheckTempFile(g:result[0]) let g:match = matchlist(g:result[1], '\v^foo (.*) bar (.*)$') Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] " The first item of the result should be a temporary filename, and it should " be the same as the escaped name in the command string. AssertEqual ale#Escape(g:result[0]), g:match[1] " The two temporary filenames formatted in should be the same. AssertEqual g:match[1], g:match[2] Execute(FormatCommand should not convert %t to a new temporary filename when the input is given as v:false): let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0, v:false, v:null, []) AssertEqual ['', 'foo %t bar %t', 0], g:result Execute(FormatCommand should signal that files are created when temporary files are needed): AssertEqual \ 1, \ ale#command#FormatCommand(bufnr('%'), '', 'foo %t', 0, v:null, v:null, [])[2] AssertEqual \ 0, \ ale#command#FormatCommand(bufnr('%'), '', 'foo %s', 0, v:null, v:null, [])[2] Execute(FormatCommand should let you combine %s and %t): let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %s', 0, v:null, v:null, []) call CheckTempFile(g:result[0]) let g:match = matchlist(g:result[1], '\v^foo (.*) bar (.*)$') Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] " The first item of the result should be a temporary filename, and it should " be the same as the escaped name in the command string. AssertEqual ale#Escape(g:result[0]), g:match[1] " The second item should be equal to the original filename. AssertEqual ale#Escape(expand('%:p')), g:match[2] Execute(FormatCommand should replace %e with the escaped executable): if has('win32') AssertEqual \ ['', 'foo foo', 0], \ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0, v:null, v:null, []) AssertEqual \ ['', '"foo bar"', 0], \ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0, v:null, v:null, []) AssertEqual \ ['', '%e %e', 0], \ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0, v:null, v:null, []) else AssertEqual \ ['', '''foo'' ''foo''', 0], \ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0, v:null, v:null, []) AssertEqual \ ['', '''foo bar''', 0], \ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0, v:null, v:null, []) AssertEqual \ ['', '%e %e', 0], \ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0, v:null, v:null, []) endif Execute(EscapeCommandPart should escape all percent signs): AssertEqual '%%s %%t %%%% %%s %%t %%%%', ale#engine#EscapeCommandPart('%s %t %% %s %t %%') Execute(EscapeCommandPart should pipe in temporary files appropriately): let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar', 1, v:null, v:null, []) call CheckTempFile(g:result[0]) let g:match = matchlist(g:result[1], '\v^foo bar \< (.*)$') Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] AssertEqual ale#Escape(g:result[0]), g:match[1] let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar %t', 1, v:null, v:null, []) call CheckTempFile(g:result[0]) let g:match = matchlist(g:result[1], '\v^foo bar (.*)$') Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] AssertEqual ale#Escape(g:result[0]), g:match[1] Execute(FormatCommand should apply filename modifiers to the current file): AssertEqual \ ale#Escape(expand('%:p:h')) \ . ' ' . ale#Escape('dummy.txt') \ . ' ' . ale#Escape(expand('%:p:h:t')) \ . ' ' . ale#Escape('txt') \ . ' ' . ale#Escape(expand('%:p:r')), \ ale#command#FormatCommand(bufnr(''), '', '%s:h %s:t %s:h:t %s:e %s:r', 0, v:null, v:null, [])[1] Execute(FormatCommand should apply filename modifiers to the temporary file): let g:result = ale#command#FormatCommand(bufnr(''), '', '%t:h %t:t %t:h:t %t:e %t:r', 0, v:null, v:null, []) AssertEqual \ ale#Escape(fnamemodify(g:result[0], ':h')) \ . ' ' . ale#Escape('dummy.txt') \ . ' ' . ale#Escape(fnamemodify(g:result[0], ':h:t')) \ . ' ' . ale#Escape('txt') \ . ' ' . ale#Escape(fnamemodify(g:result[0], ':r')), \ g:result[1] Execute(FormatCommand should apply filename mappings the current file): let g:result = ale#command#FormatCommand(bufnr('%'), '', '%s', 0, v:null, v:null, [ \ [expand('%:p:h'), '/foo/bar'], \]) Assert g:result[1] =~# '/foo/bar' Execute(FormatCommand should apply filename mappings to temporary files): let g:result = ale#command#FormatCommand(bufnr('%'), '', '%t', 0, v:null, v:null, [ \ [fnamemodify(tempname(), ':h:h'), '/foo/bar'] \]) Assert g:result[1] =~# '/foo/bar' Execute(FormatCommand should apply filename modifiers to mapped filenames): let g:result = ale#command#FormatCommand(bufnr('%'), '', '%s:h', 0, v:null, v:null, [ \ [expand('%:p:h'), '/foo/bar'], \]) AssertEqual ale#Escape('/foo/bar'), g:result[1] let g:result = ale#command#FormatCommand(bufnr('%'), '', '%t:h:h:h', 0, v:null, v:null, [ \ [fnamemodify(tempname(), ':h:h'), '/foo/bar'] \]) AssertEqual ale#Escape('/foo/bar'), g:result[1] Execute(FormatCommand should apply regular cwd paths): AssertEqual \ 'cd ' . (has('unix') ? '' : '/d ') . ale#Escape('/foo /bar') . ' && abc', \ ale#command#FormatCommand(bufnr('%'), '', 'abc', 0, v:null, '/foo /bar', [])[1] \ Execute(FormatCommand should apply cwd substitution and formatting): call ale#test#SetFilename('foo.txt') AssertEqual \ 'cd ' . (has('unix') ? '' : '/d ') . ale#Escape(getcwd()) . ' && abc', \ ale#command#FormatCommand(bufnr('%'), '', 'abc', 0, v:null, '%s:h', [])[1] ================================================ FILE: test/test_format_temporary_file_creation.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_echo_cursor Save g:ale_enabled Save g:ale_run_synchronously Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs " Disable the features we don't need to check. let g:ale_buffer_info = {} let g:ale_echo_cursor = 0 let g:ale_enabled = 1 let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks let g:ale_set_highlights = 0 let g:ale_set_loclist = 0 let g:ale_set_quickfix = 0 let g:ale_set_signs = 0 let g:output = [] function! TestCallback(buffer, output) " Extract just letters from the output. let g:output = filter( \ map(a:output, 'matchstr(v:val, ''[a-zA-Z]\+'')'), \ '!empty(v:val)' \) return [] endfunction call ale#linter#PreventLoading('foobar') call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd' : 'cat', \ 'command': has('win32') ? 'type %t' : 'cat %t', \}) After: Restore unlet! g:ale_run_synchronously_callbacks unlet! g:output delfunction TestCallback call ale#engine#Cleanup(bufnr('')) call ale#linter#Reset() Given foobar (Some imaginary filetype): foo bar baz Execute(ALE should be able to read the %t file): AssertEqual 'foobar', &filetype ALELint call ale#test#FlushJobs() AssertEqual ['foo', 'bar', 'baz'], g:output ================================================ FILE: test/test_function_arg_count.vader ================================================ Before: function! Func0() endfunction function! Func1(x) endfunction function! Func2(x,y) endfunction function! Func3(x,y,z) endfunction function! Func3a(x,y,z,...) endfunction After: delfunction Func0 delfunction Func1 delfunction Func2 delfunction Func3 delfunction Func3a Execute(We should be able to compute the argument count for function names): AssertEqual 0, ale#util#FunctionArgCount('Func0') AssertEqual 1, ale#util#FunctionArgCount('Func1') AssertEqual 2, ale#util#FunctionArgCount('Func2') AssertEqual 3, ale#util#FunctionArgCount('Func3') AssertEqual 3, ale#util#FunctionArgCount('Func3a') Execute(We should be able to compute the argument count for Funcrefs): AssertEqual 0, ale#util#FunctionArgCount(function('Func0')) AssertEqual 1, ale#util#FunctionArgCount(function('Func1')) AssertEqual 2, ale#util#FunctionArgCount(function('Func2')) AssertEqual 3, ale#util#FunctionArgCount(function('Func3')) AssertEqual 3, ale#util#FunctionArgCount(function('Func3a')) Execute(We should be able to compute the argument count for lambdas): if has('lambda') AssertEqual 0, ale#util#FunctionArgCount({->1}) AssertEqual 1, ale#util#FunctionArgCount({x->1}) AssertEqual 2, ale#util#FunctionArgCount({x,y->1}) AssertEqual 3, ale#util#FunctionArgCount({x,y,z->1}) AssertEqual 3, ale#util#FunctionArgCount({x,y,z,...->1}) endif Execute(We should be able to compute the argument count autoload functions not yet loaded): AssertEqual 1, ale#util#FunctionArgCount(function('ale#fixers#yapf#Fix')) AssertEqual 1, ale#util#FunctionArgCount('ale#fixers#yapf#Fix') ================================================ FILE: test/test_fuzzy_json_decode.vader ================================================ Execute(FuzzyJSONDecode should return the default for empty Lists): AssertEqual [], ale#util#FuzzyJSONDecode([], []) AssertEqual {}, ale#util#FuzzyJSONDecode([], {}) Execute(FuzzyJSONDecode should return the default for empty Strings): AssertEqual [], ale#util#FuzzyJSONDecode('', []) AssertEqual {}, ale#util#FuzzyJSONDecode('', {}) Execute(FuzzyJSONDecode should return the default value for ['']): AssertEqual [], ale#util#FuzzyJSONDecode([''], []) AssertEqual {}, ale#util#FuzzyJSONDecode([''], {}) Execute(FuzzyJSONDecode should return the default value for only whitespace lines): AssertEqual [], ale#util#FuzzyJSONDecode(['', "\n"], []) AssertEqual {}, ale#util#FuzzyJSONDecode(['', "\n"], {}) Execute(FuzzyJSONDecode should return the default for Lists with invalid JSON): AssertEqual [], ale#util#FuzzyJSONDecode(['x'], []) AssertEqual {}, ale#util#FuzzyJSONDecode(['x'], {}) Execute(FuzzyJSONDecode should return the default for Strings with invalid JSON): AssertEqual [], ale#util#FuzzyJSONDecode('x', []) AssertEqual {}, ale#util#FuzzyJSONDecode('x', {}) Execute(FuzzyJSONDecode should return the JSON from the JSON string): AssertEqual {'x': 3}, ale#util#FuzzyJSONDecode('{"x": 3}', []) AssertEqual {'x': 3}, ale#util#FuzzyJSONDecode('{"x": 3}', {}) AssertEqual {'x': 3}, ale#util#FuzzyJSONDecode(['{"x"', ': 3}'], []) AssertEqual {'x': 3}, ale#util#FuzzyJSONDecode(['{"x"', ': 3}'], {}) ================================================ FILE: test/test_get_abspath.vader ================================================ Execute(Relative paths should be resolved correctly): AssertEqual \ has('win32') ? '\foo\bar\baz\whatever.txt' : '/foo/bar/baz/whatever.txt', \ ale#path#GetAbsPath('/foo/bar/xyz', '../baz/whatever.txt') AssertEqual \ has('win32') ? '\foo\bar\xyz\whatever.txt' : '/foo/bar/xyz/whatever.txt', \ ale#path#GetAbsPath('/foo/bar/xyz', './whatever.txt') AssertEqual \ has('win32') ? '\foo\bar\xyz\whatever.txt' : '/foo/bar/xyz/whatever.txt', \ ale#path#GetAbsPath('/foo/bar/xyz', 'whatever.txt') if has('win32') AssertEqual \ 'C:\foo\bar\baz\whatever.txt', \ ale#path#GetAbsPath('C:\foo\bar\baz\xyz', '../whatever.txt') AssertEqual \ 'C:\foo\bar\baz\whatever.txt', \ ale#path#GetAbsPath('C:\foo\bar\baz\xyz', '..\whatever.txt') AssertEqual \ 'C:\foo\bar\baz\whatever.txt', \ ale#path#GetAbsPath('C:/foo/bar/baz/xyz', '../whatever.txt') AssertEqual \ 'C:\foo\bar\baz\whatever.txt', \ ale#path#GetAbsPath('C:/foo/bar/baz/xyz', '..\whatever.txt') endif Execute(Absolute paths should be resolved correctly): AssertEqual \ has('win32') ? '\ding\dong' : '/ding/dong', \ ale#path#GetAbsPath('/foo/bar/xyz', '/ding/dong') AssertEqual \ has('win32') ? '\ding\dong' : '/ding/dong', \ ale#path#GetAbsPath('/foo/bar/xyz', '//ding/dong') if has('win32') AssertEqual '\ding', ale#path#GetAbsPath('/foo/bar/xyz', '\\ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('/foo/bar/xyz', 'c:/ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('/foo/bar/xyz', 'c:\ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('\foo\bar\xyz', 'c:/ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('\foo\bar\xyz', 'c:\ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('c:/foo/bar/xyz', 'c:/ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('c:/foo/bar/xyz', 'c:\ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('c:\foo\bar\xyz', 'c:/ding') AssertEqual 'c:\ding', ale#path#GetAbsPath('c:\foo\bar\xyz', 'c:\ding') endif ================================================ FILE: test/test_get_loclist.vader ================================================ Before: let g:loclist = [ \ { \ 'lnum': 1, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'eslint', \ 'nr': -1, \ 'type': 'E', \ 'col': 10, \ 'text': 'Missing semicolon. (semi)' \ }, \ { \ 'lnum': 2, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'eslint', \ 'nr': -1, \ 'type': 'W', \ 'col': 10, \ 'text': 'Infix operators must be spaced. (space-infix-ops)' \ }, \] let g:ale_buffer_info = {'1': {'loclist': g:loclist}} After: unlet g:loclist let g:ale_buffer_info = {} Execute(GetLoclist should return the loclist): AssertEqual g:loclist, ale#engine#GetLoclist(1) ================================================ FILE: test/test_getmatches.vader ================================================ Execute (ale#util#GetMatches should return matches for many lines): AssertEqual \ [ \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '47', \ '14', \ 'Missing trailing comma.', \ 'Warning/comma-dangle', \ '', \ '', \ '', \ '', \ '', \ ], \ [ \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ '56', \ '41', \ 'Missing semicolon.', \ 'Error/semi', \ '', \ '', \ '', \ '', \ '', \ ], \ ], \ ale#util#GetMatches( \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ ], \ [ \ '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$', \ ] \ ) Execute (ale#util#GetMatches should accept a string for a single pattern): AssertEqual \ [ \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '47', \ '14', \ 'Missing trailing comma.', \ 'Warning/comma-dangle', \ '', \ '', \ '', \ '', \ '', \ ], \ [ \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ '56', \ '41', \ 'Missing semicolon.', \ 'Error/semi', \ '', \ '', \ '', \ '', \ '', \ ], \ ], \ ale#util#GetMatches( \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ ], \ '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$' \ ) Execute (ale#util#MapMatches should map matches): AssertEqual \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ ], \ ale#util#MapMatches( \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ ], \ '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$', \ {match -> match[0]} \ ) Execute (ale#util#GetMatches should accept a single line as a string): AssertEqual \ [ \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '47', \ '14', \ 'Missing trailing comma.', \ 'Warning/comma-dangle', \ '', \ '', \ '', \ '', \ '', \ ], \ ], \ ale#util#GetMatches( \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ [ \ '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$', \ ] \ ) Execute (ale#util#GetMatches should match multiple patterns correctly): AssertEqual \ [ \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '47', \ '14', \ 'Missing trailing comma.', \ 'Warning/comma-dangle', \ '', \ '', \ '', \ '', \ '', \ ], \ [ \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ '56', \ '41', \ 'Missing semicolon.', \ 'Error/semi', \ '', \ '', \ '', \ '', \ '', \ ], \ [ \ '/path/to/some-filename.js:13:3: Parsing error: Unexpected token', \ '13', \ '3', \ 'Parsing error: Unexpected token', \ '', \ '', \ '', \ '', \ '', \ '', \ ], \ ], \ ale#util#GetMatches( \ [ \ '/path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]', \ '/path/to/some-filename.js:56:41: Missing semicolon. [Error/semi]', \ '/path/to/some-filename.js:13:3: Parsing error: Unexpected token', \ ], \ [ \ '^.*:\(\d\+\):\(\d\+\): \(.\+\) \[\(.\+\)\]$', \ '^.*:\(\d\+\):\(\d\+\): \(.\+\)$', \ ] \ ) ================================================ FILE: test/test_go_to_definition.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.txt') Save g:ale_default_navigation let g:old_filename = expand('%:p') let g:Callback = '' let g:message_list = [] let g:expr_list = [] let g:capability_checked = '' let g:conn_id = v:null let g:InitCallback = v:null let g:ale_default_navigation = 'buffer' runtime autoload/ale/linter.vim runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) if a:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(g:conn_id) endif let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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 After: Restore 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() unlet! g:capability_checked unlet! g:InitCallback unlet! g:old_filename unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim Execute(Other messages for the tsserver handler should be ignored): call ale#definition#HandleTSServerResponse(1, {'command': 'foo'}) Execute(Tagstack should be incremented if supported): if exists('*gettagstack') && exists('*settagstack') let original_stack_depth = gettagstack().length endif call ale#definition#UpdateTagStack() if exists('*gettagstack') && exists('*settagstack') AssertEqual original_stack_depth + 1, gettagstack().length endif Execute(Failed definition responses should be handled correctly): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleTSServerResponse( \ 1, \ {'command': 'definition', 'request_seq': 3} \) AssertEqual {}, ale#definition#GetMap() Execute(Failed definition responses with no files should be handled correctly): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleTSServerResponse( \ 1, \ { \ 'command': 'definition', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [], \ } \) AssertEqual {}, ale#definition#GetMap() Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(Other files should be jumped to for definition responses): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleTSServerResponse( \ 1, \ { \ 'command': 'definition', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [ \ { \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'), \ 'start': {'line': 3, 'offset': 7}, \ }, \ ], \ } \) AssertEqual \ [ \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 7], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Other files should be jumped to for definition responses in tabs too): call ale#definition#SetMap({3: {'open_in': 'tab'}}) call ale#definition#HandleTSServerResponse( \ 1, \ { \ 'command': 'definition', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [ \ { \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'), \ 'start': {'line': 3, 'offset': 7}, \ }, \ ], \ } \) AssertEqual \ [ \ 'tabedit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 7], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Other files should be jumped to for definition responses in splits too): call ale#definition#SetMap({3: {'open_in': 'split'}}) call ale#definition#HandleTSServerResponse( \ 1, \ { \ 'command': 'definition', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [ \ { \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'), \ 'start': {'line': 3, 'offset': 7}, \ }, \ ], \ } \) AssertEqual \ [ \ 'split +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 7], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Other files should be jumped to for definition responses in vsplits too): call ale#definition#SetMap({3: {'open_in': 'vsplit'}}) call ale#definition#HandleTSServerResponse( \ 1, \ { \ 'command': 'definition', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [ \ { \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'), \ 'start': {'line': 3, 'offset': 7}, \ }, \ ], \ } \) AssertEqual \ [ \ 'vsplit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 7], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(tsserver definition requests should be sent): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEGoToDefinition " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'definition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@definition', {'file': expand('%:p'), 'line': 2, 'offset': 5}] \ ], \ g:message_list AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap() Execute(tsserver type definition requests should be sent): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEGoToTypeDefinition " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'typeDefinition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@typeDefinition', {'file': expand('%:p'), 'line': 2, 'offset': 5}] \ ], \ g:message_list AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap() Execute(tsserver implementation requests should be sent): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEGoToImplementation " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'implementation', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@implementation', {'file': expand('%:p'), 'line': 2, 'offset': 5}] \ ], \ g:message_list AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap() Execute(tsserver tab definition requests should be sent): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALEGoToDefinition -tab " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'definition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@definition', {'file': expand('%:p'), 'line': 2, 'offset': 5}] \ ], \ g:message_list AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap() Execute(The default navigation type should be used): runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) let g:ale_default_navigation = 'tab' ALEGoToDefinition " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'definition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@definition', {'file': expand('%:p'), 'line': 2, 'offset': 5}] \ ], \ g:message_list AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap() Given python(Some Python file): foo somelongerline bazxyzxyzxyz Execute(Other files should be jumped to for LSP definition responses): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ } \) AssertEqual \ [ \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 8], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Newer LocationLink items should be supported): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': { \ 'targetUri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'targetRange': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ } \) AssertEqual \ [ \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 8], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Locations inside the same file should be jumped to without using :edit): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(expand('%:p'))), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ } \) AssertEqual \ [ \ ], \ g:expr_list AssertEqual [3, 8], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Other files should be jumped to in tabs for LSP definition responses): call ale#definition#SetMap({3: {'open_in': 'tab'}}) call ale#definition#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ } \) AssertEqual \ [ \ 'tabedit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ ], \ g:expr_list AssertEqual [3, 8], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Definition responses with lists should be handled): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': [ \ { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ { \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/other_file')), \ 'range': { \ 'start': {'line': 20, 'character': 3}, \ }, \ }, \ ], \ } \) " Multiple results should either open the ALEPreview or go to quickfix AssertEqual [1, 1], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() Execute(Definition responses with null response should be handled): call ale#definition#SetMap({3: {'open_in': 'current-buffer'}}) call ale#definition#HandleLSPResponse(1, {'id': 3, 'result': v:null}) AssertEqual ['echom ''No definitions found'''], g:expr_list Execute(LSP definition requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEGoToDefinition " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'definition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/definition', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap() Execute(LSP type definition requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEGoToTypeDefinition " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'typeDefinition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/typeDefinition', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap() Execute(LSP implementation requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEGoToImplementation " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'implementation', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/implementation', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap() Execute(LSP tab definition requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEGoToDefinition -tab " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'definition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/definition', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap() Execute(LSP tab type definition requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEGoToTypeDefinition -tab " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'typeDefinition', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/typeDefinition', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap() Execute(LSP tab implementation requests should be sent): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALEGoToImplementation -tab " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'implementation', g:capability_checked AssertEqual \ 'function(''ale#definition#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/implementation', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ }], \ ], \ g:message_list AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap() ================================================ FILE: test/test_gradle_build_classpath_command.vader ================================================ Before: Save $PATH Save $PATHEXT let $PATHEXT = '.' call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/kotlin/kotlinc.vim let g:command_tail = ' -I ' . ale#Escape(ale#gradle#GetInitPath()) \ . ' -q printClasspath' let g:gradle_init_path = ale#path#Simplify(g:dir . '../../autoload/ale/gradle/init.gradle') After: Restore unlet! g:gradle_init_path unlet! g:command_tail call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return 'gradlew' command if project includes gradle wapper): call ale#test#SetFilename('test-files/gradle/wrapped-project/src/main/kotlin/dummy.kt') AssertEqual \ [ \ ale#path#Simplify(g:dir . '/test-files/gradle/wrapped-project'), \ ale#Escape(ale#path#Simplify(g:dir . '/test-files/gradle/wrapped-project/gradlew')) \ . g:command_tail, \ ], \ ale#gradle#BuildClasspathCommand(bufnr('')) Execute(Should return 'gradle' command if project does not include gradle wapper): call ale#test#SetFilename('test-files/gradle/unwrapped-project/src/main/kotlin/dummy.kt') let $PATH .= (has('win32') ? ';' : ':') \ . ale#path#Simplify(g:dir . '/test-files/gradle') AssertEqual \ [ \ ale#path#Simplify(g:dir . '/test-files/gradle/unwrapped-project'), \ ale#Escape('gradle') . g:command_tail \ ], \ ale#gradle#BuildClasspathCommand(bufnr('')) Execute(Should return empty string if gradle cannot be executed): call ale#test#SetFilename('test-files/gradle/non-gradle-project/src/main/kotlin/dummy.kt') AssertEqual \ ['', ''], \ ale#gradle#BuildClasspathCommand(bufnr('')) ================================================ FILE: test/test_gradle_find_executable.vader ================================================ Before: Save $PATH Save $PATHEXT " Count the gradle executable without .exe as executable on Windows let $PATHEXT = '.' call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/kotlin/kotlinc.vim After: Restore call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return 'gradlew' if found in parent directory): call ale#test#SetFilename('test-files/gradle/wrapped-project/src/main/kotlin/dummy.kt') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/gradle/wrapped-project/gradlew'), \ ale#gradle#FindExecutable(bufnr('')) Execute(Should return 'gradle' if 'gradlew' not found in parent directory): call ale#test#SetFilename('test-files/gradle/unwrapped-project/src/main/kotlin/dummy.kt') let $PATH .= (has('win32') ? ';': ':') . ale#path#Simplify(g:dir . '/test-files/gradle') AssertEqual \ 'gradle', \ ale#gradle#FindExecutable(bufnr('')) Execute(Should return empty string if 'gradlew' not in parent directory and gradle not in path): call ale#test#SetFilename('test-files/gradle/unwrapped-project/src/main/kotlin/dummy.kt') AssertEqual \ '', \ ale#gradle#FindExecutable(bufnr('')) ================================================ FILE: test/test_gradle_find_project_root.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/kotlin/kotlinc.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return directory for 'gradlew' if found in parent directory): call ale#test#SetFilename('test-files/gradle/wrapped-project/src/main/kotlin/dummy.kt') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/gradle/wrapped-project'), \ ale#gradle#FindProjectRoot(bufnr('')) Execute(Should return directory for 'settings.gradle' if found in parent directory): call ale#test#SetFilename('test-files/gradle/settings-gradle-project/src/main/kotlin/dummy.kt') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/gradle/settings-gradle-project'), \ ale#gradle#FindProjectRoot(bufnr('')) Execute(Should return directory for 'build.gradle' if found in parent directory): call ale#test#SetFilename('test-files/gradle/build-gradle-project/src/main/kotlin/dummy.kt') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/gradle/build-gradle-project'), \ ale#gradle#FindProjectRoot(bufnr('')) Execute(Should return empty string if gradle files are not found in parent directory): call ale#test#SetFilename('test-files/gradle/non-gradle-project/src/main/kotlin/dummy.kt') AssertEqual \ '', \ ale#gradle#FindProjectRoot(bufnr('')) ================================================ FILE: test/test_helptags.vader ================================================ Execute (helptags should run without issue): helptags ALL ================================================ FILE: test/test_highlight_placement.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_echo_cursor Save g:ale_enabled Save g:ale_run_synchronously Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs Save g:ale_exclude_highlights Save b:ale_exclude_highlights runtime autoload/ale/virtualtext.vim runtime autoload/ale/highlight.vim let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks let g:ale_set_highlights = 1 let g:ale_set_signs = 1 let g:ale_buffer_info = {} " Disable features we don't need for these tests. let g:ale_set_quickfix = 0 let g:ale_set_loclist = 0 let g:ale_echo_cursor = 0 let g:ale_exclude_highlights = [] let b:ale_exclude_highlights = [] function! GenerateResults(buffer, output) return [ \ { \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'text': 'foo', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'type': 'W', \ 'text': 'bar', \ }, \ { \ 'lnum': 3, \ 'col': 5, \ 'type': 'E', \ 'text': 'wat', \ }, \] endfunction let g:has_nvim_highlight = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace') let g:nvim_highlight_matches = {} function! ale#highlight#nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end) abort if a:line_end != -1 throw 'nvim api behavior not supported' endif let l:matches = get(g:nvim_highlight_matches, a:buffer, []) call filter( \ l:matches, \ {_, val -> val.pos1[0] < (a:line_start + 1) }, \) endfunction function! ale#highlight#nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end) abort if a:col_end == -1 throw 'nvim api behavior not supported' endif let l:matches = get(g:nvim_highlight_matches, a:buffer, []) let g:nvim_highlight_matches[a:buffer] = l:matches let l:new_match = { \ 'group': a:hl_group, \ 'priority': 10, \ 'pos1': [a:line + 1, a:col_start + 1, a:col_end - a:col_start], \} call add(l:matches, l:new_match) " sort by line number to emulate getmatches faithfully call sort(l:matches, {m1, m2 -> m1.pos1[0] - m2.pos1[0]}) endfunction " We don't care what the IDs are, just that we have some matches. " The IDs are generated. function! GetMatchesWithoutIDs() abort if g:has_nvim_highlight return get(g:nvim_highlight_matches, bufnr(''), []) else let l:list = getmatches() for l:item in l:list call remove(l:item, 'id') endfor return l:list endif endfunction function! GetLinkedGroup(grp) abort return synIDattr(synIDtrans(hlID(a:grp)), 'name') endfunction call ale#linter#Define('testft', { \ 'name': 'x', \ 'executable': has('win32') ? 'cmd': 'echo', \ 'command': has('win32') ? 'echo' : '/bin/sh -c ''echo''', \ 'callback': 'GenerateResults', \}) highlight link SomeOtherGroup SpellBad After: Restore unlet! g:ale_run_synchronously_callbacks unlet! g:items unlet! b:ale_enabled unlet! g:has_nvim_highlight unlet! g:nvim_highlight_matches delfunction GenerateResults call ale#linter#Reset() call clearmatches() call ale#sign#Clear() if has('textprop') && has('popupwin') call prop_type_delete('ale') endif highlight clear SomeOtherGroup runtime autoload/ale/highlight.vim Given testft(A Javscript file with warnings/errors): foo bar baz wat line four " Autoloading virtualtext.vim first should still properly initialize hl-groups Execute(Loading virtualtext first does not break highlight groups): AssertEqual \ "SpellBad", \ GetLinkedGroup("ALEError") AssertEqual \ "SpellCap", \ GetLinkedGroup("ALEWarning") Execute(Highlights should be set when a linter runs): ALELint call ale#test#FlushJobs() AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [2, 1, 1]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 5, 1]} \ ], \ GetMatchesWithoutIDs() " This test is important for preventing ALE from showing highlights for " the wrong files. Execute(Highlights set by ALE should be removed when buffer cleanup is done): call ale#engine#InitBufferInfo(bufnr('%')) call ale#highlight#SetHighlights(bufnr('%'), [ \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2}, \]) if !g:has_nvim_highlight " This check doesn't work with the new API, for some reason. AssertEqual \ [{'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}], \ GetMatchesWithoutIDs() endif call ale#engine#Cleanup(bufnr('%')) AssertEqual [], GetMatchesWithoutIDs() Execute(Highlights should be cleared when buffers are hidden): call ale#engine#InitBufferInfo(bufnr('%')) " The second item should be ignored, as it has no column infomration. let g:ale_buffer_info[bufnr('%')].loclist = [ \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 4, 'col': 0}, \] call ale#highlight#SetHighlights( \ bufnr('%'), \ g:ale_buffer_info[bufnr('%')].loclist \) AssertEqual 1, len(GetMatchesWithoutIDs()), 'The highlights weren''t initially set!' call ale#highlight#BufferHidden(bufnr('%')) AssertEqual 0, len(GetMatchesWithoutIDs()), 'The highlights weren''t cleared!' call ale#highlight#UpdateHighlights() AssertEqual 1, len(GetMatchesWithoutIDs()), 'The highlights weren''t set again!' Execute(Only ALE highlights should be restored when buffers are restored): call ale#engine#InitBufferInfo(bufnr('%')) let g:ale_buffer_info[bufnr('%')].loclist = [ \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2}, \] call ale#highlight#SetHighlights( \ bufnr('%'), \ g:ale_buffer_info[bufnr('%')].loclist \) call matchaddpos('SomeOtherGroup', [[1, 1, 1]]) " We should have both highlights. if g:has_nvim_highlight " When the newer NeoVim API is used, we don't have to worry about " other highlights, namespacing is available. AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}, \ ], \ GetMatchesWithoutIDs() else AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}, \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}, \ ], \ sort(GetMatchesWithoutIDs(), {m1, m2 -> m1.group < m2.group ? -1 : 1}) endif call ale#highlight#BufferHidden(bufnr('%')) " We should remove our highlight, but not the other one. if g:has_nvim_highlight AssertEqual [], GetMatchesWithoutIDs() else AssertEqual \ [ \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]} \ ], \ GetMatchesWithoutIDs() endif call ale#highlight#UpdateHighlights() " Our highlight should apper again. if g:has_nvim_highlight AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}, \ ], \ GetMatchesWithoutIDs() else AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}, \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}, \ ], \ sort(GetMatchesWithoutIDs(), {m1, m2 -> m1.group < m2.group ? -1 : 1}) endif Execute(Highlight end columns should set an appropriate size): call ale#highlight#SetHighlights(bufnr('%'), [ \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2, 'end_col': 5}, \ {'bufnr': bufnr('%'), 'type': 'W', 'lnum': 4, 'col': 1, 'end_col': 5}, \]) AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 4]}, \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [4, 1, 5]}, \ ], \ GetMatchesWithoutIDs() Execute(Highlight end columns should set an appropriate size): call ale#highlight#SetHighlights(bufnr('%'), [ \ {'bufnr': bufnr('%') - 1, 'type': 'E', 'lnum': 1, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 1, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 2, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'E', 'sub_type': 'style', 'lnum': 3, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'W', 'lnum': 4, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'W', 'lnum': 5, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'W', 'sub_type': 'style', 'lnum': 6, 'col': 1}, \ {'bufnr': bufnr('%'), 'type': 'I', 'lnum': 7, 'col': 1}, \ {'bufnr': bufnr('%') + 1, 'type': 'E', 'lnum': 1, 'col': 1}, \]) AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [2, 1, 1]}, \ {'group': 'ALEStyleError', 'priority': 10, 'pos1': [3, 1, 1]}, \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [4, 1, 1]}, \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [5, 1, 1]}, \ {'group': 'ALEStyleWarning', 'priority': 10, 'pos1': [6, 1, 1]}, \ {'group': 'ALEInfo', 'priority': 10, 'pos1': [7, 1, 1]}, \ ], \ GetMatchesWithoutIDs() Execute(Highlighting should support errors spanning many lines): let g:items = [ \ {'bufnr': bufnr(''), 'type': 'E', 'lnum': 1, 'col': 1, 'end_lnum': 10, 'end_col': 3}, \] call ale#highlight#SetHighlights(bufnr(''), g:items) if g:has_nvim_highlight " The newer NeoVim highlight API produces different output. AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [2, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [4, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [5, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [6, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [7, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [8, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [9, 1, 1073741824]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [10, 1, 3]}, \ ], \ GetMatchesWithoutIDs() else " We should set 2 highlights for the item, as we can only add 8 at a time. AssertEqual \ [ \ { \ 'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1073741824], \ 'pos2': [2], 'pos3': [3], 'pos4': [4], 'pos5': [5], 'pos6': [6], \ 'pos7': [7], 'pos8': [8], \ }, \ { \ 'group': 'ALEError', 'priority': 10, \ 'pos1': [9], 'pos2': [10, 1, 3] \ }, \ ], \ GetMatchesWithoutIDs() endif Execute(Highlights should always be cleared when the buffer highlight list is empty): if g:has_nvim_highlight " The newer API uses namespacing. We'll emulate it here. call ale#highlight#nvim_buf_add_highlight( \ bufnr(''), \ 1, \ 'ALEError', \ 0, \ 0, \ 1, \) AssertEqual \ [{'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}], \ GetMatchesWithoutIDs() else " Add our highlights and something else. call matchaddpos('ALEError', [[1, 1, 1]]) call matchaddpos('SomeOtherGroup', [[1, 1, 1]]) AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}, \ ], \ GetMatchesWithoutIDs() endif " Set the List we use for holding highlights for buffers. let b:ale_highlight_items = [] " Call the function for updating the highlights called when buffers " are entered, or when problems are presented. call ale#highlight#UpdateHighlights() " Check that we remove our highlights. if g:has_nvim_highlight AssertEqual [], GetMatchesWithoutIDs() else AssertEqual \ [{'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}], \ GetMatchesWithoutIDs() endif Execute(Highlights should be hidden when excluded): let b:ale_exclude_highlights = ['ig.*ore', 'nope'] call ale#highlight#SetHighlights(bufnr('%'), [ \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 1, 'col': 1, 'text': 'hello'}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 2, 'col': 1, 'text': 'ignore'}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 1, 'text': 'nope'}, \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 4, 'col': 1, 'text': 'world'}, \]) AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'ALEError', 'priority': 10, 'pos1': [4, 1, 1]}, \ ], \ GetMatchesWithoutIDs() Execute(Highlights should be cleared when ALE is disabled): let g:ale_enabled = 1 call ale#highlight#SetHighlights(bufnr(''), [ \ {'bufnr': bufnr(''), 'type': 'E', 'lnum': 1, 'col': 1, 'end_lnum': 10, 'end_col': 3}, \]) let g:ale_enabled = 0 call ale#highlight#UpdateHighlights() AssertEqual [], GetMatchesWithoutIDs() let g:ale_enabled = 1 call ale#highlight#SetHighlights(bufnr(''), [ \ {'bufnr': bufnr(''), 'type': 'E', 'lnum': 1, 'col': 1, 'end_lnum': 10, 'end_col': 3}, \]) let b:ale_enabled = 0 call ale#highlight#UpdateHighlights() AssertEqual [], GetMatchesWithoutIDs() Execute(Line highlights should be set when signs are disabled): " This will mess with your settings, but it needs to be tested. " We need to match highlights case-insensitively when removing them. hi link aleerrorline spellbad let g:ale_set_signs = 0 call ale#highlight#SetHighlights(bufnr(''), [ \ {'bufnr': bufnr(''), 'type': 'E', 'lnum': 1, 'col': 1}, \ {'bufnr': bufnr(''), 'type': 'W', 'lnum': 2, 'col': 1}, \ {'bufnr': bufnr(''), 'type': 'I', 'lnum': 3, 'col': 1}, \]) if g:has_nvim_highlight " The output is different with the newer NeoVIM highlight API. AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'ALEErrorLine', 'priority': 10, 'pos1': [1, 1, 1073741824]}, \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [2, 1, 1]}, \ {'group': 'ALEWarningLine', 'priority': 10, 'pos1': [2, 1, 1073741824]}, \ {'group': 'ALEInfo', 'priority': 10, 'pos1': [3, 1, 1]}, \ {'group': 'ALEInfoLine', 'priority': 10, 'pos1': [3, 1, 1073741824]} \ ], \ GetMatchesWithoutIDs() else AssertEqual \ [ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}, \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [2, 1, 1]}, \ {'group': 'ALEInfo', 'priority': 10, 'pos1': [3, 1, 1]}, \ {'group': 'aleerrorline', 'priority': 10, 'pos1': [1]}, \ {'group': 'ALEWarningLine', 'priority': 10, 'pos1': [2]}, \ {'group': 'ALEInfoLine', 'priority': 10, 'pos1': [3]}, \ ], \ GetMatchesWithoutIDs() endif " All of the highlights should be removed. call ale#highlight#RemoveHighlights() AssertEqual [], GetMatchesWithoutIDs() ================================================ FILE: test/test_highlight_position_chunking.vader ================================================ Execute(CreatePositions() should support single character matches): AssertEqual [[[1, 5, 1]]], ale#highlight#CreatePositions(1, 5, 1, 5) " When the end column is behind the start column, ignore it. AssertEqual [[[2, 5, 1]]], ale#highlight#CreatePositions(2, 5, 1, 5) Execute(CreatePositions() should support multiple character matches on a single line): AssertEqual [[[1, 5, 6]]], ale#highlight#CreatePositions(1, 5, 1, 10) " When the end column is behind the start column, ignore it. AssertEqual [[[2, 5, 6]]], ale#highlight#CreatePositions(2, 5, 1, 10) Execute(CreatePositions() should support character matches two lines): AssertEqual [[[1, 5, 1073741824], [2, 1, 10]]], ale#highlight#CreatePositions(1, 5, 2, 10) Execute(CreatePositions() should support character matches across many lines): " Test chunks from 1,3 to 1,17 AssertEqual [ \ [[1, 5, 1073741824], 2, [3, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 3, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, [4, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 4, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, [5, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 5, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, [6, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 6, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, [7, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 7, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, [8, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 8, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [[9, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 9, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, [10, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 10, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, [11, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 11, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, 11, [12, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 12, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, 11, 12, [13, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 13, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, 11, 12, 13, [14, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 14, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, 11, 12, 13, 14, [15, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 15, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, 11, 12, 13, 14, 15, [16, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 16, 10) AssertEqual [ \ [[1, 5, 1073741824], 2, 3, 4, 5, 6, 7, 8], \ [9, 10, 11, 12, 13, 14, 15, 16], \ [[17, 1, 10]], \], ale#highlight#CreatePositions(1, 5, 17, 10) " Test another random sample at higher lines. AssertEqual [ \ [[21, 8, 1073741824], 22, 23, 24, 25, 26, 27, 28], \ [29, 30, 31, 32, 33, 34, 35, 36], \ [[37, 1, 2]], \], ale#highlight#CreatePositions(21, 8, 37, 2) ================================================ FILE: test/test_history_saving.vader ================================================ Before: Save g:ale_max_buffer_history_size Save g:ale_history_enabled Save g:ale_history_log_output Save g:ale_run_synchronously Save g:ale_enabled let g:ale_enabled = 1 let g:ale_run_synchronously = 1 unlet! b:ale_fixers unlet! b:ale_enabled unlet! b:ale_history " Temporarily set the shell to /bin/sh, if it isn't already set that way. " This will make it so the test works when running it directly. let g:current_shell = &shell if !has('win32') let &shell = '/bin/sh' endif let g:history = [] let g:ale_buffer_info = {} let g:ale_max_buffer_history_size = 20 let g:ale_history_log_output = 0 function! TestFixer(buffer) return {'command': 'echo foo'} endfunction function! CollectResults(buffer, output) return [] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'CollectResults', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': has('win32') \ ? 'echo command history test' \ : '/bin/sh -c ''echo command history test''', \ 'read_buffer': 0, \}) After: Restore unlet! g:expected_results unlet! b:ale_fixers unlet! b:ale_enabled " Clear the history we changed. unlet! b:ale_history " Reset the shell back to what it was before. let &shell = g:current_shell unlet g:current_shell unlet g:history call ale#engine#Cleanup(bufnr('')) call ale#linter#Reset() let g:ale_buffer_info = {} let g:ale_max_buffer_history_size = 20 delfunction TestFixer delfunction CollectResults Given foobar (Some imaginary filetype): anything Execute(History should be set when commands are run): AssertEqual 'foobar', &filetype let b:ale_history = [] ALELint call ale#test#FlushJobs() let g:history = filter( \ copy(ale#history#Get(bufnr(''))), \ 'v:val.job_id isnot# ''executable''', \) AssertEqual 1, len(g:history) AssertEqual \ ['command', 'exit_code', 'job_id', 'status'], \ sort(keys(g:history[0])) if has('win32') AssertEqual 'cmd /s/c "echo command history test"', g:history[0].command else AssertEqual ['/bin/sh', '-c', '/bin/sh -c ''echo command history test'''], g:history[0].command endif AssertEqual 'finished', g:history[0].status AssertEqual 0, g:history[0].exit_code " The Job ID will change each time, but we can check the type. AssertEqual type(1), type(g:history[0].job_id) Execute(History should be not set when disabled): AssertEqual 'foobar', &filetype let g:ale_history_enabled = 0 ALELint call ale#test#FlushJobs() AssertEqual [], ale#history#Get(bufnr('')) Execute(History should include command output if logging is enabled): AssertEqual 'foobar', &filetype let g:ale_history_log_output = 1 " Retry this test until it works. This one can randomly fail. let b:ale_history = [] ALELint call ale#test#FlushJobs() let g:history = ale#history#Get(bufnr('')) AssertEqual 1, len(g:history) AssertEqual \ ['command history test'], \ map( \ copy(get(g:history[0], 'output', [])), \ 'substitute(v:val, ''[\r ]*$'', '''', ''g'')' \ ) Execute(History items should be popped after going over the max): let b:ale_history = map(range(20), '{''status'': ''started'', ''job_id'': v:val, ''command'': ''foobar''}') call ale#history#Add(bufnr(''), 'started', 347, 'last command') AssertEqual \ ( \ map(range(1, 19), '{''status'': ''started'', ''job_id'': v:val, ''command'': ''foobar''}') \ + [{'status': 'started', 'job_id': 347, 'command': 'last command'}] \ ), \ ale#history#Get(bufnr('')) Execute(Nothing should be added to history if the size is too low): let g:ale_max_buffer_history_size = 0 call ale#history#Add(bufnr(''), 'started', 347, 'last command') AssertEqual [], ale#history#Get(bufnr('')) let g:ale_max_buffer_history_size = -2 call ale#history#Add(1, 'started', 347, 'last command') AssertEqual [], ale#history#Get(bufnr('')) Given foobar(Some file with an imaginary filetype): a b c Execute(The history should be updated when fixers are run): call ale#test#SetFilename('dummy.txt') let b:ale_fixers = {'foobar': ['TestFixer']} let b:ale_enabled = 0 ALEFix AssertEqual ['started'], map(copy(b:ale_history), 'v:val.status') call ale#test#FlushJobs() AssertEqual ['finished'], map(copy(b:ale_history), 'v:val.status') if has('win32') AssertEqual 'cmd /s/c "echo foo ', split(b:ale_history[0].command, '<')[0] else AssertEqual '/bin/sh -c echo foo ', split(join(b:ale_history[0].command), '<')[0] endif ================================================ FILE: test/test_hover.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.txt') let g:Callback = 0 let g:message_list = [] let g:item_list = [] let g:show_message_arg_list = [] let g:ale_floating_preview = 0 let g:ale_hover_to_floating_preview = 0 let g:ale_detail_to_floating_preview = 0 runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim runtime autoload/ale/util.vim runtime autoload/ale/floating_preview.vim runtime autoload/ale/hover.vim let g:floated_lines = [] let g:floating_preview_show_called = 0 " Stub out so we can track the call function! ale#floating_preview#Show(lines, ...) abort let g:floating_preview_show_called = 1 let g:floated_lines = a:lines return win_getid() endfunction function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort let g:Callback = a:callback return { \ 'command': 'foobar', \ 'connection_id': 347, \ 'project_root': '/foo/bar', \} endfunction function! ale#lsp#Send(conn_id, message, root) abort call add(g:message_list, a:message) return 42 endfunction function! ale#util#ShowMessage(string, ...) abort call add(g:show_message_arg_list, [a:string] + a:000) endfunction function! HandleValidLSPResult(result) abort " The cursor is beyond the length of the line. " We will clamp the cursor position with the line length. call setpos('.', [bufnr(''), 1, 5, 0]) call ale#hover#SetMap({3: { \ 'buffer': bufnr(''), \ 'line': 1, \ 'column': 5, \}}) call ale#hover#HandleLSPResponse( \ 1, \ { \ 'id': 3, \ 'result': a:result, \ } \) endfunction After: call ale#hover#SetMap({}) call ale#test#RestoreDirectory() call ale#linter#Reset() unlet! g:Callback unlet! g:message_list unlet! b:ale_linters unlet! g:show_message_arg_list delfunction HandleValidLSPResult runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/floating_preview.vim Given python(Some Python file): foo somelongerline bazxyzxyzxyz Execute(Other messages for the tsserver handler should be ignored): call ale#hover#HandleTSServerResponse(1, {'command': 'foo'}) Execute(Failed hover responses should be handled correctly): call ale#hover#SetMap({3: {}}) call ale#hover#HandleTSServerResponse( \ 1, \ {'command': 'quickinfo', 'request_seq': 3} \) AssertEqual {}, ale#hover#GetMap() Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(tsserver quickinfo responses will null missing bodies should be handled): call ale#hover#SetMap({3: {}}) call ale#hover#HandleTSServerResponse( \ 1, \ { \ 'command': 'quickinfo', \ 'request_seq': 3, \ 'success': v:true, \ } \) AssertEqual {}, ale#hover#GetMap() Execute(tsserver quickinfo displayString values should be displayed): call ale#hover#SetMap({3: {'buffer': bufnr('')}}) call ale#hover#HandleTSServerResponse( \ 1, \ { \ 'command': 'quickinfo', \ 'request_seq': 3, \ 'success': v:true, \ 'body': {'displayString': 'foo bar'}, \ } \) AssertEqual [['foo bar']], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover responses with just a string should be handled): call HandleValidLSPResult({'contents': 'foobar'}) AssertEqual [['foobar', {'commands': []}]], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover null responses should be handled): call HandleValidLSPResult(v:null) AssertEqual [], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover responses with markup content should be handled): call HandleValidLSPResult({'contents': {'kind': 'markdown', 'value': 'markup'}}) AssertEqual [['markup', {'commands': []}]], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover responses with markup content missing values should be handled): call HandleValidLSPResult({'contents': {'kind': 'markdown'}}) AssertEqual [], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover response with lists of strings should be handled): call HandleValidLSPResult({'contents': [ \ "foo\n", \ "bar\n", \]}) AssertEqual [["foo\n\nbar", {'commands': []}]], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover response with lists of strings and marked strings should be handled): call HandleValidLSPResult({'contents': [ \ {'language': 'python', 'value': 'foo'}, \ "bar\n", \]}) AssertEqual [ \ [ \ "foo\n\nbar", \ { \ 'commands': [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%2l/ contains=@ALE_hover_python', \ ], \ }, \ ], \], g:show_message_arg_list AssertEqual {}, ale#hover#GetMap() Execute(LSP hover with ale_floating_preview should float): let g:ale_floating_preview = 1 call HandleValidLSPResult({'contents': "the message\ncontinuing"}) AssertEqual 1, g:floating_preview_show_called AssertEqual ["the message", "continuing"], g:floated_lines Execute(LSP hover ale_hover_to_floating_preview should float): let g:ale_hover_to_floating_preview = 1 call HandleValidLSPResult({'contents': "the message\ncontinuing"}) AssertEqual 1, g:floating_preview_show_called AssertEqual ["the message", "continuing"], g:floated_lines Execute(LSP hover by default should not float): call HandleValidLSPResult({'contents': "the message\ncontinuing"}) AssertEqual 0, g:floating_preview_show_called Execute(tsserver responses for documentation requests should be handled): call ale#hover#SetMap({3: {'show_documentation': 1, 'buffer': bufnr('')}}) call ale#hover#HandleTSServerResponse( \ 1, \ { \ 'command': 'quickinfo', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'documentation': 'foo is a very good method', \ 'displayString': 'foo bar', \ }, \ } \) " The preview window should show the text. AssertEqual ['foo is a very good method'], ale#test#GetPreviewWindowText() silent! pclose Execute(hover with show_documentation should be in the preview window, not floating): let g:ale_hover_to_floating_preview = 1 let g:ale_floating_preview = 1 call ale#hover#SetMap({3: {'show_documentation': 1, 'buffer': bufnr('')}}) call ale#hover#HandleTSServerResponse( \ 1, \ { \ 'command': 'quickinfo', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'documentation': 'foo is a very good method', \ 'displayString': 'foo bar ', \ }, \ } \) let expected = ["Every statement should end with a semicolon", "second line"] AssertEqual 0, g:floating_preview_show_called Execute(TSServer hover without show_documentation and ale_floating_preview should float): let g:ale_floating_preview = 1 call ale#hover#SetMap({3: {'buffer': bufnr('')}}) call ale#hover#HandleTSServerResponse( \ 1, \ { \ 'command': 'quickinfo', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'displayString': "the message\ncontinuing", \ }, \ } \) AssertEqual 1, g:floating_preview_show_called AssertEqual ["the message", "continuing"], g:floated_lines ================================================ FILE: test/test_hover_parsing.vader ================================================ Execute(Invalid results should be handled): AssertEqual [[], []], ale#hover#ParseLSPResult(0) AssertEqual [[], []], ale#hover#ParseLSPResult([0]) AssertEqual [[], []], ale#hover#ParseLSPResult('') AssertEqual [[], []], ale#hover#ParseLSPResult({}) AssertEqual [[], []], ale#hover#ParseLSPResult([{}]) AssertEqual [[], []], ale#hover#ParseLSPResult(['']) AssertEqual [[], []], ale#hover#ParseLSPResult({'value': ''}) AssertEqual [[], []], ale#hover#ParseLSPResult([{'value': ''}]) AssertEqual [[], []], ale#hover#ParseLSPResult({'kind': 'markdown'}) AssertEqual [[], []], ale#hover#ParseLSPResult({'kind': 'plaintext'}) AssertEqual [[], []], ale#hover#ParseLSPResult({'kind': 'x', 'value': 'xxx'}) Execute(A string with a code fence should be handled): AssertEqual \ [ \ [ \ ], \ [ \ 'def foo():', \ ' pass', \ ], \ ], \ ale#hover#ParseLSPResult(join([ \ '```', \ 'def foo():', \ ' pass', \ '```', \ ], "\n")) AssertEqual \ [ \ [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python', \ ], \ [ \ 'def foo():', \ ' pass', \ ], \ ], \ ale#hover#ParseLSPResult(join([ \ '```python', \ 'def foo():', \ ' pass', \ '```', \ ], "\n")) AssertEqual \ [ \ [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_javascript syntax/javascript.vim', \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python', \ 'syntax region ALE_hover_2 start=/\%5l/ end=/\%8l/ contains=@ALE_hover_python', \ 'syntax region ALE_hover_3 start=/\%8l/ end=/\%10l/ contains=@ALE_hover_javascript', \ ], \ [ \ 'def foo():', \ ' pass', \ '', \ 'middle line', \ '', \ 'def bar():', \ ' pass', \ '', \ 'const baz = () => undefined', \ ], \ ], \ ale#hover#ParseLSPResult(join([ \ '```python', \ 'def foo():', \ ' pass', \ '```', \ 'middle line', \ '```python', \ 'def bar():', \ ' pass', \ '```', \ '```javascript', \ 'const baz = () => undefined', \ '```', \ ], "\n")) Execute(Multiple strings with fences should be handled): AssertEqual \ [ \ [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_javascript syntax/javascript.vim', \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python', \ 'syntax region ALE_hover_2 start=/\%5l/ end=/\%8l/ contains=@ALE_hover_python', \ 'syntax region ALE_hover_3 start=/\%8l/ end=/\%10l/ contains=@ALE_hover_javascript', \ ], \ [ \ 'def foo():', \ ' pass', \ '', \ 'middle line', \ '', \ 'def bar():', \ ' pass', \ '', \ 'const baz = () => undefined', \ ], \ ], \ ale#hover#ParseLSPResult([ \ join([ \ '```python', \ 'def foo():', \ ' pass', \ '```', \ ], "\n"), \ join([ \ 'middle line', \ '```python', \ 'def bar():', \ ' pass', \ '```', \ '```javascript', \ 'const baz = () => undefined', \ '```', \ ], "\n"), \ ]) Execute(Objects with kinds should be handled): AssertEqual \ [ \ [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python', \ ], \ [ \ 'def foo():', \ ' pass', \ '', \ '```javascript', \ 'const baz = () => undefined', \ '```', \ ], \ ], \ ale#hover#ParseLSPResult([ \ { \ 'kind': 'markdown', \ 'value': join([ \ '```python', \ 'def foo():', \ ' pass', \ '```', \ ], "\n"), \ }, \ { \ 'kind': 'plaintext', \ 'value': join([ \ '```javascript', \ 'const baz = () => undefined', \ '```', \ ], "\n"), \ }, \ ]) Execute(Simple markdown formatting should be handled): AssertEqual \ [ \ [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python', \ ], \ [ \ 'def foo():', \ ' pass', \ '', \ 'formatted _ line _', \ ], \ ], \ ale#hover#ParseLSPResult(join([ \ '```python', \ 'def foo():', \ ' pass', \ '```', \ 'formatted \_ line \_', \ ], "\n")) Execute(Fences padded with spaces should be handled): AssertEqual \ [ \ [ \ 'unlet! b:current_syntax', \ 'syntax include @ALE_hover_python syntax/python.vim', \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%3l/ contains=@ALE_hover_python', \ ], \ [ \ 'def foo():', \ ' pass', \ '', \ 'formatted _ line _', \ ], \ ], \ ale#hover#ParseLSPResult(join([ \ '``` python ', \ 'def foo():', \ ' pass', \ '```', \ 'formatted \_ line \_', \ ], "\n")) Execute(Non-existent syntax files shouldn't be loaded): AssertEqual \ [ \ [ \ 'syntax region ALE_hover_1 start=/\%1l/ end=/\%2l/ contains=@ALE_hover_text', \ ], \ [ \ 'hello', \ ], \ ], \ ale#hover#ParseLSPResult(join([ \ '```text', \ 'hello', \ '```', \ ], "\n")) ================================================ FILE: test/test_ignoring_linters.vader ================================================ Before: Save g:lspconfig Save g:ale_linters_ignore Save g:ale_buffer_info Save g:ale_disable_lsp let g:lspconfig = 0 let g:lspconfig_names = {} let g:ale_disable_lsp = 0 let g:linters = [] let g:loclist = [] let g:run_linters_called = 0 runtime autoload/ale/engine.vim runtime autoload/ale/engine/ignore.vim " Mock the engine function so we can set it up. function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort let g:linters = a:linters let g:run_linters_called = 1 endfunction function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort let g:loclist = a:loclist endfunction function! ale#engine#ignore#GetLSPConfigNames() abort return g:lspconfig_names endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd' : 'true', \ 'command': has('win32') ? 'echo' : 'true', \}) call ale#test#SetDirectory('/testplugin/test') After: unlet! b:ale_linted unlet! b:ale_linters_ignore unlet! b:ale_quitting unlet! b:ale_save_event_fired unlet! b:ale_disable_lsp unlet! g:linters unlet! g:loclist unlet! g:lsp_message unlet! g:lspconfig_names Restore call ale#test#RestoreDirectory() call ale#linter#Reset() call ale#lsp_linter#ClearLSPData() runtime autoload/ale/engine.vim runtime autoload/ale/engine/ignore.vim Execute(GetList should ignore some invalid values): AssertEqual [], ale#engine#ignore#GetList('', 'foo') AssertEqual [], ale#engine#ignore#GetList('', 0) AssertEqual [], ale#engine#ignore#GetList('', v:null) Execute(GetList should handle Lists): AssertEqual ['foo', 'bar'], ale#engine#ignore#GetList('', ['foo', 'bar']) Execute(GetList should handle Dictionaries): AssertEqual \ ['linter1', 'linter2'], \ uniq(sort(ale#engine#ignore#GetList('x.y.z', { \ 'x': ['linter1'], \ 'abc': ['linter3'], \ 'z': ['linter2'], \ }))) Execute(Exclude should ignore some invalid values): AssertEqual \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo.bar', \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ 'foo', \ 0, \ ) AssertEqual \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo.bar', \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ 0, \ 0, \ ) AssertEqual \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo.bar', \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ v:null, \ 0, \ ) Execute(Exclude should handle Lists): AssertEqual \ [ \ {'name': 'linter3', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo.bar', \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ ['linter1', 'alias1'], \ 0, \ ) Execute(Exclude should handle Dictionaries): AssertEqual \ [ \ {'name': 'linter3', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo.bar', \ [ \ {'name': 'linter1', 'aliases': []}, \ {'name': 'linter2', 'aliases': ['alias1']}, \ {'name': 'linter3', 'aliases': []}, \ ], \ {'foo': ['linter1'], 'bar': ['alias1']}, \ 0, \ ) Execute(Exclude should filter LSP linters when ale_disable_lsp is set to 1): AssertEqual \ [ \ {'name': 'linter1', 'aliases': [], 'lsp': ''}, \ {'name': 'linter2', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo', \ [ \ {'name': 'linter1', 'aliases': [], 'lsp': ''}, \ {'name': 'linter2', 'aliases': []}, \ {'name': 'linter3', 'aliases': [], 'lsp': 'stdio'}, \ ], \ [], \ 1, \ ) Execute(Exclude should remove lspconfig linters with ale_disable_lsp = 'auto'): let g:lspconfig = 1 " A map is used here so you can easily see what the ignore mapping should be " remapping the nvim-lspconfig names to. let g:lspconfig_names = keys({ \ 'als': 'adals', \ 'ansiblels': 'ansible-language-server', \ 'bicep': 'bicep_language_server', \ 'cmake': 'cmake_language_server', \ 'denols': 'deno', \ 'erlangls': 'erlang_ls', \ 'html': 'vscodehtml', \ 'ocamlls': 'ocaml-language-server', \ 'puppet': 'puppet_languageserver', \ 'pyright': 'pyright', \}) " We should keep bicep, as it's different tool. AssertEqual \ [ \ {'name': 'bicep', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo', \ [ \ {'name': 'adals', 'aliases': []}, \ {'name': 'language_server', 'aliases': ['ansible-language-server']}, \ {'name': 'cmake_language_server', 'aliases': []}, \ {'name': 'deno', 'aliases': []}, \ {'name': 'erlang_ls', 'aliases': []}, \ {'name': 'vscodehtml', 'aliases': []}, \ {'name': 'bicep', 'aliases': []}, \ {'name': 'ols', 'aliases': ['ocaml-language-server']}, \ {'name': 'languageserver', 'aliases': ['puppet_languageserver']}, \ {'name': 'pyright', 'aliases': []}, \ ], \ [], \ 'auto', \ ) Execute(Exclude should check that the nvim-lspconfig plugin is installed with ale_disable_lsp = 'auto'): let g:lspconfig = 0 let g:lspconfig_names = ['pyright'] " We should keep pyright here, because g:lspconfig is 0. AssertEqual \ [ \ {'name': 'pyright', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo', \ [ \ {'name': 'pyright', 'aliases': []}, \ ], \ [], \ 'auto', \ ) Execute(Exclude should handle the lspconfig result being a Dictionary): let g:lspconfig = 1 let g:lspconfig_names = {} " We should keep pyright here, because the configuration is empty. AssertEqual \ [ \ {'name': 'pyright', 'aliases': []}, \ ], \ ale#engine#ignore#Exclude( \ 'foo', \ [ \ {'name': 'pyright', 'aliases': []}, \ ], \ [], \ 'auto', \ ) 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') let g:ale_linters_ignore = ['testlinter'] ALELint 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') let b:ale_linters_ignore = ['testlinter'] ALELint AssertEqual [], g:linters Execute(Buffer ignore lists should be applied for tsserver): call ale#test#SetFilename('filename.ts') call ale#engine#InitBufferInfo(bufnr('')) let g:lsp_message = { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': g:dir . '/filename.ts', \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': ''','' expected.', \ "code":1005 \ }, \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 14, \ 'nr': 1005, \ 'code': '1005', \ 'type': 'E', \ 'end_col': 14, \ 'end_lnum': 2, \ 'text': ''','' expected.', \ }, \ ], \ g:loclist let g:loclist = [] let b:ale_linters_ignore = ['tsserver'] call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist Execute(Buffer ignore lists should be applied for LSP linters): call ale#test#SetFilename('filename.py') call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}}) let g:lsp_message = { \ 'jsonrpc': '2.0', \ 'method': 'textDocument/publishDiagnostics', \ 'params': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'diagnostics': [ \ { \ 'severity': 1, \ 'message': 'x', \ 'range': { \ 'start': {'line': 0, 'character': 9}, \ 'end': {'line': 0, 'character': 9}, \ }, \ } \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 10, \ 'type': 'E', \ 'end_col': 9, \ 'end_lnum': 1, \ 'text': 'x', \ } \ ], \ g:loclist let b:ale_linters_ignore = ['lsplinter'] let g:loclist = [] call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist Execute(ale_disable_lsp should be applied for tsserver): call ale#test#SetFilename('filename.ts') call ale#engine#InitBufferInfo(bufnr('')) let g:lsp_message = { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': g:dir . '/filename.ts', \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': ''','' expected.', \ "code":1005 \ }, \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 14, \ 'nr': 1005, \ 'code': '1005', \ 'type': 'E', \ 'end_col': 14, \ 'end_lnum': 2, \ 'text': ''','' expected.', \ }, \ ], \ g:loclist let g:loclist = [] let b:ale_disable_lsp = 1 call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist Execute(ale_disable_lsp = 'auto' should be applied for tsserver): let g:lspconfig = 1 let g:lspconfig_names = ['tsserver'] call ale#test#SetFilename('filename.ts') call ale#engine#InitBufferInfo(bufnr('')) let g:lsp_message = { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', \ 'body': { \ 'file': g:dir . '/filename.ts', \ 'diagnostics':[ \ { \ 'start': { \ 'line':2, \ 'offset':14, \ }, \ 'end': { \ 'line':2, \ 'offset':15, \ }, \ 'text': ''','' expected.', \ "code":1005 \ }, \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 2, \ 'col': 14, \ 'nr': 1005, \ 'code': '1005', \ 'type': 'E', \ 'end_col': 14, \ 'end_lnum': 2, \ 'text': ''','' expected.', \ }, \ ], \ g:loclist let g:loclist = [] let g:ale_disable_lsp = 'auto' call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist Execute(ale_disable_lsp should be applied for LSP linters): call ale#test#SetFilename('filename.py') call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}}) let g:lsp_message = { \ 'jsonrpc': '2.0', \ 'method': 'textDocument/publishDiagnostics', \ 'params': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'diagnostics': [ \ { \ 'severity': 1, \ 'message': 'x', \ 'range': { \ 'start': {'line': 0, 'character': 9}, \ 'end': {'line': 0, 'character': 9}, \ }, \ } \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 10, \ 'type': 'E', \ 'end_col': 9, \ 'end_lnum': 1, \ 'text': 'x', \ } \ ], \ g:loclist let b:ale_disable_lsp = 1 let g:loclist = [] call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist Execute(ale_disable_lsp = 'auto' should be applied for LSP linters): let g:lspconfig = 1 let g:lspconfig_names = ['lsplinter'] call ale#test#SetFilename('filename.py') call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}}) let g:lsp_message = { \ 'jsonrpc': '2.0', \ 'method': 'textDocument/publishDiagnostics', \ 'params': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'diagnostics': [ \ { \ 'severity': 1, \ 'message': 'x', \ 'range': { \ 'start': {'line': 0, 'character': 9}, \ 'end': {'line': 0, 'character': 9}, \ }, \ } \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 10, \ 'type': 'E', \ 'end_col': 9, \ 'end_lnum': 1, \ 'text': 'x', \ } \ ], \ g:loclist let g:ale_disable_lsp = 'auto' let g:loclist = [] call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist Execute(ale_disable_lsp = 'auto' should ignore LSP linters by alias too): let g:lspconfig = 1 let g:lspconfig_names = ['lsplinter'] call ale#test#SetFilename('filename.py') call ale#engine#InitBufferInfo(bufnr('')) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'notthis', 'aliases': ['lsplinter'], 'lsp': 'stdio'}}) let g:lsp_message = { \ 'jsonrpc': '2.0', \ 'method': 'textDocument/publishDiagnostics', \ 'params': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'diagnostics': [ \ { \ 'severity': 1, \ 'message': 'x', \ 'range': { \ 'start': {'line': 0, 'character': 9}, \ 'end': {'line': 0, 'character': 9}, \ }, \ } \ ], \ }, \} call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual \ [ \ { \ 'lnum': 1, \ 'col': 10, \ 'type': 'E', \ 'end_col': 9, \ 'end_lnum': 1, \ 'text': 'x', \ } \ ], \ g:loclist let g:ale_disable_lsp = 'auto' let g:loclist = [] call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) AssertEqual [], g:loclist ================================================ FILE: test/test_line_join.vader ================================================ Before: let g:lines = [] let g:data = '' function! LineCallback(job_id, line) abort call add(g:lines, a:line) endfunction function! RawCallback(job_id, some_data) abort let g:data .= a:some_data endfunction After: unlet! g:last_line unlet! g:lines unlet! g:data delfunction LineCallback delfunction RawCallback Execute (ALE should handle empty Lists for the lines): let g:last_line = ale#util#JoinNeovimOutput(1, '', [], 'nl', function('LineCallback')) AssertEqual [], g:lines AssertEqual '', g:last_line Execute (ALE should pass on full lines for NeoVim): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['x', 'y', ''], 'nl', function('LineCallback')) AssertEqual ['x', 'y'], g:lines AssertEqual '', g:last_line Execute (ALE should pass on a single long line): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['x'], 'nl', function('LineCallback')) AssertEqual [], g:lines AssertEqual 'x', g:last_line Execute (ALE should handle just a single line of output): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['x', ''], 'nl', function('LineCallback')) AssertEqual ['x'], g:lines AssertEqual '', g:last_line Execute (ALE should join two incomplete pieces of large lines together): let g:last_line = ale#util#JoinNeovimOutput(1, 'x', ['y'], 'nl', function('LineCallback')) AssertEqual [], g:lines AssertEqual 'xy', g:last_line Execute (ALE join incomplete lines, and set new ones): let g:last_line = ale#util#JoinNeovimOutput(1, 'x', ['y', 'z', 'a'], 'nl', function('LineCallback')) AssertEqual ['xy', 'z'], g:lines AssertEqual 'a', g:last_line Execute (ALE join incomplete lines, and set new ones, with two elements): let g:last_line = ale#util#JoinNeovimOutput(1, 'x', ['y', 'z'], 'nl', function('LineCallback')) AssertEqual ['xy'], g:lines AssertEqual 'z', g:last_line Execute (ALE should pass on full lines for NeoVim for raw data): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['x', 'y', ''], 'raw', function('RawCallback')) AssertEqual "x\ny\n", g:data AssertEqual '', g:last_line Execute (ALE should pass on a single long line): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['x'], 'raw', function('RawCallback')) AssertEqual 'x', g:data AssertEqual '', g:last_line Execute (ALE should handle just a single line of output): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['x', ''], 'raw', function('RawCallback')) AssertEqual "x\n", g:data AssertEqual '', g:last_line Execute (ALE should pass on two lines and one incomplete one): let g:last_line = ale#util#JoinNeovimOutput(1, '', ['y', 'z', 'a'], 'raw', function('RawCallback')) AssertEqual "y\nz\na", g:data AssertEqual '', g:last_line ================================================ FILE: test/test_lint_file_linters.vader ================================================ Before: Save g:ale_fix_on_save Save g:ale_enabled Save g:ale_run_synchronously Save g:ale_set_lists_synchronously Save g:ale_buffer_info Save g:ale_linters let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks let g:ale_set_lists_synchronously = 1 let b:ale_save_event_fired = 0 let g:buffer_result = [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'buffer error', \ 'type': 'E', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'buffer warning', \ 'type': 'W', \ }, \] function! LintFileCallback(buffer, output) return [ \ { \ 'lnum': 1, \ 'col': 3, \ 'text': 'file warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': 'file error', \ 'type': 'E', \ }, \] endfunction function! BufferCallback(buffer, output) return deepcopy(g:buffer_result) endfunction function! GetSimplerLoclist() let l:loclist = [] for l:item in ale#test#GetLoclistWithoutNewerKeys() call add(l:loclist, { \ 'lnum': l:item.lnum, \ 'col': l:item.col, \ 'text': l:item.text, \ 'type': l:item.type, \}) endfor return l:loclist endfunction call ale#linter#Define('foobar', { \ 'name': 'lint_file_linter', \ 'callback': 'LintFileCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': 'echo', \ 'lint_file': 1, \}) call ale#linter#Define('foobar', { \ 'name': 'buffer_linter', \ 'callback': 'BufferCallback', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'command': 'echo', \ 'read_buffer': 0, \}) let g:filename = tempname() call writefile([], g:filename) call ale#test#SetFilename(g:filename) After: if !g:ale_run_synchronously call ale#engine#Cleanup(bufnr('')) endif Restore unlet! g:ale_run_synchronously_callbacks unlet! b:ale_save_event_fired unlet! b:ale_enabled unlet g:buffer_result let g:ale_buffer_info = {} call ale#linter#Reset() call setloclist(0, []) delfunction LintFileCallback delfunction BufferCallback if filereadable(g:filename) call delete(g:filename) endif unlet g:filename Given foobar (Some imaginary filetype): foo bar baz Execute(Running linters without 'lint_file' should run only buffer linters): call ale#Queue(0) call ale#test#FlushJobs() AssertEqual [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'buffer error', \ 'type': 'E', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'buffer warning', \ 'type': 'W', \ }, \], GetSimplerLoclist() Execute(Running linters with 'lint_file' should run all linters): Assert filereadable(expand('%:p')), 'The file was not readable' call ale#Queue(0, 'lint_file') call ale#test#FlushJobs() AssertEqual [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'buffer error', \ 'type': 'E', \ }, \ { \ 'lnum': 1, \ 'col': 3, \ 'text': 'file warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 1, \ 'text': 'buffer warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': 'file error', \ 'type': 'E', \ }, \], GetSimplerLoclist() Execute(Linter errors from files should be kept): Assert filereadable(expand('%:p')), 'The file was not readable' call ale#Queue(0, 'lint_file') call ale#test#FlushJobs() " Change the results for the buffer callback. let g:buffer_result = [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'new buffer error', \ 'type': 'E', \ }, \] call ale#Queue(0) call ale#test#FlushJobs() AssertEqual [ \ { \ 'lnum': 1, \ 'col': 1, \ 'text': 'new buffer error', \ 'type': 'E', \ }, \ { \ 'lnum': 1, \ 'col': 3, \ 'text': 'file warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': 'file error', \ 'type': 'E', \ }, \], GetSimplerLoclist() Execute(Linter errors from files should be kept when no other linters are run): let g:ale_linters = {'foobar': ['lint_file_linter']} Assert filereadable(expand('%:p')), 'The file was not readable' call ale#Queue(0, 'lint_file') call ale#test#FlushJobs() AssertEqual [ \ { \ 'lnum': 1, \ 'col': 3, \ 'text': 'file warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': 'file error', \ 'type': 'E', \ }, \], GetSimplerLoclist() call ale#Queue(0) AssertEqual [ \ { \ 'lnum': 1, \ 'col': 3, \ 'text': 'file warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': 'file error', \ 'type': 'E', \ }, \], GetSimplerLoclist() Execute(The Save event should respect the buffer number): let g:ale_linters = {'foobar': ['lint_file_linter']} Assert filereadable(expand('%:p')), 'The file was not readable' call ale#events#SaveEvent(bufnr('') + 1) call ale#test#FlushJobs() " We shouldn't get any prblems yet. AssertEqual [], GetSimplerLoclist() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() " We should get them now we used the right buffer number. AssertEqual [ \ { \ 'lnum': 1, \ 'col': 3, \ 'text': 'file warning', \ 'type': 'W', \ }, \ { \ 'lnum': 2, \ 'col': 3, \ 'text': 'file error', \ 'type': 'E', \ }, \], GetSimplerLoclist() Execute(The Save event should set b:ale_save_event_fired to 1): let g:ale_lint_on_save = 1 let b:ale_enabled = 1 call ale#linter#Reset() call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() " This flag needs to be set so windows can be opened, etc. AssertEqual 1, b:ale_save_event_fired Execute(b:ale_save_event_fired should be set to 0 when results are set): let b:ale_save_event_fired = 1 call ale#engine#SetResults(bufnr(''), []) call ale#test#FlushJobs() AssertEqual 0, b:ale_save_event_fired Execute(lint_file linters should stay running after checking without them): let g:ale_run_synchronously = 0 " Run all linters, then just the buffer linters. call ale#Queue(0, 'lint_file') call ale#Queue(0) " The lint_file linter should still be running. AssertEqual \ ['lint_file_linter', 'buffer_linter'], \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name') " We should have 1 job for each linter. AssertEqual \ 2, \ len(keys(get(get(ale#command#GetData(), bufnr(''), {}), 'jobs', {}))) call ale#test#WaitForJobs(2000) Execute(The save event should not lint the buffer when ALE is disabled): let g:ale_enabled = 0 call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual [], GetSimplerLoclist() AssertEqual 0, b:ale_save_event_fired ================================================ FILE: test/test_lint_on_enter_when_file_changed.vader ================================================ Before: Save &filetype Save g:ale_buffer_info Save g:ale_lint_on_enter Save g:ale_set_lists_synchronously let g:buf = bufnr('') let g:ale_lint_on_enter = 1 let g:ale_run_synchronously = 1 let g:ale_set_lists_synchronously = 1 function! TestCallback(buffer, output) return [{ \ 'lnum': 1, \ 'col': 3, \ 'text': 'baz boz', \}] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd' : 'true', \ 'command': has('win32') ? 'echo' : 'true', \}) After: Restore unlet! g:buf let g:ale_run_synchronously = 0 delfunction TestCallback call ale#linter#Reset() call setloclist(0, []) Execute(The file changed event function should set b:ale_file_changed): let g:ale_lint_on_enter = 0 if has('gui_running') new else e test endif call ale#events#FileChangedEvent(g:buf) close " We should set the flag in the other buffer AssertEqual 1, getbufvar(g:buf, 'ale_file_changed') Execute(The file changed event function should lint the current buffer when it has changed): set filetype=foobar call ale#events#FileChangedEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual [{ \ 'bufnr': bufnr(''), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 3, \ 'text': 'baz boz', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }], ale#test#GetLoclistWithoutNewerKeys() Execute(The buffer should be checked after entering it after the file has changed): let b:ale_file_changed = 1 set filetype=foobar call ale#events#ReadOrEnterEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual [{ \ 'bufnr': bufnr(''), \ 'lnum': 1, \ 'vcol': 0, \ 'col': 3, \ 'text': 'baz boz', \ 'type': 'E', \ 'nr': -1, \ 'pattern': '', \ 'valid': 1, \ }], ale#test#GetLoclistWithoutNewerKeys() ================================================ FILE: test/test_lint_on_filetype_changed.vader ================================================ Before: Save &filetype Save g:ale_lint_on_filetype_changed let g:ale_lint_on_filetype_changed = 1 let g:queue_calls = [] function! ale#Queue(...) call add(g:queue_calls, a:000) endfunction After: Restore unlet! g:queue_calls " Reload the ALE code to load the real function again. runtime autoload/ale.vim unlet! b:ale_original_filetype Execute(The original filetype should be set on BufEnter): let &filetype = 'foobar' call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 'foobar', b:ale_original_filetype let &filetype = 'bazboz' call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 'bazboz', b:ale_original_filetype Execute(Linting should not be queued when the filetype is the same): let b:ale_original_filetype = 'foobar' let g:queue_calls = [] call ale#events#FileTypeEvent(bufnr(''), 'foobar') AssertEqual [], g:queue_calls Execute(Linting should be queued when the filetype changes): let b:ale_original_filetype = 'foobar' let g:queue_calls = [] call ale#events#FileTypeEvent(bufnr(''), 'bazboz') AssertEqual [[300, 'lint_file', bufnr('')]], g:queue_calls " The original filetype should be updated, so we don't trigger linting " by setting a filetype equal to what it already is. AssertEqual 'bazboz', b:ale_original_filetype Execute(Linting should be done when the original filetype was blank): let b:ale_original_filetype = '' call ale#events#FileTypeEvent(bufnr(''), 'bazboz') AssertEqual [[300, 'lint_file', bufnr('')]], g:queue_calls AssertEqual 'bazboz', b:ale_original_filetype Execute(Linting should not be done when the setting is off): let b:ale_original_filetype = 'foobar' let g:ale_lint_on_filetype_changed = 0 call ale#events#FileTypeEvent(bufnr(''), 'bazboz') AssertEqual [], g:queue_calls " We should still update the old filetype AssertEqual 'bazboz', b:ale_original_filetype Execute(Linting should be done when the original filetype was not set): unlet! b:ale_original_filetype call ale#events#FileTypeEvent(bufnr(''), 'bazboz') AssertEqual [], g:queue_calls ================================================ FILE: test/test_linter_defintion_processing.vader ================================================ Before: Save g:ale_root Save b:ale_root let g:ale_root = {} unlet! b:ale_root let g:linter = {} After: unlet g:linter Execute (PreProcess should throw when the linter object is not a Dictionary): AssertThrows call ale#linter#PreProcess('testft', '') AssertEqual 'The linter object must be a Dictionary', g:vader_exception Execute (PreProcess should throw when there is no name): AssertThrows call ale#linter#PreProcess('testft', { \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \}) AssertEqual '`name` must be defined to name the linter', g:vader_exception Execute (PreProcess should throw when there is no callback): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'executable': 'echo', \ 'command': 'echo', \}) AssertEqual '`callback` must be defined with a callback to accept output', g:vader_exception Execute (PreProcess should throw when then callback is not a function): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 1, \ 'executable': 'echo', \ 'command': 'echo', \}) AssertEqual '`callback` must be defined with a callback to accept output', g:vader_exception Execute (PreProcess should throw when there is no executable): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'command': 'echo', \}) AssertEqual '`executable` must be defined', g:vader_exception Execute (PreProcess should throw when executable is not a string): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 123, \ 'command': 'echo', \}) AssertEqual '`executable` must be a String or Function if defined', g:vader_exception Execute (PreProcess should allow executable to be a callback): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': function('type'), \ 'command': 'echo', \}) Execute (PreProcess should throw when there is no command): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \}) AssertEqual '`command` must be defined', g:vader_exception Execute (PreProcess should throw when command is not a string): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': [], \}) AssertEqual '`command` must be a String or Function if defined', g:vader_exception Execute (PreProcess should allow command to be a callback): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': function('type'), \}) Execute (PreProcess should throw when cwd is not a string): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'cwd': [], \ 'command': 'echo', \}) AssertEqual '`cwd` must be a String or Function if defined', g:vader_exception Execute (PreProcess should allow cwd to be a callback): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'cwd': function('type'), \ 'command': 'echo', \}) Execute (PreProcess should allow cwd to be a string): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'cwd': '/foo/bar', \ 'command': 'echo', \}) Execute (PreProcess should when the output stream isn't a valid string): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \ 'output_stream': 'xxx', \}) AssertEqual "`output_stream` must be 'stdout', 'stderr', or 'both'", g:vader_exception Execute (PreProcess should not throw when everything is correct): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \}) Execute (PreProcess should accept an stdout output_stream): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \ 'output_stream': 'stdout', \}) Execute (PreProcess should accept an stderr output_stream): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \ 'output_stream': 'stderr', \}) Execute (PreProcess should accept a 'both' output_stream): call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \ 'output_stream': 'both', \}) Execute(PreProcess should process the read_buffer option correctly): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \ 'read_buffer': '0', \} AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`read_buffer` must be `0` or `1`', g:vader_exception let g:linter.read_buffer = 0 call ale#linter#PreProcess('testft', g:linter) let g:linter.read_buffer = 1 call ale#linter#PreProcess('testft', g:linter) Execute(PreProcess should set a default value for read_buffer): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \} AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer Execute(PreProcess should process the lint_file option correctly): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \ 'lint_file': 'x', \} AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`lint_file` must be `0`, `1`, or a Function', g:vader_exception let g:linter.lint_file = 0 AssertEqual 0, ale#linter#PreProcess('testft', g:linter).lint_file " The default for read_buffer should be 1 when lint_file is 0 AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer let g:linter.lint_file = 1 AssertEqual 1, ale#linter#PreProcess('testft', g:linter).lint_file " The default for read_buffer should still be 1 AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer let g:linter.read_buffer = 1 " We should be able to set `read_buffer` and `lint_file` at the same time. AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer let g:linter.lint_file = function('type') Assert type(ale#linter#PreProcess('testft', g:linter).lint_file) is v:t_func Execute(PreProcess should set a default value for lint_file): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \} AssertEqual 0, ale#linter#PreProcess('testft', g:linter).lint_file Execute(PreProcess should set a default value for aliases): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \} AssertEqual [], ale#linter#PreProcess('testft', g:linter).aliases Execute(PreProcess should complain about invalid `aliases` values): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \ 'aliases': 'foo', \} AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`aliases` must be a List of String values', g:vader_exception let g:linter.aliases = [1] AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`aliases` must be a List of String values', g:vader_exception Execute(PreProcess should accept `aliases` lists): let g:linter = { \ 'name': 'x', \ 'callback': 'x', \ 'executable': 'x', \ 'command': 'x', \ 'aliases': [], \} AssertEqual [], ale#linter#PreProcess('testft', g:linter).aliases let g:linter.aliases = ['foo', 'bar'] AssertEqual ['foo', 'bar'], ale#linter#PreProcess('testft', g:linter).aliases Execute(PreProcess should accept tsserver LSP configuration): let g:linter = { \ 'name': 'x', \ 'executable': 'x', \ 'command': 'x', \ 'lsp': 'tsserver', \ 'language': 'x', \ 'project_root': 'x', \} AssertEqual 'tsserver', ale#linter#PreProcess('testft', g:linter).lsp Execute(PreProcess should accept stdio LSP configuration): let g:linter = { \ 'name': 'x', \ 'executable': 'x', \ 'command': 'x', \ 'lsp': 'stdio', \ 'language': 'x', \ 'project_root': 'x', \} AssertEqual 'stdio', ale#linter#PreProcess('testft', g:linter).lsp Execute(PreProcess should accept LSP server configurations): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'foobar', \ 'project_root': 'x', \} AssertEqual 'socket', ale#linter#PreProcess('testft', g:linter).lsp Execute(PreProcess should accept let you specify the `language` as a Function): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': {-> 'foobar'}, \ 'project_root': 'x', \} AssertEqual 'foobar', ale#linter#PreProcess('testft', g:linter).language(bufnr('')) Execute(PreProcess should complain about invalid language values): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 0, \ 'project_root': 'x', \} AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`language` must be a String or Function if defined', g:vader_exception Execute(PreProcess should use the filetype as the language string by default): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'X', \ 'project_root': 'x', \} AssertEqual 'testft', ale#linter#PreProcess('testft', g:linter).language Execute(PreProcess should require an `address` for LSP socket configurations): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \} AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`address` must be defined for getting the LSP address', g:vader_exception Execute(PreProcess should complain about `address` for non-LSP linters): let g:linter = { \ 'name': 'x', \ 'callback': 'SomeFunction', \ 'executable': 'echo', \ 'command': 'echo', \ 'address': 'X', \} AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual '`address` cannot be used when lsp != ''socket''', g:vader_exception Execute(PreProcess accept `address` as a String): let g:linter = ale#linter#PreProcess('testft', { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'foo:123', \ 'language': 'x', \ 'project_root': 'x', \}) AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter) Execute(PreProcess accept address as a Function): let g:linter = ale#linter#PreProcess('testft', { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': {-> 'foo:123'}, \ 'language': 'x', \ 'project_root': 'x', \}) AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter) Execute(PreProcess should complain about invalid address values): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 0, \ 'language': 'x', \ 'project_root': 'x', \}) AssertEqual '`address` must be a String or Function if defined', g:vader_exception Execute(PreProcess should allow the `project_root` to be set as a String): let g:linter = ale#linter#PreProcess('testft', { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'foo:123', \ 'language': 'x', \ 'project_root': '/foo/bar', \}) AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter) Execute(PreProcess should `project_root` be set as a Function): let g:linter = ale#linter#PreProcess('testft', { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'foo:123', \ 'language': 'x', \ 'project_root': {-> '/foo/bar'}, \}) AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter) Execute(PreProcess should complain when `project_root` is invalid): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'foo:123', \ 'language': 'x', \ 'project_root': 0, \}) AssertEqual '`project_root` must be a String or Function', g:vader_exception Execute(PreProcess should throw when `initialization_options` is not a Dictionary or callback): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'x', \ 'project_root': 'x', \ 'initialization_options': 0, \}) AssertEqual '`initialization_options` must be a Dictionary or Function if defined', g:vader_exception Execute(PreProcess should accept `initialization_options` as a Dictionary): let g:linter = ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'x', \ 'project_root': 'x', \ 'initialization_options': {'foo': v:true}, \}) AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter) Execute(PreProcess should accept `initialization_options` as a Function): let g:linter = ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'x', \ 'project_root': 'x', \ 'initialization_options': {-> {'foo': v:true}}, \}) AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter) Execute(PreProcess should accept `lsp_config` as a Dictionary): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'x', \ 'project_root': 'x', \ 'lsp_config': {'foo': 'bar'}, \} AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter) Execute(PreProcess should accept `lsp_config` as a Function): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'x', \ 'project_root': 'x', \ 'lsp_config': {-> {'foo': 'bar'}}, \} AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter) Execute(PreProcess should throw when `lsp_config` is not a Dictionary or Function): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'lsp': 'socket', \ 'address': 'X', \ 'language': 'x', \ 'project_root': 'x', \ 'lsp_config': 'x', \}) AssertEqual '`lsp_config` must be a Dictionary or Function if defined', g:vader_exception ================================================ FILE: test/test_linter_retrieval.vader ================================================ Before: Save g:ale_linters Save g:ale_linter_aliases let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': ''} let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout', 'read_buffer': 0, 'lint_file': 1, 'aliases': [], 'lsp': ''} call ale#linter#Reset() call ale#linter#PreventLoading('testft') call ale#linter#PreventLoading('javascript') call ale#linter#PreventLoading('typescript') After: Restore unlet! g:testlinter1 unlet! g:testlinter2 unlet! b:ale_linters unlet! b:ale_linter_aliases call ale#linter#Reset() Execute (You should be able to get a defined linter): call ale#linter#Define('testft', g:testlinter1) AssertEqual [g:testlinter1], ale#linter#Get('testft') Execute (You should be able get select a single linter): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1']} AssertEqual [g:testlinter1], ale#linter#Get('testft') Execute (You should be able to select a linter by an alias): let g:testlinter1.aliases = ['foo', 'linter1alias'] call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['linter1alias']} AssertEqual [g:testlinter1], ale#linter#Get('testft') Execute (You should be able to select linters with a buffer option): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1', 'testlinter2']} let b:ale_linters = {'testft': ['testlinter1']} AssertEqual [g:testlinter1], ale#linter#Get('testft') Execute (b:ale_linters should work when set to a List): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1', 'testlinter2']} let b:ale_linters = ['testlinter1'] AssertEqual [g:testlinter1], ale#linter#Get('testft') Execute (b:ale_linters should disable all linters when set to an empty List): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1', 'testlinter2']} let b:ale_linters = [] AssertEqual [], ale#linter#Get('testft') Execute (b:ale_linters should enable all available linters when set to 'all'): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1']} let b:ale_linters = 'all' AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft') Execute (Buffer settings shouldn't completely replace global settings): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) let g:ale_linters = {'testft': ['testlinter1']} let b:ale_linters = {'testft2': ['testlinter1', 'testlinter2']} AssertEqual [g:testlinter1], ale#linter#Get('testft') Execute (You should be able to alias linters from one filetype to another): call ale#linter#Define('testft1', g:testlinter1) let g:ale_linter_aliases = {'testft2': 'testft1'} AssertEqual [g:testlinter1], ale#linter#Get('testft2') Execute (You should be able to filter aliased linters): call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft1', g:testlinter2) let g:ale_linters = {'testft1': ['testlinter1'], 'testft2': ['testlinter2']} let g:ale_linter_aliases = {'testft2': 'testft1'} AssertEqual [g:testlinter1], ale#linter#Get('testft1') AssertEqual [g:testlinter2], ale#linter#Get('testft2') Execute (Dot-separated filetypes should be handled correctly): call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1.testft2') Execute (Linters for multiple aliases should be loaded): call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) let ale_linter_aliases = {'testft3': ['testft1', 'testft2']} AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft3') Execute (You should be able to alias filetypes to themselves and another): call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) let ale_linter_aliases = {'testft1': ['testft1', 'testft2']} AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1') Execute (Buffer-local overrides for aliases should be used): call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) let g:ale_linter_aliases = {'testft1': ['testft2']} let b:ale_linter_aliases = {'testft1': ['testft1', 'testft2']} AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1') Execute (The local alias option shouldn't completely replace the global one): call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) let g:ale_linter_aliases = {'testft1': ['testft1', 'testft2']} " This is a key set for a different filetype. " We should look for a key in this Dictionary first, and then check the " 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) 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 (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) let g:ale_linter_aliases = {'testft1': ['testft2']} let b:ale_linter_aliases = {'testft1': ['testft1', 'testft2']} AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1') Execute (Linters new linters with the same name should replace old ones): let g:testlinter1.name = g:testlinter2.name call ale#linter#Define('testft1', g:testlinter1) call ale#linter#Define('testft1', g:testlinter2) AssertEqual [g:testlinter2], ale#linter#GetAll(['testft1']) Execute (Linters should be loaded from disk appropriately): call ale#linter#Reset() AssertEqual [{'name': 'testlinter', 'output_stream': 'stdout', 'executable': 'testlinter', 'command': 'testlinter', 'callback': 'testCB', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': ''}], ale#linter#Get('testft') Execute (Linters for later filetypes should replace the former ones): call ale#linter#Define('javascript', { \ 'name': 'eslint', \ 'executable': 'y', \ 'command': 'y', \ 'callback': 'y', \}) call ale#linter#Define('typescript', { \ 'name': 'eslint', \ 'executable': 'x', \ 'command': 'x', \ 'callback': 'x', \}) AssertEqual [ \ {'output_stream': 'stdout', 'lint_file': 0, 'read_buffer': 1, 'name': 'eslint', 'executable': 'x', 'lsp': '', 'aliases': [], 'command': 'x', 'callback': 'x'} \], ale#linter#Get('javascript.typescript') ================================================ FILE: test/test_linter_type_mapping.vader ================================================ Before: Save g:ale_type_map After: Restore unlet! b:ale_type_map Execute(It should be possible to remap errors to style errors): let g:ale_type_map = {'foo': {'E': 'ES'}} AssertEqual \ [ \ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'E', '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'}, \ {'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', 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}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ ]) Execute(It should be possible to remap errors to style errors with buffer-local variables): let b:ale_type_map = {'foo': {'E': 'ES'}} AssertEqual \ [ \ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'E', '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'}, \ {'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', 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}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ ]) Execute(It should be possible to remap warnings to style warnings): let g:ale_type_map = {'foo': {'W': 'WS'}} AssertEqual \ [ \ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'E', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'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', 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}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ ]) Execute(It should be possible to remap style errors to errors): let g:ale_type_map = {'foo': {'ES': 'E'}} AssertEqual \ [ \ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'E', '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'}, \ {'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', 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}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ ]) Execute(It should be possible to remap style warnings to warnings): let g:ale_type_map = {'foo': {'WS': 'W'}} AssertEqual \ [ \ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'E', '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'}, \ {'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', 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}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ ]) Execute(It should be possible to info problems to warnings): let g:ale_type_map = {'foo': {'I': 'W'}} AssertEqual \ [ \ {'type': 'E', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1, 'linter_name': 'foo'}, \ {'type': 'E', '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'}, \ {'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', 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}, \ {'type': 'W', 'sub_type': 'style', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ {'type': 'I', 'lnum': 1, 'text': 'x', 'bufnr': bufnr(''), 'col': 0, 'vcol': 0, 'nr': -1}, \ ]) ================================================ FILE: test/test_linting_blacklist.vader ================================================ Before: let g:ale_buffer_info = {} After: call ale#engine#Cleanup(bufnr('')) let g:ale_buffer_info = {} Given unite (A Unite.vim file): anything Execute(Running ALE on a blacklisted file shouldn't change anything): call ale#Queue(0) call ale#test#WaitForJobs(2000) AssertEqual {}, g:ale_buffer_info ================================================ FILE: test/test_linting_updates_loclist.vader ================================================ Before: Save g:ale_echo_cursor Save g:ale_set_highlights Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs Save g:ale_run_synchronously Save g:ale_set_lists_synchronously Save g:ale_buffer_info Save g:ale_sign_offset " We want to check that sign IDs are set for this test. let g:ale_set_signs = 1 let g:ale_set_loclist = 1 let g:ale_sign_offset = 2000000 " Disable features we don't need for these tests. let g:ale_set_quickfix = 0 let g:ale_set_highlights = 0 let g:ale_echo_cursor = 0 let g:ale_run_synchronously = 1 let g:ale_set_lists_synchronously = 1 let g:ale_buffer_info = {} function! TestCallback(buffer, output) return [ \ { \ 'lnum': 1, \ 'type': 'W', \ 'col': 10, \ 'text': 'Infix operators must be spaced. [Warning/space-infix-ops]', \ }, \ { \ 'lnum': 2, \ 'type': 'E', \ 'col': 10, \ 'text': 'Missing semicolon. [Error/semi]', \ } \] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd': 'true', \ 'command': 'true', \ 'read_buffer': 0, \}) sign unplace * call ale#engine#Cleanup(bufnr('')) After: Restore delfunction TestCallback call ale#linter#Reset() sign unplace * Given foobar (Some JavaScript with problems): var y = 3+3; var y = 3 Execute(The loclist should be updated after linting is done): ALELint call ale#test#FlushJobs() AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'testlinter', \ 'nr': -1, \ 'type': 'W', \ 'col': 10, \ 'text': 'Infix operators must be spaced. [Warning/space-infix-ops]', \ 'sign_id': 2000001, \ }, \ { \ 'lnum': 2, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'testlinter', \ 'nr': -1, \ 'type': 'E', \ 'col': 10, \ 'text': 'Missing semicolon. [Error/semi]', \ 'sign_id': 2000002, \ } \ ], \ get(get(g:ale_buffer_info, bufnr('%'), {}), 'loclist', []) ================================================ FILE: test/test_list_formatting.vader ================================================ Before: Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_loclist_msg_format Save g:ale_open_list Save g:ale_buffer_info Save g:ale_set_lists_synchronously let g:ale_set_lists_synchronously = 1 let g:ale_loclist_msg_format = '%code: %%s' let g:ale_open_list = 0 let g:loclist = [] let g:ale_buffer_info = {bufnr(''): {'loclist': g:loclist}} function! AddItem(data) abort let l:item = { \ 'bufnr': bufnr(''), \ 'lnum': 1, \ 'col': 1, \ 'type': 'E', \ 'linter_name': 'some_linter', \} call add(g:loclist, extend(l:item, a:data)) endfunction After: Restore unlet! g:loclist unlet! b:ale_loclist_msg_format delfunction AddItem call setloclist(0, []) call setqflist([]) Execute(Formatting with codes should work for the loclist): call AddItem({'text': "nocode\r"}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': 'nocode', \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() call remove(g:loclist, 0) call AddItem({'text': 'withcode', 'code': 'E123'}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': 'E123: withcode', \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(Formatting with codes should work for the quickfix list): let g:ale_set_loclist = 0 let g:ale_set_quickfix = 1 call AddItem({'text': "nocode\r"}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': 'nocode', \ }, \ ], \ ale#test#GetQflistWithoutNewerKeys() call remove(g:loclist, 0) call AddItem({'text': 'withcode', 'code': 'E123'}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': 'E123: withcode', \ }, \ ], \ ale#test#GetQflistWithoutNewerKeys() Execute(Formatting with the linter name should work for the loclist): let g:ale_loclist_msg_format = '(%linter%) %s' call AddItem({'text': 'whatever'}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': '(some_linter) whatever', \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() Execute(Formatting with the linter name should work for the quickfix list): let g:ale_loclist_msg_format = '(%linter%) %s' let g:ale_set_loclist = 0 let g:ale_set_quickfix = 1 call AddItem({'text': 'whatever'}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': '(some_linter) whatever', \ }, \ ], \ ale#test#GetQflistWithoutNewerKeys() Execute(The buffer loclist format option should take precedence): let g:ale_loclist_msg_format = '(%linter%) %s' let b:ale_loclist_msg_format = 'FOO %s' call AddItem({'text': 'whatever'}) call ale#list#SetLists(bufnr(''), g:loclist) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 1, \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \ 'text': 'FOO whatever', \ }, \ ], \ ale#test#GetLoclistWithoutNewerKeys() ================================================ FILE: test/test_list_opening.vader ================================================ " Author: Yann Fery Before: Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_open_list Save g:ale_keep_list_window_open Save g:ale_list_window_size Save g:ale_list_vertical Save g:ale_buffer_info Save g:ale_set_lists_synchronously let g:ale_set_loclist = 1 let g:ale_set_quickfix = 0 let g:ale_open_list = 0 let g:ale_keep_list_window_open = 0 let g:ale_list_window_size = 10 let g:ale_list_vertical = 0 let g:ale_set_lists_synchronously = 1 let g:loclist = [ \ {'bufnr': bufnr(''), 'lnum': 5, 'col': 5, 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 5, 'col': 4, 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 10, 'text': 'x'}, \ {'bufnr': bufnr(''), 'lnum': 3, 'col': 2, 'text': 'x'}, \] let g:ale_buffer_info = {bufnr(''): {'loclist': g:loclist}} function GetQuickfixHeight() abort for l:win in range(1, winnr('$')) if getwinvar(l:win, '&buftype') ==# 'quickfix' return winheight(l:win) endif endfor return 0 endfunction " If the window is vertical, window size should match column size/width function GetQuickfixIsVertical(cols) abort for l:win in range(1, winnr('$')) if getwinvar(l:win, '&buftype') is# 'quickfix' return winwidth(l:win) == a:cols endif endfor return 0 endfunction After: Restore unlet! g:loclist unlet! b:ale_list_vertical unlet! b:ale_list_window_size unlet! b:ale_open_list unlet! b:ale_keep_list_window_open unlet! b:ale_save_event_fired delfunction GetQuickfixHeight delfunction GetQuickfixIsVertical " Close quickfix window after every execute block lcl ccl call setloclist(0, []) call setqflist([]) Execute(IsQuickfixOpen should return the right output): AssertEqual 0, ale#list#IsQuickfixOpen() call setloclist(0, g:loclist) lopen AssertEqual 1, ale#list#IsQuickfixOpen() lcl AssertEqual 0, ale#list#IsQuickfixOpen() call setqflist(g:loclist) copen AssertEqual 1, ale#list#IsQuickfixOpen() ccl AssertEqual 0, ale#list#IsQuickfixOpen() Execute(The quickfix window should not open by default for the loclist): call ale#list#SetLists(bufnr('%'), g:loclist) Assert !ale#list#IsQuickfixOpen() Execute(The quickfix window should open for just the loclist): let g:ale_open_list = 1 " It should not open for an empty list. call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen() " With a non-empty loclist, the window must open. call ale#list#SetLists(bufnr('%'), g:loclist) Assert ale#list#IsQuickfixOpen() " Clear the list and it should close again. call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen() Execute(The quickfix window should open on the correct threshold): " The window should open for a value lower than number of entries. let g:ale_open_list = len(g:loclist) - 1 call ale#list#SetLists(bufnr('%'), g:loclist) Assert ale#list#IsQuickfixOpen() " Clear the list to be ready for a new value. call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen() " It should also open for a value equal to the number of entries. let g:ale_open_list = len(g:loclist) call ale#list#SetLists(bufnr('%'), g:loclist) Assert ale#list#IsQuickfixOpen() " Clear the list again, preparing for a final value. call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen() " Window should not open for values higher than number of loclist entries. let g:ale_open_list = len(g:loclist) + 1 call ale#list#SetLists(bufnr('%'), g:loclist) Assert !ale#list#IsQuickfixOpen() " Clear the list just to clean up. call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen() Execute(The quickfix window height should be correct for the loclist): let g:ale_open_list = 1 let g:ale_list_window_size = 7 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 7, GetQuickfixHeight() Execute(The quickfix window height should be correct for the loclist with buffer variables): let g:ale_open_list = 1 let b:ale_list_window_size = 8 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 8, GetQuickfixHeight() Execute(The quickfix window should be vertical for the loclist with appropriate variables): let g:ale_open_list = 1 let b:ale_list_window_size = 8 let b:ale_list_vertical = 1 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 1, GetQuickfixIsVertical(8) Execute(The quickfix window should be horizontal for the loclist with appropriate variables): let g:ale_open_list = 1 let b:ale_list_window_size = 8 let b:ale_list_vertical = 0 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 0, GetQuickfixIsVertical(8) Execute(The quickfix window should stay open for just the loclist): let g:ale_open_list = 1 let g:ale_keep_list_window_open = 1 " The window should stay open after even after it is made blank again. call ale#list#SetLists(bufnr('%'), g:loclist) call ale#list#SetLists(bufnr('%'), []) Assert ale#list#IsQuickfixOpen() Execute(The quickfix window should not open by default when quickfix is on): let g:ale_set_quickfix = 1 call ale#list#SetLists(bufnr('%'), g:loclist) Assert !ale#list#IsQuickfixOpen() Execute(The quickfix window should open for the quickfix list): let g:ale_set_quickfix = 1 let g:ale_open_list = 1 let g:ale_buffer_info[bufnr('') + 1] = { \ 'loclist': [{'bufnr': -1, 'filename': '/foo/bar', 'lnum': 5, 'col': 5, 'text': 'x'}], \} " It should not open for an empty list. call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen(), 'The quickfix window was opened when the list was empty' " With a non-empty quickfix list, the window must open. call ale#list#SetLists(bufnr('%'), g:loclist) Assert ale#list#IsQuickfixOpen(), 'The quickfix window was closed when the list was not empty' " Clear this List. The window should stay open, as there are other items. let g:ale_buffer_info[bufnr('')].loclist = [] call ale#list#SetLists(bufnr('%'), []) Assert ale#list#IsQuickfixOpen(), 'The quickfix window closed even though there are items in another buffer' " Clear the other List now. Now the window should close. call remove(g:ale_buffer_info, bufnr('') + 1) call ale#list#SetLists(bufnr('%'), []) Assert !ale#list#IsQuickfixOpen(), 'The quickfix window was not closed' Execute(The quickfix window should stay open for the quickfix list): let g:ale_set_quickfix = 1 let g:ale_open_list = 1 let g:ale_keep_list_window_open = 1 " The window should stay open after even after it is made blank again. call ale#list#SetLists(bufnr('%'), g:loclist) call ale#list#SetLists(bufnr('%'), []) Assert ale#list#IsQuickfixOpen() Execute(The quickfix window height should be correct for the quickfix list): let g:ale_set_quickfix = 1 let g:ale_open_list = 1 let g:ale_list_window_size = 7 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 7, GetQuickfixHeight() Execute(The quickfix window height should be correct for the quickfix list with buffer variables): let g:ale_set_quickfix = 1 let g:ale_open_list = 1 let b:ale_list_window_size = 8 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 8, GetQuickfixHeight() Execute(The quickfix window should be vertical for the quickfix with appropriate variables): let g:ale_open_list = 1 let b:ale_list_window_size = 8 let b:ale_list_vertical = 1 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 1, GetQuickfixIsVertical(8) Execute(The quickfix window should be horizontal for the quickfix with appropriate variables): let g:ale_open_list = 1 let b:ale_list_window_size = 8 let b:ale_list_vertical = 0 call ale#list#SetLists(bufnr('%'), g:loclist) AssertEqual 0, GetQuickfixIsVertical(8) Execute(buffer-local options should be respected): let b:ale_open_list = 1 let b:ale_keep_list_window_open = 1 call ale#list#SetLists(bufnr('%'), g:loclist) call ale#list#SetLists(bufnr('%'), []) Assert ale#list#IsQuickfixOpen() Execute(The ale_open_list='on_save' option should work): let b:ale_open_list = 'on_save' call ale#list#SetLists(bufnr('%'), g:loclist) " The list shouldn't open yet, the event wasn't fired. Assert !ale#list#IsQuickfixOpen() " Turn this option off, to ensure that we update lists immediately when we " save buffers. let g:ale_set_lists_synchronously = 0 let b:ale_save_event_fired = 1 call ale#list#SetLists(bufnr('%'), g:loclist) " Now the list should have opened. Assert ale#list#IsQuickfixOpen() call ale#list#SetLists(bufnr('%'), []) " The window should close again when the loclist is empty. Assert !ale#list#IsQuickfixOpen() Execute(The window shouldn't open on save when ale_open_list=0): let b:ale_open_list = 0 let b:ale_save_event_fired = 1 call ale#list#SetLists(bufnr('%'), g:loclist) " Now the list should have opened. Assert !ale#list#IsQuickfixOpen() ================================================ FILE: test/test_list_titles.vader ================================================ Before: Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_buffer_info Save g:ale_set_lists_synchronously let g:ale_buffer_info = {} let g:ale_set_loclist = 0 let g:ale_set_quickfix = 0 let g:ale_set_lists_synchronously = 1 call ale#test#SetDirectory('/testplugin/test') After: Restore call setloclist(0, []) call setqflist([]) call ale#test#RestoreDirectory() Execute(The loclist titles should be set appropriately): silent noautocmd file foo let g:ale_set_loclist = 1 call ale#list#SetLists(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 5, 'col': 5, 'text': 'x', 'type': 'E'}, \]) AssertEqual [{ \ 'lnum': 5, \ 'bufnr': bufnr(''), \ 'col': 5, \ 'text': 'x', \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \}], ale#test#GetLoclistWithoutNewerKeys() if !has('nvim') AssertEqual \ {'title': ale#path#Simplify(getcwd() . '/foo')}, \ getloclist(0, {'title': ''}) endif Execute(The quickfix titles should be set appropriately): silent noautocmd file foo let g:ale_set_quickfix = 1 let g:ale_buffer_info[bufnr('')] = { \ 'loclist': [{'bufnr': bufnr(''), 'lnum': 5, 'col': 5, 'text': 'x', 'type': 'E'}], \} call ale#list#SetLists(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 5, 'col': 5, 'text': 'x', 'type': 'E'}, \]) AssertEqual [{ \ 'lnum': 5, \ 'bufnr': bufnr(''), \ 'col': 5, \ 'text': 'x', \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \}], ale#test#GetQflistWithoutNewerKeys() if !has('nvim') AssertEqual \ {'title': ale#path#Simplify(getcwd() . '/foo')}, \ getqflist({'title': ''}) endif ================================================ FILE: test/test_load_all_linters.vader ================================================ Execute(Exceptions shouldn't be thrown when loading all linters): " This test will look for errors when loading any of the linter files. runtime! ale_linters/*/*.vim After: call ale#linter#Reset() ================================================ FILE: test/test_loclist_binary_search.vader ================================================ Before: let g:loclist = [ \ {'bufnr': 1, 'lnum': 2, 'col': 10}, \ {'bufnr': 1, 'lnum': 3, 'col': 2}, \ {'bufnr': 1, 'lnum': 3, 'col': 10}, \ {'bufnr': 1, 'lnum': 3, 'col': 12}, \ {'bufnr': 1, 'lnum': 3, 'col': 25}, \ {'bufnr': 1, 'lnum': 5, 'col': 4}, \ {'bufnr': 1, 'lnum': 5, 'col': 5}, \ {'bufnr': 1, 'lnum': 9, 'col': 5}, \ {'bufnr': 1, 'lnum': 10, 'col': 1}, \ {'bufnr': 2, 'lnum': 7, 'col': 10}, \ {'bufnr': 2, 'lnum': 9, 'col': 2}, \ {'bufnr': 2, 'lnum': 10, 'col': 2}, \ {'bufnr': 2, 'lnum': 11, 'col': 2}, \] After: unlet g:loclist Execute(Exact column matches should be correct): AssertEqual 1, ale#util#BinarySearch(g:loclist, 1, 3, 2) Execute(Off lines, there should be no match): AssertEqual -1, ale#util#BinarySearch(g:loclist, 1, 4, 2) Execute(Near column matches should be taken): AssertEqual 2, ale#util#BinarySearch(g:loclist, 1, 3, 11) AssertEqual 3, ale#util#BinarySearch(g:loclist, 1, 3, 13) Execute(Columns before should be taken when the cursor is far ahead): AssertEqual 4, ale#util#BinarySearch(g:loclist, 1, 3, 300) Execute(The only problems on lines in later columns should be matched): AssertEqual 7, ale#util#BinarySearch(g:loclist, 1, 9, 1) Execute(The only problems on lines in earlier columns should be matched): AssertEqual 8, ale#util#BinarySearch(g:loclist, 1, 10, 30) Execute(Lines for other buffers should not be matched): AssertEqual -1, ale#util#BinarySearch(g:loclist, 1, 7, 10) Execute(Searches for buffers later in the list should work): AssertEqual 10, ale#util#BinarySearch(g:loclist, 2, 9, 10) Execute(Searches should work with just one item): let g:loclist = [{'bufnr': 1, 'lnum': 3, 'col': 10}] AssertEqual 0, ale#util#BinarySearch(g:loclist, 1, 3, 2) Execute(Searches should return the last item on a single column): let g:loclist = [ \ {'bufnr': 1, 'lnum': 1, 'col': 10, 'type': 'W'}, \ {'bufnr': 1, 'lnum': 1, 'col': 10, 'type': 'E'}, \ {'bufnr': 1, 'lnum': 1, 'col': 11, 'type': 'W'}, \ {'bufnr': 1, 'lnum': 1, 'col': 11, 'type': 'E'}, \ {'bufnr': 1, 'lnum': 1, 'col': 20, 'type': 'W'}, \ {'bufnr': 1, 'lnum': 1, 'col': 20, 'type': 'E'}, \] " We should return the index for the last item at some column to the right. AssertEqual 1, ale#util#BinarySearch(g:loclist, 1, 1, 1) " We should return the index for the last item at the column we are on. AssertEqual 3, ale#util#BinarySearch(g:loclist, 1, 1, 11) " We should prefer items to the left of the cursor, over the right. AssertEqual 3, ale#util#BinarySearch(g:loclist, 1, 1, 19) ================================================ FILE: test/test_loclist_corrections.vader ================================================ Before: Save g:ale_filename_mappings let g:ale_filename_mappings = {} After: unlet! b:temp_name unlet! b:other_bufnr Restore Execute(FixLocList should map filenames): " Paths converted back into temporary filenames shouldn't be included. let g:ale_filename_mappings = { \ 'linter2': [['/xxx/', '/data/']], \ 'linter1': [ \ ['/bar/', '/data/special/'], \ ['/foo/', '/data/'], \ [ \ ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h:h')) . '/', \ '/x-tmp/', \ ], \ ], \} AssertEqual \ [ \ '/foo/file.txt', \ v:null, \ '/bar/file.txt', \ ], \ map( \ ale#engine#FixLocList( \ bufnr('%'), \ 'linter1', \ 0, \ [ \ {'text': 'x', 'lnum': 1, 'filename': '/data/file.txt'}, \ {'text': 'x', 'lnum': 1, 'filename': '/x-tmp/file.txt'}, \ {'text': 'x', 'lnum': 1, 'filename': '/data/special/file.txt'}, \ ], \ ), \ 'get(v:val, ''filename'', v:null)', \ ) Given foo (Some file with lines to count): foo12345678 bar12345678 baz12345678 four12345678 five12345678 six12345678 seven12345678 eight12345678 nine12345678 ten12345678 Execute(FixLocList should set all the default values correctly): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 2, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'b', \ 'lnum': 2, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [{'text': 'a', 'lnum': 2}, {'text': 'b', 'lnum': 2}], \ ) Execute(FixLocList should use the values we supply): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 3, \ 'col': 4, \ 'bufnr': 10000, \ 'vcol': 0, \ 'type': 'W', \ 'nr': 42, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [{ \ 'text': 'a', \ 'lnum': 3, \ 'col': 4, \ 'bufnr': 10000, \ 'vcol': 1, \ 'type': 'W', \ 'nr': 42, \ }], \ ) Execute(FixLocList should set items with lines beyond the end to the last line): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 10, \ 'col': 0, \ 'end_lnum': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [{'text': 'a', 'lnum': 11, 'end_lnum': 12}], \ ) Execute(FixLocList should move line 0 to line 1): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 1, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [{'text': 'a', 'lnum': 0}], \ ) Execute(FixLocList should convert line and column numbers correctly): " The numbers should be 10, not 8 as octals. AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 10, \ 'col': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [{'text': 'a', 'lnum': '010', 'col': '010'}], \ ) Execute(FixLocList should pass on end_col values): " The numbers should be 10, not 8 as octals. AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 10, \ 'col': 10, \ 'end_col': 12, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'a', \ 'lnum': 10, \ 'col': 11, \ 'end_col': 12, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [ \ {'text': 'a', 'lnum': '010', 'col': '010', 'end_col': '012'}, \ {'text': 'a', 'lnum': '010', 'col': '011', 'end_col': 12}, \ ], \ ) Execute(FixLocList should pass on end_lnum values): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 7, \ 'col': 10, \ 'end_lnum': 10, \ 'end_col': 12, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'a', \ 'lnum': 7, \ 'col': 11, \ 'end_lnum': 10, \ 'end_col': 12, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [ \ {'text': 'a', 'lnum': '07', 'col': '010', 'end_col': '012', 'end_lnum': '010'}, \ {'text': 'a', 'lnum': '07', 'col': '011', 'end_col': 12, 'end_lnum': 10}, \ ], \ ) Execute(FixLocList should allow subtypes to be set): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 10, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'sub_type': 'style', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [{'text': 'a', 'lnum': 11, 'sub_type': 'style'}], \ ) Execute(FixLocList should accept filenames): let b:other_bufnr = bufnr('/foo/bar/baz', 1) " Make sure we actually get another buffer number, or the test is invalid. AssertNotEqual -1, b:other_bufnr call ale#test#SetFilename('test.txt') AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 2, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'filename': expand('%:p'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'a', \ 'lnum': 3, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'filename': expand('%:p'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'a', \ 'lnum': 4, \ 'col': 0, \ 'bufnr': b:other_bufnr, \ 'filename': '/foo/bar/baz', \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'a', \ 'lnum': 5, \ 'col': 0, \ 'bufnr': b:other_bufnr, \ 'filename': '/foo/bar/baz', \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [ \ {'text': 'a', 'lnum': 2, 'filename': expand('%:p')}, \ {'text': 'a', 'lnum': 3, 'filename': expand('%:p')}, \ {'text': 'a', 'lnum': 4, 'filename': '/foo/bar/baz'}, \ {'text': 'a', 'lnum': 5, 'filename': '/foo/bar/baz'}, \ ], \ ) Execute(FixLocList should interpret temporary filenames as being the current buffer): let b:temp_name = tempname() AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 2, \ 'col': 0, \ 'bufnr': bufnr(''), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ { \ 'text': 'a', \ 'lnum': 3, \ 'col': 0, \ 'bufnr': bufnr(''), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ }, \ ], \ ale#engine#FixLocList( \ bufnr(''), \ 'foobar', \ 0, \ [ \ {'text': 'a', 'lnum': 2, 'filename': b:temp_name}, \ {'text': 'a', 'lnum': 3, 'filename': substitute(b:temp_name, '\\', '/', 'g')}, \ ], \ ) Execute(The error code should be passed on): AssertEqual \ [ \ { \ 'text': 'a', \ 'lnum': 10, \ 'col': 0, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'type': 'E', \ 'nr': -1, \ 'linter_name': 'foobar', \ 'code': 'some-code' \ }, \ ], \ 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): はじめまして! -私はワープです。 Execute(character positions should be converted to byte positions): AssertEqual \ [ \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 0, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 1, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 4, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 13, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 13, 'end_lnum': 1, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 17, 'end_lnum': 2, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ {'lnum': 2, 'bufnr': bufnr(''), 'col': 17, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, \ ], \ ale#engine#FixLocList( \ bufnr('%'), \ 'foobar', \ 0, \ [ \ {'text': 'a', 'lnum': 1, 'col': 0, 'vcol': 1}, \ {'text': 'a', 'lnum': 1, 'col': 1, 'vcol': 1}, \ {'text': 'a', 'lnum': 1, 'col': 2, 'vcol': 1}, \ {'text': 'a', 'lnum': 1, 'col': 3, 'vcol': 1}, \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 5, 'vcol': 1}, \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 5, 'end_lnum': 1, 'vcol': 1}, \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 7, 'end_lnum': 2, 'vcol': 1}, \ {'text': 'a', 'lnum': 2, 'col': 7, 'vcol': 1}, \ ], \ ) ================================================ FILE: test/test_loclist_jumping.vader ================================================ Before: let g:ale_buffer_info = { \ bufnr(''): { \ 'loclist': [ \ {'type': 'E', 'bufnr': bufnr('') - 1, 'lnum': 3, 'col': 2}, \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 1, 'col': 2}, \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 1, 'col': 3}, \ {'type': 'W', 'sub_type': 'style', 'bufnr': bufnr(''), 'lnum': 2, 'col': 1}, \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 2}, \ {'type': 'W', 'sub_type': 'style', 'bufnr': bufnr(''), 'lnum': 2, 'col': 3}, \ {'type': 'W', 'bufnr': bufnr(''), 'lnum': 2, 'col': 6}, \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 700}, \ {'type': 'E', 'bufnr': bufnr('') + 1, 'lnum': 3, 'col': 2}, \ ], \ }, \} function! TestJump(position, wrap, filter, subtype_filter, pos) call cursor(a:pos) if type(a:position) == type(0) call ale#loclist_jumping#JumpToIndex(a:position) else call ale#loclist_jumping#Jump(a:position, a:wrap, a:filter, \ a:subtype_filter) endif return getcurpos()[1:2] endfunction After: let g:ale_buffer_info = {} delfunction TestJump Given foobar (Some imaginary filetype): 12345678 12345678 Execute(loclist jumping should jump correctly when not wrapping): AssertEqual [2, 1], TestJump('before', 0, 'any', 'any', [2, 2]) AssertEqual [1, 3], TestJump('before', 0, 'any', 'any', [2, 1]) AssertEqual [2, 3], TestJump('after', 0, 'any', 'any', [2, 2]) AssertEqual [2, 1], TestJump('after', 0, 'any', 'any', [1, 3]) AssertEqual [2, 6], TestJump('after', 0, 'any', 'any', [2, 4]) AssertEqual [2, 8], TestJump('after', 0, 'any', 'any', [2, 6]) Execute(loclist jumping should jump correctly when wrapping): AssertEqual [2, 1], TestJump('before', 1, 'any', 'any', [2, 2]) AssertEqual [1, 3], TestJump('before', 1, 'any', 'any', [2, 1]) AssertEqual [2, 3], TestJump('after', 1, 'any', 'any', [2, 2]) AssertEqual [2, 1], TestJump('after', 1, 'any', 'any', [1, 3]) AssertEqual [2, 6], TestJump('after', 1, 'any', 'any', [2, 4]) AssertEqual [1, 2], TestJump('after', 1, 'any', 'any', [2, 8]) AssertEqual [2, 8], TestJump('before', 1, 'any', 'any', [1, 2]) Execute(loclist jumping should jump correctly with warning filters): AssertEqual [2, 1], TestJump('after', 0, 'W', 'any', [1, 2]) AssertEqual [2, 6], TestJump('after', 0, 'W', 'any', [2, 3]) AssertEqual [2, 1], TestJump('after', 1, 'W', 'any', [2, 6]) Execute(loclist jumping should jump correctly with error filters): AssertEqual [1, 2], TestJump('after', 1, 'E', 'any', [2, 700]) AssertEqual [2, 2], TestJump('before', 0, 'E', 'any', [2, 700]) AssertEqual [2, 2], TestJump('after', 1, 'E', 'any', [1, 3]) Execute(loclist jumping should jump correctly with sub type filters): AssertEqual [2, 3], TestJump('after', 0, 'any', 'style', [2, 1]) AssertEqual [2, 2], TestJump('after', 0, 'any', '', [1, 3]) AssertEqual [2, 1], TestJump('after', 1, 'any', 'style', [2, 6]) Execute(loclist jumping not jump when the loclist is empty): let g:ale_buffer_info[bufnr('%')].loclist = [] AssertEqual [1, 6], TestJump('before', 0, 'any', 'any', [1, 6]) AssertEqual [1, 6], TestJump('before', 1, 'any', 'any', [1, 6]) AssertEqual [1, 6], TestJump('after', 0, 'any', 'any', [1, 6]) AssertEqual [1, 6], TestJump('after', 1, 'any', 'any', [1, 6]) Execute(We should be able to jump to the last item): AssertEqual [2, 8], TestJump(-1, 0, 'any', 'any', [1, 6]) Execute(We shouldn't move when jumping to the last item where there are none): let g:ale_buffer_info[bufnr('%')].loclist = [] AssertEqual [1, 6], TestJump(-1, 0, 'any', 'any', [1, 6]) Execute(We should be able to jump to the first item): AssertEqual [1, 2], TestJump(0, 0, 'any', 'any', [1, 6]) Execute(We shouldn't move when jumping to the first item where there are none): let g:ale_buffer_info[bufnr('%')].loclist = [] AssertEqual [1, 6], TestJump(0, 0, 'any', 'any', [1, 6]) Execute(We should be able to jump when the error line is blank): " Add a blank line at the end. call setline(1, getline('.', '$') + ['']) " Add a problem on the blank line. call add(g:ale_buffer_info[bufnr('%')].loclist, {'type': 'E', 'bufnr': bufnr(''), 'lnum': 3, 'col': 1}) AssertEqual 0, len(getline(3)) AssertEqual [2, 8], TestJump('before', 0, 'any', 'any', [3, 1]) AssertEqual [2, 8], TestJump('before', 1, 'any', 'any', [3, 1]) AssertEqual [3, 1], TestJump('after', 0, 'any', 'any', [3, 1]) AssertEqual [1, 2], TestJump('after', 1, 'any', 'any', [3, 1]) Execute(ALE should jump to column 1 instead of 0): let g:ale_buffer_info = { \ bufnr(''): { \ 'loclist': [ \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 1, 'col': 5}, \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 0}, \ ], \ }, \} AssertEqual [2, 1], TestJump('after', 1, 'any', 'any', [1, 5]) AssertEqual [1, 5], TestJump('after', 1, 'any', 'any', [2, 1]) AssertEqual [2, 1], TestJump('before', 1, 'any', 'any', [1, 5]) AssertEqual [1, 5], TestJump('before', 1, 'any', 'any', [2, 1]) ================================================ FILE: test/test_loclist_sorting.vader ================================================ Execute(loclist item should be sorted): AssertEqual [ \ {'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2}, \ {'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2}, \ {'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2}, \ {'bufnr': 1, 'lnum': 2, 'col': 10}, \ {'bufnr': 1, 'lnum': 3, 'col': 2}, \ {'bufnr': 1, 'lnum': 5, 'col': 4}, \ {'bufnr': 1, 'lnum': 5, 'col': 5}, \ {'bufnr': 2, 'lnum': 1, 'col': 2}, \ {'bufnr': 2, 'lnum': 1, 'col': 5}, \ {'bufnr': 2, 'lnum': 5, 'col': 5}, \ {'bufnr': 3, 'lnum': 1, 'col': 1}, \ ], \ sort([ \ {'bufnr': 3, 'lnum': 1, 'col': 1}, \ {'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2}, \ {'bufnr': 1, 'lnum': 5, 'col': 5}, \ {'bufnr': 2, 'lnum': 5, 'col': 5}, \ {'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2}, \ {'bufnr': 1, 'lnum': 5, 'col': 4}, \ {'bufnr': 1, 'lnum': 2, 'col': 10}, \ {'bufnr': 2, 'lnum': 1, 'col': 5}, \ {'bufnr': 1, 'lnum': 3, 'col': 2}, \ {'bufnr': 2, 'lnum': 1, 'col': 2}, \ {'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2}, \], 'ale#util#LocItemCompare') Execute(Items should be sorted in by their problem priority when they lie on the same column): AssertEqual [ \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E', 'sub_type': 'style'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'I'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E'}, \ ], \ sort([ \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'I'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E', 'sub_type': 'style'}, \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W', 'sub_type': 'style'}, \], 'ale#util#LocItemCompare') ================================================ FILE: test/test_maven_build_classpath_command.vader ================================================ Before: Save $PATH Save $PATHEXT let $PATHEXT = '.' call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/java/javac.vim let g:expected_wrapper = '' if has('unix') let g:expected_wrapper = 'mvnw' else let g:expected_wrapper = 'mvnw.cmd' endif After: Restore unlet! g:expected_wrapper call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should use 'mvnw' in classpath command if available): call ale#test#SetFilename('test-files/maven/maven-java-project/module1/src/main/java/dummy1.java') AssertEqual \ [ \ ale#path#Simplify(g:dir . '/test-files/maven/maven-java-project/module1'), \ ale#Escape(ale#path#Simplify(g:dir . '/test-files/maven/maven-java-project/module1/' . g:expected_wrapper)) \ . ' dependency:build-classpath', \ ], \ ale#maven#BuildClasspathCommand(bufnr('')) Execute(Should use 'mvn' in classpath command if it is executable and 'mvnw' is unavailable): call ale#test#SetFilename('test-files/maven/maven-java-project/module2/src/main/java/dummy2.java') let $PATH .= (has('win32') ? ';' : ':') \ . ale#path#Simplify(g:dir . '/test-files/maven') AssertEqual \ [ \ ale#path#Simplify(g:dir . '/test-files/maven/maven-java-project/module2'), \ ale#Escape('mvn') \ . ' dependency:build-classpath', \ ], \ ale#maven#BuildClasspathCommand(bufnr('')) Execute(Should return empty string if maven cannot be executed): call ale#test#SetFilename('test-files/maven/non-maven-project/src/main/java/dummy.java') AssertEqual \ ['', ''], \ ale#maven#BuildClasspathCommand(bufnr('')) ================================================ FILE: test/test_maven_find_executable.vader ================================================ Before: Save $PATH Save $PATHEXT " Count the maven executable without .exe as executable on Windows let $PATHEXT = '.' call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/java/javac.vim let g:expected_wrapper = '' if has('unix') let g:expected_wrapper = 'mvnw' else let g:expected_wrapper = 'mvnw.cmd' endif After: Restore unlet! g:expected_wrapper call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return 'mvnw' if found in parent directory): call ale#test#SetFilename('test-files/maven/maven-java-project/module1/src/main/java/dummy1.java') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/maven/maven-java-project/module1/' . g:expected_wrapper), \ ale#maven#FindExecutable(bufnr('')) Execute(Should return 'mvn' if 'mvnw' not found in parent directory): call ale#test#SetFilename('test-files/maven/maven-java-project/module2/src/main/java/dummy2.java') let $PATH .= (has('win32') ? ';' : ':') \ . ale#path#Simplify(g:dir . '/test-files/maven') AssertEqual \ 'mvn', \ ale#maven#FindExecutable(bufnr('')) Execute(Should return empty string if 'mvnw' not in parent directory and mvn not in path): call ale#test#SetFilename('mvn-test-files/java-maven-project/module2/src/main/java/dummy2.java') AssertEqual \ '', \ ale#gradle#FindExecutable(bufnr('')) ================================================ FILE: test/test_maven_find_project_root.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') runtime ale_linters/kotlin/javac.vim After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(Should return directory for 'mvnw' if found in parent directory): call ale#test#SetFilename('test-files/maven/maven-java-project/module1/src/main/java/dummy1.java') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/maven/maven-java-project/module1'), \ ale#maven#FindProjectRoot(bufnr('')) Execute(Should return directory for 'pom.xml' if found in parent directory): call ale#test#SetFilename('test-files/maven/maven-java-project/module2/src/main/java/dummy2.java') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/maven/maven-java-project/module2'), \ ale#maven#FindProjectRoot(bufnr('')) Execute(Should return empty string if maven files are not found in parent directory): call ale#test#SetFilename('test-files/maven/non-maven-project/src/main/java/dummy.java') AssertEqual \ '', \ ale#maven#FindProjectRoot(bufnr('')) ================================================ FILE: test/test_neovim_diagnostics.vader ================================================ Before: Save g:ale_use_neovim_diagnostics_api function! CollectMessages(buffer) let l:messages = [] for l:diag in v:lua.vim.diagnostic.get(a:buffer) call add(l:messages, l:diag.message) endfor return l:messages endfunction After: unlet! b:other_bufnr delfunction CollectMessages Restore Execute(Should only set diagnostics belonging to the given buffer): if has('nvim-0.6') let b:other_bufnr = bufnr('/foo/bar/baz', 1) " Make sure we actually get another buffer number, or the test is invalid. AssertNotEqual -1, b:other_bufnr let g:ale_use_neovim_diagnostics_api = 1 call ale#engine#SetResults(bufnr('%'), [ \ { \ 'lnum': 1, \ 'col': 10, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'W', \ 'text': 'A', \ }, \ { \ 'lnum': 2, \ 'col': 10, \ 'bufnr': b:other_bufnr, \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'W', \ 'text': 'B', \ }, \ { \ 'lnum': 3, \ 'col': 1, \ 'bufnr': bufnr('%'), \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'E', \ 'text': 'C', \ }, \ { \ 'lnum': 4, \ 'col': 1, \ 'bufnr': b:other_bufnr, \ 'vcol': 0, \ 'linter_name': 'bettercode', \ 'nr': -1, \ 'type': 'E', \ 'text': 'D', \ }, \]) AssertEqual ["A", "C"], CollectMessages(bufnr('%')) endif ================================================ FILE: test/test_no_linting_on_write_quit.vader ================================================ Before: Save g:ale_echo_cursor Save g:ale_fix_on_save Save g:ale_fixers Save g:ale_lint_on_save Save g:ale_set_highlights Save g:ale_set_lists_synchronously Save g:ale_set_loclist Save g:ale_set_quickfix Save g:ale_set_signs let g:ale_run_synchronously = 1 let g:ale_set_lists_synchronously = 1 " Disable the things we don't need, but leave enabled what we do. let g:ale_echo_cursor = 0 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 [{'lnum': 1, 'col': 1, 'text': 'xxx'}] endfunction function AddLine(buffer, lines) abort return a:lines + ['x'] endfunction let g:ale_fixers = { \ 'testft': ['AddLine'], \} call ale#linter#PreventLoading('testft') call ale#linter#Define('testft', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': has('win32') ? 'cmd' : 'true', \ 'command': 'true', \}) Given testft (An empty file): After: Restore unlet! g:ale_run_synchronously unlet! b:ale_quitting delfunction TestCallback delfunction AddLine call ale#linter#Reset() call setloclist(0, []) Execute(No linting should be done on :wq or :x): let g:ale_lint_on_save = 1 let g:ale_fix_on_save = 0 " First try just the SaveEvent, to be sure that we set errors in the test. call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()) " Now try doing it again, but where we run the quit event first. call setloclist(0, []) call ale#events#QuitEvent(bufnr('')) call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() Execute(No linting should be for :w after :q fails): let g:ale_lint_on_save = 1 let g:ale_fix_on_save = 0 call ale#events#QuitEvent(bufnr('')) call ale#test#FlushJobs() " Simulate 2 seconds passing. let b:ale_quitting -= 1000 call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()) Execute(No linting should be done on :wq or :x after fixing files): let g:ale_lint_on_save = 1 let g:ale_fix_on_save = 1 call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()) " Now try doing it again, but where we run the quit event first. call setloclist(0, []) call ale#events#QuitEvent(bufnr('')) call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() Execute(Linting should be done after :q fails and fixing files): let g:ale_lint_on_save = 1 let g:ale_fix_on_save = 1 call ale#events#QuitEvent(bufnr('')) call ale#test#FlushJobs() " Simulate 2 seconds passing. let b:ale_quitting -= 1000 call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()) ================================================ FILE: test/test_organize_imports.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.txt') let g:old_filename = expand('%:p') let g:Callback = '' let g:expr_list = [] let g:message_list = [] let g:handle_code_action_called = 0 let g:code_actions = [] let g:options = {} let g:capability_checked = '' let g:conn_id = v:null let g:InitCallback = v:null runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/organize_imports.vim runtime autoload/ale/code_action.vim function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) if a:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(g:conn_id) endif let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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#code_action#HandleCodeAction(code_action, options) abort let g:handle_code_action_called = 1 AssertEqual g:ale_save_hidden || !&hidden, get(a:options, 'should_save') call add(g:code_actions, a:code_action) endfunction After: 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() unlet! g:capability_checked unlet! g:InitCallback unlet! g:old_filename unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters unlet! g:options unlet! g:code_actions unlet! g:handle_code_action_called runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/organize_imports.vim runtime autoload/ale/code_action.vim Execute(Other messages for the tsserver handler should be ignored): call ale#organize_imports#HandleTSServerResponse(1, {'command': 'foo'}) AssertEqual g:handle_code_action_called, 0 Execute(Failed organizeImports responses should be handled correctly): call ale#organize_imports#HandleTSServerResponse( \ 1, \ {'command': 'organizeImports', 'request_seq': 3} \) AssertEqual g:handle_code_action_called, 0 Execute(Code actions from tsserver should be handled): call ale#organize_imports#HandleTSServerResponse(1, { \ 'command': 'organizeImports', \ 'request_seq': 3, \ 'success': v:true, \ 'body': [], \}) AssertEqual g:handle_code_action_called, 1 AssertEqual [{ \ 'description': 'Organize Imports', \ 'changes': [], \}], g:code_actions Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(tsserver organize imports requests should be sent): call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim ALEOrganizeImports " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual \ 'function(''ale#organize_imports#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@organizeImports', { \ 'scope': { \ 'type': 'file', \ 'args': { \ 'file': expand('%:p'), \ }, \ }, \ }] \ ], \ g:message_list Given python(Some Python file): foo somelongerline bazxyzxyzxyz Execute(Should result in error message for LSP): call ale#linter#Reset() runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] ALEOrganizeImports " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual [ \ 'echom ''OrganizeImports currently only works with tsserver''', \], g:expr_list ================================================ FILE: test/test_other_sources.vader ================================================ 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 should 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#GetLoclistWithoutNewerKeys() call ale#other_source#ShowResults(bufnr(''), 'other-source-linter', []) AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() 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#GetLoclistWithoutNewerKeys() 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') ================================================ FILE: test/test_parse_command_args.vader ================================================ After: unlet! b:parse_result if exists(':ParseTest') delcommand ParseTest endif Execute(ale#args#Parse should work for an example command): command! -nargs=* ParseTest let b:parse_result = ale#args#Parse(['foo', 'bar'], ) ParseTest AssertEqual [{}, ''], b:parse_result ParseTest -- AssertEqual [{}, ''], b:parse_result ParseTest -foo AssertEqual [{'foo': ''}, ''], b:parse_result ParseTest -foo -- -- AssertEqual [{'foo': ''}, '--'], b:parse_result ParseTest -foo -bar AssertEqual [{'foo': '', 'bar': ''}, ''], b:parse_result ParseTest -foo -bar leave these alone AssertEqual [{'foo': '', 'bar': ''}, 'leave these alone'], b:parse_result Execute(ale#args#Parse should raise errors for unknown arguments): AssertThrows call ale#args#Parse(['foo', 'bar'], '-nope leave these alone') AssertEqual 'Invalid argument: -nope', g:vader_exception ================================================ FILE: test/test_path_dirname.vader ================================================ 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/') if has('win32') AssertEqual 'C:\foo', ale#path#Dirname('C:\foo\bar') AssertEqual 'C:\foo', ale#path#Dirname('C:\foo\bar\') endif ================================================ FILE: test/test_path_equality.vader ================================================ Before: function! CheckPath(path) abort return ale#path#IsBufferPath(bufnr(''), ale#path#Simplify(a:path)) endfunction After: delfunction CheckPath Execute(ale#path#Simplify should adjust paths correctly): if has('unix') " Multiple slashes should be removed correctly. AssertEqual '/foo/bar/baz', ale#path#Simplify('////foo///bar///baz') " Back slashes should be converted to forward slashes. " This means some valid filenames are adjusted incorrectly, but in practice " no filenames for code should contain back slashes, and adjusting slashes " like this makes ALE work in MSYS. AssertEqual 'foo/bar/baz', ale#path#Simplify('foo\bar\baz') else " Multiple slashes should be removed correctly. AssertEqual '\foo\bar\baz', ale#path#Simplify('\\\foo\bar\baz') " Forward slashes should be replaced with back slashes. AssertEqual 'foo\bar\baz', ale#path#Simplify('foo/bar/baz') endif Execute(ale#path#IsBufferPath should match simple relative paths): call ale#test#SetFilename('app/foo.txt') Assert CheckPath('app/foo.txt'), 'No match for foo.txt' Assert !CheckPath('app/bar.txt'), 'Bad match for bar.txt' Execute(ale#path#IsBufferPath should match relative paths with dots): call ale#test#SetFilename('app/foo.txt') " Skip these checks on Windows. if !has('win32') Assert CheckPath('../../app/foo.txt'), 'No match for ../../app/foo.txt' endif Execute(ale#path#IsBufferPath should match absolute paths): silent file! foo.txt Assert CheckPath(getcwd() . '/foo.txt'), 'No match for foo.txt' Assert !CheckPath(getcwd() . '/bar.txt'), 'Bad match for bar.txt' Execute(ale#path#IsBufferPath should match paths beginning with ./): silent file! foo.txt if !has('win32') Assert ale#path#IsBufferPath(bufnr(''), './foo.txt'), 'No match for ./foo.txt' endif Execute(ale#path#IsBufferPath should match if our path ends with the test path): silent file! foo/bar/baz.txt Assert CheckPath('bar/baz.txt'), 'No match for bar/baz.txt' Execute(ale#path#IsBufferPath should match paths with redundant slashes): silent file! foo.txt Assert CheckPath(getcwd() . '////foo.txt'), 'No match for foo.txt' Execute(ale#path#IsBufferPath should accept various names for stdin): Assert ale#path#IsBufferPath(bufnr(''), '-') Assert ale#path#IsBufferPath(bufnr(''), 'stdin') Assert ale#path#IsBufferPath(bufnr(''), '') Assert ale#path#IsBufferPath(bufnr(''), '') Execute(ale#path#IsBufferPath should match files in /tmp): call ale#test#SetFilename('app/test.ts') Assert ale#path#IsBufferPath(bufnr(''), tempname() . '/test.ts') Execute(ale#path#IsBufferPath should match Windows paths on Unix): " This test should pass Unix. " " Back slashes in paths should be replaced with forward slashes, even though " back slashes are valid in filenames on Unix. if has('unix') call ale#test#SetFilename('app/foo/test.ts') Assert ale#path#IsBufferPath(bufnr(''), 'foo\test.ts') endif ================================================ FILE: test/test_path_upwards.vader ================================================ Execute(ale#path#Upwards should return the correct path components): if has('unix') " Absolute paths should include / on the end. AssertEqual \ ['/foo/bar/baz', '/foo/bar', '/foo', '/'], \ ale#path#Upwards('/foo/bar/baz') AssertEqual \ ['/foo/bar/baz', '/foo/bar', '/foo', '/'], \ ale#path#Upwards('/foo/bar/baz///') " Relative paths do not. AssertEqual \ ['foo/bar/baz', 'foo/bar', 'foo'], \ ale#path#Upwards('foo/bar/baz') AssertEqual \ ['foo2/bar', 'foo2'], \ ale#path#Upwards('foo//..////foo2////bar') " Expect an empty List for empty strings. AssertEqual [], ale#path#Upwards('') endif if has('win32') AssertEqual \ ['C:\foo\bar\baz', 'C:\foo\bar', 'C:\foo', 'C:\'], \ ale#path#Upwards('C:\foo\bar\baz') AssertEqual \ ['C:\foo\bar\baz', 'C:\foo\bar', 'C:\foo', 'C:\'], \ ale#path#Upwards('C:\foo\bar\baz\\\') AssertEqual \ ['/foo\bar\baz', '/foo\bar', '/foo', '/'], \ ale#path#Upwards('/foo/bar/baz') AssertEqual \ ['foo\bar\baz', 'foo\bar', 'foo'], \ ale#path#Upwards('foo/bar/baz') AssertEqual \ ['foo\bar\baz', 'foo\bar', 'foo'], \ ale#path#Upwards('foo\bar\baz') " simplify() is used internally, and should sort out \ paths when actually " running Windows, which we can't test here. AssertEqual \ ['foo2\bar', 'foo2'], \ ale#path#Upwards('foo//..///foo2////bar') " Expect an empty List for empty strings. AssertEqual [], ale#path#Upwards('') " Paths starting with // return / AssertEqual \ ['/foo2\bar', '/foo2', '/'], \ ale#path#Upwards('//foo//..///foo2////bar') endif ================================================ FILE: test/test_path_uri.vader ================================================ Before: scriptencoding utf-8 Execute(ale#path#ToFileURI should work for Windows paths): AssertEqual 'file:///C:/foo/bar/baz.tst', ale#path#ToFileURI('C:\foo\bar\baz.tst') AssertEqual 'foo/bar/baz.tst', ale#path#ToFileURI('foo\bar\baz.tst') Execute(ale#path#FromFileURI should work for Unix paths): AssertEqual '/foo/bar/baz.tst', ale#path#FromFileURI('file:///foo/bar/baz.tst') AssertEqual '/foo/bar/baz.tst', ale#path#FromFileURI('file:/foo/bar/baz.tst') AssertEqual '/foo/bar/baz.tst', ale#path#FromFileURI('FILE:///foo/bar/baz.tst') AssertEqual '/foo/bar/baz.tst', ale#path#FromFileURI('FILE:/foo/bar/baz.tst') Execute(ale#path#FromFileURI should work for Windows paths): if has('win32') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('file:///C:/foo/bar/baz.tst') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('file:/C:/foo/bar/baz.tst') AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromFileURI('file:///c:/foo/bar/baz.tst') AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromFileURI('file:/c:/foo/bar/baz.tst') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('FILE:///C:/foo/bar/baz.tst') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('FILE:/C:/foo/bar/baz.tst') else AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromFileURI('file:///C:/foo/bar/baz.tst') AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromFileURI('file:/C:/foo/bar/baz.tst') AssertEqual '/c:/foo/bar/baz.tst', ale#path#FromFileURI('file:///c:/foo/bar/baz.tst') AssertEqual '/c:/foo/bar/baz.tst', ale#path#FromFileURI('file:/c:/foo/bar/baz.tst') AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromFileURI('FILE:///C:/foo/bar/baz.tst') AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromFileURI('FILE:/C:/foo/bar/baz.tst') endif Execute(ale#path#FromFileURI parse Windows paths with a pipe): if has('win32') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('file:///C|/foo/bar/baz.tst') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('file:/C|/foo/bar/baz.tst') AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromFileURI('file:///c|/foo/bar/baz.tst') AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromFileURI('file:/c|/foo/bar/baz.tst') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('FILE:///C|/foo/bar/baz.tst') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('FILE:/C|/foo/bar/baz.tst') else AssertEqual '/C|/foo/bar/baz.tst', ale#path#FromFileURI('file:///C|/foo/bar/baz.tst') AssertEqual '/C|/foo/bar/baz.tst', ale#path#FromFileURI('file:/C|/foo/bar/baz.tst') AssertEqual '/c|/foo/bar/baz.tst', ale#path#FromFileURI('file:///c|/foo/bar/baz.tst') AssertEqual '/c|/foo/bar/baz.tst', ale#path#FromFileURI('file:/c|/foo/bar/baz.tst') AssertEqual '/C|/foo/bar/baz.tst', ale#path#FromFileURI('FILE:///C|/foo/bar/baz.tst') AssertEqual '/C|/foo/bar/baz.tst', ale#path#FromFileURI('FILE:/C|/foo/bar/baz.tst') endif Execute(ale#path#FromFileURI should handle the colon for the drive letter being encoded): " These URIs shouldn't be created, but we'll handle them anyway. if has('win32') AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromFileURI('file:///C%3A/foo/bar/baz.tst') else AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromFileURI('file:///C%3A/foo/bar/baz.tst') endif Execute(ale#path#ToFileURI should work for Unix paths): AssertEqual 'file:///foo/bar/baz.tst', ale#path#ToFileURI('/foo/bar/baz.tst') AssertEqual 'foo/bar/baz.tst', ale#path#ToFileURI('foo/bar/baz.tst') Execute(ale#path#ToFileURI should keep safe characters): AssertEqual '//a-zA-Z0-9$-_.!*''(),', ale#path#ToFileURI('\/a-zA-Z0-9$-_.!*''(),') Execute(ale#path#ToFileURI should percent encode unsafe characters): AssertEqual '%20%2b%3a%3f%26%3d', ale#path#ToFileURI(' +:?&=') Execute(ale#path#FromFileURI should decode percent encodings): AssertEqual ' +:?&=', ale#path#FromFileURI('%20%2b%3a%3f%26%3d') Execute(ale#path#ToFileURI should handle UTF-8): AssertEqual 'file:///T%c3%a9l%c3%a9chargement', ale#path#ToFileURI('/Téléchargement') Execute(ale#path#FromFileURI should handle UTF-8): AssertEqual '/Téléchargement', ale#path#FromFileURI('file:///T%C3%A9l%C3%A9chargement') ================================================ FILE: test/test_pattern_options.vader ================================================ Before: Save g:ale_pattern_options Save g:ale_pattern_options_enabled Save b:ale_quitting Save b:ale_original_filetype Save &filetype unlet! b:ale_file_changed let g:ale_pattern_options_enabled = 1 let g:ale_pattern_options = {} let b:ale_enabled = 0 let b:some_option = 0 call ale#test#SetDirectory('/testplugin/test') After: Restore unlet! b:ale_enabled unlet! b:some_option call ale#test#RestoreDirectory() Execute(The pattern options function should work when there are no patterns): call ale#test#SetFilename('foobar.js') call ale#events#ReadOrEnterEvent(bufnr('')) Execute(Buffer variables should be set when filename patterns match): let g:ale_pattern_options = { \ 'baz.*\.js': { \ 'ale_enabled': 1, \ 'some_option': 347, \ '&filetype': 'pattern_option_set_filetype', \ }, \} call ale#test#SetFilename('foobar.js') call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 0, b:ale_enabled AssertEqual 0, b:some_option call ale#test#SetFilename('bazboz.js') call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 1, b:ale_enabled AssertEqual 347, b:some_option AssertEqual 'pattern_option_set_filetype', &filetype Execute(Multiple pattern matches should be applied): let g:ale_pattern_options = { \ 'foo': { \ 'some_option': 666, \ }, \ 'bar': { \ 'ale_enabled': 1, \ 'some_option': 123, \ }, \ 'notmatched': { \ 'some_option': 489, \ 'ale_enabled': 0, \ }, \} call ale#test#SetFilename('foobar.js') call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 1, b:ale_enabled AssertEqual 666, b:some_option Execute(Patterns should not be applied when the setting is disabled): let g:ale_pattern_options_enabled = 0 let g:ale_pattern_options = {'foo': {'some_option': 666}} call ale#test#SetFilename('foobar.js') call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 0, b:some_option " This test is important for making sure we update the sorted items. Execute(Patterns should be applied after the Dictionary changes): call ale#test#SetFilename('foobar.js') let g:ale_pattern_options = {} call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 0, b:some_option let g:ale_pattern_options['foo'] = {'some_option': 666} call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 666, b:some_option Execute(SetOptions should tolerate settings being unset): " This might happen if ALE is loaded in a weird way, so tolerate it. unlet! g:ale_pattern_options unlet! g:ale_pattern_options_enabled call ale#events#ReadOrEnterEvent(bufnr('')) let g:ale_pattern_options_enabled = 1 call ale#events#ReadOrEnterEvent(bufnr('')) ================================================ FILE: test/test_prepare_command.vader ================================================ Before: Save &shell Save &shellcmdflag Save g:ale_shell Save g:ale_shell_arguments Save b:ale_shell Save b:ale_shell_arguments unlet! b:ale_shell unlet! b:ale_shell_arguments unlet! g:ale_shell unlet! g:ale_shell_arguments After: Restore Execute(sh should be used when the shell is fish): if !has('win32') " Set something else, so we will replace that too. let &shellcmdflag = '-f' let &shell = 'fish' AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') let &shell = '/usr/bin/fish' AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') let &shell = '/usr/local/bin/fish' AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') endif Execute(sh should be used when the shell is powershell): if !has('win32') " Set something else, so we will replace that too. let &shellcmdflag = '-f' let &shell = 'pwsh' AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') let &shell = '/usr/bin/pwsh' AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') let &shell = '/usr/local/bin/pwsh' AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') endif Execute(Other shells should be used when set): if !has('win32') let &shell = '/bin/bash' let &shellcmdflag = '-c' let g:ale_shell = &shell AssertEqual ['/bin/bash', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') endif Execute(cmd /s/c as a string should be used on Windows): if has('win32') let &shell = 'who cares' let &shellcmdflag = 'whatever' AssertEqual 'cmd /s/c "foobar"', ale#job#PrepareCommand(bufnr(''), 'foobar') endif Execute(Setting g:ale_shell should cause ale#job#PrepareCommand to use set shell): let g:ale_shell = '/foo/bar' if has('win32') AssertEqual ['/foo/bar', '/c', 'foobar'], ale#job#PrepareCommand(bufnr(''), "foobar") else AssertEqual ['/foo/bar', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), "foobar") endif let g:ale_shell_arguments = '-x' AssertEqual ['/foo/bar', '-x', 'foobar'], ale#job#PrepareCommand(bufnr(''), "foobar") Execute(Setting b:ale_shell should cause ale#job#PrepareCommand to use set shell): let g:ale_shell = '/wrong/foo/bar' let b:ale_shell = '/foo/bar' if has('win32') AssertEqual ['/foo/bar', '/c', 'foobar'], ale#job#PrepareCommand(bufnr(''), "foobar") else AssertEqual ['/foo/bar', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), "foobar") endif let g:ale_shell_arguments = '--verbose -x' let b:ale_shell_arguments = '-x' AssertEqual ['/foo/bar', '-x', 'foobar'], ale#job#PrepareCommand(bufnr(''), "foobar") ================================================ FILE: test/test_proselint_get_command.vader ================================================ Before: runtime autoload/ale/proselint.vim let b:ale_proselint_executable = 'proselint' After: unlet! b:ale_proselint_executable Execute(Command for proselint >= 0.16.0 should use 'check'): AssertEqual \ ale#Escape('proselint') . ' check %t', \ ale#proselint#GetCommand(bufnr(''), [0, 16, 0]) AssertEqual \ ale#Escape('proselint') . ' check %t', \ ale#proselint#GetCommand(bufnr(''), [0, 17, 0]) Execute(Command for proselint < 0.16.0 should use standard arguments): AssertEqual \ ale#Escape('proselint') . ' %t', \ ale#proselint#GetCommand(bufnr(''), [0, 15, 0]) Execute(Command should respect custom executable path): let b:ale_proselint_executable = '/custom/path/to/proselint' AssertEqual \ ale#Escape('/custom/path/to/proselint') . ' check %t', \ ale#proselint#GetCommand(bufnr(''), [0, 16, 0]) ================================================ FILE: test/test_proselint_get_executable.vader ================================================ Before: Save g:ale_proselint_executable runtime autoload/ale/proselint.vim After: Restore Execute(Default executable should be detected correctly): AssertEqual \ 'proselint', \ ale#proselint#GetExecutable(bufnr('')) Execute(User specified executable should override default): let g:ale_proselint_executable = '/path/to/proselint-bin' AssertEqual \ '/path/to/proselint-bin', \ ale#proselint#GetExecutable(bufnr('')) ================================================ FILE: test/test_python_pipenv.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(ale#python#PipenvPresent is true when a pipenv environment is present): call ale#test#SetFilename('test-files/python/pipenv/whatever.py') AssertEqual \ ale#python#PipenvPresent(bufnr('%')), \ 1 Execute(ale#python#PipenvPresent is false when no pipenv environment is present): call ale#test#SetFilename('test-files/python/no_pipenv/whatever.py') AssertEqual \ ale#python#PipenvPresent(bufnr('%')), \ 0 ================================================ FILE: test/test_python_poetry.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(ale#python#poetryPresent is true when a poetry environment is present): call ale#test#SetFilename('test-files/python/poetry/whatever.py') AssertEqual \ ale#python#PoetryPresent(bufnr('%')), \ 1 Execute(ale#python#poetryPresent is false when no poetry environment is present): call ale#test#SetFilename('test-files/python/no_poetry/whatever.py') AssertEqual \ ale#python#PoetryPresent(bufnr('%')), \ 0 ================================================ FILE: test/test_python_traceback.vader ================================================ Execute(ale#python#HandleTraceback returns empty List for empty lines): AssertEqual \ [], \ ale#python#HandleTraceback([], 10) Execute(ale#python#HandleTraceback returns traceback, when present): AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'Exception: Example error (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "./example.py", line 5, in ', \ ' raise Exception(''Example message'')', \ 'Exception: Example error', \ ], "\n"), \ }], \ ale#python#HandleTraceback([ \ 'Traceback (most recent call last):', \ ' File "./example.py", line 5, in ', \ ' raise Exception(''Example message'')', \ 'Exception: Example error', \ ], 1) " SyntaxError has extra output lines about the source Execute(ale#python#HandleTraceback returns SyntaxError traceback): AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'SyntaxError: invalid syntax (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "", line 1, in ', \ ' File "example.py", line 5', \ ' +', \ ' ^', \ 'SyntaxError: invalid syntax', \ ], "\n"), \ }], \ ale#python#HandleTraceback([ \ 'Traceback (most recent call last):', \ ' File "", line 1, in ', \ ' File "example.py", line 5', \ ' +', \ ' ^', \ 'SyntaxError: invalid syntax', \ ], 1) Execute(ale#python#HandleTraceback ignores traceback after line limit): AssertEqual \ [], \ ale#python#HandleTraceback([ \ '', \ 'Traceback (most recent call last):', \ ' File "./example.py", line 5, in ', \ ' raise Exception(''Example message'')', \ 'Exception: Example error', \ ], 1) Execute(ale#python#HandleTraceback doesn't include later lines in detail): AssertEqual \ [{ \ 'lnum': 1, \ 'text': 'Exception: Example error (See :ALEDetail)', \ 'detail': join([ \ 'Traceback (most recent call last):', \ ' File "./example.py", line 5, in ', \ ' raise Exception(''Example message'')', \ 'Exception: Example error', \ ], "\n"), \ }], \ ale#python#HandleTraceback([ \ 'Traceback (most recent call last):', \ ' File "./example.py", line 5, in ', \ ' raise Exception(''Example message'')', \ 'Exception: Example error', \ 'file:1:2: Style issue', \ 'file:3:4: Non-style issue', \ ], 1) ================================================ FILE: test/test_python_uv.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(ale#python#UvPresent is true when a uv environment is present): call ale#test#SetFilename('test-files/python/uv/whatever.py') AssertEqual \ ale#python#UvPresent(bufnr('%')), \ 1 Execute(ale#python#UvPresent is false when no uv environment is present): call ale#test#SetFilename('test-files/python/no_uv/whatever.py') AssertEqual \ ale#python#UvPresent(bufnr('%')), \ 0 ================================================ FILE: test/test_python_virtualenv.vader ================================================ Before: Save $VIRTUAL_ENV let $VIRTUAL_ENV = "/opt/example/" After: Restore Execute(ale#python#FindVirtualenv falls back to $VIRTUAL_ENV when no directories match): AssertEqual \ ale#python#FindVirtualenv(bufnr('%')), \ '/opt/example/', \ 'Expected VIRTUAL_ENV environment variable to be used, but it was not' Execute(ale#python#AutoVirtualenvEnvString should return the correct values): if has('win32') AssertEqual \ 'set PATH=/opt/example/\Scripts;%PATH% && set VIRTUAL_ENV=/opt/example/ && ', \ ale#python#AutoVirtualenvEnvString(bufnr('')) else AssertEqual \ 'PATH=''/opt/example//bin''":$PATH" VIRTUAL_ENV=''/opt/example/'' ', \ ale#python#AutoVirtualenvEnvString(bufnr('')) endif ================================================ FILE: test/test_quickfix_deduplication.vader ================================================ Before: Save g:ale_buffer_info After: Restore Execute: " Results from multiple buffers should be gathered together. " Equal problems should be de-duplicated. let g:ale_buffer_info = { \ '1': {'loclist': [ \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, \ {'type': 'E', 'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'foo'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': 3, 'lnum': 1, 'col': 1, 'text': 'foo'}, \ ]}, \ '2': {'loclist': [ \ {'type': 'E', 'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'another error'}, \ ]}, \} AssertEqual \ [ \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'another error'}, \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'foo'}, \ {'type': 'E', 'bufnr': 3, 'lnum': 1, 'col': 1, 'text': 'foo'}, \ ], \ ale#list#GetCombinedList() ================================================ FILE: test/test_quitting_variable.vader ================================================ Before: Save g:ale_enabled unlet! b:ale_quitting let g:ale_enabled = 0 After: Restore unlet! b:ale_quitting unlet! b:time_before Execute(QuitEvent should set b:ale_quitting some time from the clock): let b:time_before = ale#events#ClockMilliseconds() call ale#events#QuitEvent(bufnr('')) Assert b:ale_quitting >= b:time_before Assert b:ale_quitting <= ale#events#ClockMilliseconds() Execute(ReadOrEnterEvent should set b:ale_quitting to 0): let b:ale_quitting = 1 call ale#events#ReadOrEnterEvent(bufnr('')) AssertEqual 0, b:ale_quitting Execute(The QuitRecently function should work when the variable isn't set): AssertEqual 0, ale#events#QuitRecently(bufnr('')) Execute(The QuitRecently function should return 1 when ALE quit recently): let b:ale_quitting = ale#events#ClockMilliseconds() AssertEqual 1, ale#events#QuitRecently(bufnr('')) Execute(The QuitRecently function should return 0 when a second has passed): let b:ale_quitting = ale#events#ClockMilliseconds() - 1001 AssertEqual 0, ale#events#QuitRecently(bufnr('')) ================================================ FILE: test/test_redundant_tsserver_rendering_avoided.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_disable_lsp Save g:ale_lsp_suggestions let g:ale_disable_lsp = 0 let g:ale_lsp_suggestions = 1 unlet! b:ale_disable_lsp 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': [], 'active_linter_list': []}} 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 - semantic): 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 Execute(Subsequent empty lists should be ignored - suggestion): let g:ale_buffer_info[bufnr('')].suggestion_loclist = [] call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', '')) Assert !g:ale_handle_loclist_called Execute(You should be able to disable suggestions): let g:ale_lsp_suggestions = 0 let g:ale_buffer_info[bufnr('')].suggestion_loclist = [] call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', 'x')) Assert !g:ale_handle_loclist_called Execute(Empty then non-empty suggestion messages should be handled): let g:ale_buffer_info[bufnr('')].suggestion_loclist = [] call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', 'x')) Assert g:ale_handle_loclist_called Execute(Non-empty then empt suggestion messages should be handled): let g:ale_buffer_info[bufnr('')].suggestion_loclist = CreateLoclist('x') call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', '')) Assert g:ale_handle_loclist_called Execute(Non-empty then non-empty suggestion messages should be handled): let g:ale_buffer_info[bufnr('')].suggestion_loclist = CreateLoclist('x') call ale#lsp_linter#HandleLSPResponse(1, CreateError('suggestionDiag', 'x')) Assert g:ale_handle_loclist_called ================================================ FILE: test/test_regex_escaping.vader ================================================ Execute(ale#util#EscapePCRE should escape strings for PCRE or RE2 appropriately): AssertEqual '\\\^\$\*\+\?\.\(\)\|\{\}\[\]', ale#util#EscapePCRE('\^$*+?.()|{}[]') AssertEqual 'abcABC09', ale#util#EscapePCRE('abcABC09') AssertEqual '/', ale#util#EscapePCRE('/') ================================================ FILE: test/test_rename.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') call ale#test#SetFilename('dummy.txt') let g:old_filename = expand('%:p') let g:Callback = '' let g:expr_list = [] let g:message_list = [] let g:handle_code_action_called = 0 let g:code_actions = [] let g:options = {} let g:capability_checked = '' let g:conn_id = v:null let g:InitCallback = v:null runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/rename.vim runtime autoload/ale/code_action.vim function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) if a:linter.lsp is# 'tsserver' call ale#lsp#MarkConnectionAsTsserver(g:conn_id) endif let l:details = { \ 'command': 'foobar', \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \} let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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#code_action#HandleCodeAction(code_action, options) abort let g:handle_code_action_called = 1 AssertEqual g:ale_save_hidden || !&hidden, get(a:options, 'should_save', 0) call add(g:code_actions, a:code_action) endfunction function! ale#util#Input(message, value) abort return 'a-new-name' endfunction call ale#rename#SetMap({ \ 3: { \ 'old_name': 'oldName', \ 'new_name': 'aNewName', \ }, \}) After: if g:conn_id isnot v:null call ale#lsp#RemoveConnectionWithID(g:conn_id) endif call ale#rename#SetMap({}) call ale#test#RestoreDirectory() call ale#linter#Reset() unlet! g:capability_checked unlet! g:InitCallback unlet! g:old_filename unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters unlet! g:options unlet! g:code_actions unlet! g:handle_code_action_called runtime autoload/ale/lsp_linter.vim runtime autoload/ale/lsp.vim runtime autoload/ale/util.vim runtime autoload/ale/rename.vim runtime autoload/ale/code_action.vim Execute(Other messages for the tsserver handler should be ignored): call ale#rename#HandleTSServerResponse(1, {'command': 'foo'}) AssertEqual g:handle_code_action_called, 0 Execute(Failed rename responses should be handled correctly): call ale#rename#SetMap({3: {'old_name': 'oldName', 'new_name': 'a-test'}}) call ale#rename#HandleTSServerResponse( \ 1, \ {'command': 'rename', 'request_seq': 3} \) AssertEqual g:handle_code_action_called, 0 Given typescript(Some typescript file): foo somelongerline bazxyzxyzxyz Execute(Code actions from tsserver should be handled): call ale#rename#HandleTSServerResponse(1, { \ 'command': 'rename', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'locs': [ \ { \ 'file': '/foo/bar/file1.ts', \ 'locs': [ \ { \ 'start': { \ 'line': 1, \ 'offset': 2, \ }, \ 'end': { \ 'line': 3, \ 'offset': 4, \ }, \ }, \ ], \ }, \ { \ 'file': '/foo/bar/file2.ts', \ 'locs': [ \ { \ 'start': { \ 'line': 10, \ 'offset': 20, \ }, \ 'end': { \ 'line': 30, \ 'offset': 40, \ }, \ }, \ ], \ }, \ ] \ }, \}) AssertEqual \ [ \ { \ 'description': 'rename', \ 'changes': [ \ { \ 'fileName': '/foo/bar/file1.ts', \ 'textChanges': [ \ { \ 'start': { \ 'line': 1, \ 'offset': 2, \ }, \ 'end': { \ 'line': 3, \ 'offset': 4, \ }, \ 'newText': 'aNewName', \ }, \ ], \ }, \ { \ 'fileName': '/foo/bar/file2.ts', \ 'textChanges': [ \ { \ 'start': { \ 'line': 10, \ 'offset': 20, \ }, \ 'end': { \ 'line': 30, \ 'offset': 40, \ }, \ 'newText': 'aNewName', \ }, \ ], \ }, \ ], \ } \ ], \ g:code_actions Execute(Prints a tsserver error message when unsuccessful): call ale#rename#HandleTSServerResponse(1, { \ 'command': 'rename', \ 'request_seq': 3, \ 'success': v:false, \ 'message': 'This symbol cannot be renamed', \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''Error renaming "oldName" to: "aNewName". ' . \ 'Reason: This symbol cannot be renamed'''], g:expr_list Execute(HandleTSServerResponse does nothing when no changes): call ale#rename#HandleTSServerResponse(1, { \ 'command': 'rename', \ 'request_seq': 3, \ 'success': v:true, \ 'body': { \ 'locs': [] \ } \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''Error renaming "oldName" to: "aNewName"'''], g:expr_list Execute(tsserver rename requests should be sent): call ale#rename#SetMap({}) call ale#linter#Reset() runtime ale_linters/typescript/tsserver.vim call setpos('.', [bufnr(''), 2, 5, 0]) ALERename " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'rename', g:capability_checked AssertEqual \ 'function(''ale#rename#HandleTSServerResponse'')', \ string(g:Callback) AssertEqual \ [ \ ale#lsp#tsserver_message#Change(bufnr('')), \ [0, 'ts@rename', { \ 'file': expand('%:p'), \ 'line': 2, \ 'offset': 5, \ 'arguments': { \ 'findInComments': g:ale_rename_tsserver_find_in_comments, \ 'findInStrings': g:ale_rename_tsserver_find_in_strings, \ }, \ }] \ ], \ g:message_list AssertEqual {'42': {'old_name': 'somelongerline', 'new_name': 'a-new-name'}}, \ ale#rename#GetMap() Given python(Some Python file): foo somelongerline bazxyzxyzxyz Execute(Code actions from LSP should be handled): call ale#rename#HandleLSPResponse(1, { \ 'id': 3, \ 'result': { \ 'changes': { \ 'file:///foo/bar/file1.ts': [ \ { \ 'range': { \ 'start': { \ 'line': 1, \ 'character': 2, \ }, \ 'end': { \ 'line': 3, \ 'character': 4, \ }, \ }, \ 'newText': 'bla123' \ }, \ ], \ }, \ }, \}) AssertEqual \ [ \ { \ 'description': 'rename', \ 'changes': [ \ { \ 'fileName': '/foo/bar/file1.ts', \ 'textChanges': [ \ { \ 'start': { \ 'line': 2, \ 'offset': 3, \ }, \ 'end': { \ 'line': 4, \ 'offset': 5, \ }, \ 'newText': 'bla123', \ }, \ ], \ }, \ ], \ } \ ], \ g:code_actions Execute(DocumentChanges from LSP should be handled): call ale#rename#HandleLSPResponse(1, { \ 'id': 3, \ 'result': { \ 'documentChanges': [ \ { \ 'textDocument': { \ 'version': 1.0, \ 'uri': 'file:///foo/bar/file1.ts', \ }, \ 'edits': [ \ { \ 'range': { \ 'start': { \ 'line': 1, \ 'character': 2, \ }, \ 'end': { \ 'line': 3, \ 'character': 4, \ }, \ }, \ 'newText': 'bla123', \ }, \ ], \ }, \ ], \ }, \}) AssertEqual \ [ \ { \ 'description': 'rename', \ 'changes': [ \ { \ 'fileName': '/foo/bar/file1.ts', \ 'textChanges': [ \ { \ 'start': { \ 'line': 2, \ 'offset': 3, \ }, \ 'end': { \ 'line': 4, \ 'offset': 5, \ }, \ 'newText': 'bla123', \ }, \ ], \ }, \ ], \ } \ ], \ g:code_actions Execute(Single DocumentChange from LSP should be handled): call ale#rename#HandleLSPResponse(1, { \ 'id': 3, \ 'result': { \ 'documentChanges': { \ 'textDocument': { \ 'version': 1.0, \ 'uri': 'file:///foo/bar/file1.ts', \ }, \ 'edits': [ \ { \ 'range': { \ 'start': { \ 'line': 1, \ 'character': 2, \ }, \ 'end': { \ 'line': 3, \ 'character': 4, \ }, \ }, \ 'newText': 'bla123', \ }, \ ], \ }, \ }, \}) AssertEqual \ [ \ { \ 'description': 'rename', \ 'changes': [ \ { \ 'fileName': '/foo/bar/file1.ts', \ 'textChanges': [ \ { \ 'start': { \ 'line': 2, \ 'offset': 3, \ }, \ 'end': { \ 'line': 4, \ 'offset': 5, \ }, \ 'newText': 'bla123', \ }, \ ], \ }, \ ], \ } \ ], \ g:code_actions Execute(LSP should perform no action when no result): call ale#rename#HandleLSPResponse(1, { \ 'id': 3, \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''No rename result received from server'''], g:expr_list Execute(LSP should perform no action when no changes): call ale#rename#HandleLSPResponse(1, { \ 'id': 3, \ 'result': {}, \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''No changes received from server'''], g:expr_list Execute(LSP should perform no action when changes is empty): call ale#rename#HandleLSPResponse(1, { \ 'id': 3, \ 'result': { \ 'changes': [], \ }, \}) AssertEqual g:handle_code_action_called, 0 AssertEqual ['echom ''No changes received from server'''], g:expr_list Execute(LSP rename requests should be sent): call ale#rename#SetMap({}) runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALERename " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'rename', g:capability_checked AssertEqual \ 'function(''ale#rename#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [1, 'textDocument/didChange', { \ 'textDocument': { \ 'uri': ale#path#ToFileURI(expand('%:p')), \ 'version': g:ale_lsp_next_version_id - 1, \ }, \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] \ }], \ [0, 'textDocument/rename', { \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, \ 'position': {'line': 0, 'character': 2}, \ 'newName': 'a-new-name', \ }], \ ], \ g:message_list AssertEqual {'42': {'old_name': 'foo', 'new_name': 'a-new-name'}}, \ ale#rename#GetMap() ================================================ FILE: test/test_resolve_local_path.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(We should be able to find the local version of a file): call ale#test#SetFilename('test-files/top/middle/bottom/dummy.txt') AssertEqual \ ale#path#Simplify(expand('%:p:h:h:h:h:h') . '/test-files/top/example.ini'), \ ale#path#ResolveLocalPath(bufnr('%'), 'example.ini', '/global/config.ini') Execute(We shouldn't find anything for files which don't match): AssertEqual \ '/global/config.ini', \ ale#path#ResolveLocalPath(bufnr('%'), 'missing.ini', '/global/config.ini') ================================================ FILE: test/test_results_not_cleared_when_opening_loclist.vader ================================================ Before: Save g:ale_buffer_info call ale#linter#Reset() After: Restore call setloclist(0, []) call clearmatches() call ale#sign#Clear() Given foobar (Some file): abc Execute(The loclist shouldn't be cleared when opening the loclist): call ale#engine#InitBufferInfo(bufnr('')) let g:ale_buffer_info[bufnr('')].loclist = [ \ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2}, \] call setloclist(0, g:ale_buffer_info[bufnr('')].loclist) " The cleanup function is called when the loclist window is closed. " If some cleanup is done for this buffer, for which nothing is wrong, " then the loclist for the window, which is the same window as the window " we are checking, will be cleared. :lopen :q AssertEqual 1, len(ale#test#GetLoclistWithoutNewerKeys()), 'The loclist was cleared' ================================================ FILE: test/test_sandbox_execution.vader ================================================ Before: function! TestCallback(buffer, output) return [ \ { \ 'lnum': 1, \ 'bufnr': 1, \ 'vcol': 0, \ 'linter_name': 'testlinter', \ 'nr': -1, \ 'type': 'E', \ 'col': 1, \ 'text': 'Test Error', \ }, \] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'callback': 'TestCallback', \ 'executable': 'echo', \ 'command': 'echo', \}) let g:ale_buffer_info = {} After: unlet! b:in_sandbox unlet! b:result delfunction TestCallback call ale#linter#Reset() let g:ale_buffer_info = {} Given foobar (Some imaginary filetype): foo bar baz Execute(ale#util#InSandbox should return 1 when in a sandbox): sandbox let b:in_sandbox = ale#util#InSandbox() Assert b:in_sandbox, 'ale#util#InSandbox() returned 0 for a sandbox command' Execute(ALE shouldn't blow up when run from a sandbox): AssertEqual 'foobar', &filetype sandbox call ale#Queue(0) sandbox call ale#Queue(1) 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 " before we make the sandbox call. " " You are not allowed to define any functions in the sandbox. call ale#engine#InitBufferInfo(3) let g:ale_buffer_info[3] = { \ 'temporary_file_list': ['/tmp/foo'], \ 'temporary_directory_list': ['/tmp/bar'], \} sandbox call ale#command#RemoveManagedFiles(3) AssertEqual ['/tmp/foo'], g:ale_buffer_info[3].temporary_file_list AssertEqual ['/tmp/bar'], g:ale_buffer_info[3].temporary_directory_list Execute(You shouldn't be able to define linters from the sandbox): call ale#linter#Reset() call ale#linter#PreventLoading('testft') AssertThrows sandbox call ale#linter#Define('testft', { \ 'name': 'testlinter', \ 'output_stream': 'stdout', \ 'executable': 'testlinter', \ 'command': 'testlinter', \ 'callback': 'testCB', \}) AssertEqual 'Vim(let):E48: Not allowed in sandbox', g:vader_exception AssertEqual [], ale#linter#GetAll(['testft']) Execute(You shouldn't be able to register fixers from the sandbox): call ale#fix#registry#Clear() AssertThrows sandbox call ale#fix#registry#Add('prettier', '', ['javascript'], 'prettier') AssertEqual 'Vim(let):E48: Not allowed in sandbox', g:vader_exception AssertEqual [], ale#fix#registry#CompleteFixers('', 'ALEFix ', 7) Execute(You shouldn't be able to get linters from the sandbox, to prevent tampering): AssertThrows sandbox call ale#linter#GetLintersLoaded() AssertEqual 'Vim(let):E48: Not allowed in sandbox', g:vader_exception call ale#linter#Reset() sandbox let b:result = ale#linter#GetAll(['testft']) AssertEqual 0, len(b:result) let b:result = ale#linter#GetAll(['testft']) AssertEqual 1, len(b:result) sandbox let b:result = ale#linter#GetAll(['testft']) AssertEqual 0, len(b:result) ================================================ FILE: test/test_semver_utils.vader ================================================ After: call ale#semver#ResetVersionCache() Execute(ParseVersion should return the version from the lines of output): " We should be able to parse the semver string from flake8 AssertEqual [3, 0, 4], ale#semver#ParseVersion([ \ '3.0.4 (mccabe: 0.5.2, pyflakes: 1.2.3, pycodestyle: 2.0.0) CPython 2.7.12 on Linux', \ '1.2.3', \]) Execute(ParseVersion should return an empty list when no version can be found): AssertEqual [], ale#semver#ParseVersion(['x']) AssertEqual [], ale#semver#ParseVersion([]) Execute(ParseVersion should tolerate missing patch numbers): " This goes against the semver spec, but we handle it anyway. AssertEqual [3, 4, 0], ale#semver#ParseVersion(['Version 3.4']) Execute(GTE should compare triples correctly): Assert ale#semver#GTE([3, 0, 0], [2, 0, 0]) Assert ale#semver#GTE([3, 1, 0], [3, 1, 0]) Assert ale#semver#GTE([3, 2, 0], [3, 1, 0]) Assert ale#semver#GTE([3, 2, 2], [3, 1, 6]) Assert ale#semver#GTE([3, 2, 5], [3, 2, 5]) Assert ale#semver#GTE([3, 2, 6], [3, 2, 5]) Assert !ale#semver#GTE([2, 9, 1], [3, 0, 0]) Assert !ale#semver#GTE([3, 2, 3], [3, 3, 3]) Assert !ale#semver#GTE([3, 3, 2], [3, 3, 3]) Execute(GTE should compare pairs correctly): Assert ale#semver#GTE([3, 0], [3, 0, 0]) Assert ale#semver#GTE([3, 0], [3, 0]) Assert ale#semver#GTE([3, 1], [3, 0]) Assert ale#semver#GTE([3, 1], [3, 0, 0]) Assert ale#semver#GTE([3, 0, 1], [3, 0]) Assert !ale#semver#GTE([3, 0], [3, 0, 1]) Assert !ale#semver#GTE([3, 0], [3, 1]) Assert !ale#semver#GTE([2, 9, 11], [3, 0]) Execute(GTE should permit the LHS to be an empty List): Assert !ale#semver#GTE([], [0, 0, 0]) ================================================ FILE: test/test_set_list_timers.vader ================================================ Before: Save g:ale_set_lists_synchronously Save g:ale_open_list let g:ale_set_lists_synchronously = 0 After: Restore sleep 1ms call setloclist(0, []) lclose Execute(The SetLists function should work when run in a timer): call ale#list#SetLists(bufnr(''), [ \ {'bufnr': bufnr(''), 'lnum': 5, 'col': 5, 'text': 'x', 'type': 'E'}, \]) sleep 1ms AssertEqual [{ \ 'lnum': 5, \ 'bufnr': bufnr(''), \ 'col': 5, \ 'text': 'x', \ 'valid': 1, \ 'vcol': 0, \ 'nr': 0, \ 'type': 'E', \ 'pattern': '', \}], ale#test#GetLoclistWithoutNewerKeys() ================================================ FILE: test/test_setting_loclist_from_another_buffer.vader ================================================ Before: Save g:ale_buffer_info let g:ale_buffer_info = { \ bufnr(''): { \ 'loclist': [{'bufnr': bufnr(''), 'lnum': 4, 'col': 1, 'text': 'foo'}] \ }, \} let g:original_buffer = bufnr('%') noautocmd new After: Restore unlet! g:original_buffer Execute(Errors should be set in the loclist for the original buffer, not the new one): call ale#list#SetLists( \ g:original_buffer, \ g:ale_buffer_info[(g:original_buffer)].loclist, \ ) AssertEqual [], ale#test#GetLoclistWithoutNewerKeys() AssertEqual 1, len(getloclist(bufwinid(g:original_buffer))) AssertEqual 'foo', getloclist(bufwinid(g:original_buffer))[0].text ================================================ FILE: test/test_setting_problems_found_in_previous_buffers.vader ================================================ Before: Save g:ale_buffer_info Save &filetype Save g:ale_set_lists_synchronously let g:ale_set_lists_synchronously = 1 " Set up items in other buffers which should set in this one. 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', 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', 0, [ \ {'lnum': 1, 'filename': expand('%:p'), 'text': 'foo'}, \ {'lnum': 3, 'filename': expand('%:p'), 'text': 'baz'}, \ {'lnum': 5, 'text': 'ignore this one'}, \ ]) call ale#linter#Define('foobar', { \ 'name': 'linter_one', \ 'callback': 'WhoCares', \ 'executable': 'echo', \ 'command': 'sleep 1000', \ 'lint_file': 1, \}) After: call ale#engine#Cleanup(bufnr('')) Restore call ale#linter#Reset() " Items and markers, etc. call setloclist(0, []) call clearmatches() call ale#sign#Clear() Given foobar(A file with some lines): foo bar baz Execute(Problems found from previously opened buffers should be set when linting for the first time): call ale#engine#RunLinters(bufnr(''), ale#linter#Get(&filetype), 0) AssertEqual \ [ \ { \ 'lnum': 1, \ 'bufnr': bufnr(''), \ 'col': 0, \ 'filename': expand('%:p'), \ 'linter_name': 'linter_one', \ 'nr': -1, \ 'type': 'E', \ 'vcol': 0, \ 'text': 'foo', \ 'sign_id': 1000001, \ }, \ { \ 'lnum': 2, \ 'bufnr': bufnr(''), \ 'col': 0, \ 'filename': expand('%:p'), \ 'linter_name': 'linter_one', \ 'nr': -1, \ 'type': 'E', \ 'vcol': 0, \ 'text': 'bar', \ 'sign_id': 1000002, \ }, \ { \ 'lnum': 3, \ 'bufnr': bufnr(''), \ 'col': 0, \ 'filename': expand('%:p'), \ 'linter_name': 'linter_one', \ 'nr': -1, \ 'type': 'E', \ 'vcol': 0, \ 'text': 'baz', \ 'sign_id': 1000003, \ }, \ ], \ g:ale_buffer_info[bufnr('')].loclist AssertEqual \ [ \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'E', 'pattern': '', 'text': 'foo'}, \ {'lnum': 2, 'bufnr': bufnr(''), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'E', 'pattern': '', 'text': 'bar'}, \ {'lnum': 3, 'bufnr': bufnr(''), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'E', 'pattern': '', 'text': 'baz'}, \ ], \ ale#test#GetLoclistWithoutNewerKeys() ================================================ FILE: test/test_shell_detection.vader ================================================ Before: runtime ale_linters/sh/shell.vim runtime ale_linters/sh/shellcheck.vim After: call ale#linter#Reset() unlet! b:is_bash unlet! b:is_sh unlet! b:is_kornshell Given(A file with a Bash hashbang): #!/bin/bash Execute(/bin/bash should be detected appropriately): AssertEqual 'bash', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'bash', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'bash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with /bin/sh): #!/usr/bin/env sh -eu --foobar Execute(/bin/sh should be detected appropriately): AssertEqual 'sh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'sh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'sh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with bash as an argument to env): #!/usr/bin/env bash Execute(/usr/bin/env bash should be detected appropriately): AssertEqual 'bash', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'bash', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'bash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a tcsh hash bang and arguments): #!/usr/bin/env tcsh -eu --foobar Execute(tcsh should be detected appropriately): AssertEqual 'tcsh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'tcsh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'tcsh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a zsh hash bang and arguments): #!/usr/bin/env zsh -eu --foobar Execute(zsh should be detected appropriately): AssertEqual 'zsh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'zsh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'zsh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a csh hash bang and arguments): #!/usr/bin/env csh -eu --foobar Execute(csh should be detected appropriately): AssertEqual 'csh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'csh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'csh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a ksh hashbang): #!/bin/ksh Execute(/bin/ksh should be detected appropriately): AssertEqual 'ksh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'ksh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'ksh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a ksh as an argument to env): #!/usr/bin/env ksh Execute(ksh should be detected appropriately): AssertEqual 'ksh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'ksh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'ksh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a sh hash bang and arguments): #!/usr/bin/env sh -eu --foobar Execute(sh should be detected appropriately): AssertEqual 'sh', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'sh', ale_linters#sh#shell#GetExecutable(bufnr('')) AssertEqual 'sh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file without a hashbang): Execute(The bash dialect should be used for shellcheck if b:is_bash is 1): let b:is_bash = 1 AssertEqual 'bash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Execute(The sh dialect should be used for shellcheck if b:is_sh is 1): let b:is_sh = 1 AssertEqual 'sh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Execute(The ksh dialect should be used for shellcheck if b:is_kornshell is 1): let b:is_kornshell = 1 AssertEqual 'ksh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Execute(The filetype should be used as the default shell type when there is no hashbang line): set filetype=zsh AssertEqual 'zsh', ale#handlers#sh#GetShellType(bufnr('')) set filetype=tcsh AssertEqual 'tcsh', ale#handlers#sh#GetShellType(bufnr('')) set filetype=python AssertEqual '', ale#handlers#sh#GetShellType(bufnr('')) Given(A file with /bin/ash): #!/bin/ash Execute(The ash dialect should be used for the shell and the base function): AssertEqual 'ash', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'ash', ale_linters#sh#shell#GetExecutable(bufnr('')) Execute(dash should be used for shellcheck, which has no ash dialect): AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with /bin/dash): #!/bin/dash Execute(The dash dialect should be used for the shell and the base function): AssertEqual 'dash', ale#handlers#sh#GetShellType(bufnr('')) AssertEqual 'dash', ale_linters#sh#shell#GetExecutable(bufnr('')) Execute(dash should be used for shellcheck): AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a Bash shellcheck shell directive): # shellcheck shell=bash Execute(bash dialect should be detected appropriately): AssertEqual 'bash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a sh shellcheck shell directive): #shellcheck shell=sh Execute(sh dialect should be detected appropriately): AssertEqual 'sh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a tcsh shellcheck shell directive): # shellcheck shell=tcsh Execute(tcsh dialect should be detected appropriately): AssertEqual 'tcsh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a zsh shellcheck shell directive): # shellcheck shell=zsh Execute(zsh dialect should be detected appropriately): AssertEqual 'zsh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a csh shellcheck shell directive): # shellcheck shell=csh Execute(zsh dialect should be detected appropriately): AssertEqual 'csh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a ksh shellcheck shell directive): # shellcheck shell=ksh Execute(ksh dialect should be detected appropriately): AssertEqual 'ksh', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a dash shellcheck shell directive): # shellcheck shell=dash Execute(dash dialect should be detected appropriately): AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) Given(A file with a ash shellcheck shell directive): # shellcheck shell=ash Execute(dash dialect should be detected for ash that shellcheck does not support): AssertEqual 'dash', ale#handlers#shellcheck#GetDialectArgument(bufnr('')) ================================================ FILE: test/test_should_do_nothing_conditions.vader ================================================ Before: Save g:ale_filetype_blacklist Save g:ale_maximum_file_size 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 let b:funky_command_created = 1 endif After: Restore call ale#test#RestoreDirectory() if b:funky_command_created delcommand CtrlPFunky let b:funky_command_created = 0 endif unlet! g:ale_lint_diff unlet! b:funky_command_created unlet! b:fake_mode if &diff is 1 let &diff = 0 endif runtime autoload/ale/util.vim Given foobar(An empty file): Execute(ALE shouldn't do much of anything for ctrlp-funky buffers): Assert !ale#ShouldDoNothing(bufnr('')), 'The preliminary check failed' let &l:statusline = '%#CtrlPMode2# prt %*%#CtrlPMode1# line %* ={%#CtrlPMode1# funky %*}= <-> %=%<%#CtrlPMode2# %{getcwd()} %*' Assert ale#ShouldDoNothing(bufnr('')) Execute(ALE shouldn't try to check buffers with '.' as the filename): AssertEqual \ 0, \ ale#ShouldDoNothing(bufnr('')), \ 'ShouldDoNothing() was 1 for some other reason' silent! noautocmd file . Assert ale#ShouldDoNothing(bufnr('')) Execute(DoNothing should return 1 when the filetype is empty): AssertEqual \ 0, \ ale#ShouldDoNothing(bufnr('')), \ 'ShouldDoNothing() was 1 for some other reason' set filetype= 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(DoNothing should return 1 for diff buffers): let &diff = 1 AssertEqual 1, ale#ShouldDoNothing(bufnr('')) Execute(DoNothing should return 0 for diff buffers when ale_lint_diff is set): let &diff = 1 let g:ale_lint_diff = 1 AssertEqual 0, 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 unlet! g:ale_enabled " This shouldn't throw exceptions. call ale#ShouldDoNothing(bufnr('')) ================================================ FILE: test/test_sml_command.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(smlnj finds CM file if it exists): call ale#test#SetFilename('test-files/smlnj/cm/foo.sml') AssertEqual \ ale#test#GetFilename('test-files/smlnj/cm/sources.cm'), \ ale#handlers#sml#GetCmFile(bufnr('%')) Execute(smlnj finds CM file by searching upwards): call ale#test#SetFilename('test-files/smlnj/cm/path/to/bar.sml') AssertEqual \ ale#test#GetFilename('test-files/smlnj/cm/sources.cm'), \ ale#handlers#sml#GetCmFile(bufnr('%')) Execute(smlnj returns '' when no CM file found): call ale#test#SetFilename('test-files/smlnj/file/qux.sml') AssertEqual '', ale#handlers#sml#GetCmFile(bufnr('%')) Execute(CM-project mode enabled when CM file found): call ale#test#SetFilename('test-files/smlnj/cm/foo.sml') AssertEqual 'sml', ale#handlers#sml#GetExecutableSmlnjCm(bufnr('%')) Execute(single-file mode disabled when CM file found): call ale#test#SetFilename('test-files/smlnj/cm/foo.sml') AssertEqual '', ale#handlers#sml#GetExecutableSmlnjFile(bufnr('%')) Execute(CM-project mode disabled when CM file not found): call ale#test#SetFilename('test-files/smlnj/file/qux.sml') AssertEqual '', ale#handlers#sml#GetExecutableSmlnjCm(bufnr('%')) Execute(single-file mode enabled when CM file found): call ale#test#SetFilename('test-files/smlnj/file/qux.sml') AssertEqual 'sml', ale#handlers#sml#GetExecutableSmlnjFile(bufnr('%')) ================================================ FILE: test/test_socket_connections.vader ================================================ Before: let g:can_run_socket_tests = !has('win32') \ && (exists('*ch_close') || exists('*chanclose')) if g:can_run_socket_tests call ale#test#SetDirectory('/testplugin/test') let g:channel_id_received = 0 let g:data_received = '' function! WaitForData(expected_data, timeout) abort let l:ticks = 0 while l:ticks < a:timeout " Sleep first, so we can switch to the callback. let l:ticks += 10 sleep 10ms if g:data_received is# a:expected_data break endif endwhile endfunction function! TestCallback(channel_id, data) abort let g:channel_id_received = a:channel_id let g:data_received .= a:data endfunction let g:port = 10347 let g:pid_tcp = str2nr(system( \ 'python' \ . ' ' . ale#Escape(g:dir . '/script/dumb_tcp_server.py') \ . ' ' . g:port \)) let g:pipe_path = tempname() let g:pid_pipe = str2nr(system( \ 'python' \ . ' ' . ale#Escape(g:dir . '/script/dumb_named_pipe_server.py') \ . ' ' . g:pipe_path \)) endif After: if g:can_run_socket_tests call ale#test#RestoreDirectory() unlet! g:channel_id_received unlet! g:data_received unlet! g:channel_id delfunction WaitForData delfunction TestCallback if has_key(g:, 'pid_tcp') call system('kill ' . g:pid_tcp) endif if has_key(g:, 'pid_pipe') call system('kill ' . g:pid_pipe) endif unlet! g:pid_tcp unlet! g:port unlet! g:pid_pipe unlet! g:pipe_path endif unlet! g:can_run_socket_tests Execute(Sending and receiving connections to tcp sockets should work): if g:can_run_socket_tests let g:channel_id = ale#socket#Open( \ '127.0.0.1:' . g:port, \ {'callback': function('TestCallback')} \) Assert g:channel_id >= 0, 'The socket was not opened!' call ale#socket#Send(g:channel_id, 'hello') call ale#socket#Send(g:channel_id, ' world') AssertEqual 1, ale#socket#IsOpen(g:channel_id) " Wait up to 1 second for the expected data to arrive. call WaitForData('hello world', 1000) AssertEqual g:channel_id, g:channel_id_received AssertEqual 'hello world', g:data_received AssertEqual '127.0.0.1:' . g:port, ale#socket#GetAddress(g:channel_id) call ale#socket#Close(g:channel_id) AssertEqual 0, ale#socket#IsOpen(g:channel_id) AssertEqual '', ale#socket#GetAddress(g:channel_id) endif " NeoVim versions which can't connect to sockets should just fail. if has('nvim') && !exists('*chanclose') AssertEqual -1, ale#socket#Open( \ '127.0.0.1:1111', \ {'callback': function('function')} \) endif Execute(Sending and receiving connections to named pipe sockets should work): if g:can_run_socket_tests && has('nvim-0.4') let g:channel_id = ale#socket#Open( \ g:pipe_path, \ {'callback': function('TestCallback')} \) Assert g:channel_id >= 0, 'The socket was not opened!' call ale#socket#Send(g:channel_id, 'hello') call ale#socket#Send(g:channel_id, ' world') AssertEqual 1, ale#socket#IsOpen(g:channel_id) " Wait up to 1 second for the expected data to arrive. call WaitForData('hello world', 1000) AssertEqual g:channel_id, g:channel_id_received AssertEqual 'hello world', g:data_received AssertEqual g:pipe_path, ale#socket#GetAddress(g:channel_id) call ale#socket#Close(g:channel_id) AssertEqual 0, ale#socket#IsOpen(g:channel_id) AssertEqual '', ale#socket#GetAddress(g:channel_id) endif " NeoVim versions which can't connect to sockets should just fail. if has('nvim-0.4') && !exists('*chanclose') AssertEqual -1, ale#socket#Open( \ g:pipe_path, \ {'callback': function('function')} \) endif ================================================ FILE: test/test_statusline.vader ================================================ Before: Save g:ale_buffer_info let g:ale_buffer_info = {} " A function for conveniently creating expected count objects. function! Counts(data) abort let l:res = { \ '0': 0, \ '1': 0, \ 'error': 0, \ 'warning': 0, \ 'info': 0, \ 'style_error': 0, \ 'style_warning': 0, \ 'total': 0, \} for l:key in keys(a:data) let l:res[l:key] = a:data[l:key] endfor let l:res[0] = l:res.error + l:res.style_error let l:res[1] = l:res.warning + l:res.style_warning + l:res.info let l:res.total = l:res[0] + l:res[1] return l:res endfunction " A test simplified loclist that will be used for some of the " tests in this module. let g:test_buffer_info = { \ bufnr(''): { \ 'loclist': [ \ {'bufnr': bufnr('') - 1, 'type': 'E'}, \ {'bufnr': bufnr('') - 1, 'type': 'E', 'sub_type': 'style'}, \ {'bufnr': bufnr('') - 1, 'type': 'W'}, \ {'bufnr': bufnr('') - 1, 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': bufnr('') - 1, 'type': 'I'}, \ {'bufnr': bufnr(''), 'type': 'E'}, \ {'bufnr': bufnr(''), 'type': 'E', 'sub_type': 'style'}, \ {'bufnr': bufnr(''), 'type': 'E', 'sub_type': 'style'}, \ {'bufnr': bufnr(''), 'type': 'W'}, \ {'bufnr': bufnr(''), 'type': 'W'}, \ {'bufnr': bufnr(''), 'type': 'W'}, \ {'bufnr': bufnr(''), 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': bufnr(''), 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': bufnr(''), 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': bufnr(''), 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': bufnr(''), 'type': 'I'}, \ {'bufnr': bufnr(''), 'type': 'I'}, \ {'bufnr': bufnr(''), 'type': 'I'}, \ {'bufnr': bufnr(''), 'type': 'I'}, \ {'bufnr': bufnr(''), 'type': 'I'}, \ {'bufnr': bufnr('') + 1, 'type': 'E'}, \ {'bufnr': bufnr('') + 1, 'type': 'E', 'sub_type': 'style'}, \ {'bufnr': bufnr('') + 1, 'type': 'W'}, \ {'bufnr': bufnr('') + 1, 'type': 'W', 'sub_type': 'style'}, \ {'bufnr': bufnr('') + 1, 'type': 'I'}, \ ], \ }, \} After: Restore delfunction Counts unlet g:test_buffer_info Execute (Count should be 0 when data is empty): AssertEqual Counts({}), ale#statusline#Count(bufnr('')) Execute (FirstProblem should be 0 when data is empty): AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'error') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'warning') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'style_error') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'style_warning') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'info') Execute (Count should read data from the cache): let g:ale_buffer_info = {'44': {'count': Counts({'error': 1, 'warning': 2})}} AssertEqual Counts({'error': 1, 'warning': 2}), ale#statusline#Count(44) Execute (FirstProblem should read data from the cache): let g:ale_buffer_info = \{"44": \{'count': 0, \'first_problems': \{'error': {'lnum': 3}, \'warning': {'lnum': 44}, \'style_error': {'lnum': 22}, \'style_warning': {'lnum': 223}, \'info': {'lnum': 2} \} \} \} AssertEqual {'lnum': 3}, ale#statusline#FirstProblem(44, 'error') AssertEqual {'lnum': 44}, ale#statusline#FirstProblem(44, 'warning') AssertEqual {'lnum': 223}, ale#statusline#FirstProblem(44, 'style_warning') AssertEqual {'lnum': 22}, ale#statusline#FirstProblem(44, 'style_error') AssertEqual {'lnum': 2}, ale#statusline#FirstProblem(44, 'info') Execute (The count should be correct after an update): let g:ale_buffer_info = {'44': {}} call ale#statusline#Update(44, []) AssertEqual Counts({}), ale#statusline#Count(44) Execute (FirstProblem should be correct after an update): let g:ale_buffer_info = {'44': {}} call ale#statusline#Update(44, []) AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'error') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'warning') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'style_error') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'style_warning') AssertEqual {}, ale#statusline#FirstProblem(bufnr(''), 'info') Execute (Count should match the loclist): let g:ale_buffer_info = g:test_buffer_info AssertEqual { \ 'error': 1, \ 'style_error': 2, \ 'warning': 3, \ 'style_warning': 4, \ 'info': 5, \ '0': 3, \ '1': 12, \ 'total': 15, \}, ale#statusline#Count(bufnr('')) Execute (FirstProblem should pull the first matching value from the loclist): let g:ale_buffer_info = g:test_buffer_info AssertEqual {'bufnr': bufnr(''), 'type': 'E'}, ale#statusline#FirstProblem(bufnr(''), 'error') AssertEqual {'bufnr': bufnr(''), 'type': 'W'}, ale#statusline#FirstProblem(bufnr(''), 'warning') AssertEqual {'bufnr': bufnr(''), 'type': 'E', 'sub_type': 'style'}, ale#statusline#FirstProblem(bufnr(''), 'style_error') AssertEqual {'bufnr': bufnr(''), 'type': 'W', 'sub_type': 'style'}, ale#statusline#FirstProblem(bufnr(''), 'style_warning') AssertEqual {'bufnr': bufnr(''), 'type': 'I'}, ale#statusline#FirstProblem(bufnr(''), 'info') Execute (Output should be empty for non-existent buffer): let g:ale_buffer_info = g:test_buffer_info AssertEqual Counts({}), ale#statusline#Count(9001) AssertEqual {}, ale#statusline#FirstProblem(9001, 'error') AssertEqual {}, ale#statusline#FirstProblem(9001, 'warning') AssertEqual {}, ale#statusline#FirstProblem(9001, 'style_error') AssertEqual {}, ale#statusline#FirstProblem(9001, 'style_warning') AssertEqual {}, ale#statusline#FirstProblem(9001, 'info') ================================================ FILE: test/test_swift_find_project_root.vader ================================================ Before: call ale#test#SetDirectory('/testplugin/test') After: call ale#test#RestoreDirectory() Execute(Detect root of Swift project with Package.swift correctly): call ale#test#SetFilename('test-files/swift/swift-package-project/src/folder/dummy.swift') AssertEqual \ ale#path#Simplify(g:dir . '/test-files/swift/swift-package-project'), \ ale#swift#FindProjectRoot(bufnr('')) Execute(Detect no root in case of non-Package.swift project): call ale#test#SetFilename('test-files/swift/non-swift-package-project/src/folder/dummy.swift') AssertEqual \ '', \ ale#swift#FindProjectRoot(bufnr('')) ================================================ FILE: test/test_symbol_search.vader ================================================ 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:options = {} let g:capability_checked = '' let g:conn_id = v:null let g:InitCallback = 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, Callback) abort let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {}) call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) let l:details = { \ 'buffer': a:buffer, \ 'connection_id': g:conn_id, \ 'project_root': '/foo/bar', \ 'language_id': 'python', \} let g:InitCallback = {-> a:Callback(a:linter, l:details)} endfunction function! ale#lsp#HasCapability(conn_id, capability) abort let g:capability_checked = a:capability return 1 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, options) abort let g:preview_called = 1 let g:item_list = a:item_list let g:options = a:options endfunction After: call ale#test#RestoreDirectory() call ale#linter#Reset() unlet! g:capability_checked unlet! g:InitCallback unlet! g:conn_id unlet! g:Callback unlet! g:message_list unlet! g:expr_list unlet! b:ale_linters unlet! g:options 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#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), \ 'range': { \ 'start': {'line': 2, 'character': 7}, \ }, \ }, \ }, \ { \ 'name': 'foobar', \ 'location': { \ 'uri': ale#path#ToFileURI(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/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALESymbolSearch foo bar " We shouldn't register the callback yet. AssertEqual '''''', string(g:Callback) AssertEqual type(function('type')), type(g:InitCallback) call g:InitCallback() AssertEqual 'symbol_search', g:capability_checked AssertEqual \ 'function(''ale#symbol#HandleLSPResponse'')', \ string(g:Callback) AssertEqual \ [ \ [0, 'workspace/symbol', {'query': 'foo bar'}], \ ], \ g:message_list AssertEqual {'42': {'buffer': bufnr(''), 'use_relative_paths': 0}}, ale#symbol#GetMap() Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResponse): runtime ale_linters/python/pylsp.vim let b:ale_linters = ['pylsp'] call setpos('.', [bufnr(''), 1, 5, 0]) ALESymbolSearch -relative foo bar call g:InitCallback() AssertEqual {'42': {'buffer': bufnr(''), 'use_relative_paths': 1}}, ale#symbol#GetMap() ================================================ FILE: test/test_temporary_file_management.vader ================================================ Before: Save g:ale_buffer_info let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 let g:command = 'echo test' let g:filename = '' let g:directory = '' let g:preserved_directory = '' function! TestCommandCallback(buffer) abort " We are registering a temporary file, so we should delete it. let g:filename = tempname() call writefile(['foo'], g:filename) call ale#command#ManageFile(a:buffer, g:filename) " We are registering this directory appropriately, so we should delete " the whole thing. let g:directory = tempname() call mkdir(g:directory) call writefile(['foo'], g:directory . '/bar') call ale#command#ManageDirectory(a:buffer, g:directory) " We are registering this directory as temporary file, so we " shouldn't delete it. let g:preserved_directory = tempname() call mkdir(g:preserved_directory) call writefile(['foo'], g:preserved_directory . '/bar') call ale#command#ManageFile(a:buffer, g:preserved_directory) return g:command endfunction function! TestCallback(buffer, output) abort return [] endfunction call ale#linter#Define('foobar', { \ 'name': 'testlinter', \ 'executable': has('win32') ? 'cmd' : 'echo', \ 'callback': 'TestCallback', \ 'command': function('TestCommandCallback'), \}) call ale#command#ClearData() After: Restore if !empty(g:preserved_directory) call delete(g:preserved_directory, 'rf') endif unlet! g:ale_run_synchronously unlet! g:command unlet! g:filename unlet! g:directory unlet! g:preserved_directory delfunction TestCommandCallback delfunction TestCallback call ale#linter#Reset() call ale#command#ClearData() Given foobar (Some imaginary filetype): foo bar baz Execute(ALE should delete managed files/directories appropriately after linting): AssertEqual 'foobar', &filetype call ale#Queue(0) call ale#test#FlushJobs() Assert !filereadable(g:filename), 'The temporary file was not deleted' Assert !isdirectory(g:directory), 'The temporary directory was not deleted' Assert isdirectory(g:preserved_directory), 'The temporary directory was not kept' Execute(ALE should delete managed files even if no command is run): AssertEqual 'foobar', &filetype let g:command = '' call ale#Queue(0) call ale#test#WaitForJobs(2000) Assert !filereadable(g:filename), 'The temporary file was not deleted' Assert !isdirectory(g:directory), 'The temporary directory was not deleted' Assert isdirectory(g:preserved_directory), 'The temporary directory was not kept' Execute(ALE should delete managed files when the buffer is removed): call ale#engine#InitBufferInfo(bufnr('%')) call TestCommandCallback(bufnr('%')) call ale#engine#Cleanup(bufnr('%')) Assert !filereadable(g:filename), 'The temporary file was not deleted' Assert !isdirectory(g:directory), 'The temporary directory was not deleted' Assert isdirectory(g:preserved_directory), 'The tempoary directory was not kept' Execute(ALE should create and delete directories for ale#command#CreateDirectory()): call ale#engine#InitBufferInfo(bufnr('%')) let b:dir = ale#command#CreateDirectory(bufnr('%')) let b:dir2 = ale#command#CreateDirectory(bufnr('%')) Assert isdirectory(b:dir), 'The directory was not created' " We should get the correct file permissions. " We want to ensure that the directory is not readable by 'other' if has('unix') AssertEqual 'rwxr-x---', getfperm(b:dir) endif " The two directories shouldn't be the same. AssertNotEqual b:dir2, b:dir call ale#engine#Cleanup(bufnr('%')) Assert !isdirectory(b:dir), 'The directory was not deleted' Assert !isdirectory(b:dir2), 'The second directory was not deleted' Execute(ale#command#ManageFile should add the file even if the buffer info hasn't been set yet): call ale#command#ManageFile(bufnr(''), '/foo/bar') AssertEqual \ { \ bufnr(''): { \ 'jobs': {}, \ 'file_list': ['/foo/bar'], \ 'directory_list': [], \ }, \ }, \ ale#command#GetData() Execute(ale#command#ManageDirectory should add the directory even if the buffer info hasn't been set yet): call ale#command#ManageDirectory(bufnr(''), '/foo/bar') AssertEqual \ { \ bufnr(''): { \ 'jobs': {}, \ 'file_list': [], \ 'directory_list': ['/foo/bar'], \ }, \ }, \ ale#command#GetData() ================================================ FILE: test/test_tmpdir_wrapper.vader ================================================ Before: let g:exists = exists('$TMPDIR') let g:old_value = $TMPDIR After: if g:exists let $TMPDIR = g:old_value else silent! unlet! $TMPDIR endif unlet! g:exists unlet! g:old_value Execute(ale#util#Tempname shouldn't set $TMPDIR to an empty string if it isn't set): " You can't run this test twice on old Vim versions. if has('unix') Assert ale#util#Tempname() =~# '^/tmp' Assert !exists('$TMPDIR'), '$TMPDIR exists where it shouldn''t' endif Execute(ale#util#Tempname shouldn't replace $TMPDIR and reset them to an empty string): if has('unix') let $TMPDIR = '' Assert ale#util#Tempname() =~# '^/tmp' if !has('nvim') Assert exists('$TMPDIR'), '$TMPDIR doesn''t exist where it should' endif AssertEqual '', $TMPDIR endif ================================================ FILE: test/test_vim8_processid_parsing.vader ================================================ Execute(Vim8 Process ID parsing should work): AssertEqual 123, ale#job#ParseVim8ProcessID('process 123 run') AssertEqual 347, ale#job#ParseVim8ProcessID('process 347 failed') AssertEqual 789, ale#job#ParseVim8ProcessID('process 789 dead') AssertEqual 0, ale#job#ParseVim8ProcessID('no process') ================================================ FILE: test/test_virtualtext.vader ================================================ Before: Save g:ale_buffer_info Save g:ale_virtualtext_cursor Save g:ale_virtualtext_delay Save g:ale_virtualtext_single Save g:ale_virtualtext_prefix Save b:ale_virtualtext_prefix Save g:ale_use_neovim_diagnostics_api call ale#virtualtext#ResetDataForTests() let g:setting = '' let g:ale_virtualtext_prefix = '%comment% %type%: ' let g:ale_virtualtext_delay = 0 let g:ale_virtualtext_single = 0 let g:ale_buffer_info = { \ bufnr(''): { \ 'loclist': [ \ { \ 'bufnr': bufnr(''), \ 'type': 'E', \ 'lnum': 1, \ 'col': 5, \ 'text': 'Line 1 error', \ }, \ { \ 'bufnr': bufnr(''), \ 'type': 'W', \ 'lnum': 2, \ 'col': 1, \ 'text': 'Line 2 warning 1', \ }, \ { \ 'bufnr': bufnr(''), \ 'type': 'W', \ 'lnum': 2, \ 'col': 5, \ 'text': 'Line 2 warning 2', \ }, \ { \ 'bufnr': bufnr(''), \ 'type': 'W', \ 'lnum': 3, \ 'col': 3, \ 'text': 'Line 3 warning 1', \ }, \ { \ 'bufnr': bufnr(''), \ 'type': 'E', \ 'lnum': 3, \ 'col': 5, \ 'text': 'Line 3 error 1', \ }, \ { \ 'bufnr': bufnr(''), \ 'type': 'E', \ 'lnum': 3, \ 'col': 6, \ 'text': 'Line 3 error 2', \ }, \ ], \ }, \} let g:ale_use_neovim_diagnostics_api = 0 After: Restore unlet! g:setting unlet! g:ns_id Execute(The correct highlight groups should be loaded for virtual-text): AssertEqual 'ALEVirtualTextError', ale#virtualtext#GetGroup({}) AssertEqual 'ALEVirtualTextError', ale#virtualtext#GetGroup({'type': 'E'}) AssertEqual 'ALEVirtualTextStyleError', \ ale#virtualtext#GetGroup({'type': 'E', 'sub_type': 'style'}) AssertEqual 'ALEVirtualTextWarning', ale#virtualtext#GetGroup({'type': 'W'}) AssertEqual 'ALEVirtualTextStyleWarning', \ ale#virtualtext#GetGroup({'type': 'W', 'sub_type': 'style'}) AssertEqual 'ALEVirtualTextInfo', ale#virtualtext#GetGroup({'type': 'I'}) Given python (An empty Python file): Execute(Comment text should be detected correctly for Python files): if has('patch-9.0.0297') || has('nvim-0.8.0') AssertEqual '#', ale#virtualtext#GetComment(bufnr('')) endif Given java (An empty Java file): Execute(Comment text should be detected correctly for Java files): if has('patch-9.0.0297') || has('nvim-0.8.0') AssertEqual '//', ale#virtualtext#GetComment(bufnr('')) endif Given html (An empty HTML file): Execute(Comment text should be detected correctly for HTML files): if has('patch-9.0.0297') || has('nvim-0.8.0') AssertEqual "\