let flake = builtins.getFlake "/home/lyn/flake"; pkgs = import flake.inputs.nixpkgs {}; lib = pkgs.lib; mapAttrKVs = mapFn: attrs: builtins.foldl' (acc: cur: acc // {${cur.key} = cur.value;}) {} (builtins.attrValues (builtins.mapAttrs mapFn attrs)); #kv = key: value: {inherit key value;}; recurseNaive = curPath: fn: mapAttrKVs (k: v: let match = builtins.match "(.*)[.]nix" k; in if v == "regular" && match != null then {key = builtins.elemAt match 0; value = fn (curPath + ("/" + k));} else if v == "directory" then {key = k; value = recurseNaive (curPath + ("/" + k)) fn;} else {key = null; value = null;} ) (builtins.readDir curPath); getAttrKVsRec = prefix: as: pkgs.lib.flatten (pkgs.lib.mapAttrsToList (k: v: if pkgs.lib.isAttrs v then getAttrKVsRec (prefix ++ [k]) v else [{path = prefix ++ [k]; value = v;}] ) as); getPathKVsRec = prefix: dir: getAttrKVsRec prefix (lib.packagesFromDirectoryRecursive { callPackage = path: x: path; directory = dir; }); unifyMod = (import ./modules-extracted.nix {lib = lib;}).unifyModuleSyntax; transformLocalMod = {path, value}: p: let param = p // { cfg = lib.getAttrFromPath path p.config; }; pathStr = builtins.concatStringsSep "." path; modFn = p: let i = import value; in if lib.isFunction i then i p else i; modUni = unifyMod pathStr pathStr (builtins.removeAttrs modRaw ["opt" "mod"]); meta = modRaw.mod or {}; fileCtx = str: "${modUni._file} (mkLocalMods ${str})"; enablePath = path ++ ["enable"]; merge = cur: upd: runExts = exts: let nul = x: rec { # First pass args = p; # Args to call the module with. This immediately changes the params of `raw`, `mod` etc. through Nix magic deletedKeys = ["opt" "mod"]; # Keys to delete before calling unifyModuleSyntax # Second pass imports = {}; # Put any modules to import as *attributes* here (for other extensions to modify them) raw = modFn x.args; # The raw module result, called with `args` mod = unifyMod pathStr pathStr (builtins.removeAttrs raw x.deletedKeys); # The unified module, e.g. the result of `unifyModuleSyntax .. .. raw`, and has the default module attrs meta = raw.mod or {}; # Equivalent to raw.mod, contains metadata of the module }; firstPass = builtins.foldl' (acc: ext: builtins.foldl' (acc: ext: let acc' = acc // (let acc2 = (ext acc) // acc; in rec { raw = modFn acc2.args; mod = unifyMod pathStr pathStr (builtins.removeAttrs raw acc2.deletedKeys); meta = raw.mod or {}; }); res = lib.recursiveUpdate acc' (ext acc'); in res) exts addMod = c: ctx: newMod: { mod.imports = c.mod.imports ++ [ (newMod // {_file = fileCtx ctx;}) ]; }; defaultExtensions = [ (c: { imports.opt = { name = "`opt` processor"; options = lib.setAttrByPath c.path raw.opt; };}) (c: { imports.enable = { name "`enable` definition"; opt.enable = lib.mkEnableOption (c.meta.desc or c.meta.description or c.meta.name or pathStr); };}) (c: { }) ] imports = [ { _file = fileCtx "`opt` processor"; options = lib.setAttrByPath path modRaw.opt; } { _file = fileCtx "`enable` definition"; options = lib.setAttrByPath enablePath (lib.mkEnableOption (mod.desc or mod.description or mod.name or pathStr)); } ({config, ...}: { _file = fileCtx "config wrapper"; config = lib.mkIf (lib.getAttrFromPath enablePath config) modUni.config; }) ]; newMod = modUni // { imports = modUni.imports ++ imports; config = {}; }; in newMod; mkLocalMods = {prefix ? [], dir}: { _file = "mkLocalMods collector"; imports = builtins.map transformLocalMod (getPathKVsRec prefix dir); }; in cfg: (pkgs.lib.evalModules { modules = [ (mkLocalMods {prefix = ["lyn"]; dir = ./modules;}) cfg ]; })