{ pkgs, callModule, ... }: let inherit (builtins) isPath; inherit (pkgs.lib) fileContents fix literalExample mergeAttrsList mkOption optionalAttrs types; lua = callModule ../../lua.nix {}; modules = { keymap = callModule ./keymap.nix {}; event = callModule ./event.nix {}; }; coercePkgToPlugin = pkg: { plugin = pkg; }; mkROBoolOption = default: description: mkOption { type = types.bool; inherit default; readOnly = true; description = '' Wether this plugin has ${description}. ''; }; textOrContent = content: if isPath content then fileContents content else content; getPluginName = plugin: plugin.pname or plugin.name; mkLuaDefinition = plugin: let mkTypeFn = type: let content = textOrContent plugin.${type}; in optionalAttrs (! isNull plugin.${type}) { ${type} = with lua; lambda [] (raw content); }; name = getPluginName plugin.plugin; in mergeAttrsList ([ { inherit name; dependencies = map getPluginName plugin.dependencies; } (mkTypeFn "init") (mkTypeFn "config") ] ++ (with plugin; [ (optionalAttrs lazy {lazy = true;}) (optionalAttrs hasCommands {inherit cmd;}) (optionalAttrs hasFileTypes {inherit ft;}) (optionalAttrs hasEvents {inherit events;}) (optionalAttrs hasKeymaps {inherit keymaps;}) ])); in fix (self: { module = types.submodule ({config, ...}: { options = { init = mkOption { type = with types; nullOr (either path str); default = null; description = '' The init configuration of your plugin. This will be called before loading your plugin. ''; }; config = mkOption { type = with types; nullOr (either path str); default = null; description = '' The configuration of your plugin. This will be called after loading your plugin. ''; }; optional = mkOption { type = types.bool; default = config.lazy || config.init != null; example = true; }; plugin = mkOption { # TODO Type should allow old `basicPluginType` ({name:, src:})? type = with types; nullOr package; default = null; description = '' Ensure thoses plugins are loaded before the current one ''; }; dependencies = mkOption { type = with types; listOf package; default = []; description = '' Ensure thoses plugins are loaded before the current one ''; }; extraLuaPackages = mkOption { type = with types; functionTo (listOf package); example = literalExample "p: [p.nvim-nio]"; defaultText = literalExample "_: []"; default = _: []; description = '' Ensure those packages are available ''; }; cmd = mkOption { type = with types; listOf str; default = []; description = '' List of commands on which the plugin should be loaded ''; }; ft = mkOption { type = with types; listOf str; default = []; description = '' List of filetypes on which the plugin should be loaded ''; }; keymaps = modules.keymap.option; events = modules.event.option; hasCommands = mkROBoolOption (config.cmd != []) "declared commands"; hasFileTypes = mkROBoolOption (config.ft != []) "file types"; hasKeymaps = mkROBoolOption (config.keymaps != []) "keymaps"; hasEvents = mkROBoolOption (config.events != []) "events"; lazy = mkOption { type = types.bool; default = with config; hasCommands || hasFileTypes || hasEvents || hasKeymaps; example = true; description = '' Whether to enable loading lazily the plugin. ''; }; pluginName = mkOption { type = types.str; readOnly = true; internal = true; default = getPluginName config.plugin; description = '' Name of the plugin. ''; }; luaDefinition = mkOption { type = with types; attrsOf anything; readOnly = true; internal = true; default = mkLuaDefinition config; description = '' Lua definition of the plugin. ''; }; # priority = mkOption { # type = types.int; # default = []; # description = '' # Priority of the module. Influence the order of loading plugins. # Highest values get loaded before. # ''; # }; }; }); option = mkOption { description = '' List of plugins to enable in this installation ''; type = with types; listOf (coercedTo package coercePkgToPlugin self.module); default = []; }; extract = plugin: { inherit (plugin) plugin optional; }; })