feat: check inputs of functions with yants

main
LeMarsu 2024-05-27 01:04:24 +02:00
parent ce89ae854a
commit 8584d08802
8 changed files with 323 additions and 480 deletions

View File

@ -149,12 +149,28 @@
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1660438583,
"narHash": "sha256-rJUTYxFKlWUJI3njAwEc1pKAVooAViZGJvsgqfh/q/E=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "bbd8f7cd87d0b29294ef3072ffdbd61d60f05da4",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"root": {
"inputs": {
"alejandra": "alejandra",
"nil": "nil",
"nixpkgs": "nixpkgs_2",
"utils": "utils"
"utils": "utils",
"yants": "yants"
}
},
"rust-analyzer-src": {
@ -247,6 +263,24 @@
"repo": "flake-utils-plus",
"type": "github"
}
},
"yants": {
"inputs": {
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1686863218,
"narHash": "sha256-kooxYm3/3ornWtVBNHM3Zh020gACUyFX2G0VQXnB+mk=",
"owner": "divnix",
"repo": "yants",
"rev": "8f0da0dba57149676aa4817ec0c880fbde7a648d",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "yants",
"type": "github"
}
}
},
"root": "root",

View File

@ -5,6 +5,7 @@
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
utils.url = "github:gytis-ivaskevicius/flake-utils-plus/v1.4.0";
nil.url = "github:oxalica/nil";
yants.url = "github:divnix/yants";
alejandra = {
url = "github:kamadorueda/alejandra/3.0.0";
inputs.nixpkgs.follows = "nixpkgs";
@ -13,9 +14,10 @@
outputs = {
self,
alejandra,
nixpkgs,
utils,
alejandra,
yants,
...
} @ inputs: let
versionFile = builtins.replaceStrings ["\n"] [""] (builtins.readFile ./VERSION);
@ -36,6 +38,6 @@
};
};
lib = import ./lib.nix {inherit version;};
lib = import ./lib {inherit version yants;};
};
}

477
lib.nix
View File

@ -1,477 +0,0 @@
{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);
sloth-flake.plugin = vimUtils.buildVimPlugin {
inherit version;
pname = "sloth-flake";
src = ./lua/sloth-flake;
buildPhase = ''
dir=lua/sloth-flake
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 sloth-flake]);
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 ? "sloth-flake",
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;
slothFlakeFiles = let
prefix = "nvim/lua/sloth-flake";
in {
${prefix} = {
source = ./lua/sloth-flake;
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
// slothFlakeFiles
// defaultConfig;
};
};
}

18
lib/default.nix Normal file
View File

@ -0,0 +1,18 @@
{version, yants}: let
types = import ./types.nix {inherit yants;};
in {
mkNeovimPkg = import ./mkNeovimPkg.nix {inherit version types;};
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;
};
}

113
lib/deps.nix Normal file
View File

@ -0,0 +1,113 @@
{
pkgs,
lib,
vimUtils,
dependenciesExtraArgs,
types,
...
}: let
inherit (builtins) isPath;
inherit (lib.attrsets) attrNames optionalAttrs;
inherit (lib.lists) concatMap optional;
inherit (lib.strings) concatStringsSep fileContents;
lua = callPackage ./lua.nix {};
callPackage = lib.callPackageWith (pkgs // dependenciesExtraArgs);
defaultPlugin = {
enabled = true;
init = null;
config = null;
};
remotePluginToNeovimPlugin = p:
vimUtils.buildVimPlugin rec {
inherit (p) src name;
pname = name;
};
withPluginDefaults = dep: defaultPlugin // dep;
normalizePlugin = d: let
dep = types.dependency d;
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;
mkRuntimePlugin = {
src,
version,
...
}:
vimUtils.buildVimPlugin ({
inherit src;
}
// (optionalAttrs (isNull version) {
name = "runtime";
})
// (optionalAttrs (! isNull version) {
inherit version;
pname = "runtime";
}));
mkSlothFlakePlugin = version: plugins: let
getLua = type: p: let
content = p.${type};
textContent = textOrContent content;
pluginName =
if p.plugin ? name
then p.plugin.name
else baseNameOf p.plugin;
in
optional (! isNull content)
(lua.wrapSelfInvokingFunction {
section = "${type} for ${pluginName}";
lua = textContent;
});
getAllLua = type:
concatStringsSep "\n"
(concatMap (getLua type) plugins);
in
vimUtils.buildVimPlugin {
inherit version;
pname = "sloth-flake";
src = ../lua/sloth-flake;
buildPhase = ''
dir=lua/sloth-flake
mkdir -p $dir
mv init.lua $dir
cat <<'LUA' > $dir/initialize.lua
${lua.wrapReturnFunction (getAllLua "init")}
LUA
cat <<'LUA' > $dir/config.lua
${lua.wrapReturnFunction (getAllLua "config")}
LUA
'';
};
textOrContent = content:
if isPath content
then fileContents content
else content;
in {
inherit normalizePlugins;
inherit mkSlothFlakePlugin;
inherit mkRuntimePlugin;
inherit textOrContent;
}

