From f9280a6865fd85ec3eb6fb516b2321d422af408e Mon Sep 17 00:00:00 2001 From: traxys Date: Fri, 1 Mar 2024 13:24:14 +0100 Subject: [PATCH] plugin/none-ls: Implement all builtins (#1169) * plugins/none-ls: Use upstream builtins.json to list sources This avoids the need to define sources in nixvim. We only need to define a mapping from source names to packages. This commit does not yet introduce sources for the newly available builtins * plugin/none-ls: Enable all known sources in tests * plugins/none-ls: Add all missing sources --- plugins/none-ls/helpers.nix | 64 --- plugins/none-ls/servers.nix | 643 +++++++++++++++---------- tests/fetch-tests.nix | 4 + tests/test-sources/plugins/none-ls.nix | 203 ++++---- 4 files changed, 504 insertions(+), 410 deletions(-) delete mode 100644 plugins/none-ls/helpers.nix diff --git a/plugins/none-ls/helpers.nix b/plugins/none-ls/helpers.nix deleted file mode 100644 index d89488d6b9..0000000000 --- a/plugins/none-ls/helpers.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ - mkServer = { - name, - sourceType, - description ? "${name} built-in source for none-ls", - package ? null, - extraPackages ? [], - ... - }: - # returns a module - { - pkgs, - config, - lib, - helpers, - ... - }: - with lib; let - cfg = config.plugins.none-ls.sources.${sourceType}.${name}; - # does this evaluate package? - packageOption = - if package == null - then {} - else { - package = mkOption { - type = types.package; - default = package; - description = "Package to use for ${name} by none-ls."; - }; - }; - in { - options.plugins.none-ls.sources.${sourceType}.${name} = - { - enable = mkEnableOption description; - - # TODO: withArgs can exist outside of the module in a generalized manner - withArgs = mkOption { - default = null; - type = with types; nullOr str; - description = ''Raw Lua code passed as an argument to the source's `with` method.''; - # Not sure that it makes sense to have the same example for all servers - # example = '' - # '\'{ extra_args = { "--no-semi", "--single-quote", "--jsx-single-quote" } }'\' - # ''; - }; - } - // packageOption; - - config = mkIf cfg.enable { - # Does this evaluate package? - extraPackages = extraPackages ++ optional (package != null) cfg.package; - - # Add source to list of sources - plugins.none-ls.sourcesItems = let - sourceItem = "${sourceType}.${name}"; - withArgs = - if (cfg.withArgs == null) - then sourceItem - else "${sourceItem}.with ${cfg.withArgs}"; - finalString = ''require("null-ls").builtins.${withArgs}''; - in [(helpers.mkRaw finalString)]; - }; - }; -} diff --git a/plugins/none-ls/servers.nix b/plugins/none-ls/servers.nix index bc58803737..25c8cc573b 100644 --- a/plugins/none-ls/servers.nix +++ b/plugins/none-ls/servers.nix @@ -2,277 +2,400 @@ pkgs, config, lib, + helpers, ... }: with lib; let - cmpHelpers = import ./helpers.nix; - serverData = { - code_actions = { - eslint = { - package = pkgs.nodePackages.eslint; - }; - eslint_d = { - package = pkgs.nodePackages.eslint_d; - }; - gitsigns = {}; - ltrs = { - package = pkgs.languagetool-rust; - }; - shellcheck = { - package = pkgs.shellcheck; - }; - statix = { - package = pkgs.statix; - }; - }; - completion = {}; - diagnostics = { - alex = { - package = pkgs.nodePackages.alex; - }; - ansiblelint = { - package = pkgs.ansible-lint; - }; - bandit = { - package = pkgs.python3Packages.bandit; - }; - checkstyle = { - package = pkgs.checkstyle; - }; - cppcheck = { - package = pkgs.cppcheck; - }; - deadnix = { - package = pkgs.deadnix; - }; - eslint = { - package = pkgs.nodePackages.eslint; - }; - eslint_d = { - package = pkgs.nodePackages.eslint_d; - }; - flake8 = { - package = pkgs.python3Packages.flake8; - }; - gitlint = { - package = pkgs.gitlint; - }; - golangci_lint = { - package = pkgs.golangci-lint; - }; - hadolint = { - package = pkgs.hadolint; - }; - ktlint = { - package = pkgs.ktlint; - }; - luacheck = { - package = pkgs.luaPackages.luacheck; - }; - ltrs = { - package = pkgs.languagetool-rust; - }; - markdownlint = { - package = pkgs.nodePackages.markdownlint-cli; - }; - mypy = { - package = pkgs.mypy; - }; - protolint = { - package = pkgs.protolint; - }; - pylint = { - package = pkgs.pylint; - }; - revive = { - pacakge = pkgs.revive; - }; - ruff = { - package = pkgs.ruff; - }; - shellcheck = { - package = pkgs.shellcheck; - }; - staticcheck = { - pacakge = pkgs.go-tools; - }; - statix = { - package = pkgs.statix; - }; - stylelint = { - package = pkgs.stylelint; - }; - typos = { - package = pkgs.typos; - }; - vale = { - package = pkgs.vale; - }; - vulture = { - package = pkgs.python3Packages.vulture; - }; - write_good = { - package = pkgs.write-good; - }; - yamllint = { - package = pkgs.yamllint; - }; - }; - formatting = { - alejandra = { - package = pkgs.alejandra; - }; - asmfmt = { - package = pkgs.asmfmt; - }; - astyle = { - package = pkgs.astyle; - }; - bean_format = { - package = pkgs.beancount; - }; - beautysh = { - package = pkgs.beautysh; - }; - black = { - package = pkgs.python3Packages.black; - }; - cbfmt = { - package = pkgs.cbfmt; - }; - eslint = { - package = pkgs.nodePackages.eslint; - }; - eslint_d = { - package = pkgs.nodePackages.eslint_d; - }; - fantomas = { - package = pkgs.fantomas; - }; - fnlfmt = { - package = pkgs.fnlfmt; - }; - fourmolu = { - package = pkgs.haskellPackages.fourmolu; - }; - gofmt = { - package = pkgs.go; - }; - gofumpt = { - package = pkgs.gofumpt; - }; - goimports = { - package = pkgs.gotools; - }; - goimports_reviser = { - package = pkgs.goimports-reviser; - }; - golines = { - package = pkgs.golines; - }; - google_java_format = { - package = pkgs.google-java-format; - }; - isort = { - package = pkgs.isort; - }; - jq = { - package = pkgs.jq; - }; - ktlint = { - package = pkgs.ktlint; - }; - markdownlint = { - package = pkgs.nodePackages.markdownlint-cli; - }; - nixfmt = { - package = pkgs.nixfmt; - }; - nixpkgs_fmt = { - package = pkgs.nixpkgs-fmt; - }; - pint = {}; - phpcbf = { - package = pkgs.phpPackages.php-codesniffer; - }; - prettier = { - package = pkgs.nodePackages.prettier; - }; - prettierd = { - package = pkgs.prettierd; - }; - protolint = { - package = pkgs.protolint; - }; - ruff = { - package = pkgs.ruff; - }; - ruff_format = { - package = pkgs.ruff; - }; - rustfmt = { - package = pkgs.rustfmt; - }; - shfmt = { - package = pkgs.shfmt; - }; - sqlfluff = { - package = pkgs.sqlfluff; - }; - stylelint = { - package = pkgs.stylelint; - }; - stylua = { - package = pkgs.stylua; - }; - taplo = { - package = pkgs.taplo; - }; - trim_newlines = {}; - trim_whitespace = {}; - }; + noneLsBuiltins = builtins.fromJSON ( + builtins.readFile "${pkgs.vimPlugins.none-ls-nvim.src}/doc/builtins.json" + ); + + # Can contain either: + # - a package + # - null if the source is not present in nixpkgs + # - false if this source does not need a package + builtinPackages = { + inherit + (pkgs) + actionlint + alejandra + asmfmt + astyle + autoflake + beancount + beautysh + bibclean + biome + buf + cbfmt + checkmake + checkstyle + clazy + codespell + commitlint + cppcheck + cpplint + csharpier + deadnix + dfmt + djhtml + djlint + dprint + erlfmt + fantomas + fish + fnlfmt + fprettify + gitlint + gofumpt + golines + hadolint + hclfmt + isort + joker + jq + just + ktlint + leptosfmt + mdformat + mdl + mypy + nixfmt + php + pmd + prettierd + proselint + protolint + pylint + revive + rstcheck + rubocop + rubyfmt + ruff + rufo + rustfmt + rustywind + scalafmt + selene + semgrep + shellcheck + shellharden + shfmt + smlfmt + sqlfluff + statix + stylelint + stylua + taplo + templ + tfsec + topiary + treefmt + trivy + typos + typstfmt + uncrustify + usort + vale + verilator + xmlformat + xq + yamlfmt + yamllint + yapf + yq + zprint + zsh + ; + inherit + (pkgs.nodePackages) + alex + eslint + eslint_d + prettier + ; + inherit + (pkgs.python3.pkgs) + autopep8 + bandit + black + docformatter + flake8 + pycodestyle + pydocstyle + pylama + vulture + ; + inherit + (pkgs.luaPackages) + luacheck + ; + inherit + (pkgs.haskellPackages) + fourmolu + ; + inherit + (pkgs.phpPackages) + phpmd + phpstan + psalm + ; + inherit + (pkgs.rubyPackages) + htmlbeautifier + ; + inherit + (pkgs.ocamlPackages) + ocamlformat + ; + ansiblelint = pkgs.ansible-lint; + bean_format = pkgs.beancount; + blackd = pkgs.black; + buildifier = pkgs.bazel-buildtools; + cabal_fmt = pkgs.haskellPackages.cabal-fmt; + cfn_lint = pkgs.python3.pkgs.cfn-lint; + chktex = pkgs.texliveMedium; + clang_check = pkgs.clang-tools; + clang_format = pkgs.clang-tools; + clj_kondo = pkgs.clj-kondo; + cmake_format = pkgs.cmake-format; + cmake_lint = pkgs.cmake-format; + credo = pkgs.elixir; + crystal_format = pkgs.crystal; + cue_fmt = pkgs.cue; + d2_fmt = pkgs.d2; + dart_format = pkgs.dart; + deno_fmt = pkgs.deno; + deno_lint = pkgs.deno; + dictionary = pkgs.curl; + dotenv_linter = pkgs.dotenv-linter; + editorconfig_checker = pkgs.editorconfig-checker; + elm_format = pkgs.elmPackages.elm-format; + emacs_scheme_mode = pkgs.emacs; + emacs_vhdl_mode = pkgs.emacs; + erb_format = pkgs.rubyPackages.erb-formatter; + fish_indent = pkgs.fish; + format_r = pkgs.R; + gdformat = pkgs.gdtoolkit; + gdlint = pkgs.gdtoolkit; + gitsigns = pkgs.git; + glslc = pkgs.shaderc; + gn_format = pkgs.gn; + gofmt = pkgs.go; + goimports = pkgs.gotools; + goimports_reviser = pkgs.goimports-reviser; + golangci_lint = pkgs.golangci-lint; + google_java_format = pkgs.google-java-format; + haml_lint = pkgs.mastodon; + haxe_formatter = pkgs.haxe; + isortd = pkgs.isort; + jsonnetfmt = pkgs.jsonnet; + json_tool = pkgs.python3; + latexindent = pkgs.texliveMedium; + ltrs = pkgs.languagetool-rust; + lua_format = pkgs.luaformatter; + markdownlint_cli2 = pkgs.markdownlint-cli2; + markdownlint = pkgs.nodePackages.markdownlint-cli; + mix = pkgs.elixir; + nimpretty = pkgs.nim; + nixpkgs_fmt = pkgs.nixpkgs-fmt; + opacheck = pkgs.open-policy-agent; + perltidy = pkgs.perlPackages.PerlTidy; + pg_format = pkgs.pgformatter; + phpcbf = pkgs.phpPackages.php-codesniffer; + phpcsfixer = pkgs.phpPackages.php-cs-fixer; + phpcs = pkgs.phpPackages.php-codesniffer; + prismaFmt = pkgs.nodePackages.prisma; + protoc_gen_lint = pkgs.protobuf; + ptop = pkgs.fpc; + puppet_lint = pkgs.puppet-lint; + qmlformat = pkgs.qt6.qtdeclarative; + qmllint = pkgs.qt6.qtdeclarative; + racket_fixw = pkgs.racket; + raco_fmt = pkgs.racket; + rego = pkgs.open-policy-agent; + reorder_python_imports = pkgs.python3.pkgs.reorder-python-imports; + rpmspec = pkgs.rpm; + ruff_format = pkgs.ruff; + sqlformat = pkgs.python3.pkgs.sqlparse; + staticcheck = pkgs.go-tools; + stylish_haskell = pkgs.stylish-haskell; + surface = pkgs.elixir; + swift_format = pkgs.swift-format; + teal = pkgs.luaPackages.tl; + terraform_fmt = pkgs.terraform; + terraform_validate = pkgs.terraform; + tidy = pkgs.html-tidy; + trim_newlines = pkgs.gawk; + trim_whitespace = pkgs.gawk; + tsc = pkgs.typescript; + verible_verilog_format = pkgs.verible; + vfmt = pkgs.vlang; + vint = pkgs.vim-vint; + write_good = pkgs.write-good; + xmllint = pkgs.libxml2.bin; + zigfmt = pkgs.zig; + + # Sources not present in nixpkgs + blade_formatter = null; + blue = null; + brittany = null; + bsfmt = null; + bslint = null; + cljstyle = null; + cueimports = null; + curlylint = null; + dtsfmt = null; + erb_lint = null; + fixjson = null; + forge_fmt = null; + gccdiag = null; + gersemi = null; + gospel = null; + jshint = null; + jsonlint = null; + markdown_toc = null; + markuplint = null; + misspell = null; + mlint = null; + nginx_beautifier = null; + npm_groovy_lint = null; + ocdc = null; + packer = null; + perlimports = null; + pint = null; + pretty_php = null; + puglint = null; + purs_tidy = null; + pyflyby = null; + pyink = null; + pyproject_flake8 = null; + reek = null; + regal = null; + remark = null; + rescript = null; + saltlint = null; + semistandardjs = null; + solhint = null; + spectral = null; + sqlfmt = null; + sql_formatter = null; + standardjs = null; + standardrb = null; + standardts = null; + styler = null; + stylint = null; + swiftformat = null; + swiftlint = null; + terrafmt = null; + textidote = null; + textlint = null; + twigcs = null; + vacuum = null; + xo = null; + yamlfix = null; + + # Sources without packages + gitrebase = false; + # TODO: Requires the go tree-sitter parser + gomodifytags = false; + # TODO: Requires the go tree-sitter parser + impl = false; + luasnip = false; + printenv = false; + refactoring = false; + spell = false; + tags = false; + todo_comments = false; + trail_space = false; + ts_node_action = false; + vsnip = false; }; - # Format the servers to be an array of attrs like the following example - # [{ - # name = "prettier"; - # sourceType = "formatting"; - # packages = [...]; - # }] - serverDataFormatted = - mapAttrsToList - ( - sourceType: - mapAttrsToList - ( - name: attrs: - attrs - // { - inherit sourceType name; - } - ) - ) - serverData; - dataFlattened = flatten serverDataFormatted; + + # Check if the package is set to `false` or not + hasBuiltinPackage = source: + if builtins.hasAttr source builtinPackages + then !(builtins.isBool builtinPackages.${source}) + else true; + + builtinPackage = source: builtinPackages.${source} or null; in { - imports = - (map cmpHelpers.mkServer dataFlattened) - ++ [ - ./prettier.nix - # Introduced January 22 2024. - # TODO remove in early March 2024. - ( - mkRemovedOptionModule - ["plugins" "none-ls" "sources" "formatting" "prettier_d_slim"] - "`prettier_d_slim` is no longer maintained for >3 years. Please migrate to `prettierd`" - ) - ]; + imports = [ + ./prettier.nix + ]; + + options.plugins.none-ls.sources = + builtins.mapAttrs ( + sourceType: sources: + builtins.mapAttrs + (source: _: + { + enable = mkEnableOption "the ${source} ${sourceType} source for none-ls"; + withArgs = helpers.mkNullOrLua '' + Raw Lua code passed as an argument to the source's `with` method. + ''; + } + // lib.optionalAttrs (hasBuiltinPackage source) { + package = let + pkg = builtinPackage source; + in + mkOption ({ + type = types.nullOr types.package; + description = + "Package to use for ${source} by none-ls. " + + ( + lib.optionalString (pkg == null) '' + Not handled in nixvim, either install externally and set to null or set the option with a derivation. + '' + ); + } + // optionalAttrs (pkg != null) { + default = pkg; + }); + }) + sources + ) + noneLsBuiltins; config = let cfg = config.plugins.none-ls; gitsignsEnabled = cfg.sources.code_actions.gitsigns.enable; + + flattenedSources = lib.flatten ( + lib.mapAttrsToList ( + sourceType: sources: (lib.mapAttrsToList (sourceName: source: + source + // { + inherit sourceType sourceName; + }) + sources) + ) + cfg.sources + ); + + enabledSources = builtins.filter (source: source.enable) flattenedSources; in mkIf cfg.enable { + plugins.none-ls.sourcesItems = + builtins.map ( + source: let + sourceItem = "${source.sourceType}.${source.sourceName}"; + withArgs = + if source.withArgs == null + then sourceItem + else "${sourceItem}.with(${source.withArgs}})"; + in + helpers.mkRaw '' + require("null-ls").builtins.${withArgs} + '' + ) + enabledSources; plugins.gitsigns.enable = mkIf gitsignsEnabled true; - extraPackages = optional gitsignsEnabled pkgs.git; + extraPackages = builtins.filter (p: p != null) ( + builtins.map ( + source: source.package or null + ) + enabledSources + ); }; } diff --git a/tests/fetch-tests.nix b/tests/fetch-tests.nix index d2f73fc43d..0c0442b1b1 100644 --- a/tests/fetch-tests.nix +++ b/tests/fetch-tests.nix @@ -50,6 +50,10 @@ inherit pkgs lib helpers; config = {}; }; + nonels-sources-options = import ../plugins/none-ls/servers.nix { + inherit pkgs lib helpers; + config = {}; + }; }; inherit namespace; }) diff --git a/tests/test-sources/plugins/none-ls.nix b/tests/test-sources/plugins/none-ls.nix index bdf055d960..f9351539f5 100644 --- a/tests/test-sources/plugins/none-ls.nix +++ b/tests/test-sources/plugins/none-ls.nix @@ -1,4 +1,8 @@ -{pkgs, ...}: { +{ + pkgs, + nonels-sources-options, + ... +}: { # Empty configuration empty = { plugins.none-ls.enable = true; @@ -27,7 +31,8 @@ default = { plugins.none-ls = { - enable = true; + # sandbox-exec: pattern serialization length 159032 exceeds maximum (65535) + enable = !pkgs.stdenv.isDarwin; enableLspFormat = false; border = null; @@ -47,90 +52,116 @@ shouldAttach = null; tempDir = null; updateInInsert = false; - sources = { - code_actions = { - eslint.enable = true; - eslint_d.enable = true; - gitsigns.enable = true; - ltrs.enable = true; - shellcheck.enable = true; - statix.enable = true; - }; - diagnostics = { - ansiblelint.enable = true; - bandit.enable = true; - checkstyle.enable = true; - cppcheck.enable = true; - deadnix.enable = true; - eslint.enable = true; - eslint_d.enable = true; - flake8.enable = true; - gitlint.enable = true; - golangci_lint.enable = true; - ktlint.enable = true; - ltrs.enable = true; - markdownlint.enable = true; - ruff.enable = true; - shellcheck.enable = true; - statix.enable = true; - staticcheck.enable = true; - typos.enable = true; - vale.enable = true; - vulture.enable = true; - alex.enable = true; - protolint.enable = true; - revive.enable = true; - hadolint.enable = true; - luacheck.enable = true; - mypy.enable = true; - pylint.enable = true; - write_good.enable = true; - yamllint.enable = true; - stylelint.enable = true; - }; - formatting = { - alejandra.enable = true; - asmfmt.enable = true; - astyle.enable = true; - bean_format.enable = true; - black.enable = true; - # As of 2024-01-04, cbfmt is broken on darwin - # TODO: re-enable this test when fixed - cbfmt.enable = !pkgs.stdenv.isDarwin; - eslint.enable = true; - eslint_d.enable = true; - fantomas.enable = true; - fnlfmt.enable = true; - fourmolu.enable = true; - gofmt.enable = true; - gofumpt.enable = true; - goimports.enable = true; - goimports_reviser.enable = true; - golines.enable = true; - google_java_format.enable = true; - ktlint.enable = true; - nixfmt.enable = true; - nixpkgs_fmt.enable = true; - phpcbf.enable = true; - prettier.enable = true; - prettierd.enable = true; - shfmt.enable = true; - stylua.enable = true; - stylelint.enable = true; - taplo.enable = true; - isort.enable = true; - jq.enable = true; - markdownlint.enable = true; - pint.enable = true; - protolint.enable = true; - ruff.enable = true; - ruff_format.enable = true; - rustfmt.enable = true; - sqlfluff.enable = true; - trim_newlines.enable = true; - trim_whitespace.enable = true; - }; - }; + sources = let + options = nonels-sources-options.options.plugins.none-ls.sources; + + unpackaged = + [ + "blade_formatter" + "blue" + "brittany" + "bsfmt" + "bslint" + "cljstyle" + "cueimports" + "curlylint" + "dtsfmt" + "erb_lint" + "fixjson" + "forge_fmt" + "gccdiag" + "gersemi" + "gospel" + "jshint" + "jsonlint" + "markdown_toc" + "markuplint" + "misspell" + "mlint" + "nginx_beautifier" + "npm_groovy_lint" + "ocdc" + "packer" + "perlimports" + "pint" + "pretty_php" + "puglint" + "purs_tidy" + "pyflyby" + "pyink" + "pyproject_flake8" + "reek" + "regal" + "remark" + "rescript" + "saltlint" + "semistandardjs" + "solhint" + "spectral" + "sqlfmt" + "sql_formatter" + "standardjs" + "standardrb" + "standardts" + "styler" + "stylint" + "swiftformat" + "swiftlint" + "terrafmt" + "textidote" + "textlint" + "twigcs" + "vacuum" + "xo" + "yamlfix" + ] + ++ ( + pkgs.lib.optionals + (pkgs.stdenv.isDarwin && pkgs.stdenv.isx86_64) + [ + "rubyfmt" + # Currently broken + "lua_format" + # Currently broken + "zigfmt" + ] + ) + ++ ( + pkgs.lib.optionals + pkgs.stdenv.isDarwin + [ + "rpmspec" + "clazy" + "gdformat" + "gdlint" + "haml_lint" + "verilator" + "verible_verilog_format" + # Broken due to a dependency + "jsonnetfmt" + ] + ) + ++ ( + pkgs.lib.optionals + pkgs.stdenv.isAarch64 + [ + "semgrep" + "smlfmt" + ] + ); + + sources = pkgs.lib.mapAttrs (_: sources: + pkgs.lib.mapAttrs (source: _: + { + enable = true; + } + // pkgs.lib.optionalAttrs (builtins.elem source unpackaged) { + package = null; + }) + sources) + options; + in + sources; }; }; }