sloth-flake.nvim/lib.nix

325 lines
8.7 KiB
Nix

{...}: {
mkNeovimModule = {
pluginsDir ? null,
attrName ? "neoflake",
self,
}: {
config,
lib,
pkgs,
...
}: let
cfg = config.${attrName};
inherit (builtins) baseNameOf isPath;
inherit (lib) mkEnableOption mkIf mkOption types;
# inherit (lib.debug) traceIf traceSeq traceVal traceValSeq traceValFn;
inherit (lib.attrsets) attrNames optionalAttrs;
inherit (lib.lists) concatMap filter foldl' map optional reverseList;
inherit (lib.strings) concatStringsSep fileContents hasSuffix removePrefix removeSuffix replaceStrings;
hm-file-type = import ./hm-file-type.nix {
inherit (config.home) homeDirectory;
inherit lib pkgs;
};
inherit (hm-file-type) fileTypeSubmodule;
verbatimSubmodule = types.submodule {
options = {
path = mkOption {
description = "path to copy from. Must be included in the flake folder.";
type = types.path;
};
dest = mkOption {
description = "dest into `.config/nvim`.";
type = types.str;
};
};
};
remotePluginConfig = types.addCheck (types.submodule {
options = {
name = mkOption {
type = types.str;
};
src = mkOption {
type = types.path;
};
};
}) (mod: attrNames mod == ["name" "src"]);
pluginWithConfigType = types.submodule {
options = {
enabled =
mkEnableOption "enabled"
// {
description = ''
Whether this plugin should be enabled. This option allows specific
plugins to be disabled.
'';
default = true;
};
init = mkOption {
type = types.nullOr (fileTypeSubmodule "${attrName}.plugins._.init" "{var}`xdg.configHome/nvim`" "nvim");
description = "Script to init this plugin. Run before plugin load.";
default = null;
};
config = mkOption {
type = types.nullOr (fileTypeSubmodule "${attrName}.plugins._.config" "{var}`xdg.configHome/nvim`" "nvim");
description = "Script to configure this plugin. Run after plugin load.";
default = null;
};
main = mkOption {
type = with types; nullOr str;
description = "Name of the main module to load.";
default = null;
};
## Lazy options
lazy = mkOption {
type = types.bool;
description = "Should this plugin be load lazily ?";
default = false;
};
events = mkOption {
type = with types; listOf str;
description = "List of events on which the plugin should be loaded";
default = [];
};
commands = mkOption {
type = with types; listOf str;
description = "List of commands on which the plugin should be loaded";
default = [];
};
filetypes = mkOption {
type = with types; listOf str;
description = "List of filetypes on which the plugin should be loaded";
default = [];
};
keys = mkOption {
type = with types; listOf str;
description = "List of keystrokes on which the plugin should be loaded";
default = [];
};
priority = mkOption {
type = with types; listOf str;
description = ''
Priority of the module. Influence the order of loading plugins.
Highest values get loaded before.
'';
default = [];
};
dependencies = mkOption {
# Should we accept strings?
# type = with types; listOf (either strings package);
type = with types; listOf package;
description = ''
Give the list of packages that should be loaded before the current one.
'';
};
plugin = mkOption {
type = with types; oneOf [path remotePluginConfig package];
description = "The actual vim plugin package to load";
};
};
};
hasNixSuffix = hasSuffix ".nix";
pluginNixFiles =
if isNull pluginsDir
then []
else filter hasNixSuffix (lib.fileset.toList pluginsDir);
pathToNeovimPlugin = src: let
normalizeName = replaceStrings ["."] ["-"];
in
pkgs.vimUtils.buildVimPlugin rec {
inherit src;
pname = normalizeName (baseNameOf src);
name = pname;
};
remotePluginToNeovimPlugin = p:
pkgs.vimUtils.buildVimPlugin rec {
inherit (p) src name;
pname = name;
};
mkPlugin = plugin:
if plugin ? plugin
then let
p = plugin.plugin;
in
if isPath p
then pathToNeovimPlugin p
else if attrNames p == ["name" "src"]
then remotePluginToNeovimPlugin p
else p
else plugin;
in {
# imports = map wrapImport pluginNixFiles;
imports = pluginNixFiles;
options.${attrName} = {
enable = mkEnableOption "${attrName} module";
plugins = mkOption {
description = "List all plugins to load";
type = with types; listOf (oneOf [package pluginWithConfigType]);
};
includesVerbatim = mkOption {
description = "Includes files as is in final .config/nvim.";
type = with types; listOf (either path verbatimSubmodule);
default = [];
};
defaultConfig = {
enable = mkOption {
description = "generate default configuration";
type = types.bool;
default = true;
};
};
};
config = let
defaultPlugin = {
enabled = true;
init = null;
config = null;
};
wrapIfNeeded = p:
if p ? plugin
then p
else {plugin = p;};
normalizedPlugins = map (p: defaultPlugin // (wrapIfNeeded p)) cfg.plugins;
getText = submodule:
if ! isNull submodule.text
then submodule.text
else fileContents submodule.source;
wrapLuaInFunction = section: lua: ''
-- begin ${section}
(function()
${removeSuffix "\n" lua}
end)();
-- end ${section}
'';
pluginName = p:
if p.plugin ? name
then p.plugin.name
else baseNameOf p.plugin;
getInitText = p:
optional (!(isNull p.init))
(wrapLuaInFunction "init for ${pluginName p}" (getText p.init));
getConfigText = p:
optional (!(isNull p.config))
(wrapLuaInFunction "config for ${pluginName p}" (getText p.config));
initLua =
concatStringsSep "\n"
(concatMap getInitText normalizedPlugins);
configLua =
concatStringsSep "\n"
(concatMap getConfigText normalizedPlugins);
pathToString = filePath: let
keyName = key: {
inherit key;
name = baseNameOf key;
};
list = map (n: n.name) (builtins.genericClosure {
startSet = [(keyName filePath)];
operator = item: let
parent = dirOf item.key;
in [(keyName parent)];
});
in
concatStringsSep "/" (reverseList list);
normalizeVerbatim = def:
if def ? path && def ? dest
then def
else if ! isPath def
then abort "Not a path nor a verbatim"
else let
fileStr = pathToString def;
root = pathToString self.outPath;
in {
path = def;
dest = removePrefix (root + "/") fileStr;
};
normalizedVerbatim = map normalizeVerbatim cfg.includesVerbatim;
verbatimFiles =
foldl'
(memo: verbatim:
memo
// {
"nvim/${verbatim.dest}" = {
source = verbatim.path;
recursive = true;
};
}) {}
normalizedVerbatim;
neoflakeFiles = let
prefix = "nvim/lua/neoflake";
in {
${prefix} = {
source = ./lua/neoflake;
recursive = true;
};
"${prefix}/initialize.lua".text = ''
return function ()
${initLua}
end
'';
"${prefix}/config.lua".text = ''
return function ()
${configLua}
end
'';
};
defaultConfig = optionalAttrs cfg.defaultConfig.enable {
"nvim/init.lua".source = ./lua/default_init.lua;
};
in
mkIf cfg.enable {
programs.neovim = {
enable = true;
vimAlias = true;
viAlias = true;
defaultEditor = true;
withPython3 = true;
withNodeJs = true;
plugins = map mkPlugin cfg.plugins;
};
xdg.configFile =
verbatimFiles
// neoflakeFiles
// defaultConfig;
};
};
}