neovim: use evalModule to typecheck plugins config (#488793)

This commit is contained in:
Matthieu Coudron
2026-03-11 14:47:06 +00:00
committed by GitHub
2 changed files with 140 additions and 25 deletions
+115
View File
@@ -0,0 +1,115 @@
{ config, lib, ... }:
let
/*
transform all plugins into an attrset
{ optional = bool; plugin = package; }
*/
normalizePlugins =
plugins:
let
defaultPlugin = {
plugin = null;
config = null;
optional = false;
};
in
map (x: defaultPlugin // (if (x ? plugin) then x else { plugin = x; })) plugins;
pluginWithConfigType =
with lib;
types.submodule {
options = {
config = mkOption {
type = types.nullOr types.lines;
description = "viml configuration associated with this plugin.";
default = null;
example = "set title";
};
optional = mkEnableOption "optional" // {
description = "Don't load automatically on startup (load with :packadd)";
};
plugin = mkOption {
type = types.package;
example = lib.literalExpression "vimPlugins.vim-fugitive";
description = "vim plugin";
};
};
};
in
{
options = {
plugins = lib.mkOption {
type = with lib.types; listOf (either package pluginWithConfigType);
default = [ ];
apply = normalizePlugins;
example = lib.literalExpression ''
with pkgs.vimPlugins; [
yankring
vim-nix
{ plugin = vim-startify;
config = "let g:startify_change_to_vcs_root = 0";
}
]
'';
description = ''
List of vim plugins to install optionally associated with
configuration to be placed in init.vim.
'';
};
runtimeDeps = lib.mkOption {
readOnly = true;
type = with lib.types; listOf package;
description = ''
List of derivations required at runtime
'';
};
pluginAdvisedLua = lib.mkOption {
readOnly = true;
type = lib.types.listOf lib.types.lines;
description = ''
Recommended configuration set in vim plugins via ".passthru.initLua".
'';
};
userPluginViml = lib.mkOption {
readOnly = true;
type = lib.types.listOf (lib.types.lines);
description = ''
The viml config set by the user.
'';
};
};
config =
let
pluginsNormalized = normalizePlugins config.plugins;
in
{
pluginAdvisedLua =
let
op =
acc: normalizedPlugin:
acc
++ lib.optional (
normalizedPlugin.plugin.passthru ? initLua
) normalizedPlugin.plugin.passthru.initLua;
in
lib.foldl' op [ ] pluginsNormalized;
runtimeDeps =
let
op = acc: normalizedPlugin: acc ++ normalizedPlugin.plugin.runtimeDeps or [ ];
in
lib.foldl' op [ ] pluginsNormalized;
userPluginViml = lib.foldl (
acc: p: if p.config != null then acc ++ [ p.config ] else acc
) [ ] pluginsNormalized;
};
}
+25 -25
View File
@@ -79,25 +79,30 @@ let
plugins:
let
neovimConfig =
structuredConfigure:
let
module = import ./module.nix;
# Generate init.vim configuration
cfg = (
lib.evalModules {
modules = [
module
structuredConfigure
];
}
);
in
cfg.config;
checked_cfg = neovimConfig {
inherit plugins;
};
pluginsNormalized = normalizePlugins plugins;
vimPackage = normalizedPluginsToVimPackage pluginsNormalized;
userPluginViml = lib.foldl (
acc: p: if p.config != null then acc ++ [ p.config ] else acc
) [ ] pluginsNormalized;
pluginAdvisedLua =
let
op =
acc: normalizedPlugin:
acc
++ lib.optional (
normalizedPlugin.plugin.passthru ? initLua
) normalizedPlugin.plugin.passthru.initLua;
in
lib.foldl' op [ ] pluginsNormalized;
getDeps = attrname: map (plugin: plugin.${attrname} or (_: [ ]));
requiredPlugins = vimUtils.requiredPluginsForPackage vimPackage;
@@ -108,10 +113,11 @@ let
inherit pluginPython3Packages;
# viml config set by the user along with the plugin
inherit userPluginViml;
# recommended configuration set in vim plugins ".passthru.initLua"
inherit pluginAdvisedLua;
inherit (checked_cfg)
userPluginViml
runtimeDeps
pluginAdvisedLua
;
# A Vim "package", see ':h packages'
# You most likely want to use vimPackage as follows:
@@ -119,12 +125,6 @@ let
# finalPackdir = neovimUtils.packDir packpathDirs;
inherit vimPackage;
runtimeDeps =
let
op = acc: normalizedPlugin: acc ++ normalizedPlugin.plugin.runtimeDeps or [ ];
in
lib.foldl' op [ ] pluginsNormalized;
};
/*