sloth-flake.nvim/lib/modules/plugin/default.nix

254 lines
7.1 KiB
Nix

{
pkgs,
callModule,
...
}: let
inherit (builtins) concatMap elemAt isPath length pathExists readDir;
inherit
(pkgs.lib)
assertMsg
attrsToList
concatStringsSep
fileContents
fix
hasSuffix
literalExample
mergeAttrsList
mkOption
optional
optionalAttrs
pipe
removeSuffix
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;
findLuaRequire = plugin: let
luaDir = "${plugin.plugin}/lua";
readOptionalDir = dir: optionalAttrs (pathExists dir) (readDir dir);
convertPath = attr:
if attr.value == "directory"
then optional (pathExists "${luaDir}/${attr.name}/init.lua") attr.name
else optional (hasSuffix ".lua" attr.name) (removeSuffix ".lua" attr.name);
requireNames = pipe plugin.plugin [
(path: "${path}/lua")
readOptionalDir
attrsToList
(concatMap convertPath)
];
in
if length requireNames == 1
then elemAt requireNames 0
else null;
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
assert assertMsg (with plugin; hasSetup -> hasLuaRequire) (concatStringsSep " " [
''Solth is unable to find the lib to require for plugin "${name}".''
''Either specify it with `luaRequire = "plugin-name";` or call setup''
''in a config option: `config = "require('plugin-name').setup { ... }";`.''
]);
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;})
(optionalAttrs hasLuaRequire {inherit luaRequire;})
(optionalAttrs hasSetup {inherit setup;})
]));
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:<str>, src:<source>})?
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";
hasSetup = mkROBoolOption (config.setup != null) "setup";
hasLuaRequire = mkROBoolOption (config.luaRequire != null) "luaRequire";
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.
'';
};
luaRequire = mkOption {
type = with types; nullOr str;
default = findLuaRequire config;
description = ''
Name of the lua module to require.
An heuristic should find it, but may fail sometimes.
'';
};
setup = mkOption {
type = with types; nullOr (attrsOf anything);
default = null;
description = ''
Option to pass the the setup function.
Will call `require("''${config.luaRequire}").setup(''${toLua config.setup})`.
'';
};
# 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;
};
})