lazy.nvim.nix/pkgs/lazyUtils.nix

278 lines
8.4 KiB
Nix

{
lib,
pkgs,
vPlug ? pkgs.vimPlugins,
luaUtils ? import ./luaUtils { inherit lib pkgs; },
}:
let
helpers = rec {
/**
Determines the name of a plugin.
Priority:
1. plugin.name
2. baseNameOf plugin.short
3. (derivation) plugin.dir.pname
3. (path) baseNameOf plugin.dir
Type:
getName :: Plugin -> String
*/
getName =
plugin:
if (plugin ? name && plugin.name != null) then
assert builtins.isString plugin.name;
plugin.name
else if (plugin ? short && plugin.short != null) then
assert builtins.isString plugin.short;
# TODO: Check how lazy handles this normally
baseNameOf plugin.short
else if (plugin ? dir && plugin.dir != null) then
(
assert builtins.any (isType: isType plugin.dir) [
lib.isDerivation
builtins.isString
builtins.isPath
];
if (lib.isDerivation plugin.dir) then plugin.dir.pname else (baseNameOf plugin.dir)
)
else
throw "Could not determine a plugin name.\n${builtins.toJSON plugin}";
/**
Transforms a set describing a keybind into a list (lazy-key).
Takes a set containing:
- bind: (string) the key to bind
- cmd: (optional string) the command to execute
- cmdIsFunction: (optional bool) interpret cmd as a function instead of a string
- opts: (optional set) the option set
For further information on the opts argument take a look at the lazy.nvim LazyKeysSpec definition.
Type:
getKey :: Set -> List
*/
getKey =
{
bind,
cmd ? null,
cmdIsFunction ? false,
opts ? null,
}:
assert builtins.isString bind;
assert builtins.isNull cmd || builtins.isString cmd;
assert builtins.isBool cmdIsFunction;
assert builtins.isNull opts || builtins.isAttrs opts;
lib.filter (option: !builtins.isNull option) [
bind
(if (cmdIsFunction == true) && (builtins.isString cmd) then (_: cmd) else cmd)
(if builtins.isAttrs opts then opts // { __unpack = true; } else null)
];
/**
Helper function to ensure a plugin input is correctly wrapped.
Correct inputs are:
- short plugin url (string)
- a plugin package (derivation)
- plugin (set)
Type:
pluginWrapper :: (Lambda -> String) -> Set
pluginWrapper :: (Lambda -> Derivation) -> Set
pluginWrapper :: (Lambda -> Set) -> Set
pluginWrapper :: String -> Set
pluginWrapper :: Derivation -> Set
pluginWrapper :: Set -> Set
*/
pluginWrapper =
pluginOrPackage:
if (builtins.isString pluginOrPackage) then
{ short = pluginOrPackage; }
else if
assert (builtins.isAttrs pluginOrPackage || builtins.isFunction pluginOrPackage);
(lib.isDerivation pluginOrPackage || builtins.isFunction pluginOrPackage)
then
{
dir = pluginOrPackage;
}
else
pluginOrPackage;
/**
Transforms plugin inputs into
Valid plugin attributes are:
- short, dir, url, name, dev, lazy, enabled, cond, dependencies, init, opts, config, main, build, branch, tag, commit, version, pin, submodules, event, cmd, ft, keys, module, priority, optional
Type:
pluginNormalize :: Set -> Set
*/
pluginNormalize =
pluginOrPackage:
let
plugin = pluginWrapper pluginOrPackage;
runIfSet =
fn: key:
let
val = if (plugin ? "${key}") then plugin."${key}" else null;
in
if (builtins.isNull val) then val else fn val;
# Wrap function arguments in function so they are inserted as is when parsed.
stringLiteral = value: if (builtins.isString value) then (_: value) else value;
resolvePlugin = value: if (builtins.isFunction value) then value vPlug else value;
in
lib.pipe plugin [
# Resolve dir and dependencies first so getName can resolve names
(
plugin:
plugin
// {
dir = runIfSet resolvePlugin "dir";
dependencies = runIfSet (
pluginListFn:
(map (pluginOrPackage: getName (pluginWrapper pluginOrPackage))) (resolvePlugin pluginListFn)
) "dependencies";
}
)
(
plugin:
plugin
// {
__posArgs = runIfSet lib.flatten "short";
name = getName plugin;
enabled = runIfSet stringLiteral "enabled";
cond = runIfSet stringLiteral "cond";
init = runIfSet stringLiteral "init";
opts = runIfSet stringLiteral "opts";
config = runIfSet stringLiteral "config";
build = runIfSet stringLiteral "build";
cmd = runIfSet stringLiteral "cmd";
ft = runIfSet stringLiteral "ft";
keys = runIfSet (map getKey) "keys";
}
)
# Remove unused attributes
(lib.filterAttrs (key: value: !builtins.isNull value))
# short is a positional argument so it has do be removed
(plugin: builtins.removeAttrs plugin [ "short" ])
];
};
in
rec {
inherit helpers;
/**
Takes a plugin definition normalizes it and convets it into Lua.
Returns only the plugin table so it can be inlined.
Type:
lazyPluginClosure :: String -> String
lazyPluginClosure :: Derivation -> String
lazyPluginClosure :: Set -> String
*/
lazyPluginClosure = plugin: luaUtils.setToLua (helpers.pluginNormalize plugin);
/**
Takes a plugin definition normalizes it and convets it into Lua.
Wraps the result of lazyPluginClosure and adds a return statement in front of it.
Type:
lazyPluginFile :: String -> String
lazyPluginFile :: Derivation -> String
lazyPluginFile :: Set -> String
*/
lazyPluginFile =
plugin: # lua
''return ${lazyPluginClosure plugin}'';
/**
Takes a plugin and passes it to lazyPluginFile.
The output is formatted and written to "lua/lazyWrapper/plugins/${name}"
Note: ${name} is the Plugin name but all '.' are replaced with '-'.
Type:
writeLazyPluginDir :: String -> Derivation
writeLazyPluginDir :: Derivation -> Derivation
writeLazyPluginDir :: Set -> Derivation
*/
writeLazyPluginDir =
plugin:
let
normalizedPlugin = helpers.pluginNormalize plugin;
name = lib.replaceStrings [ "." ] [ "-" ] normalizedPlugin.name;
in
luaUtils.writeLuaFileDir "lua/lazyWrapper/plugins/${name}" ''return ${luaUtils.setToLua normalizedPlugin}'';
/**
Builds and configures the lazy plugin directory.
Takes a set containing:
- lazyPlugins: (list) the list of plugins to link
- lazyConfig: (set) lazy config attributes
Type:
lazyPluginsJoin :: Set -> Derivation
*/
lazyPluginsJoin =
{
lazyPlugins ? [ ],
lazyConfig ? { },
}:
let
init = lazyLuaInit {
inherit lazyConfig;
hasPlugins = (lib.length lazyPlugins > 0);
};
in
pkgs.symlinkJoin {
name = "nvim-lazy-plugins";
paths = [ init ] ++ (map (plugin: writeLazyPluginDir plugin) lazyPlugins);
};
/**
Generates the init function for nvim.lazy.
Takes a set containing:
- lazyConfig: (set) lazy config attributes
- hasPlugins: (bool) will not load any plugins if set to false
Type:
lazyLuaInit :: Set -> Derivation
*/
lazyLuaInit =
{
lazyConfig ? { },
hasPlugins ? false,
}:
let
lazyBaseConfig = {
checker = {
notify = false;
};
change_detection = {
enabled = false;
notify = false;
};
performance = {
# TODO: Check if this is really needed
reset_packpath = false;
rtp = {
reset = false;
};
};
};
in
pkgs.writeTextDir "lua/lazyWrapper/init.lua" # lua
''
vim.opt.rtp:prepend("${vPlug.lazy-nvim}")
require("lazy").setup(
${
# Plugin import on an empty/non existent directory causes an error
# Only specify import path if there are plugins to load
if hasPlugins then ''"lazyWrapper.plugins"'' else "{}"
}
, ${
# Merge defaults with user config and generate the lua table
luaUtils.setToLua (lib.recursiveUpdate lazyBaseConfig lazyConfig)
} )
'';
}