diff --git a/flake.lock b/flake.lock index 9d9525e..8df0811 100755 --- a/flake.lock +++ b/flake.lock @@ -1,24 +1,6 @@ { "nodes": { "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1753121425, - "narHash": "sha256-TVcTNvOeWWk1DXljFxVRp+E0tzG1LhrVjOGGoMHuXio=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "644e0fc48951a860279da645ba77fe4a6e814c5e", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "flake-parts_2": { "inputs": { "nixpkgs-lib": [ "nixvim", @@ -57,6 +39,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "ixx": { "inputs": { "flake-utils": [ @@ -87,35 +87,20 @@ }, "nixpkgs": { "locked": { - "lastModified": 1753694789, - "narHash": "sha256-cKgvtz6fKuK1Xr5LQW/zOUiAC0oSQoA9nOISB0pJZqM=", + "lastModified": 1760862643, + "narHash": "sha256-PXwG0TM7Ek87DNx4LbGWuD93PbFeKAJs4FfALtp7Wo0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "dc9637876d0dcc8c9e5e22986b857632effeb727", + "rev": "33c6dca0c0cb31d6addcd34e90a63ad61826b28c", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-unstable", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1751159883, - "narHash": "sha256-urW/Ylk9FIfvXfliA1ywh75yszAbiTEVgpPeinFyVZo=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "14a40a1d7fb9afa4739275ac642ed7301a9ba1ab", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, "nixpkgs_2": { "locked": { "lastModified": 1753432016, @@ -132,12 +117,28 @@ "type": "github" } }, + "nixpkgs_3": { + "locked": { + "lastModified": 1760596604, + "narHash": "sha256-J/i5K6AAz/y5dBePHQOuzC7MbhyTOKsd/GLezSbEFiM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "3cbe716e2346710d6e1f7c559363d14e11c32a43", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "nixvim": { "inputs": { - "flake-parts": "flake-parts_2", + "flake-parts": "flake-parts", "nixpkgs": "nixpkgs_2", "nuschtosSearch": "nuschtosSearch", - "systems": "systems_2" + "systems": "systems_3" }, "locked": { "lastModified": 1753878247, @@ -155,7 +156,7 @@ }, "nuschtosSearch": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "ixx": "ixx", "nixpkgs": [ "nixvim", @@ -178,9 +179,10 @@ }, "root": { "inputs": { - "flake-parts": "flake-parts", + "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", - "nixvim": "nixvim" + "nixvim": "nixvim", + "treefmt-nix": "treefmt-nix" } }, "systems": { @@ -212,6 +214,39 @@ "repo": "default", "type": "github" } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1760945191, + "narHash": "sha256-ZRVs8UqikBa4Ki3X4KCnMBtBW0ux1DaT35tgsnB1jM4=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "f56b1934f5f8fcab8deb5d38d42fd692632b47c2", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 212b19f..b7793e0 100755 --- a/flake.nix +++ b/flake.nix @@ -1,47 +1,54 @@ { - description = "A nixvim configuration"; - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05"; nixvim.url = "github:nix-community/nixvim"; - flake-parts.url = "github:hercules-ci/flake-parts"; + + flake-utils.url = "github:numtide/flake-utils"; + treefmt-nix.url = "github:numtide/treefmt-nix"; }; outputs = { + self, + nixpkgs, nixvim, - flake-parts, + flake-utils, + treefmt-nix, ... - } @ inputs: - flake-parts.lib.mkFlake {inherit inputs;} { - systems = [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; + }: + flake-utils.lib.eachDefaultSystem ( + system: let + namespace = "yumevim"; + + pkgs = import nixpkgs {inherit system;}; + mergedLib = pkgs.lib.extend (final: prev: {${namespace} = import ./lib {lib = pkgs.lib;};}); - perSystem = { - pkgs, - system, - ... - }: let nixvimLib = nixvim.lib.${system}; nixvim' = nixvim.legacyPackages.${system}; nixvimModule = { inherit pkgs; - module = import ./config; # import the module directly + module = import ./config; extraSpecialArgs = { + lib = mergedLib.extend nixvim.lib.overlay; + namespace = namespace; }; }; + nvim = nixvim'.makeNixvimWithModule nixvimModule; + + treefmtConfig = {...}: { + projectRootFile = "flake.nix"; + programs = { + alejandra.enable = true; + }; + }; + treefmtEval = treefmt-nix.lib.evalModule pkgs (treefmtConfig {inherit pkgs;}); in { checks = { default = nixvimLib.check.mkTestDerivationFromNixvimModule nixvimModule; + treefmt = treefmtEval.config.build.check self; }; - packages = { - default = nvim; - }; - }; - }; + packages.default = nvim; + } + ); } diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..3df8f5f --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,185 @@ +{lib, ...}: +with lib; rec { + ## Create a NixOS module option. + ## + ## ```nix + ## lib.mkOpt nixpkgs.lib.types.str "My default" "Description of my option." + ## ``` + ## + #@ Type -> Any -> String + mkOpt = type: default: description: + mkOption {inherit type default description;}; + + ## Create a NixOS module option without a description. + ## + ## ```nix + ## lib.mkOpt' nixpkgs.lib.types.str "My default" + ## ``` + ## + #@ Type -> Any -> String + mkOpt' = type: default: mkOpt type default null; + + ## Create a boolean NixOS module option. + ## + ## ```nix + ## lib.mkBoolOpt true "Description of my option." + ## ``` + ## + #@ Type -> Any -> String + mkBoolOpt = mkOpt types.bool; + + ## Create a boolean NixOS module option without a description. + ## + ## ```nix + ## lib.mkBoolOpt true + ## ``` + ## + #@ Type -> Any -> String + mkBoolOpt' = mkOpt' types.bool; + + ## Quickly enable an option. + ## + ## ```nix + ## services.nginx = enabled; + ## ``` + ## + #@ true + enabled = { + enable = true; + }; + + ## Quickly disable an option. + ## + ## ```nix + ## services.nginx = enabled; + ## ``` + ## + #@ false + disabled = { + enable = false; + }; + + ## Recursively nest an attribute set under a list of keys. + ## + ## For example: + ## ```nix + ## mkNestedAttrs { enable = true; } [ "foo" "bar" ] + ## ``` + ## returns: + ## ```nix + ## { foo = { bar = { enable = true; }; }; } + ## ``` + ## + ## @param attrs Attribute set to nest. + ## @param keys List of keys (strings) to nest under. + ## @return Nested attribute set. + mkNestedAttrs = attrs: keys: + if keys == [] + then attrs + else { + "${lib.head keys}" = mkNestedAttrs attrs (lib.tail keys); + }; + + ## Nest an attribute set under a dot-separated namespace string. + ## + ## For example: + ## ```nix + ## mkOptionsWithNamespace "foo.bar" { enable = true; } + ## ``` + ## returns: + ## ```nix + ## { foo = { bar = { enable = true; }; }; } + ## ``` + ## + ## @param namespace A string like "foo.bar.baz". + ## @param options An attribute set to nest under the namespace. + ## @return A nested attribute set. + mkOptionsWithNamespace = namespace: options: + namespace + |> splitString "." + |> mkNestedAttrs options; + + ## Get a deeply nested attribute from a dot-separated path string. + ## + ## For example: + ## ```nix + ## getAttrByNamespace "foo.bar.baz" config + ## ``` + ## is equivalent to: + ## ```nix + ## lib.getAttrFromPath [ "foo" "bar" "baz" ] config + ## ``` + ## + ## @param set The attribute set to query. + ## @param namespace Dot-separated string path. + ## @return The value at the nested path. + getAttrByNamespace = set: namespace: + namespace + |> splitString "." + |> (path: getAttrFromPath path set); + + ## Resolve the IP address of a given host from a devices attribute set. + ## + ## @param devices A set mapping hostnames to their configuration (must include `IP`). + ## @param node The hostname to resolve. + ## @return The IP address for the given node. + ## @throws If the node is not defined in the devices set. + resolveHostIP = devices: node: + if builtins.hasAttr node devices + then devices.${node}.IP + else builtins.throw "Host '${node}' does not exist in the devices configuration."; + + ## Check for configuration conflicts between mount and share declarations. + ## + ## @param shares A list of folder names that are shared. + ## @param hostName The name of the current host. + ## @param folder The folder being mounted or shared. + ## @param host The host the folder is being mounted from. + ## @return Null if valid; throws an error if a conflict is detected. + ## @throws If the host is self-mounting or if the folder appears in both shares and mounts. + checkHostMountConflict = { + shares, + hostName, + }: folder: host: + if host == hostName + then throw "Conflict: Mount host '${host}' cannot be the same as this host '${hostName}' for folder '${folder}'." + else if builtins.elem folder shares + then throw "Conflict: Folder '${folder}' is listed in both shares and mounts. Please resolve." + else null; + + ## Attempt to read a JSON file and return null of not valid JSON. + ## + ## @param path path to the json file to read + ## + ## @return JSON if valid; returns {} if invalid JSON. + readJsonOrEmpty = path: let + result = + path + |> builtins.readFile + |> builtins.fromJSON + |> builtins.tryEval; + in + if result.success + then result.value + else {}; + + ## Safe get for deeply nested keys + ## + ## @param pathStr dot-separated list for the nested attribute to retrieve + ## @param attrs attribute list for getting the keys + ## @return attribute value if found; otherwise null + getIn = pathStr: attrs: let + path = splitString "." pathStr; + go = attrs: p: + if p == [] + then attrs + else let + key = builtins.head p; + rest = builtins.tail p; + in + if builtins.hasAttr key attrs + then go (attrs.${key}) rest + else null; + in + go attrs path; +}