478 lines
13 KiB
Nix
478 lines
13 KiB
Nix
{version}: {
|
|
mkNeovimPkg = {
|
|
pkgs,
|
|
package ? pkgs.neovim-unwrapped,
|
|
namePrefix ? "",
|
|
nameSuffix ? "",
|
|
dependencies ? [],
|
|
dependenciesExtraArgs ? {},
|
|
runtime ? {},
|
|
...
|
|
}: let
|
|
inherit (builtins) isPath;
|
|
inherit (pkgs) lib vimUtils;
|
|
callPackage = lib.callPackageWith (pkgs // dependenciesExtraArgs);
|
|
inherit (lib.lists) concatMap filter foldl' map optional reverseList;
|
|
inherit (lib.attrsets) attrNames optionalAttrs;
|
|
inherit (lib.strings) concatStringsSep fileContents hasSuffix removePrefix removeSuffix replaceStrings;
|
|
inherit (lib.sources) sourceByRegex;
|
|
# inherit (lib.debug) traceIf traceSeq traceVal traceValSeq traceValFn;
|
|
|
|
remotePluginToNeovimPlugin = p:
|
|
vimUtils.buildVimPlugin rec {
|
|
inherit (p) src name;
|
|
pname = name;
|
|
};
|
|
|
|
defaultPlugin = {
|
|
enabled = true;
|
|
init = null;
|
|
config = null;
|
|
};
|
|
|
|
withPluginDefaults = dep: defaultPlugin // dep;
|
|
normalizePlugin = dep: let
|
|
p =
|
|
if ! dep ? plugin
|
|
then {plugin = dep;}
|
|
else let
|
|
inherit (dep) plugin;
|
|
in
|
|
if attrNames plugin == ["name" "src"]
|
|
then {plugin = remotePluginToNeovimPlugin plugin;}
|
|
else dep;
|
|
in
|
|
withPluginDefaults p;
|
|
normalizeOrImportPlugin = dep:
|
|
if isPath dep
|
|
then normalizePlugins (callPackage dep {})
|
|
else [(normalizePlugin dep)];
|
|
normalizePlugins = concatMap normalizeOrImportPlugin;
|
|
|
|
wrapLuaInFunction = section: lua: ''
|
|
-- begin ${section}
|
|
(function()
|
|
${removeSuffix "\n" lua}
|
|
end)();
|
|
-- end ${section}
|
|
'';
|
|
|
|
getLua = type: p: let
|
|
pluginName =
|
|
if p.plugin ? name
|
|
then p.plugin.name
|
|
else baseNameOf p.plugin;
|
|
|
|
content = p.${type};
|
|
|
|
textContent =
|
|
if isPath content
|
|
then fileContents content
|
|
else content;
|
|
in
|
|
optional (! isNull content)
|
|
(wrapLuaInFunction "${type} for ${pluginName}" textContent);
|
|
|
|
getAllLua = type:
|
|
concatStringsSep "\n"
|
|
(concatMap (getLua type) plugins);
|
|
|
|
neoflake.plugin = vimUtils.buildVimPlugin {
|
|
inherit version;
|
|
pname = "neoflake";
|
|
src = ./lua/neoflake;
|
|
buildPhase = ''
|
|
dir=lua/neoflake
|
|
mkdir -p $dir
|
|
mv init.lua $dir
|
|
|
|
cat <<'LUA' > $dir/initialize.lua
|
|
return function ()
|
|
${getAllLua "init"}
|
|
end
|
|
LUA
|
|
|
|
cat <<'LUA' > $dir/config.lua
|
|
return function()
|
|
${getAllLua "config"}
|
|
end
|
|
LUA
|
|
'';
|
|
};
|
|
|
|
runtimePlugin.plugin = vimUtils.buildVimPlugin ({
|
|
inherit (runtime) src;
|
|
}
|
|
// (optionalAttrs (isNull runtime.version) {
|
|
name = "runtime";
|
|
})
|
|
// (optionalAttrs (! isNull runtime.version) {
|
|
inherit (runtime) version;
|
|
pname = "runtime";
|
|
}));
|
|
|
|
plugins = normalizePlugins (dependencies ++ [runtimePlugin neoflake]);
|
|
|
|
extractPlugin = map (p: p.plugin);
|
|
|
|
customRC = let
|
|
rc =
|
|
if runtime ? init
|
|
then runtime.init
|
|
else "";
|
|
in
|
|
if isPath rc
|
|
then lib.fileContents rc
|
|
else rc;
|
|
|
|
neovimConfig =
|
|
pkgs.neovimUtils.makeNeovimConfig {
|
|
inherit customRC;
|
|
plugins = extractPlugin plugins;
|
|
}
|
|
// {
|
|
luaRcContent = customRC;
|
|
};
|
|
pkg = pkgs.wrapNeovimUnstable package (removeAttrs neovimConfig ["manifestRc" "neovimRcContent"]);
|
|
# TODO nameSuffix is buggy :'(
|
|
name = "${namePrefix}${pkg.name}${nameSuffix}";
|
|
in
|
|
pkg // {inherit name;};
|
|
|
|
sourcesWith = path: paths: let
|
|
samePath = a: let a' = builtins.toString a; in b: a' == builtins.toString b;
|
|
isRoot = samePath "/";
|
|
isInPath = path: subPath:
|
|
if isRoot subPath
|
|
then false
|
|
else (samePath path subPath) || (isInPath path (builtins.dirOf subPath));
|
|
filter = src: _type: builtins.any (includePath: isInPath includePath src) paths;
|
|
in
|
|
builtins.path {
|
|
inherit path filter;
|
|
};
|
|
|
|
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;
|
|
};
|
|
};
|
|
}
|