14
lib/lua.nix Normal file
View File

@ -0,0 +1,14 @@
{lib, ...}: let
inherit (lib.strings) removeSuffix;
in rec {
wrapFunction = content: "function()\n${content}\nend";
wrapReturnFunction = content: "return ${wrapFunction content}";
wrapSelfInvokingFunction = {
section,
lua,
}: ''
-- begin ${section}
(${wrapFunction (removeSuffix "\n" lua)})();
-- end ${section}
'';
}

44
lib/mkNeovimPkg.nix Normal file
View File

@ -0,0 +1,44 @@
{
version,
types,
}: {
pkgs,
package ? pkgs.neovim-unwrapped,
namePrefix ? "",
nameSuffix ? "",
dependencies ? [],
dependenciesExtraArgs ? {},
runtime ? {},
...
} @ config: let
inherit (builtins) map;
inherit (pkgs) callPackage;
# 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.debug) traceIf traceSeq traceVal traceValSeq traceValFn;
deps = callPackage ./deps.nix {inherit dependenciesExtraArgs types;};
sloth-flake.plugin = deps.mkSlothFlakePlugin version plugins;
runtimePlugin.plugin = deps.mkRuntimePlugin runtime;
plugins = deps.normalizePlugins (dependencies ++ [runtimePlugin sloth-flake]);
extractPlugin = map (p: p.plugin);
customRC = let
rc = ({init ? "", ...}: init) runtime;
in
deps.textOrContent 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
builtins.seq (types.mkNeovimPkgOptions config) pkg // {inherit name;}

95
lib/types.nix Normal file
View File

@ -0,0 +1,95 @@
{yants, ...}: rec {
# The runtime object
runtimeType = with yants;
struct "runtime" {
# The version of the runtime
version = option string;
# The init configuration file
init = option (either path string);
# The content of the runtime directory
src = any;
};
# As simple remote plugin definition
basicPluginType = with yants;
struct "basicPlugin" {
# The name of your plugin.
name = string;
# The sources of your plugin
# TODO What is the type of a source ?
src = any;
};
# The plugin type of dependencies
pluginType = with yants;
# let stringList = list string in
struct "plugin" {
# Whether this plugin should be enabled. This option allows specific
# plugins to be disabled.
# enable = option bool;
# The init configuration of your plugin.
# This should be called before loading your plugin.
init = option (either path string);
# The configuration of your plugin.
# This should be called after loading your plugin.
config = option (either path string);
# Ensure thoses plugins are loaded before the current one
plugin = either drv basicPluginType;
# Ensure thoses plugins are loaded before the current one
dependencies = option (list drv);
# Should this plugin be load lazily ?
# lazy = option bool;
# List of events on which the plugin should be loaded
# events = option stringList;
# List of commands on which the plugin should be loaded
# commands = option stringList;
# List of filetypes on which the plugin should be loaded
# filetypes = option stringList;
# List of keystrokes on which the plugin should be loaded
# keys = option stringList;
# Priority of the module. Influence the order of loading plugins.
# Highest values get loaded before.
# priority = option int;
};
# A dependency.
# TODO Complete doc
dependency = with yants; eitherN [path drv pluginType];
mkNeovimPkgOptions = with yants;
struct "mkNeovimPkgOptions" {
# The configuration of mkNeovimPkg
pkgs = attrs any;
# The neovim package to wrap with your conifguration.
# Default is pkgs.neovim-unwrapped
package = option drv;
# The prefix to add to the name of the package
namePrefix = option string;
# The suffix to add to the name of the package
nameSuffix = option string;
# An array of dependencies.
dependencies = list dependency;
# Extra argument to pass to dependencies files
dependenciesExtraArgs = attrs any;
# Runtime configuration
runtime = runtimeType;
};
}