diff --git a/plugins/by-name/conform-nvim/auto-install.nix b/plugins/by-name/conform-nvim/auto-install.nix new file mode 100644 index 00000000..2e1cf4a9 --- /dev/null +++ b/plugins/by-name/conform-nvim/auto-install.nix @@ -0,0 +1,78 @@ +{ + pkgs, + lib, + ... +}: +let + inherit (lib) elem throwIfNot; + inherit (builtins) + filter + isString + isAttrs + attrValues + attrNames + concatMap + partition + ; + + inherit (import ./formatter-packages.nix { inherit pkgs lib; }) sType formatter-packages; + sTypeList = attrValues sType; + isSTypeAttrSet = x: lib.elem (x.mark or null) sTypeList; +in +rec { + cleanMaybePackageList = filter (x: !isSTypeAttrSet x); + + getPackageByName = + { configuredFormatters, overrides }: + name: + let + permittedNames = attrNames configuredFormatters; + isSType = x: elem x sTypeList; + notFoundMsg = '' + A package for the conform-nvim formatter '${name}' could not be found. + It is not a user defined formatter. Is the formatter name correct? + ''; + maybePackage = + overrides.${name} or formatter-packages.${name} or pkgs.${name} + or (throwIfNot (elem name permittedNames) notFoundMsg null); + in + if isSType maybePackage then + { + inherit name; + mark = maybePackage; + } + else + maybePackage; + + mkWarnsFromMaybePackageList = + opts: list: + let + mkWarn = + { name, mark }: + lib.nixvim.mkWarnings "conform-nvim" [ + { + when = true; + message = '' + You have enabled the '${name}' formatter that relies on a package marked '${mark}'. + Because of that it will not be installed. To disable this warning, explicitly disable installing the package + by setting the '${opts.autoInstall.overrides}.${name}' option to 'null'. You can also disable + all warnings related to packages not installed by 'autoInstall' with '${opts.autoInstall.enableWarnings}'. + ''; + } + ]; + in + concatMap mkWarn (filter isSTypeAttrSet list); + + collectFormatters = + formatters: + let + partitioned = lib.pipe formatters [ + lib.flatten + (filter (x: isString x || isAttrs x)) + (partition isString) + ]; + in + lib.optionals (formatters != [ ]) ( + partitioned.right ++ concatMap (fmts: collectFormatters (attrValues fmts)) partitioned.wrong + ); +} diff --git a/plugins/by-name/conform-nvim/default.nix b/plugins/by-name/conform-nvim/default.nix index 5e411ea9..9a696a5f 100644 --- a/plugins/by-name/conform-nvim/default.nix +++ b/plugins/by-name/conform-nvim/default.nix @@ -1,9 +1,11 @@ { lib, + pkgs, ... }: let inherit (lib) types; + inherit (builtins) attrValues; inherit (lib.nixvim) defaultNullOpts; in lib.nixvim.plugins.mkNeovimPlugin { @@ -12,7 +14,10 @@ lib.nixvim.plugins.mkNeovimPlugin { packPathName = "conform.nvim"; description = "Lightweight yet powerful formatter plugin for Neovim."; - maintainers = [ lib.maintainers.khaneliman ]; + maintainers = with lib.maintainers; [ + khaneliman + saygo-png + ]; # TODO: added 2024-08-23 remove after 24.11 deprecateExtraOptions = true; @@ -43,6 +48,36 @@ lib.nixvim.plugins.mkNeovimPlugin { "formatOnSave" ]; + extraOptions = { + autoInstall = { + enable = lib.mkEnableOption '' + automatic installation of formatters listed in `settings.formatters_by_ft` and `settings.formatters` + ''; + + enableWarnings = lib.mkOption { + default = true; + example = false; + description = "Whether to enable warnings."; + type = lib.types.bool; + }; + + overrides = lib.mkOption { + type = with types; attrsOf (nullOr package); + default = { }; + example = lib.literalExpression '' + { + "treefmt" = null; + "pyproject-fmt" = pkgs.python312Packages.pyproject-parser; + }; + ''; + description = '' + Attribute set of formatter names to nix packages. + You can set a formatter to `null` to disable auto-installing its package. + ''; + }; + }; + }; + settingsOptions = let lsp_format = @@ -234,4 +269,27 @@ lib.nixvim.plugins.mkNeovimPlugin { } ``` ''; + + extraConfig = + cfg: opts: + let + inherit (cfg.autoInstall) enable enableWarnings; + inherit (import ./auto-install.nix { inherit pkgs lib; }) + getPackageByName + collectFormatters + cleanMaybePackageList + mkWarnsFromMaybePackageList + ; + getPackageByNameWith = getPackageByName { + configuredFormatters = cfg.settings.formatters; + inherit (cfg.autoInstall) overrides; + }; + names = collectFormatters (attrValues cfg.settings.formatters_by_ft); + packageList = map getPackageByNameWith names; + warns = (mkWarnsFromMaybePackageList opts) packageList; + in + { + warnings = lib.mkIf (enable && warns != [ ] && enableWarnings) warns; + extraPackages = lib.mkIf enable (cleanMaybePackageList packageList); + }; } diff --git a/plugins/by-name/conform-nvim/formatter-packages.nix b/plugins/by-name/conform-nvim/formatter-packages.nix new file mode 100644 index 00000000..38ccf6c7 --- /dev/null +++ b/plugins/by-name/conform-nvim/formatter-packages.nix @@ -0,0 +1,146 @@ +{ + pkgs, + ... +}: +with pkgs; +rec { + sType = { + broken = "broken"; + darwinOnly = "Darwin only"; + unpackaged = "unpackaged"; + }; + + formatter-packages = { + swift_format = if !stdenv.isDarwin then sType.darwinOnly else swift-format; + swiftlint = if !stdenv.isDarwin then sType.darwinOnly else swiftlint; + + # 2025-09-13 build failure + inko = sType.broken; + # 2025-09-13 build failure + commitmsgfmt = sType.broken; + # 2025-09-17 build failure + gci = sType.broken; + + format-queries = null; # Uses neovim itself + init = null; # Internal thingamajig + injected = null; # Internal formatter + trim_newlines = null; # Conform native formatter + trim_whitespace = null; # Conform native formatter + + auto_optional = sType.unpackaged; + bake = sType.unpackaged; + blue = sType.unpackaged; + bpfmt = sType.unpackaged; + bsfmt = sType.unpackaged; + caramel_fmt = sType.unpackaged; + crlfmt = sType.unpackaged; + darker = sType.unpackaged; + dcm_fix = sType.unpackaged; + dcm_format = sType.unpackaged; + easy-coding-standard = sType.unpackaged; + findent = sType.unpackaged; + ghokin = sType.unpackaged; + gluon_fmt = sType.unpackaged; + grain_format = sType.unpackaged; + hledger-fmt = sType.unpackaged; + imba_fmt = sType.unpackaged; + janet-format = sType.unpackaged; + liquidsoap-prettier = sType.unpackaged; + llf = sType.unpackaged; + markdown-toc = sType.unpackaged; + markdownfmt = sType.unpackaged; + mdslw = sType.unpackaged; + mojo_format = sType.unpackaged; + nomad_fmt = sType.unpackaged; + npm-groovy-lint = sType.unpackaged; + packer_fmt = sType.unpackaged; + pangu = sType.unpackaged; + perlimports = sType.unpackaged; + pint = sType.unpackaged; + purs-tidy = sType.unpackaged; + pycln = sType.unpackaged; + pyink = sType.unpackaged; + pymarkdownlnt = sType.unpackaged; + reformat-gherkin = sType.unpackaged; + rescript-format = sType.unpackaged; + runic = sType.unpackaged; + spotless_gradle = sType.unpackaged; + spotless_maven = sType.unpackaged; + standard-clj = sType.unpackaged; + standardjs = sType.unpackaged; + tlint = sType.unpackaged; + twig-cs-fixer = sType.unpackaged; + vsg = sType.unpackaged; + ziggy = sType.unpackaged; + ziggy_schema = sType.unpackaged; + + inherit (python313Packages) autopep8; + awk = gawk; + bean-format = beancount; + biome-check = biome; + biome-organize-imports = biome; + cabal_fmt = haskellPackages.cabal-fmt; + clang_format = clang-tools; + clang-format = clang-tools; + cmake_format = cmake-format; + css_beautify = nodePackages.js-beautify; + cue_fmt = cue; + dart_format = dart; + deno_fmt = deno; + dioxus = dioxus-cli; + inherit (python313Packages) docformatter; + elm_format = elmPackages.elm-format; + erb_format = rubyPackages.erb-formatter; + fish_indent = fishMinimal; + forge_fmt = foundry; + format-dune-file = dune_3; + gdformat = gdtoolkit_4; + gofmt = go; + goimports = gotools; + hcl = hclfmt; + inherit (haskellPackages) hindent; + html_beautify = nodePackages.js-beautify; + inherit (rubyPackages) htmlbeautifier; + hurlfmt = hurl; + js_beautify = nodePackages.js-beautify; + jsonnetfmt = jsonnet; + inherit (texlive.pkgs) latexindent; + lua-format = luaformatter; + mago_format = mago; + mago_lint = mago; + markdownlint = markdownlint-cli; + mix = beamMinimal28Packages.elixir; + nginxfmt = nginx-config-formatter; + nimpretty = nim; + nixpkgs_fmt = nixpkgs-fmt; + inherit (ocamlPackages) ocp-indent; + odinfmt = ols; + opa_fmt = open-policy-agent; + perltidy = perl538Packages.PerlTidy; + pg_format = pgformatter; + php_cs_fixer = php83Packages.php-cs-fixer; + phpcbf = php84Packages.php-codesniffer; + inherit (php84Packages) phpinsights; + prolog = swi-prolog; + pyproject-fmt = python313Packages.pyproject-parser; + inherit (python313Packages) python-ly; + qmlformat = libsForQt5.qt5.qtdeclarative; + inherit (python313Packages) reorder-python-imports; + ruff_fix = ruff; + ruff_format = ruff; + ruff_organize_imports = ruff; + sql_formatter = sql-formatter; + inherit (python313Packages) sqlfmt; + squeeze_blanks = coreutils; + standardrb = rubyPackages.standard; + styler = R; + inherit (rubyPackages) syntax_tree; + terraform_fmt = tenv; + terragrunt_hclfmt = terragrunt; + tofu_fmt = opentofu; + v = vlang; + xmlformatter = xmlformat; + xmllint = libxml2; + zigfmt = zig; + }; +} diff --git a/tests/test-sources/plugins/by-name/conform-nvim/default.nix b/tests/test-sources/plugins/by-name/conform-nvim/default.nix index 9a640b9c..12a14349 100644 --- a/tests/test-sources/plugins/by-name/conform-nvim/default.nix +++ b/tests/test-sources/plugins/by-name/conform-nvim/default.nix @@ -4,6 +4,21 @@ plugins.conform-nvim.enable = true; }; + all-formatters = + let + allFormatters = lib.importJSON ../../../../../generated/conform-formatters.json; + in + { + plugins.conform-nvim = { + enable = true; + autoInstall = { + enable = true; + enableWarnings = false; + }; + settings.formatters_by_ft."*" = allFormatters; + }; + }; + default = { plugins.conform-nvim = { enable = true;