diff --git a/lib/neovim-plugin.nix b/lib/neovim-plugin.nix index 250692a5..1f1b05d2 100644 --- a/lib/neovim-plugin.nix +++ b/lib/neovim-plugin.nix @@ -89,6 +89,7 @@ options.${namespace}.${name} = { enable = lib.mkEnableOption originalName; + lazyLoad = lib.nixvim.mkLazyLoadOption originalName; package = if lib.isOption package then package @@ -113,13 +114,6 @@ ''; internal = true; }; - - lazyLoad = lib.nixvim.mkLazyLoadOption { - inherit originalName; - lazyLoadDefaults = lib.optionalAttrs (isColorscheme && colorscheme != null) { - inherit colorscheme; - }; - }; } // lib.optionalAttrs hasSettings { settings = lib.nixvim.mkSettingsOption { @@ -168,33 +162,42 @@ # Add the plugin setup code `require('foo').setup(...)` to the lua configuration (lib.optionalAttrs callSetup { ${namespace}.${name}.luaConfig.content = setupCode; }) - # Write the lua configuration `luaConfig.content` to the config file + # Write the lua configuration `luaConfig.content` to the config file when lazy loading is not enabled (lib.mkIf (!cfg.lazyLoad.enable) (setLuaConfig cfg.luaConfig.content)) - ]) - ++ (lib.optionals hasConfigAttrs [ - (lib.mkIf (cfg.lazyLoad.backend == "lz.n") { + + # When lazy loading is enabled for this plugin, route its configuration to the enabled provider + (lib.mkIf cfg.lazyLoad.enable { + assertions = [ + { + assertion = (isColorscheme && colorscheme != null) || cfg.lazyLoad.settings != { }; + message = "You have enabled lazy loading for ${originalName} but have not provided any configuration."; + } + ]; plugins.lz-n = { - # infinite recursion? - # enable = true; plugins = [ - { - # TODO: handle this for every plugin properly - __unkeyed-1 = originalName; - # Use provided after, otherwise fallback to normal lua content - after = if cfg.lazyLoad.after != null then cfg.lazyLoad.after else cfg.luaConfig.content; - inherit (cfg.lazyLoad) - enabled - priority - before - beforeAll - event - cmd - ft - keys - colorscheme - extraSettings - ; - } + ( + { + __unkeyed-1 = originalName; + # Use provided after, otherwise fallback to normal lua content + after = + if cfg.lazyLoad.settings.after != null then + cfg.lazyLoad.settings.after + else + # We need to wrap it in a function so it doesn't execute immediately + "function()\n " + cfg.luaConfig.content + " \nend"; + colorscheme = + if cfg.lazyLoad.settings.colorscheme != null then + cfg.lazyLoad.settings.colorscheme + else if (isColorscheme && colorscheme != null) then + colorscheme + else + null; + } + // lib.removeAttrs cfg.lazyLoad.settings [ + "after" + "colorscheme" + ] + ) ]; }; }) diff --git a/lib/options.nix b/lib/options.nix index 2ee3e194..050ad1ab 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -335,14 +335,14 @@ rec { }; mkLazyLoadOption = - { - originalName, - lazyLoadDefaults ? { }, - }: + originalName: lib.mkOption { description = '' Lazy-load settings for ${originalName}. ''; + default = { + enable = false; + }; type = let triggerType = @@ -353,100 +353,94 @@ rec { (listOf str) ]; in - types.submodule { - options = with defaultNullOpts; { - - enable = lib.mkEnableOption '' - lazy-loading for ${originalName} - ''; - - backend = - mkEnumFirstDefault - [ - "lz.n" - ] - '' - The lazy-loading backend to use. + types.submodule ( + { config, ... }: + { + options = with defaultNullOpts; { + enable = lib.mkOption { + default = lib.any (x: x != null) (builtins.attrValues config.settings); + description = '' + lazy-loading for ${originalName} ''; + }; - # Spec loading: - enabled = mkStrLuaFnOr types.bool (lazyLoadDefaults.enabledInSpec or null) '' - When false, or if the function returns false, then ${originalName} will not be included in the spec. + settings = lib.mkOption { + description = ''''; + default = { }; + type = + with types; + submodule { + freeformType = attrsOf anything; + options = { + # Spec loading: + enabled = mkStrLuaFnOr types.bool null '' + When false, or if the function returns false, then ${originalName} will not be included in the spec. - Equivalence: lz.n => enabled; lazy.nvim => enabled - ''; + Equivalence: lz.n => enabled; lazy.nvim => enabled + ''; - priority = mkNullable types.number (lazyLoadDefaults.priority or null) '' - Only useful for start plugins (not lazy-loaded) to force loading certain plugins first. + priority = mkNullable types.number null '' + Only useful for start plugins (not lazy-loaded) to force loading certain plugins first. - Equivalence: lz.n => priority; lazy.nvim => priority - ''; + Equivalence: lz.n => priority; lazy.nvim => priority + ''; - # Spec setup - # Actions - beforeAll = mkLuaFn (lazyLoadDefaults.beforeAll or null) '' - Always executed before any plugins are loaded. + # Spec setup + # Actions + beforeAll = mkLuaFn null '' + Always executed before any plugins are loaded. - Equivalence: lz.n => beforeAll; lazy.nvim => init - ''; + Equivalence: lz.n => beforeAll; lazy.nvim => init + ''; - before = mkLuaFn (lazyLoadDefaults.before or null) '' - Executed before ${originalName} is loaded. + before = mkLuaFn null '' + Executed before ${originalName} is loaded. - Equivalence: lz.n => before; lazy.nvim => None - ''; + Equivalence: lz.n => before; lazy.nvim => None + ''; - after = mkLuaFn (lazyLoadDefaults.after or null) '' - Executed after ${originalName} is loaded. + after = mkLuaFn null '' + Executed after ${originalName} is loaded. - Equivalence: lz.n => after; lazy.nvim => config - ''; + Equivalence: lz.n => after; lazy.nvim => config + ''; - # Triggers - event = mkNullable triggerType (lazyLoadDefaults.event or null) '' - Lazy-load on event. Events can be specified as `BufEnter` or with a pattern like `BufEnter *.lua` + # Triggers + event = mkNullable triggerType null '' + Lazy-load on event. Events can be specified as `BufEnter` or with a pattern like `BufEnter *.lua` - Equivalence: lz.n => event; lazy.nvim => event - ''; + Equivalence: lz.n => event; lazy.nvim => event + ''; - cmd = mkNullable triggerType (lazyLoadDefaults.cmd or null) '' - Lazy-load on command. + cmd = mkNullable triggerType null '' + Lazy-load on command. - Equivalence: lz.n => cmd; lazy.nvim => cmd - ''; + Equivalence: lz.n => cmd; lazy.nvim => cmd + ''; - ft = mkNullable triggerType (lazyLoadDefaults.ft or null) '' - Lazy-load on filetype. + ft = mkNullable triggerType null '' + Lazy-load on filetype. - Equivalence: lz.n => ft; lazy.nvim => ft - ''; + Equivalence: lz.n => ft; lazy.nvim => ft + ''; - keys = mkListOf (types.attrsOf types.anything) (lazyLoadDefaults.keys or null) '' - Lazy-load on key mapping. + keys = mkListOf (types.attrsOf types.anything) null '' + Lazy-load on key mapping. - Equivalence: lz.n => keys; lazy.nvim => keys - ''; + Equivalence: lz.n => keys; lazy.nvim => keys + ''; - colorscheme = mkNullable triggerType (lazyLoadDefaults.colorscheme or null) '' - Lazy-load on colorscheme. + colorscheme = mkNullable triggerType null '' + Lazy-load on colorscheme. - Equivalence: lz.n => colorscheme; lazy.nvim => None - ''; - - extraSettings = mkSettingsOption { - description = '' - Extra settings to pass to the lazy loader backend. - ''; - example = { - dependencies = { - __unkeyed-1 = "nvim-lua/plenary.nvim"; - lazy = true; - }; + Equivalence: lz.n => colorscheme; lazy.nvim => None + ''; + }; + }; }; }; - }; - }; - default = lazyLoadDefaults; + } + ); }; } // removed diff --git a/tests/test-sources/plugins/lazy-load.nix b/tests/test-sources/plugins/lazy-load.nix index 0044a5c7..98cfb7bd 100644 --- a/tests/test-sources/plugins/lazy-load.nix +++ b/tests/test-sources/plugins/lazy-load.nix @@ -1,6 +1,6 @@ { - lazy-load-neovim-plugin = - { config, ... }: + lazy-load-neovim-plugin-configured = + { config, lib, ... }: { plugins = { lz-n = { @@ -11,13 +11,15 @@ enable = true; lazyLoad = { enable = true; - keys = [ - { - __unkeyed-1 = "nt"; - __unkeyed-3 = "Neotest summary"; - desc = "Summary toggle"; - } - ]; + settings = { + keys = [ + { + __unkeyed-1 = "nt"; + __unkeyed-3 = "Neotest summary"; + desc = "Summary toggle"; + } + ]; + }; }; }; }; @@ -30,22 +32,31 @@ { assertion = let - plugin = builtins.head config.plugins.lz-n.plugins; - keys = if builtins.isList plugin.keys then plugin.keys else [ ]; + plugins = config.plugins.lz-n.plugins or [ ]; + plugin = if builtins.length plugins > 0 then builtins.head plugins else null; + keys = if plugin != null && builtins.isList plugin.keys then plugin.keys else [ ]; in (builtins.length keys) == 1; message = "`lz-n.plugins[0].keys` should have contained a configuration."; } + { + assertion = + let + plugins = config.plugins.lz-n.plugins or [ ]; + plugin = if builtins.length plugins > 0 then builtins.head plugins else null; + in + plugin != null && lib.hasInfix config.plugins.neotest.luaConfig.content plugin.after.__raw; + message = "`lz-n.plugins[0].after` should have contained `neotest` lua content."; + } ]; }; - lazy-load-lz-n = - { config, ... }: + lazy-load-lz-n-configured = + { config, lib, ... }: { plugins = { codesnap = { enable = true; - lazyLoad.enable = true; }; lz-n = { enable = true; @@ -109,7 +120,7 @@ let plugin = builtins.head config.plugins.lz-n.plugins; in - "`lz-n.plugins[0].keys` should have contained 4 key configurations, but contained ${builtins.toJSON (plugin.keys)}"; + "`lz-n.plugins[0].keys` should have contained 4 key configurations, but contained ${builtins.toJSON plugin.keys}"; } { assertion = @@ -122,7 +133,171 @@ let plugin = builtins.head config.plugins.lz-n.plugins; in - "`lz-n.plugins[0].cmd` should have contained 4 cmd configurations, but contained ${builtins.toJSON (plugin.cmd)}"; + "`lz-n.plugins[0].cmd` should have contained 4 cmd configurations, but contained ${builtins.toJSON plugin.cmd}"; + } + { + assertion = + let + plugin = builtins.head config.plugins.lz-n.plugins; + in + lib.hasInfix config.plugins.codesnap.luaConfig.content plugin.after.__raw; + message = "`lz-n.plugins[0].after` should have contained `codesnap` lua content."; + } + ]; + }; + + dont-lazy-load-colorscheme-automatically = + { config, ... }: + { + colorschemes.catppuccin.enable = true; + plugins = { + lz-n = { + enable = true; + }; + }; + + assertions = [ + { + assertion = (builtins.length config.plugins.lz-n.plugins) == 0; + message = "`lz-n.plugins` should have contained no plugin configuration, but contained ${builtins.toJSON config.plugins.lz-n.plugins}"; + } + ]; + }; + + dont-lazy-load-unconfigured = + { config, ... }: + { + plugins = { + neotest = { + enable = true; + # Empty attrset shouldn't trigger lazy loading + lazyLoad = { }; + }; + lz-n = { + enable = true; + }; + }; + + assertions = [ + { + assertion = (builtins.length config.plugins.lz-n.plugins) == 0; + message = "`lz-n.plugins` should have contained no plugin configuration, but contained ${builtins.toJSON config.plugins.lz-n.plugins}"; + } + ]; + }; + + lazy-load-colorscheme-properly = + { config, lib, ... }: + { + colorschemes.catppuccin = { + enable = true; + lazyLoad.enable = true; + }; + + plugins = { + lz-n = { + enable = true; + }; + }; + + assertions = [ + { + assertion = (builtins.length config.plugins.lz-n.plugins) == 1; + message = "`lz-n.plugins` should have contained no plugin configuration, but contained ${builtins.toJSON config.plugins.lz-n.plugins}"; + } + { + assertion = + let + plugin = builtins.head config.plugins.lz-n.plugins; + in + plugin.colorscheme == "catppuccin"; + message = + let + plugin = builtins.head config.plugins.lz-n.plugins; + in + "`lz-n.plugins[0].colorscheme` should have been `catppuccin`, but contained ${builtins.toJSON plugin.colorscheme}"; + } + { + assertion = + let + plugin = builtins.head config.plugins.lz-n.plugins; + in + lib.hasInfix config.colorschemes.catppuccin.luaConfig.content plugin.after.__raw; + message = "`lz-n.plugins[0].after` should have contained `catppuccin` lua content."; + } + ]; + }; + + lazy-load-enabled-automatically = + { config, ... }: + { + plugins = { + lz-n = { + enable = true; + }; + neotest = { + enable = true; + lazyLoad = { + # Not setting lazyLoad.enable with configuration should enable + settings = { + keys = [ + { + __unkeyed-1 = "nt"; + __unkeyed-3 = "Neotest summary"; + desc = "Summary toggle"; + } + ]; + }; + }; + }; + }; + + assertions = [ + { + assertion = (builtins.length config.plugins.lz-n.plugins) == 1; + message = "`lz-n.plugins` should have contained a single plugin configuration, but contained ${builtins.toJSON config.plugins.lz-n.plugins}"; + } + { + assertion = + let + plugins = config.plugins.lz-n.plugins or [ ]; + plugin = if builtins.length plugins > 0 then builtins.head plugins else null; + keys = if plugin != null && builtins.isList plugin.keys then plugin.keys else [ ]; + in + (builtins.length keys) == 1; + message = "`lz-n.plugins[0].keys` should have contained a configuration."; + } + ]; + }; + + wrap-functionless-luaConfig = + { config, ... }: + { + plugins = { + lz-n = { + enable = true; + }; + web-devicons.enable = false; + telescope = { + enable = true; + lazyLoad = { + enable = true; + }; + }; + }; + + assertions = [ + { + assertion = (builtins.length config.plugins.lz-n.plugins) == 1; + message = "`lz-n.plugins` should have contained a single plugin configuration, but contained ${builtins.toJSON config.plugins.lz-n.plugins}"; + } + { + assertion = + let + plugin = builtins.head config.plugins.lz-n.plugins; + in + plugin.after.__raw == "function()\n " + config.plugins.telescope.luaConfig.content + " \nend"; + message = "`lz-n.plugins[0].after` should have contained a function wrapped `telescope` lua content."; } ]; };